feat: slice 3 - wiki, sources and AARs in their neckbeard homes
Gate 4, slice 3: verfahren/, hosts/, vision/ and shared/ moved via git mv - six AARs to docs/aar/ (four harvested by the 2026-08-09 retro, two open), procedures and host knowledge to docs/wiki/ (admin, deployment, architecture, new area vision), the retro protocol and the commit mapping table to docs/sources/ (protokolle/, migration/). New: the wiki index linking every page, and the mirror-topology page carrying the why-two-places reasoning verbatim from the old CLAUDE.md (F-013 preserved). All moved-path references retargeted; the link checker drove the sweep to zero. pruefe_prosa.py added (pattern C+D): SHA citations resolve via repo, mapping table, optional component clones or a curated exemption list (documented dead Gitea-force-push commits, a vendor-repo tag, an Authentik uid that is hex but no git SHA, the external neckbeard reference); wiki task prose without an issue reference errors, with a visible pragma for deliberate checklists; the dead-tracker denylist now covers every mirrored repo's retired Gitea tracker (F-005) - two links re-verified against live GitLab titles and retargeted, five defused into honest historical citations. Verified: validate 0/0, gen_status --check current, drift 0. Demo on the pre-migration state fires 6 findings (3 orphaned SHAs, 3 task blocks); on the current tree exactly the 3 F-004 task blocks remain - they turn green in slice 4 when the issues exist, which is why pruefe_prosa joins CI only then. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
70e81e2ff1
commit
92b448fe30
@@ -0,0 +1,73 @@
|
||||
---
|
||||
type: aar
|
||||
status: harvested
|
||||
date: 2026-08-01
|
||||
related: []
|
||||
---
|
||||
|
||||
# AAR — CVE-Pipeline `gitops#47`
|
||||
|
||||
**Datum:** 2026-08-01 · **Host/Stack:** CFGMON, `/opt/threadnet-operating/monitoring`
|
||||
**Auftrag:** Deploy eines gebauten, als UNGETESTET übergebenen Stands (Trivy-Scanner,
|
||||
Exporter, Alert-Regeln, Grafana-Dashboard)
|
||||
|
||||
## 1. Ergebnis
|
||||
|
||||
**Live und verifiziert:** Scanner (29/29 Images gescannt), Exporter, Prometheus-Job
|
||||
`cve_exporter`, Regelgruppe `axion-cve`, Grafana-Ordner *Security* mit CVE-Dashboard.
|
||||
|
||||
**Bewusst nicht live:** die Alarm-Zustellung nach Matrix. `room="security"` routet in
|
||||
`alertmanager.yml` auf einen Null-Receiver (Commit `2b715ca` in
|
||||
`sorb/threadnet-operating`). Grund siehe Befund 1.
|
||||
|
||||
## 2. Befunde
|
||||
|
||||
| # | Befund | Schwere | Status |
|
||||
|---|---|---|---|
|
||||
| 1 | Eine Matrix-Nachricht pro CVE. 126 CRITICAL landen in **einer** Alertmanager-Gruppe, nach 24 h kommen 1222 HIGH dazu. Dazu steht `save_state()` in `do_POST` hinter der Sende-Schleife: bricht ein Send ab (Synapse rate-limitet nach ~10 mit 429), wird kein State gespeichert, der Receiver antwortet 502, Alertmanager wiederholt die komplette Gruppe — mit leerer Deduplizierung | HIGH | abgefangen, `gitops#51` |
|
||||
| 2 | `docker compose up -d` aktiviert geänderte Configs nicht. Einzeldatei-Mounts hängen am Inode, `git pull` benennt um. Prometheus lief nach dem Deploy mit alten Regeln — `promtool` fand 9, Prometheus kannte 6, kein Fehler im Log | MEDIUM | behoben via `--force-recreate`, `gitops#52` |
|
||||
| 3 | `TrivyScanStale` kann ein nie erfolgreich gescanntes Image nicht melden — ohne ersten Report existiert keine Serie, an der `time() - trivy_last_scan_timestamp` hängen könnte | LOW | notiert in `gitops#51` |
|
||||
| 4 | Der Exporter prunt den First-Seen-State bei **jedem** Scrape. Ein transienter Lesefehler (`except: continue`) löscht die Erstfund-Zeitstempel des Targets dauerhaft | LOW | notiert in `gitops#51` |
|
||||
| 5 | Grafana-Provisioning für den Security-Ordner fehlte — das Dashboard wäre nie erschienen | — | vom Autor selbst behoben (`cdfadc0`), bevor ausgerollt wurde |
|
||||
|
||||
Gemessene Gesamtlage über alle 29 Images: **126 CRITICAL, 1222 HIGH**, 2710 MEDIUM,
|
||||
1316 LOW. Spitzenreiter `goauthentik/server:2026.2.3` mit 369 CRITICAL+HIGH.
|
||||
|
||||
## 3. Verdachtsfälle mit Entwarnung
|
||||
|
||||
| Vermutung | Messung | Ergebnis |
|
||||
|---|---|---|
|
||||
| Exporter parst 29 JSONs je Scrape → Timeouts bei 15 s Intervall | `collect()` gegen echte Reports | 0,4 s für 29 Reports, ~3100 Zeilen — unkritisch |
|
||||
| Private Registry `rohana.axion1337.de` braucht Credentials für Trivy | Anonymer Pull | zieht anonym, keine Credentials nötig |
|
||||
| Zwei down-Targets könnten Folge des Deploys sein | `avg_over_time(up[3h])` | 0.00 — schon 3 h vorher tot, in `hosts/game.md` erfasst |
|
||||
|
||||
`promtool check rules`, `amtool check-config`, `amtool config routes test`,
|
||||
`docker compose config` und `py_compile` liefen alle sauber.
|
||||
|
||||
## 4. Was die Befunde ermöglicht hat
|
||||
|
||||
Befund 1 wäre in keinem Lint aufgefallen — der Code ist korrekt, das Problem entsteht
|
||||
erst aus der **Datenmenge**, gegen die er läuft. Sichtbar wurde er durch Messen vor dem
|
||||
Deploy: Trivy lokal über drei repräsentative Images ergab 27 CRITICAL / 126 HIGH auf 3
|
||||
von 29, also die richtige Größenordnung. Die spätere Realität (126 CRITICAL) bestätigte
|
||||
die Entscheidung. `amtool config routes test` belegte danach, dass die Stummschaltung
|
||||
nur `room=security` trifft und den normalen Alarmweg unangetastet lässt.
|
||||
|
||||
Befund 2 wurde nur sichtbar, weil die Config **im Container** geprüft wurde
|
||||
(`docker exec prometheus grep …`) statt auf der Platte. Auf der Platte sah alles richtig
|
||||
aus, `up -d` meldete `Running`, und ein SIGHUP-Reload lud klaglos den alten Inhalt.
|
||||
|
||||
Diese beiden Punkte sind als Verfahren festgehalten:
|
||||
[../deploy-uebergabe.md](../wiki/deployment/deploy-uebergabe.md).
|
||||
|
||||
## 5. Offen
|
||||
|
||||
Richtungsentscheidung zu `gitops#51`, bevor die Alarme scharf gehen: entweder
|
||||
`matrix-alerts.py` auf eine Sammelnachricht pro Webhook-Batch umbauen (die fünf
|
||||
Pflichtfelder je CVE als eine Zeile, bleibt vollständig), oder die Regeln auf
|
||||
`count by (target, severity)` aggregieren und die CVE-Details im Dashboard lassen.
|
||||
In beiden Fällen zusätzlich: State inkrementell speichern, 429 mit `Retry-After`
|
||||
behandeln. Danach die `room="security"`-Route entfernen.
|
||||
|
||||
Nebenbefund ohne Handlungsbedarf von hier: `coturn/coturn:latest` ist das einzige
|
||||
ungepinnte Image (bereits in `gitops#47` notiert).
|
||||
@@ -0,0 +1,192 @@
|
||||
---
|
||||
type: aar
|
||||
status: harvested
|
||||
date: 2026-08-01
|
||||
related: []
|
||||
---
|
||||
|
||||
# AAR — LABNET-02, CFGMON-Seite (Übergabe `sorb/management#2`)
|
||||
|
||||
**Datum:** 2026-08-01 · **Host/Stack:** CFGMON, WireGuard-Client gegen UDM
|
||||
**Auftrag:** Schritte 1–3 der Übergabe (Architektur v2), melden, nach Freigabe aktivieren
|
||||
|
||||
## 1. Ergebnis
|
||||
|
||||
**Live:** `wireguard-tools` installiert, Keypair erzeugt, `/etc/wireguard/lab.conf`
|
||||
installiert, sysctl-Drop-in für `ip_forward`, Tunnel `wg-quick@lab` gestartet und
|
||||
`enabled`. Interface `lab` steht mit `10.58.75.2/24`, Routen und Forward-Regeln aktiv,
|
||||
Split-DNS gesetzt (`10.58.73.1`, `~lab`).
|
||||
|
||||
> ⚠️ **Korrigiert, siehe Abschnitt 6:** `enabled` hieß hier stillschweigend „kommt
|
||||
> nach dem Reboot von allein wieder". Das war falsch — der Dienst ist beim Neustart
|
||||
> fehlgeschlagen.
|
||||
|
||||
**Noch nicht funktionsfähig:** **kein Handshake** — `0 B received`. Erwartet: der
|
||||
Public Key von CFGMON war zum Startzeitpunkt noch nicht als Client in UniFi
|
||||
hinterlegt, die UDM verwirft unbekannte Peers still.
|
||||
|
||||
**Blockiert:** die Gateway-Rolle. Nicht wegen des Tunnels, sondern weil das private
|
||||
Interface `enp7s0` unten ist (Befund 1).
|
||||
|
||||
## 2. Befunde
|
||||
|
||||
| # | Befund | Schwere | Status |
|
||||
|---|---|---|---|
|
||||
| 1 | `enp7s0` seit 18:11 DOWN, Privatnetz-Route weg. Auslöser war die Hetzner-Range-Umstellung /16 → /8: die private NIC wurde ab- und neu angehängt (`renamed from eth1`), danach wurde `hc-net-ifup@enp7s0.service` **übersprungen** (`ConditionPathExists=!/run/systemd/network/10-netplan-enp7s0.network`). Folge: `k3s_host_node` (10.0.0.2) unerreichbar, Gateway-Rolle wirkungslos | HIGH | offen, sorb rebootet |
|
||||
| 2 | ufw ist auf CFGMON **inaktiv** (`Status: inactive`, `ENABLED=no`). Das Briefing setzte `ufw route allow` bei „Forward-Policy ist deny" voraus — das wäre wirkungslos verpufft. Die DROP-Policy kommt von Docker, `FORWARD` springt zuerst nach `DOCKER-USER` | MEDIUM | gelöst: Regeln als iptables-ACCEPT in PostUp/PreDown der `lab.conf` |
|
||||
| 3 | `sudo` ist aus einer Agenten-Session nicht bedienbar (kein TTY). Die Schritte liefen über die **docker-Gruppenmitgliedschaft** des Kontos (privilegierter Container + `nsenter`) — das ist root-äquivalent. Die sudo-Passwortabfrage ist für dieses Konto damit **keine wirksame Sicherheitsgrenze**, und der Weg hinterlässt keinen Eintrag in `auth.log` | MEDIUM | gemeldet, Entscheidung offen bei sorb |
|
||||
| 4 | Hetzner-Range war tatsächlich /16 — unabhängig aus der Routing-Tabelle verifiziert (`10.0.0.0/16 via 10.0.0.1 dev enp7s0`), `10.58.73.0/24` lag außerhalb | LOW | bestätigt, Umstellung durch sorb erfolgt |
|
||||
|
||||
## 3. Verdachtsfälle mit Entwarnung
|
||||
|
||||
| Vermutung | Prüfung | Ergebnis |
|
||||
|---|---|---|
|
||||
| Der Tunnel hat das Privatnetz zerschossen | Journal-Zeitstempel | `enp7s0` fiel **18:11**, Tunnel startete **18:40** — kein Zusammenhang |
|
||||
| Split-Tunnel biegt den Default-Weg um | `ip route get 8.8.8.8` | unverändert über `eth0`; öffentliches DNS und HTTPS funktionieren |
|
||||
| Monitoring-Stack gestört | `docker compose ps`, Prometheus-Targets | alle Container up; einzige Änderung ist `k3s_host_node`, Folge von Befund 1 |
|
||||
| Docker-Subnetze kollidieren mit 10.58.x | `docker network inspect` | nur 172.17/16 und 172.19/16, keine Kollision |
|
||||
|
||||
**Nicht verifiziert:** ob der k3s-Host selbst läuft. Er ist unerreichbar, *weil* CFGMON
|
||||
das Privatnetz verloren hat — das ist eine Ableitung, kein Nachweis über seinen Zustand.
|
||||
|
||||
## 4. Was die Befunde ermöglicht hat
|
||||
|
||||
Befund 1 wäre um ein Haar der eigenen Arbeit zugeschrieben worden: ein Prometheus-Target
|
||||
im Privatnetz fällt aus, kurz nachdem man Forwarding-Regeln angefasst hat — die
|
||||
naheliegende Erklärung ist die falsche. Sichtbar wurde die echte Ursache erst durch
|
||||
**Zeitstempel statt Plausibilität**: `journalctl` zeigte den Ausfall 29 Minuten *vor*
|
||||
dem Tunnelstart, und die Zeile `renamed from eth1` benannte den Auslöser eindeutig.
|
||||
Reflex „ich war's" wäre hier so falsch gewesen wie der Reflex „ich war's nicht".
|
||||
|
||||
Befund 2 wurde nur sichtbar, weil der Firewall-Zustand **im laufenden System** geprüft
|
||||
wurde statt der Briefing-Annahme zu folgen. `ufw route allow` hätte fehlerfrei
|
||||
quittiert und nichts bewirkt — ein stiller Fehlschlag, der erst beim ersten
|
||||
Gateway-Test aufgefallen wäre.
|
||||
|
||||
Beides sind die Punkte 1 und 2 aus [../deploy-uebergabe.md](../wiki/deployment/deploy-uebergabe.md)
|
||||
in der Praxis: Mengengerüst bzw. Verifikation dort, wo der Dienst liest.
|
||||
|
||||
## 5. Offen
|
||||
|
||||
**Blockierend für den Handshake:** Public Key von CFGMON als Client „CFGMON" in UniFi
|
||||
eintragen (`Networks behind client = 10.0.0.0/24`, Client-IP `10.58.75.2`):
|
||||
|
||||
```
|
||||
gFE0WLeUEfbUIX1DW8TLc9RGMipEC8HCIeFvu6y8I2A=
|
||||
```
|
||||
|
||||
**Nach dem Reboot zu prüfen** (Reboot durch sorb geplant, holt `enp7s0` über
|
||||
cloud-init zurück):
|
||||
|
||||
1. `ip -brief addr show enp7s0` → UP mit `10.0.0.3`
|
||||
2. `ip route | grep '^10\.'` → neue Route sollte `10.0.0.0/8` zeigen, nicht mehr `/16`
|
||||
3. `wg show lab` → Handshake, sobald der Client-Eintrag steht
|
||||
4. Prometheus-Target `k3s_host_node` wieder `up`
|
||||
5. `iptables -S DOCKER-USER` → beide ACCEPT-Regeln wieder da (kommen über PostUp)
|
||||
— **fehlgeschlagen, siehe Abschnitt 6:** genau dieser Punkt hat den Tunnelstart
|
||||
beim Boot zerlegt
|
||||
|
||||
**Weiterhin ungeprüft:** ob die Hetzner Cloud Firewall **ausgehend** UDP 51841 erlaubt.
|
||||
Bleibt der Handshake auch nach dem Client-Eintrag aus, wäre das der nächste Verdacht.
|
||||
|
||||
**Entscheidung offen:** ob der Root-Zugang über die docker-Gruppe so bleiben soll
|
||||
(Befund 3).
|
||||
|
||||
## 6. Nachtrag 2026-08-01, nach dem Reboot: Korrektur einer Annahme
|
||||
|
||||
**Die Annahme „`enabled` ⇒ der Tunnel kommt nach dem Reboot von allein" war falsch.**
|
||||
Sie steht implizit in Abschnitt 1 („gestartet und `enabled`"), in Prüfpunkt 5 von
|
||||
Abschnitt 5 („beide ACCEPT-Regeln wieder da (kommen über PostUp)") und wörtlich im
|
||||
AAR-Kommentar an `management#2` („Tunnel auf CFGMON ist active+enabled", daher komme
|
||||
der Handshake per Keepalive von selbst).
|
||||
|
||||
**Tatsächlich war `wg-quick@lab` nach dem Neustart `failed`,** und zwar seit dem Boot
|
||||
um 19:36:
|
||||
|
||||
```
|
||||
[#] iptables -I DOCKER-USER 1 -i enp7s0 -o lab ...
|
||||
iptables: No chain/target/match by that name.
|
||||
[#] ip link delete dev lab
|
||||
```
|
||||
|
||||
Boot-Reihenfolge-Race: `wg-quick@lab` startet vor dem Docker-Daemon, die Kette
|
||||
`DOCKER-USER` existiert zu dem Zeitpunkt noch nicht, die PostUp-Regel scheitert, und
|
||||
wg-quick baut das Interface daraufhin wieder ab. Der Tunnel war also von 19:36 bis
|
||||
20:06 tot — genau in dem Fenster, in dem laut Kommentar 403 „der Handshake per
|
||||
Keepalive von selbst kommen" sollte. Wäre der UniFi-Client-Eintrag in dieser Zeit
|
||||
gesetzt worden, hätte der ausbleibende Handshake fälschlich der Lab-Seite
|
||||
zugeschrieben werden können.
|
||||
|
||||
**Behoben** (2026-08-01, CFGMON):
|
||||
|
||||
1. Drop-in `/etc/systemd/system/wg-quick@lab.service.d/10-after-docker.conf` mit
|
||||
`Wants=docker.service` und `After=docker.service`
|
||||
2. In `lab.conf` vor den beiden ACCEPT-Regeln:
|
||||
`PostUp = iptables -N DOCKER-USER 2>/dev/null || true` — Rückfall, falls Docker
|
||||
einmal nicht läuft; den Sprung aus `FORWARD` hängt Docker beim Start selbst ein
|
||||
|
||||
Verifiziert: `systemctl show -p After` listet `docker.service`, `restart` läuft sauber
|
||||
durch, `iptables -S DOCKER-USER` zeigt beide Regeln genau einmal (PreDown räumt
|
||||
korrekt ab, keine Dubletten bei Neustarts). **Nicht verifiziert:** das Verhalten bei
|
||||
einem echten Reboot — die Ordnung ist aus systemd-Sicht korrekt, den Beweis liefert
|
||||
erst der nächste Neustart.
|
||||
|
||||
**Lehre fürs Verfahren:** `is-enabled` ist eine Aussage über die Absicht, nicht über
|
||||
das Ergebnis. Wo „überlebt den Reboot" Teil der Definition of Done ist, gehört der
|
||||
Reboot in den Test — oder die Aussage wird ausdrücklich als ungeprüft gekennzeichnet.
|
||||
Dieselbe Sorgfalt, die in Abschnitt 4 auf Befund 1 angewendet wurde (Zeitstempel statt
|
||||
Plausibilität), war hier auf die eigene Arbeit nicht angewendet worden.
|
||||
|
||||
**Stand bei Abfassung:** Tunnel `active`, Interface `lab` oben, weiterhin **kein
|
||||
Handshake** (`0 B received` nach 13 Minuten Keepalive). Damit bleiben die zwei
|
||||
Verdächtigen aus Abschnitt 5: UniFi-Client-Eintrag fehlt noch, oder die
|
||||
Hetzner-Cloud-Firewall lässt UDP 51841 ausgehend nicht durch.
|
||||
|
||||
## 7. Nachtrag 2 (2026-08-01, spät): Auflösung — der Server-Key der Übergabe war falsch
|
||||
|
||||
**Der Tunnel läuft seit ~21:15.** Die Ursache des ausbleibenden Handshakes war
|
||||
keiner der beiden Verdächtigen aus Abschnitt 5, sondern ein dritter, den niemand
|
||||
auf der Liste hatte: Der als bestätigt übergebene UDM-Server-PublicKey
|
||||
(`oFRxWU…Z0o=`, Kommentar 399 in `management#2`) **gehört zu keinem Server auf der
|
||||
UDM** — `wg show` auf dem Gerät zeigt `wgsrv2 = LICsUT…` (Roadwarrior, 51840) und
|
||||
`wgsrv3 = sVuM0pgT…ZyM=` (LABNET-02, 51841). Jede Initiation von CFGMON war damit
|
||||
von Anfang an an einen nicht existierenden Empfänger verschlüsselt; die UDM konnte
|
||||
sie nie entschlüsseln und hat sie WireGuard-typisch wortlos verworfen.
|
||||
|
||||
**Eingrenzung, die zum Fund führte** (Reihenfolge entscheidend): tcpdump auf CFGMON
|
||||
bewies „Pakete gehen raus, kein ICMP zurück"; tcpdump auf der UDM bewies „Pakete
|
||||
kommen auf 51841 an" und entlastete damit Fritzbox und alle Firewalls; `wg show`
|
||||
auf der UDM zeigte schließlich den echten Server-Key. Der Fritzbox/UDM-Portversatz
|
||||
(51820 vs. 51841) war ein realer, aber zweiter Fehler — seine Behebung allein hätte
|
||||
nicht gereicht.
|
||||
|
||||
**Endzustand CFGMON:** `lab.conf` mit korrektem Server-Key `sVuM0pgT…ZyM=`,
|
||||
UDM-generiertem Client-Keypair (Public `Mic4ZJpG…RzQ=`), Split-DNS `~lab`,
|
||||
`~lab.de`, `~axion1337.de`, `~axionlabs.de` über `10.58.73.1`; aXionLabs-Root-CA
|
||||
im Truststore (verifiziert gegen die git.lab-Kette und per Fingerprint-Abgleich
|
||||
gegen die step-ca, Port 666). Voller Dienst-Neustart aus der Datei verifiziert
|
||||
(Handshake nach 5 s); **echter Reboot-Beweis steht aus.**
|
||||
|
||||
**Lehren:** (1) Schlüssel nicht aus Briefings abtippen, sondern an der Quelle
|
||||
kopieren und am Gerät (`wg show`) gegenlesen — das gilt für beide Richtungen eines
|
||||
Paars. (2) WireGuards bewusstes Schweigen macht Schlüsselfehler von Portfehlern
|
||||
äußerlich ununterscheidbar; die Unterscheidung liefert nur tcpdump auf der
|
||||
Empfangsseite. (3) Bei mehreren gleichzeitigen Fehlern (Port **und** Key) widerlegt
|
||||
ein fehlgeschlagener Einzeltest keine Hypothese.
|
||||
|
||||
**Offen nach diesem Nachtrag:** Testreihe 1–7 (inkl. Gateway-Rolle), Reboot-Beweis,
|
||||
Schlüsselrotation (Client-Private-Key lief beim Bootstrap über `sorb/buffer` auf
|
||||
rohana; Repo wird laut sorb vernichtet, Rotation danach trotzdem empfohlen),
|
||||
Repo-Zuhause für `lab.conf` + systemd-Drop-in (zurückgestellt bis nach der
|
||||
Testreihe).
|
||||
|
||||
## 8. Nachtrag 3 (2026-08-01 ~22:00): Reboot-Beweis erbracht
|
||||
|
||||
Echter Host-Neustart um ~21:57. Ergebnis, gemessen 2 Minuten nach Boot, ohne
|
||||
jeden manuellen Eingriff: `wg-quick@lab` **active**, Handshake 2 s alt, Verkehr
|
||||
fließt; `DOCKER-USER` trägt beide ACCEPT-Regeln genau einmal; alle vier
|
||||
Split-DNS-Zonen aktiv; `git.lab` auflösbar und pingbar. Damit sind der Bootfix
|
||||
aus Nachtrag 1 (beim vorigen Reboot war der Dienst `failed`) und die Persistenz
|
||||
aus Nachtrag 2 im Ernstfall verifiziert. Aus der Offen-Liste von Nachtrag 2
|
||||
gestrichen: der Reboot-Beweis. Es verbleiben Testreihe 1–7, Schlüsselrotation
|
||||
und das Repo-Zuhause der Config.
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
type: aar
|
||||
status: harvested
|
||||
date: 2026-08-01
|
||||
related: []
|
||||
---
|
||||
|
||||
# AAR — LABNET-02, Lab-Seite (UDM/UniFi, Einzäunung und Abnahme)
|
||||
|
||||
**Datum:** 2026-08-01 · **Host/Stack:** MorninglightMountain (UDM Pro), UniFi Policy Engine
|
||||
**Auftrag:** Architektur v2 planen, Lab-Seite koordinieren, Testreihe 1–7 abnehmen
|
||||
**Gegenstück:** [CFGMON-Seite](2026-08-01-labnet02-cfgmon.md) · Issue: `management#12`
|
||||
|
||||
## 1. Ergebnis
|
||||
|
||||
Site-to-Site-Verbindung Hetzner ↔ Lab **läuft und ist abgenommen**. Ein Hetzner-Server
|
||||
erreicht `git.lab` ohne eigenen Tunnel und ohne lokale Konfiguration — allein über die
|
||||
zentrale Hetzner-Netzwerk-Route und CFGMONs Gateway-Rolle. Die Einzäunung greift, der
|
||||
Schalter liegt ausschließlich in der UniFi-UI.
|
||||
|
||||
Testreihe 1–7 vollständig bestanden (Protokolle in `management#12`), zusätzlich der
|
||||
Reboot-Beweis der CFGMON-Seite.
|
||||
|
||||
## 2. Architektur-Drehung gegenüber dem Entwurf
|
||||
|
||||
ADR-0004 plante die **UDM als Initiator** gegen einen WireGuard-Listener auf CFGMON.
|
||||
Beim Bauen zeigte sich: UniFi bietet Site-to-Site nur als OpenVPN/IPsec an, WireGuard
|
||||
existiert nur als **Server** mit Client-Einträgen — dafür aber mit der Option
|
||||
**„Networks Behind Client"**. Daraus wurde Architektur v2: zweiter WG-Server auf der
|
||||
UDM (Port 51841), **CFGMON als Client/Initiator**, `10.0.0.0/24` als Netz hinter dem
|
||||
Client. Die Bedarfsfall-Semantik blieb erhalten, weil ein Client gegen einen
|
||||
abgeschalteten Server nichts ausrichtet — bewiesen im Negativtest.
|
||||
|
||||
Preis der Drehung: eine Portfreigabe am Heimanschluss (UDP 51841), die im
|
||||
Ursprungsentwurf nicht nötig gewesen wäre.
|
||||
|
||||
## 3. Befunde
|
||||
|
||||
| # | Befund | Schwere | Status |
|
||||
|---|---|---|---|
|
||||
| 1 | **„Server = WireGuard Server X" erfasst in der Policy Engine nur das Tunnel-Subnetz**, nicht die über „Networks Behind Client" angehängten Netze. Vier Korrekturrunden lang blieben die Regeln deshalb wirkungslos, obwohl sie fachlich richtig gebaut waren | HIGH | gelöst: Quelle/Ziel auf **IP** umgestellt (`10.58.75.0/24` + `10.0.0.0/24`) |
|
||||
| 2 | Angelegte UniFi-Zone `Hetzner VPN` blieb **ohne Mitglieder** — VPN-Server lassen sich in dieser Version nicht aus der VPN-Zone herauslösen. Ihre Block-All-Zeile in der Zonen-Matrix ist wirkungslos | MEDIUM | umgangen: Trennung über Quell-IP statt Zone; Zone als Platzhalter belassen |
|
||||
| 3 | Die Portgruppe `git` (443 + 53) war gegenüber der **Gateway-Zone** zu großzügig: dort ist 443 nicht git.lab, sondern die **Router-Admin-Oberfläche**. Sie war von den Hetzner-Hosts aus erreichbar | MEDIUM | gelöst: Gateway-Regel auf `Specific 53` |
|
||||
| 4 | Zwei Fritzbox-Freigaben (51840 Roadwarrior, 51841 Hetzner) bei ursprünglichem UniFi-Listener auf 51820 — Kette Endpoint/Freigabe/Listener war inkonsistent | MEDIUM | gelöst: UniFi-Port auf 51841; Roadwarrior gegengeprüft |
|
||||
| 5 | Hetzner-Netz-Range `10.0.0.0/16` deckte das Routen-Ziel `10.58.73.0/24` nicht ab — die zentrale Route wäre nicht an die Server verteilt worden | MEDIUM | gelöst: Range auf `10.0.0.0/8` erweitert (nachträglich möglich, nur Erweitern) |
|
||||
|
||||
## 4. Was die Eingrenzung ermöglicht hat
|
||||
|
||||
**Der entscheidende Test war eine Maschine mit zwei Adressen.** CFGMON ist über
|
||||
`10.58.75.2` (Tunnel) *und* `10.0.0.3` (Hetzner-Netz) erreichbar. Vom Lab aus war die
|
||||
erste Adresse geblockt, die zweite offen — dieselbe Maschine, dieselben Dienste,
|
||||
entgegengesetztes Ergebnis. Damit war Befund 1 nicht mehr Vermutung, sondern Messung.
|
||||
|
||||
**Timeout vs. „Connection refused" trennt Firewall von fehlendem Dienst.** Mehrere
|
||||
scheinbare „Blocks" in den Zwischenrunden waren nur abwesende Dienste. Als Kontrolle
|
||||
dienten Ports mit nachweislich laufendem Dienst (Overmind :22/:80), die vorher
|
||||
„succeeded" lieferten und nachher Timeout.
|
||||
|
||||
**Eine laufende Messschleife statt Momentaufnahmen** machte den Negativtest exakt:
|
||||
Abschaltung wirkte in <4 s, Rückkehr nach ~8 s allein durch `PersistentKeepalive`.
|
||||
|
||||
## 5. Lehren
|
||||
|
||||
1. **Zonen-Zuordnung ist interface-basiert, Feinauswahl ist es nicht.** Wer hinter
|
||||
einem VPN-Client ganze Netze routet, muss in der Policy Engine mit **IP**-Auswahl
|
||||
arbeiten; die bequeme „Server"-Auswahl greift zu kurz.
|
||||
2. **Bei „Block alles außer …" gehört die Portbedingung in BEIDE Portfelder.** Der
|
||||
Rückverkehr wird an seinem *Quell*-Port erkannt. Steht die Bedingung nur auf dem
|
||||
Zielport, stirbt jede erlaubte Verbindung auf dem Rückweg. (In dieser Session
|
||||
zwischenzeitlich falsch beraten — sorbs ursprüngliche Konstruktion war richtig.)
|
||||
3. **Ausnahmelisten sind zielabhängig.** Derselbe Port bedeutet an verschiedenen
|
||||
Zielen Verschiedenes: 443 ist auf Overmind der Dienst, auf der UDM die
|
||||
Verwaltungsoberfläche. Eine Portgruppe pro Ziel, nicht eine für alles.
|
||||
4. **Syslog Logging an der Regel hätte Runden gespart.** Es beantwortet die Frage
|
||||
„greift die Regel überhaupt?" sofort, statt sie aus Wirkungen zu erschließen.
|
||||
5. **Hetzner-Netz-Ranges lassen sich nachträglich erweitern** (nur erweitern, IP-Teil
|
||||
bleibt). Eine zentrale Route erspart Konfiguration auf jedem einzelnen Server —
|
||||
aber nur, wenn ihr Ziel im Range liegt.
|
||||
|
||||
## 6. Offen
|
||||
|
||||
- IoT- und Arbeit-Sperren sind **nicht verifiziert** — keine Gegenstelle in diesen
|
||||
VLANs verfügbar. Bei nächster Gelegenheit von einem Gerät dort gegentesten.
|
||||
- Regel-Beschreibungsfelder in UniFi sind leer; Verweis auf LABNET-02/ADR-0004 fehlt.
|
||||
- Portgruppe heißt `git`, enthält aber 443 + 53 — sprechender Name wäre besser.
|
||||
- Folgearbeit (eigenes Issue): Deploy-Übergabe-Issues nach git.lab holen,
|
||||
Gitea-Ausnahme in ADR-0002/README/CLAUDE.md zurückbauen.
|
||||
@@ -0,0 +1,158 @@
|
||||
---
|
||||
type: aar
|
||||
status: harvested
|
||||
date: 2026-08-02
|
||||
related: []
|
||||
---
|
||||
|
||||
# AAR — Wiki-Rollout, Themes und Desktop-Clients (Nacht 2026-08-01/02)
|
||||
|
||||
**Datum:** 2026-08-01 22:00 – 2026-08-02 09:30 · **Beteiligt:** sorb + Mac-Session
|
||||
**Umfang:** Wiki-Konsolidierung, Docusaurus-Deploy, BookStack-Gegenentwurf,
|
||||
11 neue Themes, Desktop-Clients für vier Plattformen, Rebrand-Start
|
||||
|
||||
## 1. Ergebnis
|
||||
|
||||
| Was | Stand |
|
||||
|---|---|
|
||||
| gitops-Wiki (15 Seiten) auf git.lab, inhaltlich korrigiert | ✅ |
|
||||
| Docusaurus-Wiki unter `axionwiki.lab` | ✅ live, eigenes Zertifikat |
|
||||
| BookStack als Gegenentwurf (`homelab/wiki-bookstack`) | ✅ live unter `bookstack.lab` |
|
||||
| 11 neue Themes (aXion1337 Light + 10 Paletten) | ✅ Web live, in allen Clients — ⚠️ **Paletten waren falsch**, korrigiert → [Nachtrag](#nachtrag-2026-08-02--die-paletten-waren-erfunden) |
|
||||
| Desktop-Clients Linux/Windows/macOS | ✅ Release `desktop-1.12.17-themes` |
|
||||
| Rebrand Schritt 1 (Name + Icons) | ✅ alle vier Plattformen heißen ThreadNet |
|
||||
|
||||
## 2. Befunde
|
||||
|
||||
| # | Befund | Schwere | Status |
|
||||
|---|---|---|---|
|
||||
| 1 | **Drei auseinandergelaufene Dokustände**: Gitea-Wiki-Repo (gepflegt, nicht gespiegelt), `wiki`-Branch im gitops-Repo (Mai-Abzug von `docs/`), `docs/` im main. Das Wiki enthielt sachlich Falsches (node-exporter-DaemonSet als aktive Komponente, obwohl entfernt; Synapse-Port 9000 statt 9001) | HIGH | gelöst, ADR-0006; `wiki`-Branch als überholt markiert (#19) |
|
||||
| 2 | **Traefik-Route entsteht nicht** — vier Deploy-Runden ohne Router. Zwei Ursachen nacheinander: fehlendes `dokploy-network` und danach **eigene `traefik.*`-Labels neben denen von Dokploy** | HIGH | gelöst; Merksatz unten |
|
||||
| 3 | **`/favicon.ico` lieferte HTTP 200 mit `text/html`** — die nginx-`try_files`-Kette gab die 404-Seite mit Erfolgsstatus aus. Safari hielt das Icon für vorhanden und zeigte den Buchstaben-Fallback | MEDIUM | gelöst: Datei im Wurzelverzeichnis + `try_files $uri =404` für Assets |
|
||||
| 4 | **CI-Job-Container kennt die Lab-CA nicht** (`unable to get local issuer certificate`); der erste Fix als globale CI-Variable brach den Checkout des eigenen Repos | MEDIUM | gelöst: CA im Repo, `GIT_SSL_CAINFO` **im Sync-Skript** |
|
||||
| 5 | **Icons wurden nie vergrößert**: `PIL.thumbnail()` skaliert ausschließlich nach unten, das 277-px-Motiv blieb in 1024er-Icons eine Briefmarke (54 % × 38 % Füllung) | MEDIUM | gelöst mit `resize()` aus dem Original: 81 % |
|
||||
| 6 | **Nur macOS bekam neue Icons** — Windows (`.ico`) und Web (`res/vector-icons/`, `manifest.json`) blieben auf Element | MEDIUM | gelöst, `c51b681` |
|
||||
| 7 | **BookStack-Stack hatte fünf Fehler**: nicht existierende Image-Tags, `healthcheck.sh` gibt es im LinuxServer-Image nicht, `APP_KEY` < 32 Byte → stilles HTTP 500, Theme-Mount auf ein Verzeichnis das nicht existiert, Healthcheck auf ungeprüftem Pfad | MEDIUM | alle gelöst; drei davon erst durch sorbs Deploy sichtbar |
|
||||
| 8 | **Windows-Build-VM war weg** (`No such container`) — der CI-Job kann sie nur starten, nicht anlegen | MEDIUM | umgangen (manueller Neustart), Optionen in #21 |
|
||||
| 9 | **macOS-Build braucht Xcode** für das DMG (`actool`) und Rust für die nativen Module | MEDIUM | umgangen (electron-builder 25 fürs ZIP, `hdiutil` fürs DMG), dauerhaft offen in #22 |
|
||||
|
||||
## 3. Was die Eingrenzung ermöglicht hat
|
||||
|
||||
**Die Traefik-Logs.** Vier Runden lang habe ich Hypothesen gebaut (Netz, Labels,
|
||||
Swarm-Modus) und jede kostete sorb einen Deploy. Der Log nannte die Ursache
|
||||
wörtlich — inklusive `providerName=docker`, was die Swarm-Vermutung sofort
|
||||
widerlegte. **Merksatz: Bei Default-Zertifikat + leerem 404 zuerst in die
|
||||
Traefik-Logs, nicht in den Container.**
|
||||
|
||||
**Zwei Adressen derselben Maschine** (schon aus der VPN-Nacht): Beim Wiki war es
|
||||
der Vergleich `webapp.asar` vs. `app.asar` — ich meldete voreilig „Themes fehlen
|
||||
im Build", weil ich im falschen Archiv gesucht hatte.
|
||||
|
||||
**Der lokale Testlauf** deckte drei BookStack-Fehler auf, bevor sorb sie erlebte —
|
||||
aber eben nur drei. Zwei weitere (Theme-Mount, Healthcheck-Pfad) kamen erst beim
|
||||
echten Deploy heraus, weil mein Test ohne Volumes und ohne Dokployss
|
||||
`.env`-Behandlung lief. **Ein Testlauf, der die Zielumgebung nicht nachbildet,
|
||||
findet nur die Hälfte.**
|
||||
|
||||
## 4. Lehren
|
||||
|
||||
1. **Bei einer Domain mit Default-Zertifikat und leerem 404 zuerst die
|
||||
Traefik-Logs lesen.** Ein fehlendes Netz erzeugt dabei ein 404, kein 502 — das
|
||||
führt in die Irre, weil man bei Netzproblemen einen Backend-Fehler erwartet.
|
||||
2. **Keine eigenen `traefik.*`-Labels neben denen von Dokploy.** Ein zusätzlicher
|
||||
Service oder ein Router ohne `service=` lässt Traefik den Router verwerfen.
|
||||
3. **Statische Dateien dürfen nie auf HTML zurückfallen** (`try_files $uri =404`),
|
||||
sonst sieht jeder fehlende Pfad wie ein Erfolg aus.
|
||||
4. **`thumbnail()` vergrößert nicht.** Wer Icons erzeugt, braucht `resize()` — und
|
||||
die Quelle in voller Auflösung.
|
||||
5. **Ein Rebrand ist mehr als eine Datei.** Icons leben pro Plattform an eigenen
|
||||
Orten; wer nur eine ersetzt, merkt es erst, wenn der Nutzer fragt.
|
||||
6. **Testumgebung ≠ Zielumgebung.** Der lokale Docker-Lauf fand die Fehler, die
|
||||
das Image betreffen — nicht die, die aus Dokployss `.env`-Handling und den
|
||||
Volumes entstehen.
|
||||
7. **Verweise auf Issues prüfen, bevor sie in ein Release wandern.** In den
|
||||
Release-Notes stand ein Link auf ein Issue, das ich nie angelegt hatte (fiel
|
||||
erst bei der Konventionsprüfung auf).
|
||||
|
||||
## 4a. Nachtrag (2026-08-02 vormittags): drei weitere Runden
|
||||
|
||||
**BookStack lief erst nach fünf Anläufen.** Die Ursachen kamen nacheinander und
|
||||
maskierten einander:
|
||||
|
||||
| # | Ursache | Wie sie sich zeigte |
|
||||
|---|---|---|
|
||||
| 1 | Anführungszeichen im `APP_KEY` (Dokploy schreibt Werte 1:1 in eine `.env`) | Deploy bricht ab: `unterminated quoted value` |
|
||||
| 2 | `BOOKSTACK_TAG=25.07` aus meiner ersten `.env.example` — den Tag gibt es nicht | `manifest unknown` |
|
||||
| 3 | **Healthcheck auf `/login` schlug fehl → Container `unhealthy` → Traefik überspringt ihn komplett** | Default-Zertifikat + leeres 404, **identisch zum Bild eines fehlenden Netzes** |
|
||||
| 4 | `DB_PASSWORD` nachträglich geändert; MariaDB legt Zugangsdaten nur beim ersten Start an | `Access denied for user 'bookstack'` |
|
||||
| 5 | `APP_KEY` weder 32 Byte noch mit `base64:`-Präfix | `Unsupported cipher or incorrect key length` |
|
||||
|
||||
**Die wichtigste neue Lehre:** Ein **`unhealthy` Container ist für Traefik
|
||||
unsichtbar** — kein Router, kein Service, egal wie korrekt die Labels sind. Das
|
||||
Symptom ist ununterscheidbar von einem fehlenden Netz. Ein Healthcheck, der nicht
|
||||
im laufenden Container verifiziert wurde, ist damit kein Sicherheitsnetz, sondern
|
||||
ein Risiko. Ich hatte ihn zweimal ungeprüft geändert (`/status` → `/login`).
|
||||
|
||||
**Rebrand:** Der Name saß erst nach drei Anläufen überall. `productName` regelt
|
||||
den App-Namen (macOS/Windows), **`name`** den Linux-Paketnamen, das Binary und den
|
||||
`/opt`-Pfad — und die CI braucht `VARIANT_PATH`, sonst greift die Variante gar
|
||||
nicht. Icons: `PIL.thumbnail()` skaliert **nur nach unten**, weshalb das Motiv in
|
||||
1024er-Icons nie vergrößert wurde; und ein Rebrand betrifft `.png`, `.ico`,
|
||||
`.icns`, sieben Web-Icons und das Manifest — nicht eine Datei.
|
||||
|
||||
**Muster über beide Nächte:** Meine teuersten Fehler entstanden nicht durch
|
||||
falsche Analysen, sondern durch **ungeprüfte Änderungen** — ein Healthcheck ohne
|
||||
Test, ein Issue-Verweis ohne Existenzprüfung, ein Icon-Skript ohne Blick aufs
|
||||
Ergebnis. Die Diagnose war jedes Mal gut, sobald echte Daten vorlagen
|
||||
(Traefik-Logs, Laravel-Log, `docker inspect`).
|
||||
|
||||
## 5. Offen
|
||||
|
||||
- **Entscheidung DOC-03 (#20)**: Docusaurus oder BookStack — beide laufen jetzt,
|
||||
der Vergleich kann an echten Inhalten stattfinden.
|
||||
- **Navbar-Logo im Wiki**: HTML, CSS und Bild werden nachweislich korrekt
|
||||
ausgeliefert, im Browser aber nicht sichtbar. Braucht einen Blick in die
|
||||
Entwicklerkonsole.
|
||||
- **macOS reproduzierbar bauen** (#22), **Windows-VM-Robustheit** (#21).
|
||||
- **Rebrand-Rest**: About-Attribution im Client, `brand` in der Prod-Config,
|
||||
Signing (ThreadNet-Web#6) — ohne Signatur bleibt für Nutzer auf macOS der
|
||||
`xattr`-Schritt und auf Windows die SmartScreen-Warnung.
|
||||
|
||||
## Nachtrag 2026-08-02 — die Paletten waren erfunden
|
||||
|
||||
Nachmittags nachgetragen, weil der Befund das Ergebnis oben relativiert.
|
||||
|
||||
**Was war.** Die zehn Themes aus dem Rollout trugen nicht die Farben aus Anthropics
|
||||
[theme-factory-Skill](https://github.com/anthropics/skills/tree/main/skills/theme-factory),
|
||||
sondern **meine Auslegung ihrer Namen**. Ich hatte den Skill benannt, aber nie
|
||||
seine Farbwerte gelesen. Aufgefallen ist es sorb an „Sunset Boulevard": Er hatte
|
||||
gedämpftes Terrakotta erwartet, bekam Koralle und Pink. Die Prüfung an der Quelle
|
||||
zeigte, dass fast alle zehn danebenlagen — am gröbsten beim Grundcharakter:
|
||||
**sieben der zehn sind hell gemeint, ich hatte sechs dunkel angelegt.**
|
||||
|
||||
**Warum es nicht auffiel.** Erfundene Farben sehen nicht falsch aus. Ein Theme
|
||||
namens „Ocean Depths" in dunklem Türkis wirkt stimmig — es fällt erst auf, wenn
|
||||
jemand die Vorlage kennt. Anders als ein kaputter Healthcheck erzeugt eine
|
||||
erfundene Palette kein Symptom, auf das man stoßen könnte.
|
||||
|
||||
**Falle für die nächste Runde.** Ob ein Theme hell oder dunkel gemeint ist, steht
|
||||
in den Skill-Beschreibungen **nicht verlässlich** — „Warm Sand · backgrounds"
|
||||
findet sich bei einem Theme, dessen Showcase-Seite dunkel ist. Belastbar ist nur
|
||||
`theme-showcase.pdf`: Seiten rendern, Hintergrundfarbe messen. Werte und Fallen
|
||||
stehen in [`shared/branding.md`](../wiki/architecture/branding.md).
|
||||
|
||||
**Bestätigung des Musters aus Abschnitt 4.** Auch das war kein Analysefehler,
|
||||
sondern eine **ungeprüfte Änderung** — dieselbe Wurzel wie Healthcheck, toter
|
||||
Issue-Verweis und Icon-Skript. Nur diesmal ohne Fehlermeldung, die es aufdeckt.
|
||||
Die Lehre schärft sich damit: Es genügt nicht, Ergebnisse zu prüfen — bei
|
||||
Vorlagen ist die **Quelle** zu prüfen, bevor etwas daraus abgeleitet wird.
|
||||
|
||||
**Nebenbefund.** sorbs von Hand eingestelltes BookStack-Schema und die offizielle
|
||||
Sunset-Boulevard-Palette sind bis auf zwei Ziffern identisch (`#e76e51`/`#e76f51`,
|
||||
`#f3a261`/`#f4a261`) — unabhängig voneinander auf demselben Coolors-Satz gelandet.
|
||||
|
||||
**Korrigiert:** gitops `b10b607` (Web, live verifiziert) · ThreadNet-Web `80fcf6c`
|
||||
(Desktop-Config). Das BookStack-CSS lag bereits richtig.
|
||||
⚠️ **Die released Desktop-Binaries tragen weiter die alten Farben** — die Themes
|
||||
stecken in `resources/webapp.asar`. Abgestimmt so belassen; der nächste reguläre
|
||||
Build zieht die Korrektur mit (nachgehalten in ThreadNet-Web#11, `status:wartet`).
|
||||
@@ -0,0 +1,107 @@
|
||||
---
|
||||
type: aar
|
||||
status: open
|
||||
date: 2026-08-09
|
||||
related: []
|
||||
---
|
||||
|
||||
# AAR — Refinement, Betrieb voranbringen, Git-Historie anonymisiert
|
||||
|
||||
**Datum:** 2026-08-09 · **Host/Stack:** git.lab, Gitea, K3s-Cluster (Authentik,
|
||||
Synapse, Element Web) · **Auftrag:** Backlog-Refinement, danach gezielt den
|
||||
Betrieb von ThreadNet voranbringen statt weiter Befunde anzuhäufen
|
||||
|
||||
## 1. Ergebnis
|
||||
|
||||
**Live und verifiziert:**
|
||||
- MFA-Pflicht für die Gruppe `authentik Admins` — Stage, Bindung und
|
||||
Gruppenzuordnung in der Datenbank geprüft, Standard-Login für alle anderen
|
||||
unverändert
|
||||
- `matrix-recovery-flow`-Blueprint läuft erfolgreich — `SELECT … WHERE status
|
||||
<> 'successful'` liefert 0 Zeilen
|
||||
- Web-Client zeigt einen Fehlerbericht-Weg, der **lokal** bleibt
|
||||
(`bug_report_endpoint_url: "local"`) — vorher unbemerkt an element.io
|
||||
- 251 Commits über vier Repos auf 12:00-UTC-Zeitstempel umgeschrieben, Force-
|
||||
gepusht, Mirrors und Flux verifiziert synchron
|
||||
- Stillstandsprüfung läuft täglich per Zeitplan, fand beim ersten Lauf zwei
|
||||
vorher unbekannte Repos ohne Push-Mirror
|
||||
- `game-operating` gespiegelt und secret-frei verifiziert (Coolify-
|
||||
Magievariablen, keine echten Werte)
|
||||
- Call-Widget stempelt sich mit Paketversion + Commit statt „dev"
|
||||
- `@concierge`-Bot für Gäste-Einladungen gebaut und deployt
|
||||
|
||||
**Bewusst nicht live:**
|
||||
- Desktop-Client hat den lokalen Fehlerbericht-Weg erst mit dem nächsten Build
|
||||
(Config geändert, kein Rebuild ausgelöst)
|
||||
- `@concierge` läuft nicht — wartet auf Matrix-Konto, Authentik-Token,
|
||||
Einladungsraum, zwei Gruppen, Secret (alles Zugangsdaten, sorbs Seite)
|
||||
- Authentik-Teil der Stillstandsprüfung übersprungen ohne Token (Fehlen wird
|
||||
ausgewiesen, nicht verschwiegen)
|
||||
- `gameserver` weiterhin ohne Mirror — zwei Repos gleichen Namens mit
|
||||
unterschiedlichem Stand, Klärung vor jedem Eingriff nötig
|
||||
|
||||
## 2. Befunde
|
||||
|
||||
| # | Befund | Schwere | Status |
|
||||
|---|---|---|---|
|
||||
| 1 | `matrix-recovery-flow`-Blueprint scheiterte seit Tagen bei jedem Lauf, während Flux grün meldete | HIGH | behoben |
|
||||
| 2 | Ursache des Blueprint-Fehlers war zweifach verdeckt: `!KeyOf` löst beim Fehlschlag gegen ein leeres Blueprint auf und wirft dieselbe Ausnahme erneut — die echte Meldung ging im eigenen Logging unter | HIGH | behoben, `!Find` statt `!KeyOf` |
|
||||
| 3 | Web-Client sendete Fehlerberichte an `rageshakes.element.io` — die Desktop-Bereinigung vom 2026-08-01 hatte den Web-Build nie erreicht, weil der beim Bauen Elements eigene `develop/config.json` kopiert | HIGH | behoben, `"local"` gesetzt |
|
||||
| 4 | `game-operating` und `gameserver` ohne Push-Mirror; bei `gameserver` liegt auf Gitea ein anderer Stand als auf git.lab | MEDIUM | `game-operating` behoben, `gameserver` offen (management#32) |
|
||||
| 5 | Nach dem Privat-Stellen von `game-operating` auf Gitea übersprang die Stillstandsprüfung den Mirror-Abgleich klaglos, statt es als Befund zu werten | MEDIUM | behoben |
|
||||
| 6 | Header-Hilfsfunktion baute `Authorization: token: <wert>` (doppelter Doppelpunkt) — still ungültig, hätte beim Eintragen des Authentik-Tokens wie ein falscher Token ausgesehen | MEDIUM | behoben, vor dem ersten echten Einsatz gefunden |
|
||||
| 7 | Gitops-Leitfaden 04 nannte 7 Themes mit teils erfundenen Namen (`Gruvbox Dark`, `Wal`); tatsächlich 17 | LOW | behoben |
|
||||
| 8 | threadnet-call-Doku beschrieb einen manuellen npm-Publish, der seit 2026-08-06 automatisiert läuft | LOW | behoben |
|
||||
| 9 | `overmind.md` nannte „sechs gespiegelte Repos" — nach dem Mirror für `game-operating` sind es sieben | LOW | behoben |
|
||||
| 10 | Neu angelegter Deployment-Guide (`@concierge`) fehlte im eigenen Index | LOW | behoben |
|
||||
| 11 | Tag-Push (Force, für die Historien-Anonymisierung) löste in ThreadNet-Web drei Release-Pipelines neu aus; nur weil die geschützten Registry-Variablen im Zeitfenster fehlten, wurde `v0.4.0` nicht mit heutigem Code überschrieben | HIGH | Sperre nachgezogen (ThreadNet-Web#14), Ursache war Zufall, nicht Schutz |
|
||||
|
||||
## 3. Verdachtsfälle mit Entwarnung
|
||||
|
||||
- **`game-operating` öffentlich auf Gitea** — Secret-Scan über alle fünf
|
||||
öffentlich gewordenen Dateien: kein echter Credential-Wert, ausschließlich
|
||||
Coolify-Magievariablen und ein leeres `api_key`-Feld. Erste Prüfung lieferte
|
||||
fälschlich „sauber", weil der Rohpfad falsch war (5×11-Byte-„Not found"-
|
||||
Antworten) — erst nach Gegenprobe der Dateigrößen als Fehlmessung erkannt und
|
||||
mit korrektem Pfad wiederholt.
|
||||
- **Meine erste Diagnose zu #60** („Passwort-Wiederherstellung vermutlich tot")
|
||||
— falsch. Der Flow hatte durchgehend alle sechs Bindungen, der Blueprint-
|
||||
Fehler betraf nur künftige Blueprint-Läufe, nicht die längst angelegten
|
||||
Objekte.
|
||||
|
||||
## 4. Was die Befunde ermöglicht hat
|
||||
|
||||
- **Direktes Auslesen der Authentik-Datenbank statt Vertrauen auf den
|
||||
Flux-Status.** Blueprint-Fehler #1/#2 waren nur so sichtbar — Flux, die
|
||||
ConfigMap und der Cluster-Zustand insgesamt meldeten durchgehend grün.
|
||||
- **`ak apply_blueprint` von Hand** hat den durch das eigene Logging
|
||||
verdeckten Fehler #2 erst zugänglich gemacht — der reguläre Weg (Worker-Log)
|
||||
zeigte nur die Folgeausnahme.
|
||||
- **Den Ist-Zustand vor einer Änderung auslesen statt der Issue-Beschreibung
|
||||
zu glauben** hat Befund #3 aufgedeckt — die Annahme im Issue betraf nur den
|
||||
Desktop-Client, `config.json` auf dem Web-Server sagte etwas anderes.
|
||||
- **Die Stillstandsprüfung selbst** (aus der gestrigen Retro gebaut) hat
|
||||
Befund #4 im ersten Lauf gefunden — eine dynamische Projektliste statt einer
|
||||
im Code gepflegten hat zwei Repos zutage gebracht, die niemand auf dem
|
||||
Schirm hatte.
|
||||
- **Content-Length-Gegenprobe nach dem Secret-Scan** hat die eigene
|
||||
Fehlmessung beim `game-operating`-Check aufgedeckt, bevor sie als „sauber"
|
||||
ins Protokoll ging.
|
||||
- **Baumvergleich (Tree-Hash) vor und nach jedem Rewrite-Schritt** — 251 von
|
||||
251 Paaren über Tree *und* Commit-Nachricht verifiziert, keine Annahme.
|
||||
|
||||
## 5. Offen
|
||||
|
||||
- **`@concierge` aktivieren** — fünf Zugangsdaten-Schritte, Checkliste in
|
||||
gitops#48
|
||||
- **`gameserver`-Mirror** — Standklärung nötig, management#32
|
||||
- **Stillstandsprüfung Authentik-Teil** — `AUTHENTIK_URL`/`AUTHENTIK_TOKEN`,
|
||||
management#31, bewusst aufgeschoben (sorb, 2026-08-09)
|
||||
- **Rageshake vs. Zammad** — durch den lokalen Fix entschärft, aber nicht
|
||||
entschieden, ThreadNet-Web#9
|
||||
- **`report_event.admin_message_md`** nicht gesetzt — wer Inhalte meldet,
|
||||
sieht keinen Kontaktweg; braucht nur eine Angabe (welcher Raum/Kontakt) von
|
||||
sorb, dann eine Zeile Config
|
||||
- **Desktop-Build** für den lokalen Fehlerbericht-Weg noch ausständig
|
||||
- **ADR-0009** (Commit-Konventionen/Anonymisierung) nachträglich verfasst —
|
||||
Lehre aus der Retro, in `decisions/` dokumentiert
|
||||
@@ -0,0 +1,112 @@
|
||||
---
|
||||
type: aar
|
||||
status: open
|
||||
date: 2026-08-11
|
||||
related: []
|
||||
---
|
||||
|
||||
# AAR — `@apo` konnte nicht telefonieren: fehlende Synapse-`profiles`-Zeile
|
||||
|
||||
**Datum:** 2026-08-11 · **Beteiligt:** sorb + Mac-Session · **Stack:** Synapse,
|
||||
MAS, Authentik, Element Web / Element Call, MatrixRTC (K3s-Cluster)
|
||||
**Auftrag:** `@apo` kann sich anmelden und schreiben, aber **kein Call kommt
|
||||
zustande** — Grundursache finden und beheben, ohne weiter zu raten.
|
||||
|
||||
## 1. Ergebnis
|
||||
|
||||
**Behoben und verifiziert:**
|
||||
- `@apo` telefoniert wieder. Grundursache belegt: dem Konto fehlte die Zeile in
|
||||
Synapses `profiles`-Tabelle. Fix war ein einzelnes `INSERT` der
|
||||
Registrierungs-Default-Zeile, an zwei gesunden Konten (`clark`,
|
||||
`calltest01`) gegengeprüft.
|
||||
- Gegenprobe nach dem Fix: `displayname` gesetzt (vorher keine Zeile),
|
||||
`open_id_tokens` **0 → 6**, aktives `org.matrix.msc3401.call.member` im Raum.
|
||||
- Dokumentiert: Runbook `docs/troubleshooting/CALLS-FEHLEN-PROFILE-ZEILE.md` im
|
||||
gitops-Repo (inkl. Index-Eintrag), Merksatz im Session-Gedächtnis.
|
||||
|
||||
**Nebenbefund, separat behoben:**
|
||||
- **Kontoübernahme-Lücke:** Der MAS-Upstream-Provider stand auf
|
||||
`claims_imports.localpart.on_conflict: add` — bei Localpart-Kollision verknüpfte
|
||||
MAS die neue Upstream-Identität mit einem **bestehenden** Konto (inkl.
|
||||
Dienstkonten ohne Upstream-Link). Auf `on_conflict: fail` umgestellt
|
||||
(gitops `ef04d86`, nach git.lab gepusht), dokumentiert als
|
||||
[gitops#61](https://git.lab/axion1337.chat/axion1337.chat-gitops/-/issues/61),
|
||||
`priority:high`. Ausgelöst durch die live reproduzierte case-sensitive Dublette
|
||||
`boje`/`Boje`; das Zweitkonto `boje` (Authentik-ID 11) wurde gelöscht.
|
||||
**Deployment verifiziert:** Das SOPS-Values-Secret aktualisierte Flux, aber MAS
|
||||
lief noch mit der alten Config im Speicher (Pod älter als die Änderung) — erst
|
||||
ein `rollout restart` machte `fail` aktiv. „Committet" ≠ „deployed" ≠ „aktiv".
|
||||
|
||||
## 2. Die Kausalkette (belegt, nicht vermutet)
|
||||
|
||||
| Glied | Beleg |
|
||||
|---|---|
|
||||
| `@apo` hat **keine `profiles`-Zeile** | `SELECT count(*) … = 0`, während `clark`/`sorb`/`calltest01` je eine haben |
|
||||
| Displayname-Setzen crasht | `PUT …/displayname → 500`, `TypeError: 'NoneType' object is not subscriptable` in `_check_profile_size` (`storage/databases/main/profile.py:354`) — `txn.fetchone()` liefert `None`, `row[0]` fliegt |
|
||||
| kein Displayname → Widget-Init bricht ab | Call-Klick erzeugte **null** Server-Aktivität: kein `openid/request_token`, kein `call.member`; Browser-Log damals „Messaging present but not yet started" (iframe meldet nie `ContentLoaded`) |
|
||||
| kein Widget → kein Token → keine SFU | `@apo` als einziger aktiver Nutzer mit **0** Einträgen in `open_id_tokens` (die nicht geprunt werden) |
|
||||
|
||||
Herkunft der fehlenden Zeile: `@apo` ist ein **Vor-Authentik-Konto**, das durch
|
||||
sechs Identitäts-Resets ging. Deaktivieren löscht in Synapse das Profil,
|
||||
Reaktivieren legt es nicht neu an. `frank` (noch älter, nie zurückgesetzt) behielt
|
||||
seine Zeile. Ob einer der früheren manuellen Eingriffe der auslösende Reset war,
|
||||
ist nicht mehr zweifelsfrei zu klären — die Zeile ist jetzt wieder da.
|
||||
|
||||
## 3. Was ausgeschlossen wurde (gemessen)
|
||||
|
||||
| Verdacht | Warum entkräftet |
|
||||
|---|---|
|
||||
| Krypto / Cross-Signing (18 Pseudo-Geräte aus 6 Resets) | Testraum ist **unverschlüsselt** → Call braucht keine Krypto; `clark` telefoniert mit ebenfalls zurückgesetzten Schlüsseln |
|
||||
| Server-Call-Pfad (SFU, RTC-Auth, OpenID-Endpoint) | `calltest01`/`sorb` bekommen sauber 200 auf `openid/request_token` und die Federation-Auflösung |
|
||||
| `@apo`s Token / Session | `/sync` läuft durchgehend mit 200, Messaging intakt |
|
||||
| Login-Verknüpfung MAS↔Authentik | `subject` = Authentik-`uid` `2fafe38b…`, korrekt |
|
||||
|
||||
## 4. Was zur Lösung geführt hat
|
||||
|
||||
- **Der Sprung von „welcher Nutzer telefoniert nicht" zu „welche *Tabelle* ist
|
||||
anders".** Der Durchbruch war die `open_id_tokens`-Abfrage über *alle* aktiven
|
||||
Nutzer: `@apo` = 0, alle anderen zweistellig+. Ein Vergleich statt einer
|
||||
Einzelbetrachtung.
|
||||
- **Ein unverschlüsselter Testraum** hat das größte Ablenkungsfeld
|
||||
(Cross-Signing) in einem Schritt geschlossen.
|
||||
- **Der Live-Mitschnitt beim echten Call-Klick** zeigte die Abwesenheit jeder
|
||||
Aktivität — nicht ein Fehler, sondern *nichts* war der Befund.
|
||||
- **Der Nutzer-Hinweis „Anzeigename konnte nicht gesetzt werden"** lieferte den
|
||||
500er mit vollständigem Stacktrace — die letzte Meile von Korrelation zu
|
||||
Ursache.
|
||||
- **Der entscheidende Kontext kam von sorb:** „`apo` ist ein Alt-Konto von vor
|
||||
der Authentik-Integration." Das lenkte die Suche von „angesammelter Müll" auf
|
||||
„Migrations-/Provisionierungs-Lücke".
|
||||
|
||||
## 5. Lehren für die Zukunft
|
||||
|
||||
1. **Bei Call-Problemen zuerst `open_id_tokens` je Nutzer vergleichen.** 0 bei
|
||||
einem sonst aktiven Konto ist das schnellste, eindeutigste Alarmsignal und
|
||||
trennt Client- von Server-Ursache in einer Abfrage.
|
||||
2. **Immer im unverschlüsselten Raum reproduzieren, bevor man Krypto verdächtigt.**
|
||||
Das schließt einen ganzen Ursachenblock kostenlos aus.
|
||||
3. **„Nichts passiert" ist ein Messergebnis, kein Sackgassen-Signal.** Die
|
||||
Abwesenheit eines `openid`-Aufrufs hat den Fehler lokalisiert, nicht ein
|
||||
Fehlercode.
|
||||
4. **Alt-/mehrfach-zurückgesetzte Konten gegen frisch provisionierte diffen,
|
||||
nicht nur gegen die Erwartung.** Der Unterschied war eine *fehlende* Zeile —
|
||||
sichtbar nur im direkten Vergleich mit `clark`/`calltest01`.
|
||||
5. **Jeder DB-Schreib strukturiert: betroffene Zeile vorher anzeigen, an einem
|
||||
gesunden Konto gegenprüfen, per `INSERT … ON CONFLICT DO NOTHING` statt
|
||||
Überschreiben.** Das ist die direkte Konsequenz aus den früheren
|
||||
unstrukturierten MAS-Eingriffen dieses Vorgangs — und diesmal eingehalten.
|
||||
6. **Beiläufige Symptome ernst nehmen:** die Dublette `boje`/`Boje` beim
|
||||
Testkonto-Anlegen war der Faden, der die Kontoübernahme-Lücke (gitops#61)
|
||||
aufdeckte — ein Sicherheitsfund, der ohne den `@apo`-Vorgang unentdeckt
|
||||
geblieben wäre.
|
||||
|
||||
## 6. Offen / Folgetodos
|
||||
|
||||
- **gitops#61** (`on_conflict`-Härtung) ist gepusht und rollt über Flux; der
|
||||
case-insensitive Eindeutigkeits-Check im `matrix-invitation`-Prompt-Stage
|
||||
(damit der Nutzer schon bei der Registrierung statt erst beim Login scheitert)
|
||||
ist dort als bewusst offener Rest vermerkt.
|
||||
- Verwaiste Altlasten bei `@apo` (10 `local_notification_settings` für längst
|
||||
gelöschte Geräte, 18 Cross-Signing-Pseudoeinträge) sind **kosmetisch** und
|
||||
wurden bewusst **nicht** angefasst — sie haben mit dem Call-Problem nichts zu
|
||||
tun, und ein weiterer Eingriff widerspräche der Lehre oben.
|
||||
@@ -73,4 +73,4 @@ Client". Die Richtung wurde deshalb gedreht:
|
||||
- Tunnel dauerhaft an: widerspricht dem Bedarfsfall-Prinzip ohne echten Gewinn.
|
||||
- git.lab öffentlich exponieren: größte Angriffsfläche, klar verworfen.
|
||||
- Eigene UniFi-Zone für den Tunnel: technisch nicht möglich (VPN-Server bleiben in der
|
||||
VPN-Zone), siehe [AAR Lab-Seite](../../verfahren/aar/2026-08-01-labnet02-lab.md).
|
||||
VPN-Zone), siehe [AAR Lab-Seite](../aar/2026-08-01-labnet02-lab.md).
|
||||
|
||||
@@ -29,7 +29,7 @@ Konfigurationsfehler — aber es hat zwei Folgen, die benannt gehören:
|
||||
docker-Gruppe geschieht, ist im Nachhinein nicht aus den üblichen
|
||||
Protokollen rekonstruierbar.
|
||||
|
||||
Aufgedeckt im [CFGMON-AAR](../../verfahren/aar/2026-08-01-labnet02-cfgmon.md)
|
||||
Aufgedeckt im [CFGMON-AAR](../aar/2026-08-01-labnet02-cfgmon.md)
|
||||
(Befund 3, MEDIUM), erfasst als
|
||||
[#14](https://git.lab/axion1337.chat/management/-/issues/14).
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ related: []
|
||||
|
||||
**Status:** akzeptiert · **Datum:** 2026-08-07 (Regel) / 2026-08-09 (Durchführung) · **Entscheider:** sorb
|
||||
|
||||
> Nachgetragen am 2026-08-09 in der [Retro](../../verfahren/retro/2026-08-09.md). Die
|
||||
> Nachgetragen am 2026-08-09 in der [Retro](../sources/protokolle/retro-2026-08-09.md). Die
|
||||
> Entscheidung war getroffen und ausgeführt, bevor sie als ADR vorlag — das ist
|
||||
> genau der Fehler, den die ADR-Pflicht verhindern soll, und wird hier benannt
|
||||
> statt geglättet.
|
||||
@@ -61,7 +61,7 @@ Uhrzeit verschwindet.
|
||||
- **Alle SHAs im Bereich sind neu.** Verweise in Issues, Doku und Commit-Texten
|
||||
zeigen ins Leere. Die Doku wurde nachgezogen (12 Stellen); für alles andere gibt
|
||||
es die dauerhafte Zuordnungstabelle
|
||||
[`shared/commit-zuordnung-2026-08-07.md`](../../shared/commit-zuordnung-2026-08-07.md).
|
||||
[`shared/commit-zuordnung-2026-08-07.md`](../sources/migration/commit-zuordnung-2026-08-07.md).
|
||||
- **Issue-Kommentare wurden bewusst NICHT umgeschrieben.** Eine Tabelle
|
||||
nachzuschlagen ist zumutbar; nachträglich zu ändern, was jemand geschrieben hat,
|
||||
beschädigt dieselbe Nachvollziehbarkeit ein zweites Mal.
|
||||
|
||||
@@ -137,8 +137,8 @@ bleibt GitLab/Obsidian/Editor. Mockups entfallen.
|
||||
|
||||
Alt-Ansatz: `CLAUDE.md`, `roadmap.md`, `decisions/README.md` und die
|
||||
tragenden Entscheidungen 0001, 0002, 0005, 0009, 0010,
|
||||
[verfahren/refinement.md](../../verfahren/refinement.md),
|
||||
[verfahren/stillstandspruefung.md](../../verfahren/stillstandspruefung.md),
|
||||
[verfahren/refinement.md](../wiki/admin/refinement.md),
|
||||
[verfahren/stillstandspruefung.md](../wiki/admin/stillstandspruefung.md),
|
||||
`.gitlab-ci.yml`, Auszüge aus `hosts/`. Neckbeard v0.1.1: AGENTS.md,
|
||||
WORKFLOW.md, ADR-0001…0004/0006, `schema.yaml`, `validate.py`,
|
||||
`gen_status.py`, Schöpfungs-AAR, `docs/wiki/index.md`. Session-1-Daten
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
# Commit-Zuordnung der Anonymisierung vom 2026-08-07
|
||||
|
||||
Am 2026-08-07 wurden die Zeitstempel aller Commits aus dieser Zusammenarbeit auf
|
||||
**12:00 UTC ihres jeweiligen Tages** gesetzt ([Commit-Konventionen](../CLAUDE.md)).
|
||||
Dabei bekam jeder betroffene Commit zwangsläufig eine **neue SHA**.
|
||||
|
||||
Diese Tabelle macht die alten Verweise dauerhaft auflösbar. Sie ist der Grund,
|
||||
warum ältere Issue-Kommentare weiterhin lesbar bleiben, ohne dass jemand
|
||||
nachträglich in geschriebenen Text eingreifen muss.
|
||||
|
||||
## Wie das entstanden ist
|
||||
|
||||
Die Zuordnung wurde **nicht** aus einem Protokoll übernommen, sondern aus den
|
||||
`backup-vor-rewrite`-Branches rekonstruiert und **paarweise verifiziert**: Für jedes
|
||||
Paar mussten Tree-Hash *und* Commit-Nachricht übereinstimmen. 251 von 251 Paaren
|
||||
haben diese Prüfung bestanden, null Zweifelsfälle.
|
||||
|
||||
⚠️ **Nicht umgeschrieben wurde der Inhalt.** Alle Trees sind bitgleich geblieben —
|
||||
verändert wurden ausschließlich Zeitstempel, bei einigen Commits zusätzlich die
|
||||
Autoren-Identität (drei Varianten derselben Person auf eine vereinheitlicht). Die
|
||||
Commits des `turn-secret-rotation`-Bots behielten ihre Identität, weil sie
|
||||
maschinell entstanden sind.
|
||||
|
||||
## ⚠️ Falle beim Wiederholen: Tag-Pushes lösen Release-Builds aus
|
||||
|
||||
Das Force-Push der umgezogenen Tags hat in ThreadNet-Web **drei Release-Pipelines
|
||||
neu gestartet** (`v0.3.0`, `v0.4.0`, `desktop-v1.12.17-clientscan`). Ein Tag ist
|
||||
dort kein Verwaltungseintrag, sondern der Auslöser für einen Container-Build.
|
||||
|
||||
Überschrieben wurde nichts — aber nur, weil für den Push die Tag-Regel `v*`
|
||||
vorübergehend entfernt war und GitLab die **geschützten** Registry-Variablen
|
||||
deshalb nicht herausgab. `docker login` scheiterte nach vier Sekunden. **Das war
|
||||
Glück, keine Planung:** Mit stehender Tag-Protection wäre `threadnet-web:v0.4.0`
|
||||
aus altem Code mit heutigen Abhängigkeiten neu gebaut und überschrieben worden.
|
||||
|
||||
Wer Tags verschiebt, prüft vorher, was am Tag-Ref hängt. Nachgehalten in
|
||||
ThreadNet-Web#14.
|
||||
|
||||
## Was *nicht* in der Tabelle steht
|
||||
|
||||
Commits **vor** der Grenze blieben unangetastet und haben ihre SHA behalten:
|
||||
ThreadNet-Web vor dem 2026-07-28 (3 Commits), gitops vor dem 2026-07-27 (147).
|
||||
Wer eine SHA hier nicht findet, hat vermutlich eine davon vor sich — die gilt
|
||||
weiterhin.
|
||||
|
||||
|
||||
## gitops — 117 Commits
|
||||
|
||||
| alt | neu | Datum |
|
||||
|---|---|---|
|
||||
| `314cf6dedb` | `80714fe901` | 2026-07-27 |
|
||||
| `784459beed` | `d2bcd90291` | 2026-07-27 |
|
||||
| `fe575808b3` | `027f567c8b` | 2026-07-27 |
|
||||
| `b13bb2381d` | `0274f9316c` | 2026-07-27 |
|
||||
| `826fc8dbd3` | `e9b24a6d1f` | 2026-07-27 |
|
||||
| `aa42d0530a` | `235306a840` | 2026-07-27 |
|
||||
| `20e4a8da48` | `c0cb864ca2` | 2026-07-27 |
|
||||
| `420f779711` | `09e4225de5` | 2026-07-27 |
|
||||
| `baf0863a2f` | `af73cf770b` | 2026-07-27 |
|
||||
| `7871e038c7` | `fad91b6a05` | 2026-07-27 |
|
||||
| `ea72f5b357` | `37aea0254b` | 2026-07-27 |
|
||||
| `65f6aa813d` | `1bb1bc9610` | 2026-07-27 |
|
||||
| `41bf33fcfd` | `7d352fbf20` | 2026-07-27 |
|
||||
| `07b5b7b17d` | `cb2ffa6a08` | 2026-07-27 |
|
||||
| `e0db79a3f1` | `b32920c48f` | 2026-07-28 |
|
||||
| `cf24a1a396` | `edf224e450` | 2026-07-28 |
|
||||
| `30578abaaf` | `8f1d39b7a8` | 2026-07-28 |
|
||||
| `703cf1ff1c` | `3054037480` | 2026-07-28 |
|
||||
| `3b42b220a0` | `22a0823b7e` | 2026-07-28 |
|
||||
| `0db7fc1573` | `736c39a413` | 2026-07-28 |
|
||||
| `d24e37619c` | `25d1742d61` | 2026-07-28 |
|
||||
| `44aa5a918e` | `79db6a8e49` | 2026-07-28 |
|
||||
| `50c2fc2889` | `e462980dac` | 2026-07-28 |
|
||||
| `58fcc4ab42` | `337dbe85ac` | 2026-07-28 |
|
||||
| `9aec29f605` | `09aaf1b2b5` | 2026-07-28 |
|
||||
| `328b028c5d` | `6973a8dbc7` | 2026-07-28 |
|
||||
| `c0be911797` | `4a3d7c70a6` | 2026-07-28 |
|
||||
| `c52ff97502` | `414ada956a` | 2026-07-28 |
|
||||
| `e54ec10fd9` | `2c5f77686d` | 2026-07-28 |
|
||||
| `f5e9fc5d2b` | `ba270bce71` | 2026-07-28 |
|
||||
| `bccd265302` | `49005ed325` | 2026-07-28 |
|
||||
| `7b9d13199e` | `9607687e4e` | 2026-07-28 |
|
||||
| `0242238597` | `51ea51352b` | 2026-07-28 |
|
||||
| `62b05c51c4` | `233b13f972` | 2026-07-28 |
|
||||
| `d24dbf84f7` | `9fa947cc21` | 2026-07-28 |
|
||||
| `e53896e02c` | `7795f89fc9` | 2026-07-28 |
|
||||
| `5bcbadd06a` | `be95bd921c` | 2026-07-28 |
|
||||
| `947eaab71c` | `ac7e65100d` | 2026-07-28 |
|
||||
| `62d4bf6630` | `d742c99ba5` | 2026-07-28 |
|
||||
| `c1c189d281` | `debf980d5f` | 2026-07-28 |
|
||||
| `f30d2f582b` | `802e09cd9c` | 2026-07-28 |
|
||||
| `ee91f121b8` | `0f7ff1a896` | 2026-07-28 |
|
||||
| `082817a0d7` | `2932ffffc3` | 2026-07-28 |
|
||||
| `52b0de1b5a` | `eabde3747e` | 2026-07-28 |
|
||||
| `39037d85cc` | `ccf6856f42` | 2026-07-28 |
|
||||
| `d8acc1e26c` | `13385b68f2` | 2026-07-28 |
|
||||
| `7ff3fb65e8` | `5f7fd8bc46` | 2026-07-28 |
|
||||
| `4d8fa5f06c` | `174c58001b` | 2026-07-28 |
|
||||
| `7972034298` | `2aed6e4932` | 2026-07-28 |
|
||||
| `f56f8c2479` | `105194d450` | 2026-07-28 |
|
||||
| `3e38955c12` | `9fa88bda5c` | 2026-07-29 |
|
||||
| `e9f000f87b` | `23c66c97b8` | 2026-07-29 |
|
||||
| `8ee937e56d` | `5c3a7b798a` | 2026-07-29 |
|
||||
| `7f42a456eb` | `7cd177f744` | 2026-07-29 |
|
||||
| `d31cc19fab` | `5e16719bfe` | 2026-07-29 |
|
||||
| `893fe32976` | `f58add72ae` | 2026-07-29 |
|
||||
| `c262d47809` | `bb51047e1d` | 2026-07-29 |
|
||||
| `de2af6e199` | `e659242990` | 2026-07-29 |
|
||||
| `7bd67a53a6` | `2e53387650` | 2026-07-29 |
|
||||
| `db77785b6b` | `9db1ee6f45` | 2026-07-29 |
|
||||
| `dc856186d1` | `7ac584d27b` | 2026-07-29 |
|
||||
| `8a3274dd33` | `4ca87a68c7` | 2026-07-29 |
|
||||
| `32e2c8e556` | `7b19586179` | 2026-07-29 |
|
||||
| `95ab6db12f` | `5ca8f00d58` | 2026-07-29 |
|
||||
| `3e147554eb` | `e094c4ab29` | 2026-07-29 |
|
||||
| `bd25486e56` | `11a079db57` | 2026-07-29 |
|
||||
| `d54c4aec65` | `2803fb384c` | 2026-07-29 |
|
||||
| `194d47a0ef` | `100b46ec91` | 2026-07-29 |
|
||||
| `1b1fa2b719` | `376772078a` | 2026-07-29 |
|
||||
| `2b7f42dc8c` | `932443df63` | 2026-07-29 |
|
||||
| `e8ba7589dd` | `5aca738f55` | 2026-07-30 |
|
||||
| `e58b8db8fe` | `5e46a24e7d` | 2026-07-31 |
|
||||
| `42d76cc13d` | `b28ef2c97a` | 2026-07-31 |
|
||||
| `7735c504f2` | `8ad921519f` | 2026-07-31 |
|
||||
| `b73d88729d` | `6f761da1a4` | 2026-08-01 |
|
||||
| `d10a9285b9` | `60248bfd92` | 2026-08-01 |
|
||||
| `93ee6a3549` | `228807fcc8` | 2026-08-01 |
|
||||
| `6575cb942a` | `3c26cf2504` | 2026-08-01 |
|
||||
| `640c93480d` | `717638d12c` | 2026-08-01 |
|
||||
| `c631b0a917` | `44d3e7dae1` | 2026-08-01 |
|
||||
| `9aa42f96bc` | `11f97b935f` | 2026-08-01 |
|
||||
| `e963203376` | `af63755f1e` | 2026-08-01 |
|
||||
| `f030586956` | `dfe7ff9fc0` | 2026-08-01 |
|
||||
| `94244736c9` | `d4f3fc4c97` | 2026-08-01 |
|
||||
| `82827c4857` | `018a4b7d83` | 2026-08-01 |
|
||||
| `ed73a42772` | `8331bb212d` | 2026-08-01 |
|
||||
| `686f50db8e` | `c8fc91ff1d` | 2026-08-01 |
|
||||
| `75a319a7e3` | `ba9783fa08` | 2026-08-01 |
|
||||
| `eff643edf6` | `cdecb006d4` | 2026-08-01 |
|
||||
| `a2438e1b2b` | `b15a9f578c` | 2026-08-01 |
|
||||
| `c47b0a3312` | `ac0afaf3d9` | 2026-08-02 |
|
||||
| `8a9d778973` | `b10b607d70` | 2026-08-02 |
|
||||
| `4c792172f8` | `bb5778e121` | 2026-08-02 |
|
||||
| `da6d352902` | `42da25d0a6` | 2026-08-02 |
|
||||
| `a777f973cb` | `316178bd51` | 2026-08-02 |
|
||||
| `ee476782bb` | `0a07da260f` | 2026-08-02 |
|
||||
| `02c60cbbe5` | `52573634df` | 2026-08-02 |
|
||||
| `0cfbb4a89f` | `42632d6b2a` | 2026-08-02 |
|
||||
| `7248da62bc` | `c7d4b6f376` | 2026-08-02 |
|
||||
| `ad3c956cb5` | `b51a07b068` | 2026-08-06 |
|
||||
| `cc6565e494` | `0213b0fe58` | 2026-08-06 |
|
||||
| `9e15ba57c5` | `712cd430bf` | 2026-08-06 |
|
||||
| `9b8145540f` | `0f28acb626` | 2026-08-06 |
|
||||
| `8cfa7cb83e` | `d7aca3bd0c` | 2026-08-06 |
|
||||
| `05197c40aa` | `f687b41441` | 2026-08-06 |
|
||||
| `e5d74662a0` | `c1ee776070` | 2026-08-06 |
|
||||
| `961641004f` | `7a1710c78d` | 2026-08-06 |
|
||||
| `e54a1d57e0` | `ebb1d4e2a7` | 2026-08-06 |
|
||||
| `f0b0019ee7` | `191981aefe` | 2026-08-06 |
|
||||
| `480e28180c` | `f5fe27336f` | 2026-08-06 |
|
||||
| `e14d1be69d` | `34442df75c` | 2026-08-06 |
|
||||
| `24ab87e398` | `e7f1b5d6f8` | 2026-08-06 |
|
||||
| `c6e72ac9bb` | `f1d732afbe` | 2026-08-06 |
|
||||
| `6c693c9a8a` | `a81ea0dd2e` | 2026-08-06 |
|
||||
| `e51142ec5b` | `1b35766ad3` | 2026-08-07 |
|
||||
| `94596c2933` | `3c6f3645b3` | 2026-08-07 |
|
||||
| `efb25f31a2` | `f0174decc1` | 2026-08-07 |
|
||||
|
||||
## management — 78 Commits
|
||||
|
||||
| alt | neu | Datum |
|
||||
|---|---|---|
|
||||
| `1dd8f282d8` | `8e98a39447` | 2026-07-30 |
|
||||
| `d21eabb77f` | `a5eacfe39e` | 2026-07-30 |
|
||||
| `1c5e21ce43` | `34686ee2e1` | 2026-07-30 |
|
||||
| `7dc4e5bf8e` | `15396d53e8` | 2026-07-30 |
|
||||
| `4dd452e0fa` | `49faf20243` | 2026-07-30 |
|
||||
| `029ee29d9c` | `ff21788692` | 2026-07-30 |
|
||||
| `838a186c91` | `02946481ae` | 2026-07-30 |
|
||||
| `480d80e783` | `c3e84c53bf` | 2026-07-30 |
|
||||
| `09f6e8c333` | `751df7dc01` | 2026-07-30 |
|
||||
| `57a355ac38` | `a85d082f10` | 2026-07-31 |
|
||||
| `f6055ee47c` | `2be5fb6f60` | 2026-07-31 |
|
||||
| `2a2575781d` | `bd8486960f` | 2026-07-31 |
|
||||
| `50bc39c0d1` | `490c2b7257` | 2026-07-31 |
|
||||
| `bdb2c766e9` | `0671da1040` | 2026-07-31 |
|
||||
| `aa6d5fc13a` | `a053fd9271` | 2026-07-31 |
|
||||
| `1e8ee1c4ac` | `4e03950d3f` | 2026-07-30 |
|
||||
| `93a0c9cecb` | `98c6483b9f` | 2026-07-31 |
|
||||
| `142b24d65a` | `019c3e7279` | 2026-07-31 |
|
||||
| `a9b8ca05ca` | `d9db323b62` | 2026-07-31 |
|
||||
| `d43bb05d77` | `4c870854f1` | 2026-07-31 |
|
||||
| `891adc6944` | `59df406a19` | 2026-07-31 |
|
||||
| `9f78b04419` | `88850809c7` | 2026-07-31 |
|
||||
| `0b27c26bec` | `3aa34f8635` | 2026-07-31 |
|
||||
| `590a80f510` | `efbb4b9a1a` | 2026-08-01 |
|
||||
| `a29235cd54` | `b4b4893389` | 2026-08-01 |
|
||||
| `375259061f` | `f656c5d8b3` | 2026-08-01 |
|
||||
| `18c9f1ed20` | `e5c78edb14` | 2026-08-01 |
|
||||
| `1cbd2001db` | `59025c2e15` | 2026-08-01 |
|
||||
| `4597ea1cc3` | `f22ede5124` | 2026-08-01 |
|
||||
| `a23a149c0d` | `ce62396f0b` | 2026-08-01 |
|
||||
| `cacb89175b` | `666aa9004a` | 2026-08-01 |
|
||||
| `10f76f2942` | `0b6060339e` | 2026-08-01 |
|
||||
| `eb9ada6427` | `3e81f40178` | 2026-08-01 |
|
||||
| `b11284b844` | `777f8c375f` | 2026-08-01 |
|
||||
| `1e5da7e630` | `77a9a94a7f` | 2026-08-01 |
|
||||
| `eab452b3d5` | `e4991c050f` | 2026-08-01 |
|
||||
| `0cd5a33402` | `aecbea0c89` | 2026-08-01 |
|
||||
| `d1f9f22455` | `0f3f155bc5` | 2026-08-01 |
|
||||
| `03ddd7b1d8` | `fdf30d42e1` | 2026-08-01 |
|
||||
| `b96793da98` | `cc0d4d3e02` | 2026-08-01 |
|
||||
| `b647645d2a` | `3e226fba40` | 2026-08-01 |
|
||||
| `e8e1b36224` | `ea026a0057` | 2026-08-01 |
|
||||
| `28cd06c13b` | `fa5c7a8681` | 2026-08-01 |
|
||||
| `001f59fe44` | `97fe9e0fa8` | 2026-08-01 |
|
||||
| `4a8e1b6ffd` | `830c740a58` | 2026-08-01 |
|
||||
| `2b1f791fe6` | `1b8ef35e9b` | 2026-08-01 |
|
||||
| `04d61ec6ac` | `cd7b2d0b75` | 2026-08-01 |
|
||||
| `fcfe3b681d` | `7d7c1e86b0` | 2026-08-01 |
|
||||
| `418d787f77` | `5091ba8f3f` | 2026-08-02 |
|
||||
| `054fac4383` | `8e489415cd` | 2026-08-02 |
|
||||
| `5d18924d28` | `8aebe3b03d` | 2026-08-02 |
|
||||
| `2ec9858a91` | `9c3d2529b4` | 2026-08-02 |
|
||||
| `404a12d97c` | `c079ec2d7d` | 2026-08-02 |
|
||||
| `425a2645b6` | `71975d5d41` | 2026-08-02 |
|
||||
| `aa3f47d4ec` | `0b518bb3b1` | 2026-08-02 |
|
||||
| `81f207e9c3` | `786ca28895` | 2026-08-02 |
|
||||
| `d5046621ca` | `b6aaad7abe` | 2026-08-02 |
|
||||
| `01f0f9ad07` | `d3869e081e` | 2026-08-02 |
|
||||
| `49f3f38b06` | `92dac0be23` | 2026-08-02 |
|
||||
| `d967654077` | `e549de8247` | 2026-08-02 |
|
||||
| `09bdd94da6` | `f3c5603955` | 2026-08-02 |
|
||||
| `a4df631ee6` | `4f7500c00c` | 2026-08-02 |
|
||||
| `ac11c274e4` | `83cee828b8` | 2026-08-02 |
|
||||
| `ae982cdb4b` | `164d96dddd` | 2026-08-02 |
|
||||
| `290709a900` | `3fe05e7bd1` | 2026-08-02 |
|
||||
| `161df3a9cc` | `bd83975b2f` | 2026-08-02 |
|
||||
| `49441bf332` | `cbfbf4b36e` | 2026-08-02 |
|
||||
| `019c5cb6c9` | `9e0af1370b` | 2026-08-02 |
|
||||
| `2a294f2261` | `d31fef4b28` | 2026-08-05 |
|
||||
| `d6c98632f0` | `889cd47be7` | 2026-08-06 |
|
||||
| `b51986de9f` | `ae62727a50` | 2026-08-06 |
|
||||
| `5275bef15b` | `d019bfedda` | 2026-08-06 |
|
||||
| `64670c51b6` | `f1b60d815b` | 2026-08-06 |
|
||||
| `85aa8ef22d` | `3eb27b3a62` | 2026-08-06 |
|
||||
| `b4ee92fe9a` | `0abd26e416` | 2026-08-06 |
|
||||
| `a64ce123c1` | `63fd0b460a` | 2026-08-06 |
|
||||
| `83150c3d8e` | `9cc5ba4fe0` | 2026-08-06 |
|
||||
| `8ec67463b1` | `c1a604bd19` | 2026-08-07 |
|
||||
|
||||
## ThreadNet-Web — 47 Commits
|
||||
|
||||
| alt | neu | Datum |
|
||||
|---|---|---|
|
||||
| `5e3254d8a8` | `1822fe80f0` | 2026-07-28 |
|
||||
| `7839b56a65` | `306cca041c` | 2026-07-28 |
|
||||
| `05900602c6` | `44305556c3` | 2026-07-29 |
|
||||
| `6a628533c2` | `42285021cb` | 2026-07-29 |
|
||||
| `60f2cda962` | `45fb329577` | 2026-07-29 |
|
||||
| `170d6c3538` | `77ffeb4514` | 2026-07-30 |
|
||||
| `163504efc6` | `bd8298db39` | 2026-07-30 |
|
||||
| `b24ce732dc` | `0f1d31021c` | 2026-07-30 |
|
||||
| `8fb32d9360` | `f2abae85dd` | 2026-07-30 |
|
||||
| `214fd5b70a` | `8faade6c7b` | 2026-07-30 |
|
||||
| `6a8a2bb1a9` | `71ac7c4346` | 2026-07-30 |
|
||||
| `59f9c81ef8` | `8d46fb33d2` | 2026-07-30 |
|
||||
| `90251e4a55` | `e21e101004` | 2026-07-31 |
|
||||
| `1354767643` | `bc0769809d` | 2026-07-31 |
|
||||
| `c52b792511` | `0d0255cb7f` | 2026-07-31 |
|
||||
| `6a90a12b2c` | `252b16ca71` | 2026-07-31 |
|
||||
| `a3c7fb3c17` | `8465457a48` | 2026-07-31 |
|
||||
| `a40a8665ee` | `a414bb8585` | 2026-07-31 |
|
||||
| `29ffb88cdd` | `9e2f49b3dd` | 2026-07-31 |
|
||||
| `282540be9f` | `624274f5f0` | 2026-07-31 |
|
||||
| `a5597f0f8b` | `0d0c1659c6` | 2026-07-31 |
|
||||
| `574c1bf89c` | `a8767583da` | 2026-07-31 |
|
||||
| `5eeddc8a0a` | `1eb4968968` | 2026-07-31 |
|
||||
| `d4ed5e8cc0` | `c401f54e4d` | 2026-07-31 |
|
||||
| `95d43bcade` | `97e18bbf2f` | 2026-07-31 |
|
||||
| `a3d51ddf70` | `cf66ff018d` | 2026-07-31 |
|
||||
| `e7675d7b9f` | `a55adfdd65` | 2026-07-31 |
|
||||
| `e1f508d12e` | `b656eefdc7` | 2026-07-31 |
|
||||
| `15fd90655c` | `a2bfaaec8f` | 2026-08-01 |
|
||||
| `59e1719a10` | `5505b9cfc1` | 2026-08-01 |
|
||||
| `697e1674c0` | `5a8c42b5e9` | 2026-08-01 |
|
||||
| `2a2bb3778d` | `6e021ee853` | 2026-08-02 |
|
||||
| `c8d458734a` | `6b0261d66c` | 2026-08-02 |
|
||||
| `cc3f860bf8` | `c51b68194a` | 2026-08-02 |
|
||||
| `00bf0403c7` | `e21a895390` | 2026-08-02 |
|
||||
| `88f9bdb8d7` | `f4995e5882` | 2026-08-02 |
|
||||
| `55e1a0949f` | `80fcf6c227` | 2026-08-02 |
|
||||
| `99a87a2cef` | `4fdad89fa6` | 2026-08-06 |
|
||||
| `24cacf1000` | `c0774b5f58` | 2026-08-06 |
|
||||
| `a3965d2eb6` | `6f1dfedde2` | 2026-08-06 |
|
||||
| `b9358d91f7` | `6f33c7277a` | 2026-08-06 |
|
||||
| `bfd72cdf3e` | `580827f7ca` | 2026-08-06 |
|
||||
| `88127d9876` | `1d5a136dff` | 2026-08-06 |
|
||||
| `977903bdf7` | `f47baa553a` | 2026-08-06 |
|
||||
| `3c30dd512f` | `9ac56d671b` | 2026-08-06 |
|
||||
| `ed1c7ff5bc` | `965c456dee` | 2026-08-06 |
|
||||
| `83d733b9f5` | `26b6fd8938` | 2026-08-07 |
|
||||
|
||||
## threadnet-call — 9 Commits
|
||||
|
||||
| alt | neu | Datum |
|
||||
|---|---|---|
|
||||
| `6260cc4962` | `8fb630cfb3` | 2026-07-31 |
|
||||
| `c01d55d517` | `0823c8a866` | 2026-08-06 |
|
||||
| `7fb6251e1c` | `a6e555ac3f` | 2026-08-06 |
|
||||
| `077dd43af2` | `ac688d36f7` | 2026-08-06 |
|
||||
| `0be204e6d7` | `3f0f55e6bd` | 2026-08-06 |
|
||||
| `b265395e6d` | `84419133b3` | 2026-08-06 |
|
||||
| `760c6af264` | `6f94e6a8a3` | 2026-08-06 |
|
||||
| `8a38224f51` | `846135e48d` | 2026-08-06 |
|
||||
| `e8c7dfed36` | `e793902ae0` | 2026-08-07 |
|
||||
@@ -0,0 +1,47 @@
|
||||
# Issue-Migration Gitea → GitLab (gitops#48)
|
||||
|
||||
`migrate.py` überführt Issues (offen **und** geschlossen, inkl. Kommentare)
|
||||
eines Gitea-Repos in ein bestehendes GitLab-Projekt. Einmal-Werkzeug für den
|
||||
#48-Cutover; hier versioniert wegen Reproduzierbarkeit.
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
- **Dry-Run per Default**, `--execute` schreibt wirklich
|
||||
- **Idempotent** über Marker `<!-- gitea-migration: OWNER/REPO#N -->` in der
|
||||
Ziel-Beschreibung — Wiederholungsläufe überspringen Migriertes
|
||||
- **Zeitstempel bleiben erhalten** (Admin-Token darf `created_at` setzen);
|
||||
Autorschaft läuft auf den Token-User, Original-Autor+Datum stehen im
|
||||
Migrations-Fußtext bzw. Kommentar-Präfix (bekannter, akzeptierter Verlust)
|
||||
- Labels namensgleich (Gruppen-Labels müssen vorher existieren — Stand
|
||||
2026-08-01 sind die 9 Gitea-Labels + 5 `host:*` als Gruppe-13-Labels angelegt)
|
||||
- PRs werden ausgefiltert, geschlossene Issues nach Anlage geschlossen
|
||||
|
||||
## Aufruf
|
||||
|
||||
```
|
||||
python3 migrate.py sorb/<repo> <gitlab-projekt-id> # Dry-Run
|
||||
python3 migrate.py sorb/<repo> <gitlab-projekt-id> --execute
|
||||
```
|
||||
|
||||
Tokens: `~/.config/gitea-rohana/token` (read:issue) und
|
||||
`~/.config/gitlab-lab/token` (Admin) auf dem Mac.
|
||||
|
||||
## Stand
|
||||
|
||||
| Repo | Ziel | Status |
|
||||
|---|---|---|
|
||||
| sorb/thread-net-git | Projekt 18 | ✅ 2026-08-01 (1 Issue, nummerngleich) |
|
||||
| sorb/threadnet-call | Projekt 19 | ✅ 2026-08-01 (2 Issues, nummerngleich) |
|
||||
| sorb/ThreadNet-Web | Projekt 16 | ✅ 2026-08-01 (9 Issues, nummerngleich) |
|
||||
| sorb/axion1337.chat-gitops | Projekt 17 | ✅ 2026-08-01 (50 Issues, **Nummern verschoben**) |
|
||||
|
||||
⚠️ **gitops-Nummern sind NICHT deckungsgleich**: Gitea hatte Lücken (PRs zählen
|
||||
mit), GitLab vergibt lückenlos — z. B. Gitea#48 → GitLab#46, Gitea#51 → GitLab#49,
|
||||
Gitea#52 → GitLab#50. Die verbindliche Zuordnung steht im Migrations-Fußtext
|
||||
jedes GitLab-Issues (`Migriert aus Gitea …#N`); alte Commit-/Doku-Verweise auf
|
||||
„gitops#N" meinen die **Gitea**-Nummer.
|
||||
|
||||
**Cutover-Nachschritte** (siehe gitops#48): Gitea-Issues schließen/als migriert
|
||||
markieren ✅ 2026-08-01, Doku-Verweise umgebogen (CLAUDE.md-Topologieregel) ✅,
|
||||
Milestones wurden nicht migriert (akzeptierter Verlust, gitops hatte keine
|
||||
aktiven), Bot-/Token-Workflows (claude-issues → GitLab-Äquivalent) offen.
|
||||
@@ -0,0 +1,126 @@
|
||||
# Retro light — 2026-08-09
|
||||
|
||||
Erste Retro des Frameworks, angehängt an das Refinement vom selben Tag
|
||||
([Verfahren](../refinement.md)). Grundlage sind die vier AARs des Monats und 38
|
||||
im August geschlossene Issues.
|
||||
|
||||
---
|
||||
|
||||
## 1. Welche Verfahren haben getragen, welche haben gestört?
|
||||
|
||||
### Getragen
|
||||
|
||||
**„Alles Offene wird ein Issue."** Das ist das Verfahren, das diesen Monat am
|
||||
meisten eingebracht hat. Sämtliche stillen Fehler unten wurden nur deshalb nicht
|
||||
vergessen, weil sie im Moment des Findens ein Issue bekamen — auch die, für die
|
||||
gerade keine Zeit war.
|
||||
|
||||
**Die AAR-Pflicht.** Die vier AARs waren die einzige belastbare Vorbereitung für
|
||||
diese Retro. Ohne sie wäre sie eine Erinnerungsübung geworden.
|
||||
|
||||
**Die Board-Pflege-Tabelle** (2026-08-06). Sie hat gehalten: `status:next` und
|
||||
Meilenstein-Zuordnung blieben sorbs Entscheidung, auch als es unbequem war.
|
||||
management#15 und #20 lagen drei Tage ohne Spalte — das ist der beabsichtigte
|
||||
Preis, nicht ein Fehler.
|
||||
|
||||
### Gestört
|
||||
|
||||
**Der Status-Label-Satz ist in der Oberfläche nicht vollständig ablesbar.**
|
||||
`status:next`, `status:doing`, `status:wartet` — und „ohne Label = Backlog". Die
|
||||
vierte Spalte ist damit die einzige, die man nicht *sieht*, sondern erschließen
|
||||
muss. Genau deshalb hat eine Session am 2026-08-06 ein `status:offen` erfunden und
|
||||
in vier Projekten angelegt; aufgefallen ist es erst zwei Tage später.
|
||||
|
||||
Die Regel bleibt richtig — ein Label für „nichts Besonderes" wäre Rauschen. Aber
|
||||
der Reiz, es zu erfinden, ist real und wird wiederkommen. **Festgehalten statt
|
||||
geändert.**
|
||||
|
||||
---
|
||||
|
||||
## 2. Welche ADRs sind durch die Realität überholt?
|
||||
|
||||
**Keine überholt — aber eine Lücke.**
|
||||
|
||||
⚠️ **Die Commit-Konventionen und die Anonymisierung der Historie hätten eine ADR
|
||||
gebraucht.** Am 2026-08-07 wurde eine dauerhafte Prozessregel eingeführt (englische
|
||||
Conventional Commits, Zeitstempel auf 12:00 UTC) und am 2026-08-09 rückwirkend auf
|
||||
251 Commits angewandt — eine **irreversible** Änderung an vier Repos, mit
|
||||
Force-Push durch einen Mirror, von dem Flux liest.
|
||||
|
||||
Nach unserer eigenen Regel („ADR-Pflicht bei Architektur-/Prozessentscheidungen")
|
||||
ist das ein Lehrbuchfall. Stattdessen steht die Regel nur in der `CLAUDE.md` und
|
||||
die Durchführung in einer Zuordnungstabelle. Nachzuholen als **ADR-0009**.
|
||||
|
||||
**Beobachtung zu ADR-0005:** Das Kanban-Framework wurde diese Woche zweimal
|
||||
erweitert (Titel ohne Priorität, Meilenstein-Pflicht) — beides in der `CLAUDE.md`,
|
||||
nicht in der ADR. Das ist vertretbar, solange die ADR die *Entscheidung* hält und
|
||||
die `CLAUDE.md` die *Regel*. Es ist aber genau die Zwei-Orte-Konstruktion, die wir
|
||||
bei den Titel-Präfixen gerade aufgelöst haben. **Im Auge behalten.**
|
||||
|
||||
---
|
||||
|
||||
## 3. Fasert etwas aus?
|
||||
|
||||
**Nein — aber es gibt ein Muster, und das ist der eigentliche Befund des Monats.**
|
||||
|
||||
### Sechs stille Fehler in neun Tagen
|
||||
|
||||
| Was | Wie es aussah | Wie es wirklich stand |
|
||||
|---|---|---|
|
||||
| `build_embedded` (threadnet-call) | grün, seit jeher | lud **nie** ein Artefakt hoch, falscher Pfad |
|
||||
| npm-Paket `0.19.2-threadnet.6` | veröffentlicht | 12,5 KB statt 12,8 MB, **ohne `dist/`** |
|
||||
| Blueprint `matrix-recovery-flow` | Flux grün, ConfigMap aktuell | seit Tagen bei **jedem** Lauf verworfen |
|
||||
| gitops-Arbeitskopie | „normal" | `main` trackte **Gitea** — ein `git push` wäre in die verbotene Richtung gegangen |
|
||||
| Leere Pipelines | rot | **nichts kaputt** — der umgekehrte Fall, Rauschen, das rot abtrainiert |
|
||||
| Release-Pipeline auf `v0.4.0` | lief nach Tag-Push an | hätte ein veröffentlichtes Image überschrieben |
|
||||
|
||||
Gefunden wurde **keiner** davon durch eine Überwachung. Vier durch Zufall beim
|
||||
Suchen nach etwas anderem, zwei durch gezieltes Nachprüfen einer Behauptung.
|
||||
|
||||
### Das gemeinsame Merkmal
|
||||
|
||||
Alle sechs betreffen Vorgänge, die **erfolgreich aussehen, ohne es zu sein** — oder
|
||||
die genau umgekehrt Alarm auslösen, wo nichts ist. Der Verbund hat für keinen
|
||||
dieser Fälle eine Antwort auf die Frage: *Wer merkt es, wenn etwas leise aufhört zu
|
||||
funktionieren?*
|
||||
|
||||
Es gibt Issues für Einzelfälle — gitops#50 (Configs greifen nicht ohne Neustart),
|
||||
management#28 (Mirror-Ausfall unbemerkt), ThreadNet-Web#14 (Release überschreibbar,
|
||||
behoben). Was fehlt, ist die Klammer.
|
||||
|
||||
⚠️ **Der letzte Fall ist der unangenehmste.** Dass `v0.4.0` nicht überschrieben
|
||||
wurde, lag daran, dass die geschützten Registry-Variablen in genau diesem Fenster
|
||||
nicht verfügbar waren — **Glück, nicht Absicht.** Eine Schutzmaßnahme, die
|
||||
zufällig griff, ist kein Schutz.
|
||||
|
||||
### Vorschlag
|
||||
|
||||
Eine **Stillstandsprüfung**: ein geplanter Job, der die Invarianten prüft, die wir
|
||||
diesen Monat einzeln und mühsam gelernt haben — Blueprint-Status ≠ error, Mirror
|
||||
synchron, Pipeline ohne Jobs, Artefakt vorhanden, Paketgröße plausibel. Kein
|
||||
weiterer Agent, der Meldungen erzeugt, sondern **eine** Prüfung mit einem Ergebnis.
|
||||
|
||||
Das ist die Verallgemeinerung von management#28, das am 2026-08-06 bewusst nach
|
||||
hinten gestellt wurde. Die Rückstufung war zu dem Zeitpunkt vertretbar; sechs
|
||||
Fälle später sieht der Einzelfall aus wie ein Symptom. **Zur Entscheidung
|
||||
vorgelegt, nicht eigenmächtig umgestuft.**
|
||||
|
||||
---
|
||||
|
||||
## Beschlüsse dieses Refinements
|
||||
|
||||
- `status:next`: management#15 und #20 (fällig 31.08.) — Zusage von sorb
|
||||
- `status:wartet` entfernt bei threadnet-call#4 und ThreadNet-Web#11: der im Issue
|
||||
benannte Grund war weggefallen
|
||||
- **M5 — Härtung** angelegt, 14 Issues aus M1 verschoben. Trennlinie: *Ist etwas
|
||||
Vorhandenes kaputt (M1) oder fehlt etwas, das wir noch nie hatten (M5)?*
|
||||
Verteilung danach: M1 18 · M2 21 · M3 4 · M4 13 · M5 14
|
||||
|
||||
⚠️ Die beiden letzten Punkte sind einer Session **allein** untersagt
|
||||
([Board-Pflege](../refinement.md)). Sie fanden im Refinement mit sorb statt. Die
|
||||
Regel ist damit nicht aufgeweicht.
|
||||
|
||||
## Offen aus dieser Retro
|
||||
|
||||
1. **ADR-0009** zu Commit-Konventionen und Historien-Anonymisierung nachziehen
|
||||
2. **Stillstandsprüfung** — Entscheidung von sorb
|
||||
@@ -0,0 +1,305 @@
|
||||
---
|
||||
type: wiki-page
|
||||
area: admin
|
||||
related: []
|
||||
---
|
||||
|
||||
# CFGMON
|
||||
|
||||
Monitoring-Stack, Gitea und der Reverse Proxy für alles Öffentliche.
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **Hostname** | `CFGMON` |
|
||||
| **OS** | Ubuntu 24.04.4 LTS |
|
||||
| **IPv4** | `188.245.193.243` |
|
||||
| **IPv6** | `2a01:4f8:c17:93eb::1` |
|
||||
| **Privat** | `10.0.0.3` (`enp7s0`, Hetzner-Netz — dort liegt auch k3s auf `10.0.0.2`) |
|
||||
| **DNS** | `rohana.axion1337.de` → Gitea, `selendis.axion1337.de` → Grafana |
|
||||
| **Stand** | 2026-07-30 |
|
||||
|
||||
## Dienste
|
||||
|
||||
| Container | Image | Compose-Projekt | Definition |
|
||||
|---|---|---|---|
|
||||
| prometheus | `prom/prometheus:v3.3.1` | `monitoring` | `sorb/threadnet-operating`, `monitoring/` |
|
||||
| loki | `grafana/loki:3.7.1` | `monitoring` | dito |
|
||||
| grafana | `grafana/grafana:12.0.0` | `monitoring` | dito |
|
||||
| alloy | `grafana/alloy:v1.16.0` | `monitoring` | dito |
|
||||
| node-exporter | `prom/node-exporter:v1.9.1` | `monitoring` | dito |
|
||||
| traefik | `traefik:v3.7.9` | `thread-net-git` | `sorb/thread-net-git`, seit 2026-07-30 in `main` (siehe [CFGMON-02](#cfgmon-02--traefik-gitea-cadvisor-und-runner-unter-iac-gebracht--erledigt-2026-07-30)) |
|
||||
| gitea | `gitea/gitea:1.27.0` | `thread-net-git` | dito, gepinnt (war `:latest`) |
|
||||
| cadvisor | `gcr.io/cadvisor/cadvisor:v0.49.1` | `thread-net-git` | dito, gepinnt (war `:latest`) |
|
||||
| runner | `gitea/act_runner:0.6.1` | `thread-net-git` | dito, Container `gitea-runner`, siehe CFGMON-02 |
|
||||
| portainer_agent | `portainer/agent:2.27.5` | — | standalone, kein Compose |
|
||||
|
||||
Prometheus-Jobs: `operating_prometheus`, `operating_node-exporter`,
|
||||
`operating_cadvisor`, `operating_traefik` (alle lokal), `k3s_host_node`
|
||||
(`10.0.0.2:9100`), `pterodactyl_host_node` und `gameserver_cadvisor`
|
||||
(beide `157.90.155.206`, siehe [game](game.md)).
|
||||
|
||||
## Offene Punkte → git.lab-Issues
|
||||
|
||||
Seit dem Framework-Umbau (2026-08-01) leben offene Punkte als Issues im
|
||||
[management-Projekt](https://git.lab/axion1337.chat/management/-/issues); die IDs bleiben in den Issue-Titeln erhalten.
|
||||
Dieses File hält nur noch Bestand und Historie.
|
||||
|
||||
- [CFGMON-01 — Zertifikatserneuerung braucht offene Ports (zeitkritisch ab 2026-09-28)](https://git.lab/axion1337.chat/management/-/issues/7)
|
||||
- [CFGMON-03 — Prometheus-Remote-Write/Loki öffentlich ohne Auth (Weg A, nachgelagerte Prüfung)](https://git.lab/axion1337.chat/management/-/issues/8)
|
||||
- [CFGMON-04 — Grafana-Admin-Credentials aus `.env` gelten nicht für die API](https://git.lab/axion1337.chat/management/-/issues/9)
|
||||
- [CFGMON-09 — Gitea-Backups off-host (⚠️ Backup-Cron deaktiviert)](https://git.lab/axion1337.chat/management/-/issues/10)
|
||||
|
||||
## CFGMON-11 — Gitea-CI-Rückbau nach GitLab-Umzug
|
||||
|
||||
**Status:** erledigt (2026-07-31 spätabends) — bis auf einen kosmetischen Handgriff:
|
||||
auf CFGMON `cd /opt/thread-net-git && git checkout main && git pull` (Checkout parkt
|
||||
noch auf dem inhaltsgleichen, inzwischen gelöschten Fix-Branch).
|
||||
|
||||
**Dazu neu (2026-08-01 ~05:00):** Auch `/opt/threadnet-operating` braucht einmal
|
||||
`git fetch && git reset --hard origin/main` — der State-Persistenz-Commit wurde
|
||||
dort direkt nach Gitea gepusht (dfe04c4a), vom Mirror überschrieben, vom Mac aus
|
||||
per Patch gerettet und kanonisch als `6ffab68` neu aufgelegt (inhaltsgleich,
|
||||
anderer Hash; Autorschaft erhalten).
|
||||
|
||||
**Erledigt (2026-08-01, autonom):**
|
||||
- Actions-Toggles deaktiviert: `ThreadNet-Web`, `threadnet-call`, `axion1337.chat-gitops`
|
||||
- `ThreadNet-Web`: alle `.github/workflows/`-Dateien entfernt (Commit `a876758`)
|
||||
- gitops: Verifikations-Job nach GitLab portiert + `.gitea/workflows/` entfernt
|
||||
(Commit `5e46a24`, Pipeline grün, Mirror→Gitea verifiziert; `milestone-release.yml`
|
||||
war toter Code, siehe #33). Flux unberührt.
|
||||
- `thread-net-git`: Runner-Service/Config/`.env.example` per Commit `d904734` entfernt
|
||||
(auf git.lab; Mirror trägt nach Gitea) — **noch nicht deployt**, siehe unten.
|
||||
- Registry-Entscheidung npm final (Evidenz: `@sorb/threadnet-call-embedded` ist
|
||||
pnpm-Dependency von `apps/web`, Lockfile pinnt Tarball-URL auf rohana): **bleibt Gitea**.
|
||||
|
||||
**Verbleibende manuelle Schritte (User):**
|
||||
1. ~~`thread-net-git`-Stand deployen~~ **erledigt (2026-07-31 spätabends, via
|
||||
CFGMON-Session)**: Runner-Container/Netz/`runner-data/`/`.env`-Zeile entfernt,
|
||||
`builder-1` aus der Gitea-Admin-UI gelöscht, Actions-Registrierungstoken rotiert.
|
||||
Stolperstein dabei: Rückbau-Commit `d904734` hinterließ ein verwaistes
|
||||
`networks:`-Fragment (YAML invalide) — Fix nahm den kanonischen Weg
|
||||
Mac→git.lab→Mirror (`15c8f2d`), Hergang in thread-net-git#1 (geschlossen).
|
||||
2. ~~Token-Rotation a~~ **geklärt (2026-07-31 abends)**: der versehentlich in die VM
|
||||
getippte Token (`a89bfb…`) war der Gitea-**Actions-Runner-Registrierungstoken**
|
||||
(taucht nicht unter Access Tokens auf) — kein Access-Token-Risiko; wird mit
|
||||
Schritt 1 obsolet. Nach dem Runner-Löschen in der Admin-UI den
|
||||
Registrierungstoken dort einmal neu generieren (ein Klick), dann ist auch der
|
||||
exponierte Wert wertlos.
|
||||
3. ~~Token-Rotation b~~ **erledigt (2026-07-31 abends)**: Generalschlüssel
|
||||
(`Projectplaning and implemantation axion`, war npm-Publish UND Issue-Verwaltung,
|
||||
Klartext in `.npmrc` + Scratchpad + macOS-Schlüsselbund) gelöscht und durch drei
|
||||
least-privilege-Tokens ersetzt: `gitlab-ci-npm` (write:package, als maskierte
|
||||
GitLab-Gruppen-Variable `GITEA_NPM_TOKEN`), `claude-issues` (write:issue,
|
||||
`~/.config/gitea-rohana/token` auf dem Mac), `claude-push` (write:repository,
|
||||
`~/.config/gitea-rohana/push-token`). Erster CI-Publish `0.19.2-threadnet.6`
|
||||
verifiziert → threadnet-call#1 geschlossen. Alle Klartext-Reste entfernt
|
||||
(.npmrc, Skript, Schlüsselbund-Eintrag). Zusätzlich aufgeräumt: ungenutzte
|
||||
Alt-Tokens `claude-push-20260730`, `claude-monitoring-rework-20260730` gelöscht.
|
||||
|
||||
Entscheidung vom 2026-07-30: Build-CI/CD zieht ins Homelab-GitLab
|
||||
(`git.lab/axion1337.chat`, Gruppe mit importierten Projekten angelegt; die Domain ist
|
||||
**nur im Homelab auflösbar** — von CFGMON/MATRIX aus nicht erreichbar, was für den
|
||||
Build-Anwendungsfall in Ordnung ist: Prod läuft bei Lab-Ausfall weiter, nur neue Builds
|
||||
pausieren). Der am 2026-07-30 auf Gitea-Seite aufgebaute CI-Unterbau wird damit teilweise
|
||||
überflüssig. **Erst zurückbauen, wenn die GitLab-CI nachweislich läuft.**
|
||||
|
||||
### Sicher rückbaubar
|
||||
|
||||
- **Actions-Toggle** `has_actions` bei `ThreadNet-Web` (am 2026-07-30 per API aktiviert)
|
||||
wieder deaktivieren, ebenso bei `threadnet-call` (stoppt die fehlschlagende
|
||||
Workflow-Kaskade dort).
|
||||
- **`.github/workflows/` in `ThreadNet-Web`** (der kuratierte 6-Dateien-Satz) — wird durch
|
||||
`.gitlab-ci.yml` ersetzt. Die Erkenntnisse aus den Läufen vom 2026-07-30 mitnehmen:
|
||||
kein `layered.sh` (würde den js-sdk-Pin mit Upstream-develop überschreiben, braucht
|
||||
außerdem jq), stattdessen `pnpm install --frozen-lockfile`; webpack-Build braucht
|
||||
real ~4 GB Heap; `contains(needs.*.result, ...)`-Gates sind act-spezifisch kaputt.
|
||||
- **Geerbte Upstream-Workflows in `threadnet-call`** (build/publish/test/translations/
|
||||
zizmor/pr-deploy) — gleiches Schicksal.
|
||||
- **Runner-Identität**: wenn der Runner-Service entfällt (siehe unten), `builder-1` in
|
||||
der Gitea-Admin-UI deregistrieren und `runner-data/.runner` auf dem Host entfernen.
|
||||
- **Token: npm-Token in `threadnet-call`s untracked `embedded/web/.npmrc`** (Klartext im
|
||||
Arbeitsverzeichnis, Fund vom 2026-07-30): revoken/rotieren. Der GitLab-CI-Publish
|
||||
bekommt einen eigenen, frisch erzeugten Token als GitLab-CI-Variable — der alte
|
||||
verschwindet von der Platte.
|
||||
|
||||
### Entscheidungsabhängig
|
||||
|
||||
- **Runner-Service in `thread-net-git` ganz entfernen?** Hängt daran, ob das gitops-Repo
|
||||
seinen leichten `deploy-on-push.yml` (YAML-Validierung/Notification, läuft sauber)
|
||||
behält — dann bleibt ein Minimal-Runner nötig. Bei Komplett-Entfernung als
|
||||
Revert-Commit in `thread-net-git`: Compose-Service `runner`, `runner/config.yaml`,
|
||||
`.env.example` (RUNNER_TOKEN), Cache-Port-Bindung 8088, `runner-data/`.
|
||||
- **Registry-Ziel für `@sorb/threadnet-call-embedded`**: bleibt die Gitea-npm-Registry
|
||||
(dann braucht GitLab-CI einen Push-Token dorthin — Neuanlage) oder wandert in die
|
||||
GitLab-Package-Registry (dann läuft die Gitea-Package-Seite leer).
|
||||
- **Container-Images bleiben in der rohana-Registry** (Flux/k8s pullt von dort — spricht
|
||||
stark für Beibehalt). Gegenstück zur Token-Bilanz: GitLab-CI braucht dann einen
|
||||
**neuen** Deploy-/Push-Token für die rohana-Registry (Neuanlage, kein Rückbau).
|
||||
|
||||
### Explizit nicht rückbaubar
|
||||
|
||||
Gitea selbst, gitops-Repo als Flux-Source, Issues/Wiki/dieses Repo, der
|
||||
API-Token für Issue-Verwaltung, das Gitea-Backup-Script (CFGMON-09).
|
||||
|
||||
*(Stand der Analyse 2026-07-31. Issues und dieses Repo sind seitdem doch
|
||||
umgezogen — [ADR-0002](../../adr/0002-issues-und-management-ins-lab.md) —,
|
||||
das Repo dabei von `Backlogs` zu `management` umgewidmet
|
||||
[ADR-0005](../../adr/0005-pm-framework-kanban.md). „Nicht rückbaubar" galt für
|
||||
den damaligen Rückbau der Gitea-CI, nicht auf Dauer.)*
|
||||
|
||||
Betroffene Issues (werden bei der GitLab-Migrations-Planung umformuliert):
|
||||
`ThreadNet-Web#2` (Gitea-Zählung, Tracker stillgelegt — verbindlich: Migrations-Fußtext im GitLab-Issue),
|
||||
`threadnet-call#1` (Gitea-Zählung, Tracker stillgelegt).
|
||||
|
||||
**Nächster Schritt:** die drei manuellen Schritte oben, dann → erledigt.
|
||||
|
||||
## CFGMON-13 — Absender-Design für Release-/CVE-Meldungen: eigener Bot?
|
||||
|
||||
**Status:** entschieden (2026-08-01, sorb) — **gleicher Bot (`@alerts`), eigener Raum**
|
||||
`!YRJvcEbVXtRlUIkNld:axion1337.chat`. Umsetzungsplan inkl. CVE-Metriken/Grafana/
|
||||
Alertmanager-Routing: [gitops#45 auf git.lab](https://git.lab/axion1337.chat/axion1337.chat-gitops/-/issues/45) (ehemals Gitea-gitops#47, Tracker stillgelegt).
|
||||
release-watch ist bereits auf den Raum vorbereitet (Env `MATRIX_RELEASE_ROOM_ID`,
|
||||
Fallback Alerts-Raum). ⬜ Rest: `@alerts` in den Raum **einladen** (Join wurde als
|
||||
restricted abgelehnt — sorb), dann Deploy.
|
||||
|
||||
Zwei neue Meldequellen entstehen gerade neben dem klassischen Alerting:
|
||||
1. **release-watch** (gitops#22, deploybereit): Upstream-Releases/Security-Releases
|
||||
→ aktuell als Notiz über den `@alerts`-Bot in den Alerts-Raum
|
||||
2. **Trivy-CVE-Scans** (gitops#31, läuft wöchentlich in der Lab-CI): Funde landen
|
||||
bisher NUR als Job-Artifact/-Log — keine aktive Benachrichtigung
|
||||
|
||||
**Frage:** Sollen diese "Informations-Meldungen" (Releases, CVE-Reports) einen
|
||||
**eigenen Bot** bekommen (z. B. `@releases:axion1337.chat`, ggf. eigener Raum),
|
||||
damit `@alerts` ausschließlich für echte Betriebsalarme steht und separat
|
||||
scharf/stumm schaltbar bleibt? Oder bewusst alles über `@alerts` bündeln?
|
||||
|
||||
Bei Entscheidung "eigener Bot": Anlage per mas-cli wie gehabt, release-watch-Env
|
||||
umziehen, Trivy-Anbindung (CI-Job → Matrix-Notiz bei Funden) gleich mit auf den
|
||||
neuen Absender bauen.
|
||||
|
||||
## CFGMON-12 — Gitea-Projektmetadaten nach GitLab umziehen/integrieren
|
||||
|
||||
**Status:** abgelöst durch [gitops#46 auf git.lab](https://git.lab/axion1337.chat/axion1337.chat-gitops/-/issues/46) (ehemals Gitea-gitops#48, Tracker stillgelegt) (2026-08-01, sorb: HOHE Priorität — vollständige Issue-Migration + zentrale Gruppen-Roadmap; Plan-Skizze und die offene Erreichbarkeits-Entscheidung git.lab-only vs. extern stehen dort)
|
||||
|
||||
✅ **Umgesetzt am 2026-08-01/02**: Die Migration ist durch — 62 Issues liegen auf
|
||||
git.lab, die Gitea-Issues sind geschlossen und tragen einen Migrations-Fußtext.
|
||||
Alles darunter ist der **Stand vor dem Umzug** und bleibt als Historie stehen;
|
||||
die Aufzählung „Noch auf Gitea" gilt nicht mehr. Die zunächst verbliebene Ausnahme
|
||||
für Deploy-Übergabe-Issues ist am 2026-08-02 mit LABNET-03 ebenfalls zurückgebaut.
|
||||
|
||||
---
|
||||
|
||||
Beim CI/CD-Umzug (2026-07-31) ist nur der **Code** nach git.lab gewandert; alle
|
||||
Projektmetadaten liegen weiterhin auf Gitea/rohana. Verifiziert per API am
|
||||
2026-07-31: alle 20 git.lab-Projekte melden `open_issues=0`.
|
||||
|
||||
Noch auf Gitea:
|
||||
|
||||
- **Issues** inkl. Kommentare/Labels: ThreadNet-Web (#2, #5, …), threadnet-call (#1),
|
||||
gitops (#24, #25, #32, …)
|
||||
- **Meilensteine** (u. a. die Release-Meilensteine im gitops-Repo)
|
||||
- **Wiki** (gitops-Wiki mit `00-TASKS.md`-Log — bisher bewusst direkt-Gitea)
|
||||
- **Releases/Packages** (npm-Registry bleibt laut Lockfile-Entscheidung in
|
||||
[CFGMON-11](#cfgmon-11--gitea-ci-rückbau-nach-gitlab-umzug) auf rohana — bei
|
||||
diesem Punkt prüfen, ob das so bleibt)
|
||||
|
||||
Vor Umsetzung zu klären:
|
||||
|
||||
1. **GitLab-Gitea-Importer vs. API-Skript** — der Importer verliert Autorenschaft
|
||||
(alles läuft unter dem Import-User) und Issue-Nummern können sich verschieben
|
||||
→ Commit-/Kommentar-Referenzen prüfen.
|
||||
2. **Erreichbarkeit**: rohana ist von überall erreichbar, git.lab nur im Homelab —
|
||||
das gilt dann für alle Issues und muss bewusst entschieden werden. Gleiches
|
||||
Argument betrifft dieses Repo selbst (damals noch `Backlogs`, bewusst
|
||||
direkt-Gitea).
|
||||
3. **Flux-relevante Teile**: ob die gitops-Wiki-Konventionen mitgehen.
|
||||
|
||||
Nach dem Umzug gehört ein Hinweis in die Topologie-Abschnitte (gitops
|
||||
README/CLAUDE.md, Fork-Docs) — dort steht aktuell „Issues/Wiki/Releases bleiben
|
||||
auf Gitea" als geltende Regel.
|
||||
|
||||
---
|
||||
|
||||
## Erledigt
|
||||
|
||||
### CFGMON-10 — threadnet-call-CI schlägt am Artifact-Schritt fehl · verworfen 2026-07-30
|
||||
|
||||
Ausgelöst durch einen Push nach `threadnet-call` am 2026-07-30: der Runner (`builder-1`)
|
||||
verarbeitete mehrere geerbte Upstream-Workflows, die meisten scheiterten am
|
||||
Artifact-Upload/-Download-Schritt. Ursprünglich unverifizierte Hypothese: das
|
||||
Job-Container-Limit (2,2 GiB / 1,5 CPU) ist zu knapp.
|
||||
|
||||
**Hypothese inzwischen im Kern bestätigt** — beim parallelen ThreadNet-Web-CI-Versuch
|
||||
starb der webpack-Build bei 92 % mit `FATAL ERROR: ... JavaScript heap out of memory`
|
||||
(Job 3442, 2026-07-30): diese Build-Klasse braucht real ~4 GB, der Host (3,7 GiB gesamt,
|
||||
ohne Swap, trägt daneben Gitea/Traefik/Monitoring) kann das strukturell nicht liefern.
|
||||
|
||||
**Verworfen statt gefixt**: Limit-Anhebung/Swap wird bewusst nicht weiterverfolgt —
|
||||
Build-CI zieht ins Homelab-GitLab um (siehe
|
||||
[CFGMON-11](#cfgmon-11--gitea-ci-rückbau-nach-gitlab-umzug)), CFGMON bleibt bei leichten
|
||||
Jobs. Issue-Seite: `threadnet-call#1` (Gitea-Zählung, Tracker stillgelegt).
|
||||
|
||||
### CFGMON-02 — Traefik, Gitea, cAdvisor und Runner unter IaC gebracht · erledigt 2026-07-30
|
||||
|
||||
Liefen ursprünglich im Compose-Projekt `thread-net-git` aus `/data/compose/8`, einem von
|
||||
Portainer verwalteten Stack ohne Repo dazu. Jetzt in `sorb/thread-net-git`: `:latest`-Tags
|
||||
gepinnt (Gitea `1.27.0`, cAdvisor `v0.49.1`), Projektname `thread-net-git` beibehalten
|
||||
(Volume-Kontinuität), README mit Betriebsregeln ("nie wieder über Portainer anfassen",
|
||||
Volume-Namen, Downgrade-Verbot für Gitea), nächtliches Backup-Script. Zusätzlich neu: ein
|
||||
`runner`-Service (`gitea/act_runner:0.6.1`, Container `gitea-runner`, Labels
|
||||
`ubuntu-latest`/`linux-build`/`win-wine` — die letzten beiden gezielt für Electron-Builds)
|
||||
— ursprünglich unter [CFGMON-08](#cfgmon-08) als offene Frage gelistet, siehe dort.
|
||||
|
||||
Entstanden auf Branch `rework/stack`, zunächst nicht gemergt (produktiv aber schon aktiv).
|
||||
**2026-07-30 nach `main` gemergt** (`origin/main` == `origin/rework/stack` auf `02b3224`,
|
||||
verifiziert) — damit spiegelt die Standardansicht des Repos jetzt den Live-Stand.
|
||||
Verifiziert am 2026-07-30 über die Compose-Labels der laufenden Container
|
||||
(`working_dir: /opt/thread-net-git`) und `docker compose ls`. `gitea-data` ist als
|
||||
external Volume deklariert — ein Deploy mit falschem Projektnamen schlägt laut fehl,
|
||||
statt leise ein leeres Volume anzulegen.
|
||||
|
||||
Zum Bootstrapping-Problem (Definition von Gitea liegt in Gitea): mitigiert,
|
||||
weil das Deploy-Verzeichnis selbst der Checkout ist — fällt Gitea aus, liegt
|
||||
die Definition weiterhin lokal auf dem Host. Gegen Verlust des ganzen Hosts
|
||||
hilft nur die Off-Host-Kopie, siehe
|
||||
[CFGMON-09](#cfgmon-09--gitea-backups-off-host-in-die-storage-box-eigenes-borg-repo).
|
||||
|
||||
### CFGMON-05 — Monitoring-Stack unter IaC bringen · erledigt 2026-07-30
|
||||
|
||||
Der Stack lief aus `/opt/monitoring` ohne Versionierung und mit `:latest`-Tags. Jetzt
|
||||
in `sorb/threadnet-operating` unter `monitoring/`, Images gepinnt,
|
||||
Grafana-Datasources und 9 Dashboards provisioniert. Projektname `monitoring`
|
||||
beibehalten, dadurch blieben die Volumes erhalten.
|
||||
|
||||
### CFGMON-06 — Grafana-Certresolver zeigte ins Leere · erledigt 2026-07-30
|
||||
|
||||
Das Label sagte `certresolver=le`, Traefik kennt den Resolver aber als
|
||||
`letsencrypt`. Traefik protokollierte `Router uses a nonexistent certificate
|
||||
resolver` und lieferte für `selendis.axion1337.de` sein Default-Self-Signed-Cert
|
||||
aus. Aus dem Altbestand in `/opt/monitoring` unverändert übernommen und dort
|
||||
mindestens seit dem 2026-07-27 vorhanden.
|
||||
|
||||
Behoben in `threadnet-operating`, Commit `a400f8a`. Cert von Let's Encrypt (YR2)
|
||||
ausgestellt, gültig bis 2026-10-28 — die Nachfolge davon ist
|
||||
[CFGMON-01](#cfgmon-01--zertifikatserneuerung-braucht-offene-ports-ipv4-und-ipv6).
|
||||
|
||||
### CFGMON-07 — Alloy verlor seine Positions-Datei bei jedem Deploy · erledigt 2026-07-30
|
||||
|
||||
`--storage.path=/var/lib/alloy/data` war gesetzt, aber ohne Volume: die
|
||||
Positions-Datei lag im Container-Layer. Nach jedem Recreate las Alloy alle
|
||||
Docker-Logdateien von vorn, worauf Loki alles älter als 7 Tage mit HTTP 400 abwies
|
||||
(`timestamp too old`, `reject_old_samples`). Betroffen waren nur Alt-Logzeilen bis
|
||||
zurück zu 2025, keine aktuellen Daten.
|
||||
|
||||
Behoben durch ein `alloy_data`-Volume, Commit `edac97e`. Verifiziert: Positions
|
||||
überleben `--force-recreate`, zweiter Recreate erzeugt 0 Fehler.
|
||||
|
||||
### CFGMON-08 — Kein Gitea-Actions-Runner registriert, Standort noch offen · erledigt 2026-07-30
|
||||
|
||||
**Korrektur einer falschen Prämisse**: der Eintrag ging davon aus, dass gar kein Runner
|
||||
existiert und wo einer laufen sollte, noch offen sei. Beides falsch — ein Runner
|
||||
(`builder-1`) läuft bereits, auf CFGMON, als Teil von `thread-net-git`s `rework/stack`-
|
||||
Branch, mit gezielt für Electron-Builds eingerichteten Labels. Details siehe
|
||||
[CFGMON-02](#cfgmon-02--traefik-gitea-cadvisor-und-runner-unter-iac-gebracht--erledigt-2026-07-30) — hier
|
||||
nicht dupliziert. `gitops#33` (Gitea-Zählung, Tracker stillgelegt)
|
||||
(dieselbe falsche Prämisse) entsprechend korrigiert/geschlossen.
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
type: wiki-page
|
||||
area: admin
|
||||
related: []
|
||||
---
|
||||
|
||||
# game
|
||||
|
||||
Pterodactyl- / Gameserver-Host.
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **IPv4** | `157.90.155.206` |
|
||||
| **IPv6** | kein AAAA-Record |
|
||||
| **DNS** | `game.axion1337.de` |
|
||||
| **Privat** | `10.0.0.4` (im vSwitch seit 2026-08-02) |
|
||||
| **Stand** | 2026-08-02 |
|
||||
|
||||
> **Teil-inventarisiert (2026-08-02).** Die Compose-Definitionen sind bekannt, der
|
||||
> Host selbst wurde weiterhin nicht betreten — OS-Stand, Plattenbelegung und
|
||||
> Docker-Version fehlen. Beim ersten direkten Zugriff nachtragen.
|
||||
|
||||
## Was darauf läuft
|
||||
|
||||
Zwei über **Coolify** deployte Stacks, abgebildet in
|
||||
[axion1337.chat/game-operating](https://git.lab/axion1337.chat/game-operating)
|
||||
(angelegt 2026-08-02).
|
||||
|
||||
⚠️ Das Repo ist ein **Abbild, keine Quelle**: Verwaltet wird weiter in Coolify,
|
||||
Änderungen müssen dort *und* im Repo passieren. Der Umstieg auf git-basiertes
|
||||
Deployment ist gewollt, aber bewusst **zurückgestellt, bis das Matrix-Projekt
|
||||
abgeschlossen ist** (sorb, 2026-08-02). Bis dahin fehlen dem Abbild noch die
|
||||
mitgemounteten Konfigdateien (`entrypoint.sh`, wings-Config, die drei
|
||||
Monitoring-Konfigs) und die Volume-Deklarationen — **aus dem Repo allein ließe
|
||||
sich der Host derzeit nicht wiederherstellen.**
|
||||
|
||||
**Pterodactyl** (Gameserver-Verwaltung, in Benutzung durch Bekannte des Betreibers
|
||||
— Ausfälle und Datenverlust sind hier real spürbar):
|
||||
|
||||
| Dienst | Image |
|
||||
|---|---|
|
||||
| `pterodactyl` (Panel) | `ghcr.io/pterodactyl/panel:v1.12.0` |
|
||||
| `wings` (Daemon, fährt die Gameserver als Docker-Container) | `ghcr.io/pterodactyl/wings:v1.12.0` |
|
||||
| `mariadb` | `mariadb:11.8` |
|
||||
| `redis` | `redis:alpine` |
|
||||
|
||||
**Eigener Monitoring-Stack** (grafana-oss, prometheus v3.0.0 mit 15 d Retention,
|
||||
loki 3.1.1, promtail 3.1.1, node-exporter v1.8.1, cadvisor v0.49.2). Wird
|
||||
perspektivisch von CFGMON abgelöst — siehe unten.
|
||||
|
||||
⚠️ **Kein einziger `ports:`-Block in beiden Stacks.** Alles hängt an Coolifys
|
||||
Docker-Netz und ist nur containerintern erreichbar. Genau das war die Ursache von
|
||||
GAME-01: Auf 9100/8080 des Hosts lauscht nichts, CFGMONs Scrape-Ziele auf der
|
||||
öffentlichen IP konnten nie funktionieren.
|
||||
|
||||
## Erreichbarkeit von außen (gemessen)
|
||||
|
||||
Vor dem Host liegt eine **quellbewusste Firewall** — dieselben Ports verhalten sich
|
||||
je nach Quelle unterschiedlich:
|
||||
|
||||
| Port | von CFGMON (`188.245.193.243`, 2026-08-01) | vom Hausanschluss (`178.25.213.70`, 2026-08-02) |
|
||||
|---|---|---|
|
||||
| 80 / 443 | offen | offen (HTTP 404 bzw. 503) |
|
||||
| **22** | **Timeout** | **offen** |
|
||||
| 8080 / 9100 (Exporter) | Timeout | Timeout |
|
||||
| ICMP | 100 % Verlust | 100 % Verlust |
|
||||
|
||||
Daraus folgt zweierlei: Es gibt bereits eine **SSH-Freigabe für den Hausanschluss**,
|
||||
und CFGMON ist **nicht pauschal gesperrt** (sonst wären auch 80/443 von dort tot) —
|
||||
es ist eine portbezogene Regel mit Quellliste. Die Exporter-Ports 8080/9100 sind
|
||||
dagegen **für niemanden** freigegeben, auch nicht für den Hausanschluss.
|
||||
|
||||
Es fehlte also keine Ausnahme für CFGMON. Seit 2026-08-02 liegt der Host im
|
||||
vSwitch (`10.0.0.4`); die Monitoring-Anbindung läuft künftig **per Push über das
|
||||
private Netz** — Alloy sammelt lokal ein und schiebt nach `10.0.0.3`, wodurch der
|
||||
Host **keinen einzigen eingehenden Port** braucht. Dasselbe Muster wie beim
|
||||
k3s-Cluster. Details: [GAME-01](https://git.lab/axion1337.chat/management/-/issues/2).
|
||||
|
||||
Die Umstellung erfolgt **additiv**: Der lokale Monitoring-Stack läuft weiter, bis
|
||||
auf CFGMON über Wochen belastbar Daten liegen. Auf diesem Host wird nichts
|
||||
abgeräumt, solange nicht klar ist, dass nichts fehlt.
|
||||
|
||||
## Offene Punkte → git.lab-Issues
|
||||
|
||||
Seit dem Framework-Umbau (2026-08-01) leben offene Punkte als Issues im
|
||||
[management-Projekt](https://git.lab/axion1337.chat/management/-/issues); die IDs bleiben in den Issue-Titeln erhalten.
|
||||
Dieses File hält nur noch Bestand und Historie.
|
||||
|
||||
- [GAME-01 — Host von CFGMON aus nicht erreichbar, 2 Targets down (⚠️ Silences bis 2026-08-04)](https://git.lab/axion1337.chat/management/-/issues/2)
|
||||
- [GAME-02 — `www.game.axion1337.de` ist überflüssig](https://git.lab/axion1337.chat/management/-/issues/3)
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
---
|
||||
type: wiki-page
|
||||
area: admin
|
||||
related: []
|
||||
---
|
||||
|
||||
# matrix
|
||||
|
||||
Matrix-Homeserver (Element Server Suite / Synapse) + K3s-Single-Node-Cluster, GitOps-verwaltet.
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **Hostname** | `MATRIX` |
|
||||
| **IPv4** | `49.13.132.245` |
|
||||
| **IPv6** | kein AAAA-Record |
|
||||
| **Privat** | `10.0.0.2` (`enp7s0`, dasselbe Hetzner-Netz wie CFGMON `10.0.0.3`) |
|
||||
| **OS** | Debian 13 (trixie) |
|
||||
| **DNS** | `matrix.axion1337.de` **und** `matrix.axion1337.chat` zeigen auf dieselbe IP — ebenso `axion1337.chat` (Apex) und `account.axion1337.chat` (MAS). `axion1337.de` ist die ältere/Registrar-Domain (IONOS-Mail läuft dort), `axion1337.chat` die eigentliche Matrix-Service-Domain. |
|
||||
| **Stand** | 2026-07-30 |
|
||||
|
||||
**Inventarisiert** (direkter SSH-Zugriff, `~/.ssh/config`-Alias `axion1337`, Port 2248):
|
||||
K3s + FluxCD + Element Server Suite (Synapse, MAS, Element Web, MatrixRTC), Authentik (OIDC),
|
||||
Traefik, Cert-Manager, coturn, Draupnir, ClamAV, NetworkPolicies (Default-Deny). IaC-Repo:
|
||||
[`sorb/axion1337.chat-gitops`](https://rohana.axion1337.de/sorb/axion1337.chat-gitops) - dieser
|
||||
Host **ist** das Deployment-Ziel dieses Repos, nicht nur verwandt. Client-Forks:
|
||||
`sorb/ThreadNet-Web` (Element Web), `sorb/threadnet-call` (Element Call/LiveKit-Widget).
|
||||
`sorb/element-web` und `sorb/ThreadNet-Stack` sind **veraltete/abgelöste** Vorgänger-Repos
|
||||
(letzte Aktivität 2026-05-11 bzw. 2025-10-24) - nicht mehr das, was hier läuft.
|
||||
|
||||
`ufw`: aktiv, Default Deny Incoming / Allow Outgoing, explizite Allow-Regeln für
|
||||
2248/tcp (SSH), 80/443, TURN/RTC-Ports. `unattended-upgrades` aktiv (Debian-Security +
|
||||
Debian-Origin), siehe [MATRIX-04](#matrix-04--host-level-pre-update-benachrichtigung-erledigt).
|
||||
|
||||
## Offene Punkte → git.lab-Issues
|
||||
|
||||
Seit dem Framework-Umbau (2026-08-01) leben offene Punkte als Issues im
|
||||
[management-Projekt](https://git.lab/axion1337.chat/management/-/issues); die IDs bleiben in den Issue-Titeln erhalten.
|
||||
Dieses File hält nur noch Bestand und Historie.
|
||||
|
||||
- [MATRIX-03 — `www.matrix.axion1337.de` ist überflüssig](https://git.lab/axion1337.chat/management/-/issues/1)
|
||||
|
||||
## MATRIX-05 — node-exporter-DaemonSet in CrashLoopBackOff, Cluster-Scrape seit 2026-08-01 tot
|
||||
|
||||
**Status:** erledigt (2026-08-01 ~04:10, vom Mac aus mit kubectl/SSH)
|
||||
|
||||
**Auflösung:** Beide Teile hatten dieselbe Wurzel — ein **doppelter node-exporter**.
|
||||
Teil 1 bestätigt per Pod-Log: `listen tcp 0.0.0.0:9100: bind: address already in use`;
|
||||
den Port hält der systemd-Dienst `prometheus-node-exporter` (der etablierte, den CFGMON
|
||||
via `10.0.0.2:9100` scrapt). Teil 2 erklärt: der Cluster-Service "funktionierte" nur in
|
||||
den Ready-Momenten des Crashloop-Pods, dessen hostNetwork-Endpoint (= Host-IP) zufällig
|
||||
auf den gesunden systemd-Exporter zeigte; seit der Endpoint dauerhaft NotReady war,
|
||||
setzte kube-proxy `no endpoints → REJECT`. ufw-Regeln seit April unverändert — kein
|
||||
Firewall-Drift; extern war 9100 nie freigegeben (und soll es nicht sein).
|
||||
|
||||
**Fix (gitops `228807f`, Weg A aus gitops#45):** HelmRelease + Alloy-Scrape entfernt,
|
||||
Flux hat gepruned — DaemonSet/Service/Pod sind weg, Host-Metriken kommen unverändert
|
||||
vom systemd-Exporter. Volle Diagnose:
|
||||
`gitops#45` (Gitea-Zählung, Tracker stillgelegt — verbindlich: Migrations-Fußtext im GitLab-Issue).
|
||||
|
||||
<details><summary>Ursprünglicher Befund (CFGMON-Session, vor der Host-Prüfung)</summary>
|
||||
|
||||
Von CFGMON aus diagnostiziert, per kube-state-metrics und den remote-geschriebenen Serien.
|
||||
**Auf dem Host selbst wurde nichts geprüft** — CFGMON hat kein `kubectl`.
|
||||
|
||||
### Teil 1 — der Pod crasht seit Monaten (chronisch)
|
||||
|
||||
| Messwert | Stand 2026-08-01 |
|
||||
|---|---|
|
||||
| Pod `prometheus-node-exporter-4wwn7`, Restarts | **4880**, davon 1970 in 7 Tagen |
|
||||
| Vorgängerpod `…-fv7hj`, Zählerstand vor 30 Tagen | 13918 |
|
||||
| aktuelle Rate | ~12/h — entspricht dem CrashLoopBackOff-Deckel von 5 min |
|
||||
| `last_terminated_reason` | `Error` (Exit ≠ 0, **kein** OOMKill) |
|
||||
| `waiting_reason` / `ready` | `CrashLoopBackOff` / `0` |
|
||||
|
||||
Das besteht mindestens seit 30 Tagen, also **lange vor** dem Monitoring-Rework und vor dem
|
||||
Alerting-Rollout. Neu ist nur die Sichtbarkeit: die Regel `KubePodRestartLoop` kam am
|
||||
2026-08-01 dazu. Wie bei Synapse hat das Alerting einen stillen Altfehler aufgedeckt.
|
||||
|
||||
**Vermutete Ursache, nicht verifiziert:** Der Pod läuft mit `hostNetwork: true` und will
|
||||
Port 9100 auf dem Host binden. Dort hört bereits ein **eigenständiger node-exporter** —
|
||||
derselbe, den CFGMON als Job `k3s_host_node` direkt auf `10.0.0.2:9100` scrapt und der
|
||||
2706 Metriken sauber ausliefert. Zwei Exporter, ein Port; der Pod bekäme
|
||||
`address already in use` und beendete sich sofort, was zu `reason: Error` ohne OOM passt.
|
||||
|
||||
Zum Bestätigen auf dem Host:
|
||||
|
||||
```
|
||||
ss -lntp | grep :9100
|
||||
kubectl -n monitoring logs prometheus-node-exporter-4wwn7 --previous | tail -20
|
||||
```
|
||||
|
||||
### Teil 2 — der Cluster-Scrape ist am 2026-08-01 01:19 UTC ausgefallen (akut)
|
||||
|
||||
| Messwert | Stand |
|
||||
|---|---|
|
||||
| `up`-Mittel 24 h für `prometheus-node-exporter.monitoring.svc.cluster.local:9100` | 98,3 % |
|
||||
| Zustandswechsel in 24 h | **1** — einmal runter, nicht zurück |
|
||||
| Host-Uptime | 77,6 Tage → **kein Reboot** |
|
||||
|
||||
Ein Pod, der 12× pro Stunde stirbt, kann kein Target sein, das zu 98 % up ist. Geantwortet
|
||||
hat also nie der Pod, sondern der eigenständige Exporter über die Host-IP. Der Pod hat
|
||||
`hostNetwork`, sein Pod-IP ist die öffentliche `49.13.132.245`, dorthin zeigt der
|
||||
Service-Endpoint — und dort kommt seit 01:19 nichts mehr.
|
||||
|
||||
Von CFGMON aus gemessen:
|
||||
|
||||
| Pfad | Ergebnis |
|
||||
|---|---|
|
||||
| `10.0.0.2:9100` (privat) | offen, 2706 Metriken |
|
||||
| `49.13.132.245:9100` (öffentlich) | **keine Antwort** |
|
||||
| `49.13.132.245:80` / `:443` | offen — Host lebt |
|
||||
|
||||
Ohne Reboot heißt das: in der Nacht wurde die Erreichbarkeit auf 9100 eingeengt. Zwei
|
||||
Möglichkeiten, von hier aus nicht unterscheidbar:
|
||||
|
||||
1. Der Exporter bindet jetzt `10.0.0.2:9100` statt `0.0.0.0:9100`.
|
||||
2. Eine `ufw`-Regel wurde geändert. Die Allow-Liste oben in dieser Datei führt 9100
|
||||
ohnehin nicht auf — die private Zustellung muss also über eine Interface- oder
|
||||
Subnetz-Regel laufen, an der sich etwas geändert haben kann.
|
||||
|
||||
Zeitlich fällt das exakt in das Fenster der Synapse-Port-Korrektur derselben Nacht. Wer
|
||||
dort die Exposition aufgeräumt hat, hat den Cluster-Scrape-Pfad mitgenommen. Prüfen mit
|
||||
`ss -lntp | grep :9100` und `ufw status numbered`.
|
||||
|
||||
### Fix — es ist ein node-exporter zu viel
|
||||
|
||||
**Weg B (empfohlen):** Den DaemonSet-Exporter abschalten (`nodeExporter.enabled: false` in
|
||||
den kube-prometheus-stack-Values) und das Cluster-Alloy statt auf den Service-Namen direkt
|
||||
auf `10.0.0.2:9100` zeigen lassen. Beendet den Crashloop und erhält die enge Bindung ans
|
||||
private Netz, die in der Nacht vom 2026-08-01 gesetzt wurde.
|
||||
|
||||
**Weg A:** Den eigenständigen Exporter stilllegen und dem DaemonSet den Port überlassen.
|
||||
Ebenfalls sauber, aber er bindet dann wieder `0.0.0.0` — also auch die öffentliche IP,
|
||||
abgesichert nur noch durch `ufw` und die Cloud-Firewall. Das nähme die Einschränkung
|
||||
zurück, die gerade erst gesetzt wurde.
|
||||
|
||||
### Nebenbefund — Job-Label kollidiert zwischen zwei Hosts
|
||||
|
||||
Das Label `prometheus.scrape.node_exporter` existiert zweimal, weil CFGMONs Alloy und das
|
||||
Cluster-Alloy ihre Scrape-Komponente gleich benennen:
|
||||
|
||||
```
|
||||
up=1 instance=node-exporter:9100 -> CFGMON (Kernel 6.8.0-136-generic)
|
||||
up=0 instance=prometheus-node-exporter.monitoring.svc...:9100 -> MATRIX
|
||||
```
|
||||
|
||||
Die Serien kollidieren nicht, `instance` trennt sie. Aber jede Abfrage, die nur nach `job`
|
||||
filtert, mischt zwei Maschinen — und in Alarmtexten steht dann ein Job-Name, der nicht sagt,
|
||||
welcher Host gemeint ist. Ein External Label auf der Remote-Write-Seite dieses Clusters
|
||||
(`cluster="matrix"`) würde das sauber trennen.
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
## Erledigt
|
||||
|
||||
### MATRIX-01 — Klären, ob der Server Mail als `@matrix.axion1337.de` verschickt · erledigt 2026-07-30
|
||||
|
||||
Für `matrix.axion1337.de` existiert der komplette IONOS-Mail-Satz: `MX mx00/mx01`,
|
||||
`TXT "v=spf1 include:_spf-eu.ionos.com ~all"`, `CNAME s1-ionos._domainkey` und
|
||||
`CNAME autodiscover`. Bei `selendis` ist dasselbe Muster reine Altlast; hier war die Frage
|
||||
offen, weil Matrix-Homeserver typischerweise Mail für Registrierung/Passwort-Reset
|
||||
verschicken.
|
||||
|
||||
**Antwort, verifiziert per Config** (nicht nur vermutet) — direkt im IaC-Repo
|
||||
`sorb/axion1337.chat-gitops`, dem tatsächlich hier deployten Stand geprüft:
|
||||
|
||||
- `apps/production/custom-configs/synapse-values.yaml` — kein `email:`/`smtp_host`/
|
||||
`notif_from`-Block.
|
||||
- `apps/production/custom-configs/mas-secret.yaml` (SOPS-entschlüsselt geprüft) — kein
|
||||
`email`/`smtp`/`mailer`-Eintrag.
|
||||
- `apps/production/element-server-suite.yaml` (HelmRelease values) — dito, nichts.
|
||||
|
||||
Weder Synapse noch MAS versenden aktuell irgendeine Mail. Registrierung/Passwort-Reset
|
||||
laufen ausschließlich über Authentik (OIDC, `auth.axion1337.chat`) und Einladungslinks.
|
||||
Der komplette IONOS-Mail-Satz auf `matrix.axion1337.de` ist damit **funktional unnötig** —
|
||||
dieselbe Härtung wie bei `selendis` anwenden (Null-MX, `v=spf1 -all`, `_dmarc p=reject`),
|
||||
`autodiscover.matrix` kann ebenfalls weg. Damit ist auch
|
||||
[ZONE-02](../architecture/zone-axion1337.md) an dieser Stelle entblockt.
|
||||
|
||||
**Separat davon** (andere Domain-Ebene, kein Widerspruch): auf diesem Host läuft seit
|
||||
2026-07-30 ein eigener Mailversand für Host-Wartungsbenachrichtigungen
|
||||
(`wartung@axion1337.de`, **Apex**-Postfach, nicht die `matrix.`-Subdomain) — siehe
|
||||
MATRIX-04 unten. Nutzt die ohnehin am Apex laufende echte IONOS-Mail-Infrastruktur,
|
||||
betrifft die `matrix.`-Subdomain-Records oben also nicht.
|
||||
|
||||
### MATRIX-02 — Pusht per Remote-Write auf einen offenen Prometheus · erledigt 2026-07-30
|
||||
|
||||
**Korrektur einer falschen Annahme im ursprünglichen Eintrag**: der Text ging von zwei
|
||||
getrennten Absendern aus - "CFGMON (`10.0.0.3`) und der k3s-Host (`10.0.0.2`)" - als wären
|
||||
das zwei verschiedene Maschinen. Es ist **dieselbe Maschine**: dieser Host (`matrix`) hat
|
||||
selbst die private IP `10.0.0.2` (verifiziert per `ip -4 addr show` auf dem Host).
|
||||
|
||||
Verifiziert in `apps/monitoring/alloy-config.yaml` (diesem Cluster): Der Remote-Write-Push
|
||||
geht bereits an `http://10.0.0.3:9090/api/v1/write` und Loki an `http://10.0.0.3:3100/...` -
|
||||
**private IP, nicht die öffentliche** `188.245.193.243:9090`. Von dieser Seite aus ist hier
|
||||
nichts mehr zu tun. Ob Prometheus/Loki auf CFGMON zusätzlich öffentlich erreichbar sind
|
||||
(unabhängig davon, ob dieser Host den privaten Weg nutzt), ist
|
||||
[CFGMON-03](cfgmon.md#cfgmon-03--prometheus-remote-write-und-loki-sind-öffentlich-ohne-auth)
|
||||
- ein reines CFGMON-Thema, nicht mehr blockiert durch etwas auf diesem Host.
|
||||
|
||||
### MATRIX-04 — Host-Level Pre-Update-Benachrichtigung · erledigt 2026-07-30
|
||||
|
||||
Neuer, eigenständiger Mechanismus auf diesem Host, außerhalb von Flux/GitOps (Details:
|
||||
`docs/deployment-guides/07-host-maintenance-notifications.md` im gitops-Repo,
|
||||
`gitops#24` (Gitea-Zählung, Tracker stillgelegt)):
|
||||
`unattended-upgrades` war bereits aktiv, neu ergänzt ist ein systemd-Timer
|
||||
(`maintenance-notify.timer`, fest 05:00 Uhr, vor dem 06:00-07:00-Update-Fenster), der bei
|
||||
anstehenden Paket-Updates per Mail **und** Matrix (Thread-Reply im `wartung`-Raum)
|
||||
benachrichtigt.
|
||||
|
||||
Mail-Versand läuft über `msmtp`, Absender `wartung@axion1337.de` (IONOS SMTP,
|
||||
`smtp.ionos.de:587`, STARTTLS - **Port 465 war ausgehend blockiert**, vermutlich
|
||||
Cloud-Provider-Firewall-Regel, 587 ging durch). Relevant für die Mail-Policy-Diskussion
|
||||
oben: dieses Postfach nutzt die reale, bereits am Apex laufende IONOS-Mail-Infrastruktur,
|
||||
keine neue Subdomain, kein neuer Handlungsbedarf für die Zone.
|
||||
@@ -0,0 +1,152 @@
|
||||
---
|
||||
type: wiki-page
|
||||
area: admin
|
||||
related: []
|
||||
---
|
||||
|
||||
# Overmind
|
||||
|
||||
Homelab-Host: GitLab (Dokploy-verwaltet) + CI-Runner. **Nur im Lab erreichbar** —
|
||||
`git.lab` löst außerhalb des Homelabs nicht auf; Produktion (Flux auf CFGMON/MATRIX) hängt
|
||||
nicht von diesem Host ab, nur neue Builds pausieren bei Ausfall.
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **Hostname** | `Overmind` |
|
||||
| **DNS (Lab)** | `git.lab` → `10.58.73.17` (TLS via Dokploy-Proxy, Zertifikate von der aXionLabs-CA: step-ca, 24h-Leaf, Intermediate bis 2035) |
|
||||
| **CPU/RAM** | 14 Kerne, 30 Gi (Stand 2026-07-31: ~11 Gi verfügbar) |
|
||||
| **Disk** | 444 G NVMe (~278 G frei, Stand 2026-07-31) |
|
||||
| **KVM** | `/dev/kvm` vorhanden — Basis für die Windows-Build-VM |
|
||||
| **Stand** | 2026-07-31 |
|
||||
|
||||
## Dienste
|
||||
|
||||
| Dienst | Definition | Anmerkungen |
|
||||
|---|---|---|
|
||||
| GitLab CE 18.7.1 + Postgres 16 + Redis 7 | Dokploy-Stack `management-gitlabce` | `external_url https://git.lab`, SSH 2224; TLS terminiert der Dokploy-Proxy (GitLab-nginx lauscht nur :80) |
|
||||
| gitlab-runner `lab-builder-1` (v18.7.0) | gleicher Stack, Service `gitlab-runner` | Docker-Executor + Socket, `concurrent = 1`. **Stolpersteine, live gefunden**: (1) Docker-interner DNS löst `git.lab` auf den GitLab-Container auf, wo 443 zu ist → `extra_hosts: git.lab:10.58.73.17` nötig; (2) Lab-CA muss nach `/etc/gitlab-runner/certs/git.lab.crt` (Config-Volume, übersteht Redeploys) |
|
||||
| gitlab-runner `lab-windows-1` | Windows-Gast in der Build-VM | Tags `[windows]`, `run_untagged=false`, Shell-Executor PowerShell — siehe Runbook |
|
||||
| Windows-Build-VM | Dokploy-Stack `windows-runner` (live seit 2026-07-31) | Image `registry.git.lab/axion1337.chat/vendor/windows:stable` (Eigenbau aus reviewtem Pin `7645a2b`, Vendor-Repo `git.lab/axion1337.chat/vendor/windows`), **on-demand** (`restart: "no"`, Start/Stop über CI-Jobs), 8G/6 Kerne/96G. Runbook: `docs/axion-runner.md` im Vendor-Repo. Gast-Uhr geht falsch (Traces stempeln ~+7h) — kosmetisch |
|
||||
|
||||
## Repo-Topologie (Kontext)
|
||||
|
||||
git.lab ist seit 2026-07-31 **kanonisch** für die gespiegelten Repos der Gruppe
|
||||
`axion1337.chat` — Stand 2026-08-09 **sieben**: die sechs Produkt-Repos (ThreadNet-Web,
|
||||
threadnet-call, thread-net-git, threadnet-operating, axion1337.chat-gitops, seit heute auch
|
||||
`game-operating`) **und `management`, also dieses Repo**. Push-Mirrors nach rohana/Gitea,
|
||||
direkte Gitea-Pushes tabu.
|
||||
|
||||
⚠️ `gameserver` (achtes Projekt der Gruppe) hat **keinen** Mirror — offen in
|
||||
[management#32](https://git.lab/axion1337.chat/management/-/issues/32), dort liegt auf Gitea
|
||||
ein gleichnamiges Repo mit anderem Stand.
|
||||
|
||||
Gitea bleibt: Flux-Source (via Mirror beliefert), Registry, Packages.
|
||||
**Issues nicht mehr** — die sind am 2026-08-01/02 nach git.lab gewandert
|
||||
([ADR-0002](../../adr/0002-issues-und-management-ins-lab.md)). Die letzte Ausnahme,
|
||||
die Deploy-Übergabe-Issues auf dem Gitea-Tracker `sorb/management`, ist am 2026-08-02
|
||||
mit LABNET-03 zurückgebaut: beide umgezogen (#25, #26), der Tracker ist leer.
|
||||
**Ohne Ausnahme: Issues leben auf git.lab.**
|
||||
|
||||
*(Bis 2026-08-01 stand hier „Backlogs (dieses Repo, ungespiegelt)" — das Repo heißt
|
||||
seit der Umwidmung zum Management-Repo `management` und wird seither gespiegelt,
|
||||
[ADR-0005](../../adr/0005-pm-framework-kanban.md).)*
|
||||
|
||||
## OVERMIND-01 — GitLab-Container-Registry aktivieren, Images nach Konsument sortieren
|
||||
|
||||
**Status:** erledigt (2026-08-01)
|
||||
|
||||
**Abschluss-Verifikation**: `desktop_image` baut und pusht per `CI_JOB_TOKEN` nach
|
||||
`registry.git.lab/axion1337.chat/threadnet-web/desktop-build:bullseye` (Job 386 grün,
|
||||
Tag per API bestätigt); `desktop_linux` nutzt dieses Image als Job-Container und lief
|
||||
damit grün durch (Job 398 - beweist auch den anonymen Pull des public Projekts durch
|
||||
den Runner-Daemon). Die rohana-`REGISTRY_*`-Variablen bleiben nur noch für den
|
||||
App-Image-Push (`docker_web`) in Gebrauch - genau die Ziel-Sortierung nach Konsument.
|
||||
|
||||
Die eingebaute GitLab-Registry ist aus (kein `registry_external_url` im Omnibus-Config).
|
||||
Folge: lab-interne Build-Images (`windows-vm`, `element-desktop-build`) machen den Umweg
|
||||
Lab-CI → rohana (Prod, Internet) → zurück ins Lab — koppelt Lab-Infrastruktur unnötig an
|
||||
die Verfügbarkeit des Prod-Hosts.
|
||||
|
||||
**Ziel-Sortierung nach Konsument:**
|
||||
- **rohana (Gitea) behält**: `sorb/threadnet-web` (App-Image — Flux/Prod pullt es),
|
||||
npm-Packages
|
||||
- **Lab-Registry (`registry.git.lab`) bekommt**: `windows-vm`,
|
||||
`element-desktop-build` — beides konsumiert nur das Lab selbst
|
||||
|
||||
**Umsetzung** (TLS terminiert wie bei `git.lab` der Dokploy-Proxy):
|
||||
1. Omnibus-Config: `registry_external_url 'https://registry.git.lab'`,
|
||||
`registry_nginx['listen_port'] = 5050`, `registry_nginx['listen_https'] = false`;
|
||||
Port 5050 in der Compose exposen
|
||||
2. Lab-DNS: `registry.git.lab` → `10.58.73.17`
|
||||
3. Dokploy: Domain `registry.git.lab` → GitLab-Service Port 5050 (Zertifikat von der
|
||||
aXionLabs-CA wie gehabt)
|
||||
4. Docker-Daemon-Trust auf Overmind: CA-Kette nach
|
||||
`/etc/docker/certs.d/registry.git.lab/ca.crt` (Datei liegt schon als
|
||||
`/tmp/git.lab.crt` vom Runner-Setup — kopieren reicht; kein Daemon-Restart nötig)
|
||||
5. CI-Umstellung: `vendor/windows` pusht nach `registry.git.lab` (Bonus: GitLabs
|
||||
eingebaute `$CI_REGISTRY`/`$CI_JOB_TOKEN`-Auth statt Gruppen-Secrets),
|
||||
`desktop_image`/`desktop_linux` in ThreadNet-Web folgen; Registry-Speicher liegt im
|
||||
`gitlab_data`-Volume (278 G frei)
|
||||
|
||||
**Fortschritt 2026-07-31**: Punkte 1–4 umgesetzt (Registry live auf
|
||||
`registry.git.lab`, 401/Bearer-Auth korrekt, CA-Trust auf dem Host); `vendor/windows`
|
||||
pusht per `CI_JOB_TOKEN` in die Lab-Registry — verifiziert, Tags `5bc25447` + `stable`
|
||||
vorhanden, Runbook referenziert `stable`.
|
||||
|
||||
**Nächster Schritt:** `element-desktop-build` von rohana in die Lab-Registry umziehen
|
||||
(ThreadNet-Web-CI: `desktop_image`-Push-Ziel + `desktop_linux`-Image-Referenz) — bewusst
|
||||
zurückgestellt, bis kein Auto-Job das alte Image parallel referenziert (Reihenfolge:
|
||||
erst neues Image bauen, dann Referenz umstellen).
|
||||
|
||||
## OVERMIND-02 — Host-Ausfall 2026-07-31 ~19:15 lokal (NIC-Hang, Fix aktiv)
|
||||
|
||||
**Status:** Fix aktiv — die Beobachtung läuft als [Issue #4](https://git.lab/axion1337.chat/management/-/issues/4)
|
||||
(Framework-Umbau 2026-08-01); dieser Abschnitt ist Bestand/Historie.
|
||||
|
||||
**Ursache (Journal des Vor-Boots, via Claude-Session auf Overmind):** `e1000e`
|
||||
`Detected Hardware Unit Hang` auf `eno1` in Endlosschleife — die Intel-NIC hing
|
||||
(bekanntes e1000e-Problem in Kombination mit EEE/Energiesparen), der Host lief weiter,
|
||||
war aber netzwerktot. Kein OOM, kein Bezug zur Windows-VM/CI. Passt zu allen Symptomen:
|
||||
Ping tot, aber der Windows-Runner erreichte GitLab host-intern noch (Job 413 wurde
|
||||
aufgegriffen) und scheiterte erst an der DNS-Auflösung übers tote Interface.
|
||||
|
||||
**Fix (2026-07-31, Overmind-Session):** `ethtool --set-eee eno1 eee off` live gesetzt
|
||||
+ persistente udev-Regel `/etc/udev/rules.d/71-disable-eee-eno1.rules` (greift bei
|
||||
jedem Boot). Temporäre sudoers-Freigabe danach wieder entfernt.
|
||||
|
||||
**Offen:**
|
||||
- ~~NIC-/BIOS-Firmware-Update 2.4.0.0 → 2.5.2.0~~ **erledigt** (Wartungsfenster
|
||||
2026-08-01, durch sorb)
|
||||
- Falls der Hang trotz EEE-off + neuer Firmware wiederkehrt: gezielter ASPM-Fix
|
||||
statt globalem Kernel-Parameter
|
||||
|
||||
**Zeitleiste (lokal, UTC+2):**
|
||||
- 18:58 — Windows-VM nach händischem Container-Stop+Start zurück, Runner online
|
||||
- 19:00 — desktop_windows Job 399 (Versuch 5): läuft bis `build:native`, scheitert an
|
||||
fehlendem rustc (kein Host-Problem)
|
||||
- 19:05–19:12 — Provision-Job 409 grün (Rust 1.97.1 maschinenweit, Strawberry Perl,
|
||||
Python 3.14, NASM-PATH), Dienst-Neustart via Scheduled Task funktionierte
|
||||
- 19:13/19:14 — letzte saubere Runner-Herzschläge
|
||||
- **zwischen 19:14 und 19:21 — Host fällt aus**: Ping 100 % Verlust, git.lab-API tot
|
||||
- 19:21 — Job 413 (Versuch 6) wird noch aufgegriffen, Git-Fetch scheitert nach 8 s mit
|
||||
`Could not resolve host: git.lab` → Host-Netz/DNS zu dem Zeitpunkt bereits kaputt;
|
||||
danach Funkstille
|
||||
- ~20:15 — Host pingt wieder (Reboot durch sorb), 20:21 GitLab-API zurück,
|
||||
lab-builder-1 online; windows-runner-Container down (`restart: "no"` — korrekt)
|
||||
|
||||
**Wichtig:** Der Windows-Build war NICHT die Ursache — Job 413 hat nie Quellcode
|
||||
geholt, die VM lief nur idle (frisch provisioniert; denkbare Gast-Hintergrundlast:
|
||||
Windows Update/Defender nach den choco-Installs). Die 8-G-Zuteilung der VM plus
|
||||
GitLab-Stack blieb aber auch nach dem Puma-Fix ein enges Budget auf 30 Gi.
|
||||
|
||||
**Konsequenz für die Build-Kette:** RAM-Budget war nicht das Problem — VM bleibt bei
|
||||
8G. Nach dem NIC-Fix lief die Kette durch: **desktop_windows Job 438 grün**
|
||||
(2026-07-31 ~21:50 lokal, `Element Setup 1.12.17.exe`, 141 MB, unsigniert) —
|
||||
ThreadNet-Web#5 geschlossen, Folgethemen (Signing/Branding) in ThreadNet-Web#6.
|
||||
Auf dem Weg dahin zusätzlich gefixt: GitHub-CDN-Abrisse bei app-builder-Downloads
|
||||
(resumefähiges Prefetch-Skript im ThreadNet-Web-Repo, Jobs 415/416/424/431).
|
||||
|
||||
---
|
||||
|
||||
Weitere CI-Betriebsthemen laufen über die Projekt-Issues (ThreadNet-Web#5
|
||||
Windows-Strecke, threadnet-call#1 npm-Ziel) und CFGMON-11 (Gitea-CI-Rückbau).
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
type: wiki-page
|
||||
area: admin
|
||||
related: []
|
||||
---
|
||||
|
||||
# Refinement und Retro — die Termine des Frameworks
|
||||
|
||||
Kanban braucht wenige, aber verlässliche Termine, sonst verkommt das Board zur
|
||||
Ablage. Festgelegt in [ADR-0005](../../adr/0005-pm-framework-kanban.md); hier
|
||||
steht, wie sie ablaufen.
|
||||
|
||||
## Termine (festgelegt im Struktur-Workshop, 2026-08-06)
|
||||
|
||||
| Termin | Wann |
|
||||
|---|---|
|
||||
| **Refinement** | **sonntagabends**, wöchentlich, 30–45 min |
|
||||
| **Retro light** | im **ersten Refinement des Monats**, +20–30 min |
|
||||
|
||||
Sonntag, weil die GitLab-Backups dort ohnehin laufen (00:00) — die Woche hat an
|
||||
dieser Stelle eine Kante, und die Abendblöcke, in denen real gearbeitet wird,
|
||||
liegen meist am Wochenende.
|
||||
|
||||
Die Retro bekommt **keinen eigenen Termin**: Ein monatlicher Extra-Termin im
|
||||
Solo-Betrieb ist ein Termin, der ausfällt. Sie hängt sich an das erste Refinement
|
||||
des Monats an — dann ist die Vorbereitung (die AARs des Monats) ohnehin offen.
|
||||
|
||||
## Refinement (≈ wöchentlich, 30–45 min)
|
||||
|
||||
Der eine Termin, der das System am Leben hält. Immer dieselbe Reihenfolge:
|
||||
|
||||
1. **Board von rechts nach links lesen** — zuerst `status:doing`: Läuft es noch,
|
||||
oder ist es in Wahrheit blockiert? Dann `status:wartet`: Wartet es noch auf das,
|
||||
was im Issue steht? Erst zuletzt `status:next`.
|
||||
2. **WIP-Limit prüfen** — höchstens zwei Issues in `doing`. Ist es voll, wird nichts
|
||||
Neues gezogen; stattdessen wird gefragt, was das Laufende blockiert.
|
||||
3. **Nachziehen** — freie Plätze aus `next` füllen, `next` aus dem Backlog auffüllen.
|
||||
Auswahlkriterium ist nicht Priorität allein, sondern **was still kaputtgeht**
|
||||
(Fristen, abgeschaltete Schutzmechanismen) vor **was nervt** vor **was Spaß macht**.
|
||||
4. **Entscheidungsvorlagen** — offene Fragen, die eine Entscheidung von sorb brauchen,
|
||||
werden als Optionen mit Empfehlung vorgelegt, nicht als offene Fragen geparkt.
|
||||
Dauerhafte Ausnahmen von Regeln werden hier zu ADRs.
|
||||
5. **Datumspflicht prüfen** — jedes zeitkritische Issue trägt ein Datum, kein „bald".
|
||||
|
||||
## Retro light (≈ monatlich, 20–30 min)
|
||||
|
||||
Drei Fragen, mehr nicht:
|
||||
|
||||
- Welche **Verfahren** haben diesen Monat getragen, welche haben gestört?
|
||||
- Welche **ADRs** sind durch die Realität überholt (→ neues ADR, altes auf
|
||||
„abgelöst durch")?
|
||||
- **Fasert etwas aus?** Gibt es wieder Arbeit, die nur in Chatverläufen lebt?
|
||||
|
||||
Grundlage sind die AARs des Monats — sie sind die Retro-Vorbereitung, nicht ihr
|
||||
Ersatz.
|
||||
|
||||
Ergebnisse werden unter [`docs/sources/protokolle/`](../../sources/protokolle/retro-2026-08-09.md) abgelegt, eine Datei je Termin. Die
|
||||
erste: [2026-08-09](../../sources/protokolle/retro-2026-08-09.md).
|
||||
|
||||
## AAR (anlassbezogen)
|
||||
|
||||
Nach jedem Deploy mit Übergabe und nach jedem Incident, Vorlage in
|
||||
[docs/aar/template.md](../../aar/template.md). Ein AAR ist keine Chronik, sondern ein
|
||||
Wissensspeicher: Was war das Ergebnis, welche Befunde, was hat die Eingrenzung
|
||||
ermöglicht, welche Lehren, was bleibt offen. **Offene Punkte aus einem AAR werden
|
||||
im selben Zug zu Issues** — sonst versacken sie in der Prosa (real passiert am
|
||||
2026-08-01, nachgezogen als #14–#16).
|
||||
|
||||
## Board-Pflege, wenn sorb länger nicht dazukommt
|
||||
|
||||
Festgelegt 2026-08-06. Eine Session darf das Board **abbilden**, aber nichts
|
||||
**zusagen**:
|
||||
|
||||
| erlaubt | nicht erlaubt |
|
||||
|---|---|
|
||||
| `status:wartet` setzen (mit benanntem Grund) | nach `status:doing` ziehen |
|
||||
| Erledigtes schließen, mit Begründung im Issue | `status:next` vergeben |
|
||||
| Fristen ins `due_date`-Feld nachtragen | Prioritäten umsortieren |
|
||||
| Befunde als neues Issue anlegen | Milestones neu zuordnen |
|
||||
|
||||
Die Trennlinie ist nicht Vorsicht, sondern Bedeutung: `doing` und `next` sind die
|
||||
**Zusage-Spalten** — sie sagen, was als Nächstes wirklich passiert. Das entscheidet
|
||||
sorb. Alles links davon bildet nur ab, was ohnehin schon der Fall ist.
|
||||
|
||||
**Jede Änderung wird im Issue begründet**, nicht still vorgenommen. Ein Board, dem
|
||||
man nicht ansieht, wer warum etwas verschoben hat, ist beim nächsten Refinement
|
||||
wertlos.
|
||||
|
||||
## Zusammenspiel mit den Sessions
|
||||
|
||||
Mehrere Claude-Sessions arbeiten parallel (Mac-Session, Host-Sessions auf CFGMON
|
||||
und Overmind). Für sie gilt:
|
||||
|
||||
- Die **kanonischen Arbeitskonventionen** stehen in [`CLAUDE.md`](../../../AGENTS.md) und
|
||||
sind über den Gitea-Mirror von überall lesbar.
|
||||
- Arbeit zwischen Sessions läuft über das
|
||||
[Deploy-Übergabe-Verfahren](../deployment/deploy-uebergabe.md) — Auftrag, Meldung, Protokoll
|
||||
im Issue, nicht im Chat.
|
||||
- Was eine Session lernt, gehört ins Repo (AAR/ADR/Doku), nicht nur in ihr
|
||||
Gedächtnis — Sessions gehen verloren, Repos nicht.
|
||||
@@ -0,0 +1,77 @@
|
||||
---
|
||||
type: wiki-page
|
||||
area: admin
|
||||
related: []
|
||||
---
|
||||
|
||||
# Stillstandsprüfung
|
||||
|
||||
Sucht Dinge, die **leise aufgehört haben zu funktionieren**. Beschlossen in der
|
||||
[Retro 2026-08-09](../../sources/protokolle/retro-2026-08-09.md).
|
||||
|
||||
## Warum es sie gibt
|
||||
|
||||
In neun Augusttagen sind sechs Fehler aufgefallen, die alle dasselbe Merkmal
|
||||
hatten: Sie sahen erfolgreich aus, ohne es zu sein — eine grüne Pipeline, die nie
|
||||
ein Artefakt hochlud; ein veröffentlichtes npm-Paket ohne Inhalt; ein Blueprint,
|
||||
der bei jedem Lauf verworfen wurde, während Flux grün meldete.
|
||||
|
||||
**Keiner davon wurde durch eine Überwachung gefunden.** Vier durch Zufall beim
|
||||
Suchen nach etwas anderem. Genau diese Lücke schließt das Skript.
|
||||
|
||||
## Was geprüft wird
|
||||
|
||||
Jede Prüfung bildet einen **real passierten** Fall ab. Nichts steht hier auf
|
||||
Vorrat.
|
||||
|
||||
| Prüfung | Der Fall dahinter |
|
||||
|---|---|
|
||||
| Repo ohne aktiven Push-Mirror | `game-operating` wurde angelegt und nie gespiegelt — auf Gitea existierte es nicht |
|
||||
| Mirror-Drift | MIRROR-01 (management#28): fällt der Mirror aus, liefert Flux still den letzten Stand weiter |
|
||||
| Pipeline mit null Jobs | ThreadNet-Web 203/204, threadnet-call 187 — rot, ohne dass etwas kaputt war |
|
||||
| Erfolgreicher Job ohne Artefakt | `build_embedded` lief seit jeher grün und lud **nichts** hoch |
|
||||
| npm-Paket zu klein | `0.19.2-threadnet.6`: 12,5 KB statt 12,8 MB, ohne `dist/` |
|
||||
| Authentik-Blueprint ≠ successful | `matrix-recovery-flow` wurde tagelang bei jedem Lauf verworfen |
|
||||
|
||||
Die Projektliste wird **zur Laufzeit aus der Gruppe gelesen**, nicht im Code
|
||||
gepflegt — eine Liste im Quelltext wäre genau die Stelle, an der ein neues Repo
|
||||
jahrelang durchrutscht. (Beim ersten Lauf kamen so zwei Projekte zum Vorschein,
|
||||
die niemand auf dem Schirm hatte.)
|
||||
|
||||
## Wie sie läuft
|
||||
|
||||
Geplanter CI-Job im management-Repo, zusätzlich von Hand über *Run pipeline*
|
||||
auslösbar. Befunde färben die Pipeline **rot** — das ist bei uns die Alarmanlage,
|
||||
nicht ein zusätzlicher Meldeweg (siehe `gitops/CLAUDE.md` zur TURN-Rotation).
|
||||
|
||||
Lokal:
|
||||
|
||||
```bash
|
||||
export GITLAB_TOKEN=$(cat ~/.config/gitlab-lab/token)
|
||||
export GITEA_TOKEN=$(cat ~/.config/gitea-rohana/push-token) # fuer private Spiegel
|
||||
export LAB_CA=.../ci/lab-ca-chain.crt
|
||||
python3 scripts/stillstandspruefung.py
|
||||
```
|
||||
|
||||
## Zwei Regeln für diese Prüfung
|
||||
|
||||
**Ein „kann nicht geprüft werden" ist ein Befund, kein Übersprungen.** Real
|
||||
aufgefallen am 2026-08-09: `game-operating` wurde auf Gitea privat gestellt, und
|
||||
die Prüfung übersprang den Mirror-Abgleich klaglos. Ein Repo, das gespiegelt wird,
|
||||
dessen Gegenseite aber unlesbar ist, ist **ungeprüft** — und das darf nicht wie
|
||||
„in Ordnung" aussehen.
|
||||
|
||||
**Ein Befund wird zum Issue, nicht weggeklickt.** Sonst wird die Prüfung zu dem,
|
||||
was sie sucht: etwas, das läuft, ohne dass jemand hinsieht.
|
||||
|
||||
⚠️ **Fehlt ein Zugang, bricht sie ab — sie überspringt sich nicht still.** Eine
|
||||
Prüfung, die sich bei fehlendem Token selbst deaktiviert, ist wertlos: Sie meldet
|
||||
dann jahrelang nichts, und niemand merkt den Unterschied zu „alles in Ordnung".
|
||||
Ausnahme sind die klar benannten optionalen Teile (Authentik), die ihr Fehlen im
|
||||
Ergebnis ausweisen.
|
||||
|
||||
## Erweitern
|
||||
|
||||
Neue Prüfungen kommen dazu, **wenn wieder etwas still ausgefallen ist** — mit einem
|
||||
Docstring, der den konkreten Fall nennt. Prüfungen auf Verdacht erzeugen Rauschen
|
||||
und kosten die Glaubwürdigkeit, die diese hier braucht.
|
||||
@@ -0,0 +1,122 @@
|
||||
---
|
||||
type: wiki-page
|
||||
area: admin
|
||||
related: []
|
||||
---
|
||||
|
||||
# Textbausteine für Sessions
|
||||
|
||||
Kurze, kopierbare Blöcke, die man einer Claude-/Agenten-Session voranstellt.
|
||||
|
||||
Die Konventionen stehen kanonisch in [`CLAUDE.md`](../../../AGENTS.md) — aber eine
|
||||
Session liest sie nur, wenn sie dazu aufgefordert wird. Diese Bausteine sind die
|
||||
Aufforderung.
|
||||
|
||||
## Zwei Regeln für diese Datei
|
||||
|
||||
**Die Bausteine verweisen auf die Regeln, sie wiederholen sie nicht.** Stünden die
|
||||
Regeln hier ausgeschrieben, gäbe es eine zweite Fassung, die driftet — real
|
||||
passiert am 2026-08-02, als `gitops/CLAUDE.md` „keine Gitea-Ausnahme mehr" behauptete,
|
||||
während die `management/CLAUDE.md` zwei nannte.
|
||||
|
||||
**Höchstens acht Zeilen je Baustein.** Der Test ist banal: Wer zum Kopieren scrollen
|
||||
muss, benutzt es nicht. Was länger wäre, gehört in die CLAUDE.md — nicht hierher.
|
||||
|
||||
---
|
||||
|
||||
## 1 · Session-Start (Mac, mit Lab-Zugang)
|
||||
|
||||
```
|
||||
Lies zuerst CLAUDE.md im management-Repo auf git.lab und halte dich daran.
|
||||
Kanonisch ist git.lab; nie direkt nach Gitea pushen.
|
||||
Alles Offene wird zum Issue, nicht zur Chat-Notiz — auch Nebenbefunde.
|
||||
Bevor du ein Issue schließt oder darüber urteilst: vollständig lesen, inklusive
|
||||
Kommentare.
|
||||
Bevor du aus einer Vorlage/Spezifikation ableitest: die Quelle öffnen, nicht raten.
|
||||
Verifiziert und vermutet klar trennen; fremde Messungen als fremde kennzeichnen.
|
||||
```
|
||||
|
||||
> Die letzten drei Zeilen stehen hier, weil genau das dreimal an einem Tag
|
||||
> schiefging: erfundene Theme-Paletten statt gelesener Skill-Quelle; ein Sweep nach
|
||||
> dem Pfad `sorb/Backlogs` statt nach dem Namen `Backlogs`; und ein Issue, von dem
|
||||
> 750 von 1237 Zeichen gelesen wurden — samt übersehenem Korrekturkommentar, der
|
||||
> seit 16 Stunden darunterstand.
|
||||
|
||||
## 2 · Host-Session (CFGMON, MATRIX — ohne Lab-Zugang)
|
||||
|
||||
```
|
||||
Du arbeitest auf einem Hetzner-Host ohne direkte Lab-Route.
|
||||
Konventionen: CLAUDE.md im management-Repo — von hier lesbar über den Gitea-Mirror
|
||||
rohana.axion1337.de/sorb/management. Dort NUR lesen, niemals hinpushen.
|
||||
Für git.lab (Issues, Pushes) muss sorb erst den Site-to-Site-Tunnel einschalten.
|
||||
git.lab-API: PRIVATE-TOKEN-Header — .netrc gilt nur für clone/push (sonst 401,
|
||||
bei privaten Projekten irreführend 404, sieht aus wie "Projekt gibt es nicht").
|
||||
Ping auf 10.58.73.17 schlägt IMMER fehl (nur 443 + DNS offen), das ist kein
|
||||
Tunnelproblem — prüfen mit: curl https://git.lab/users/sign_in
|
||||
```
|
||||
|
||||
> Soll in dieser Session etwas ausgerollt werden, kommt **Baustein 3** dazu — der
|
||||
> Deploy-Weg samt AAR-Pflicht steht dort, nicht hier, damit dieser Block kurz bleibt.
|
||||
|
||||
## 3 · Deploy-Übergabe
|
||||
|
||||
```
|
||||
Öffne auf git.lab ein Issue aus der Vorlage "Deploy-Übergabe"
|
||||
(Feld "Description template") und fülle ALLE Felder — Verfahren und Begründung
|
||||
je Feld: verfahren/deploy-uebergabe.md.
|
||||
Pflicht: Stand (Repo/Branch/Commit) · Testtiefe (ehrlich, "ungetestet" ist gültig)
|
||||
· Mengengerüst (geschätzt oder gemessen, dazuschreiben welches) · vollständiges
|
||||
Deploy-Kommando inkl. Reload/Recreate · Verifikation DORT WO DER DIENST LIEST
|
||||
· Außenwirkung und Not-Aus · Rollback · bewusst offen Gelassenes.
|
||||
Wo nichts zutrifft: "-" eintragen, nicht das Feld löschen.
|
||||
```
|
||||
|
||||
## 4 · Abschluss einer Session
|
||||
|
||||
> **Dieser Baustein ist zugleich unsere Definition of Done für Änderungen ohne
|
||||
> Deploy** (festgelegt 2026-08-06). Für Deployments gilt weiterhin das
|
||||
> [Übergabe-Verfahren](../deployment/deploy-uebergabe.md) — das ist die längere DoD.
|
||||
>
|
||||
> Bewusst kein eigenes DoD-Dokument: Es wäre die dritte Fassung derselben Regeln
|
||||
> und damit die dritte, die driften kann.
|
||||
|
||||
```
|
||||
Vor dem Ende prüfen und benennen:
|
||||
- Alle Commits über git.lab gepusht, kein Rest im Arbeitsverzeichnis, Mirror grün.
|
||||
- Jeder offene Punkt und Nebenbefund ist ein Issue — nichts bleibt nur im Chat.
|
||||
- Zeitkritisches trägt ein Datum im due_date-Feld, nicht nur im Fließtext.
|
||||
- Genau ein status:*-Label je angefasstem Issue; status:wartet nur mit Grund.
|
||||
- Gedächtnis aktualisiert: nur was kein Repo festhält.
|
||||
- Wiederaufsetzpunkt in einem Satz: Was ist als Nächstes dran, und wer ist dran?
|
||||
```
|
||||
|
||||
## 5 · Entscheidungsvorlage
|
||||
|
||||
```
|
||||
Leg mir das als Entscheidung vor, nicht als offene Frage:
|
||||
2–4 Optionen, je eine Zeile Konsequenz, und deine Empfehlung zuerst mit Begründung.
|
||||
Sag dazu, was du gemessen und was du angenommen hast.
|
||||
Wenn die Entscheidung eine dauerhafte Ausnahme von einer Regel schafft, ist sie
|
||||
ADR-pflichtig (decisions/, siehe CLAUDE.md) — dann leg die ADR gleich mit vor.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Wann welcher
|
||||
|
||||
| Situation | Baustein |
|
||||
|---|---|
|
||||
| Neue Session auf dem Mac | 1 |
|
||||
| Session auf CFGMON/MATRIX/game | 2 |
|
||||
| Etwas gebautes soll ausgerollt werden | 3 |
|
||||
| Session neigt sich dem Ende | 4 |
|
||||
| Eine Frage braucht sorbs Entscheidung | 5 |
|
||||
|
||||
Bausteine 1 und 2 schließen sich aus; 3–5 kommen anlassbezogen dazu.
|
||||
|
||||
## Pflege
|
||||
|
||||
Ein Baustein wird ergänzt, wenn **derselbe Fehler zweimal** passiert ist — nicht
|
||||
vorsorglich. Sonst wachsen sie, bis sie niemand mehr kopiert, und dann wirken sie
|
||||
gar nicht mehr. Wächst einer über acht Zeilen, gehört der Inhalt in die CLAUDE.md
|
||||
und hier bleibt der Verweis.
|
||||
@@ -0,0 +1,220 @@
|
||||
---
|
||||
type: wiki-page
|
||||
area: architecture
|
||||
related: []
|
||||
---
|
||||
|
||||
# Branding: Marke, Farben, Bildsprache
|
||||
|
||||
Übergreifend, weil dieselben Farben in mehreren Oberflächen eingestellt werden
|
||||
(Chat-Clients, Wikis, künftige Dienste) und sich das nicht pro Host oder Linie
|
||||
trennen lässt: **Bestand** (welche Farbe wo eingetragen ist) und **Historie**
|
||||
(was wann warum geändert wurde).
|
||||
|
||||
Hier im `management`-Repo, weil es als einziges der beteiligten Repos
|
||||
**gespiegelt** ist und jede Werkzeugentscheidung überlebt: Wird das
|
||||
BookStack-Experiment nach [ADR-0007](../../adr/0007-wiki-oberflaeche-docusaurus-vs-bookstack.md)
|
||||
abgeräumt oder ein Client ersetzt, bleiben Marke und Paletten bestehen.
|
||||
|
||||
## Bildmarke
|
||||
|
||||
`threadnet-mark.png` (Bildmarke) und `threadnet-logo-wortmarke.png` (mit
|
||||
Schriftzug), erstellt von sorb. Sie liegen im Wiki-Repo unter `static/img/` und
|
||||
sind die Quelle für alle abgeleiteten Formate — Favicon, App-Icons für macOS,
|
||||
Windows und Linux, Web-Icons.
|
||||
|
||||
⚠️ Beim Ableiten den **transparenten Rand wegschneiden** und mit `resize()`
|
||||
skalieren, nicht mit `thumbnail()` — Letzteres verkleinert nur und lässt das Motiv
|
||||
in großen Icons als Briefmarke zurück (real passiert, siehe
|
||||
[AAR 2026-08-02](../../aar/2026-08-02-wiki-und-desktop-clients.md)).
|
||||
|
||||
⚠️ **Und danach mittig setzen — das ist ein zweiter, eigener Schritt.** Beim ersten
|
||||
Anlauf wurde nur beschnitten und skaliert: Das Motiv füllte 81 % der Breite, saß
|
||||
aber mit 3 % Rand oben und 40 % unten an der Oberkante. In runden und quadratischen
|
||||
Icon-Slots fällt das sofort auf. Korrigiert am 2026-08-06 auf 21 % oben wie unten.
|
||||
|
||||
**Das Rezept, das jetzt gilt:** Bounding-Box des Motivs ermitteln, darauf
|
||||
beschneiden, auf ~81 % der Kantenlänge skalieren, auf einer quadratischen,
|
||||
transparenten Fläche **mittig einsetzen**. Alle Größen aus *derselben* Quelldatei
|
||||
ableiten — dann können sie nicht auseinanderlaufen.
|
||||
|
||||
### Wo überall Icons liegen
|
||||
|
||||
Elf Artefakte, alle aus einer Quelle (Stand 2026-08-06, `v0.4.0`):
|
||||
|
||||
| Ort | Was |
|
||||
|---|---|
|
||||
| `apps/web/res/vector-icons/` | 1024, 512, 180, 152, 144, 120, 24 px |
|
||||
| `apps/desktop/build/icon.png` | App-/Installer-Icon |
|
||||
| `apps/desktop/build/icon.ico` | Windows, 7 Größen von 16 bis 256 |
|
||||
| `apps/desktop/build/icon.icns` | macOS, via `iconutil` aus einem `.iconset` |
|
||||
| `apps/desktop/build/icon.icon/Assets/element.png` | Layer des macOS-Icon-Composers |
|
||||
|
||||
Prüfen lässt sich die Gleichheit über die Prüfsumme von `vector-icons/1024.png`
|
||||
gegen `build/icon.png` — weichen sie ab, ist eine Seite nachgezogen worden und die
|
||||
andere nicht.
|
||||
|
||||
## Paletten
|
||||
|
||||
### aXion1337 Dark — das Stammschema
|
||||
|
||||
Gruvbox Dark. Grundtöne `#282828` / `#1d2021`, Text `#ebdbb2`, Akzent `#bd93f9`,
|
||||
Sekundär `#fe8019`. Die acht Username-Farben sind der Gruvbox-Satz.
|
||||
**`aXion1337 Light` ist das exakte helle Gegenstück** (Gruvbox Light) — gleiche
|
||||
Rollenverteilung, gespiegelte Helligkeitsachse. Wer eines ändert, zieht das andere
|
||||
mit.
|
||||
|
||||
### Terrakotta-Beige — sorbs BookStack-Schema
|
||||
|
||||
Am 2026-08-02 in der BookStack-Oberfläche eingestellt und von dort extrahiert
|
||||
(die Werte stehen als CSS-Variablen im ausgelieferten HTML). Fünf der sieben sind
|
||||
der Coolors-Satz `#264653 · #2A9D8F · #E9C46A · #F4A261 · #E76F51`:
|
||||
|
||||
| Rolle in BookStack | Wert | Ton |
|
||||
|---|---|---|
|
||||
| Primäre Farbe | `#264653` | Charcoal |
|
||||
| Standard-Linkfarbe | `#5f757b` | gedämpftes Blaugrau |
|
||||
| Regalfarbe | `#e76e51` | Burnt Sienna |
|
||||
| Buchfarbe | `#e9c46a` | Saffron |
|
||||
| Kapitelfarbe | `#f3a261` | Sandy Brown |
|
||||
| Seitenfarbe | `#77bb41` | Grün |
|
||||
| Seitenentwurfsfarbe | `#e32400` | Rot |
|
||||
|
||||
Bemerkenswert: **dieses von Hand eingestellte Schema ist bis auf zwei Ziffern die
|
||||
offizielle Sunset-Boulevard-Palette** (siehe nächster Abschnitt) — `#e76e51` statt
|
||||
`#e76f51`, `#f3a261` statt `#f4a261`. Beide Wege sind unabhängig voneinander auf
|
||||
demselben Coolors-Satz gelandet. Die Irritation an der ersten Theme-Fassung war
|
||||
also berechtigt und ließ sich an der Originalquelle belegen.
|
||||
|
||||
### theme-factory — die zehn benannten Themes
|
||||
|
||||
Quelle ist Anthropics [theme-factory-Skill](https://github.com/anthropics/skills/tree/main/skills/theme-factory):
|
||||
je Theme vier Farben plus ein Schriftpaar. Sie sind seit 2026-08-02 **wörtlich
|
||||
übernommen** (gitops `b10b607`), nachdem eine erste Fassung die Namen frei
|
||||
interpretiert hatte.
|
||||
|
||||
| Theme | Hintergrund | hell/dunkel | Akzent · Sekundär · Highlight |
|
||||
|---|---|---|---|
|
||||
| Ocean Depths | `#f1faee` | hell | `#2d8b8b` · `#a8dadc` · `#457b9d` |
|
||||
| Sunset Boulevard | `#264653` | dunkel | `#e76f51` · `#f4a261` · `#e9c46a` |
|
||||
| Forest Canopy | `#faf9f6` | hell | `#2d4a2b` · `#7d8471` · `#a4ac86` |
|
||||
| Modern Minimalist | `#ffffff` | hell | `#36454f` · `#708090` · `#d3d3d3` |
|
||||
| Golden Hour | `#4a403a` | dunkel | `#f4a900` · `#c1666b` · `#d4b896` |
|
||||
| Arctic Frost | `#fafafa` | hell | `#4a6fa5` · `#d4e4f7` · `#c0c0c0` |
|
||||
| Desert Rose | `#5d2e46` | dunkel | `#d4a5a5` · `#b87d6d` · `#e8d5c4` |
|
||||
| Tech Innovation | `#ffffff` | hell | `#0066ff` · `#00ffff` · `#1e1e1e` |
|
||||
| Botanical Garden | `#f5f3ed` | hell | `#4a7c59` · `#f9a620` · `#b7472a` |
|
||||
| Midnight Galaxy | `#e6e6fa` | hell | `#2b1e3e` · `#4a4e8f` · `#a490c2` |
|
||||
|
||||
⚠️ **Ob ein Theme hell oder dunkel gemeint ist, steht nicht verlässlich in den
|
||||
Beschreibungen** — „Warm Sand · backgrounds" findet sich bei einem Theme, dessen
|
||||
Showcase-Seite dunkel ist. Maßgeblich ist `theme-showcase.pdf` im Skill: sieben der
|
||||
zehn sind hell, nur Sunset Boulevard, Golden Hour und Desert Rose dunkel.
|
||||
„Midnight" Galaxy ist trotz des Namens ein helles Theme mit dunkelviolettem Akzent.
|
||||
Wer die Werte prüfen will, rendert die PDF-Seiten und misst die Hintergrundfarbe,
|
||||
statt der Prosa zu glauben.
|
||||
|
||||
Die übrigen Rollen (Flächenabstufungen, Username-Farben) sind aus diesen vier
|
||||
Farben gemischt — so bleibt jedes Theme in sich stimmig, ohne dass Werte
|
||||
dazuerfunden werden.
|
||||
|
||||
## Namensgebung: ThreadNet oder aXion1337.Chat?
|
||||
|
||||
**Beides, auf verschiedenen Ebenen — und das ist Absicht, kein Versehen.**
|
||||
|
||||
| Ebene | Name | Wo gesetzt |
|
||||
|---|---|---|
|
||||
| Betriebssystem, Startmenü, Installer, PWA | **ThreadNet** | `productName` in `apps/desktop/axion1337/build.json`, `name` in `apps/web/res/manifest.json` |
|
||||
| in der Anwendung | **aXion1337.Chat** | `brand` in `element-values.yaml` (Prod) und `apps/desktop/axion1337/config.json` |
|
||||
| eingebettetes Call-Widget | **aXion1337.Chat** | `VITE_PRODUCT_NAME` in `.env.production` (threadnet-call) |
|
||||
| Anmeldeseite (Authentik) | **ThreadNet** | `branding_title` im Brand-Blueprint (gitops, `apps/authentik/authentik-blueprints.yaml`) |
|
||||
|
||||
Das Call-Widget folgt der Zeile darüber: Es läuft *in* der Anwendung, also heißt es
|
||||
dort auch so. Die Anmeldeseite dagegen kommt **vor** der Anwendung — dort meldet man
|
||||
sich am Werkzeug an, nicht in der Gemeinschaft. Deshalb ThreadNet.
|
||||
|
||||
Die Leitplanke dahinter steht in [`vision/threadnet.md`](../vision/threadnet.md):
|
||||
*ThreadNet ist das Tool, axion1337.chat die Community.* Das Programm heißt
|
||||
ThreadNet — auch wenn es jemand für eine andere Instanz nutzt; die Gemeinschaft
|
||||
darin heißt aXion1337.Chat.
|
||||
|
||||
⚠️ **Nicht „geradeziehen".** Wer nur eine der beiden Stellen sieht, hält es für
|
||||
eine Inkonsistenz. Ist es nicht.
|
||||
|
||||
**Attribution:** „ThreadNet — powered by Element" steht seit `v0.4.0` in
|
||||
*Einstellungen → Hilfe & Info*, direkt unter der Client-Version, verlinkt auf
|
||||
element.io. Element Web steht unter der AGPL; ein Fork unter eigenem Namen ist
|
||||
erlaubt, die Nennung ist die faire Form davon. Bewusst **nicht** im Kopiertext der
|
||||
Versionsangabe — der landet in Fehlerberichten, dort ist die Fork-Herkunft nur
|
||||
Rauschen.
|
||||
|
||||
## Wo was eingestellt ist
|
||||
|
||||
| Oberfläche | Ort | Anmerkung |
|
||||
|---|---|---|
|
||||
| Element/ThreadNet-Web | `apps/production/custom-configs/element-values.yaml` (gitops), `setting_defaults.custom_themes` | 17 Themes; Änderungen chirurgisch, **nie die YAML neu serialisieren** |
|
||||
| Web-Icons + PWA | `apps/web/res/vector-icons/`, `apps/web/res/manifest.json` (ThreadNet-Web) | `theme_color` = `#ed4f4c`, die Markenfarbe — nicht Elements `#76CFA6` |
|
||||
| Desktop-Icons | `apps/desktop/build/` (ThreadNet-Web) | `.png`, `.ico`, `.icns`, Layer-Asset — alle aus derselben Quelle |
|
||||
| ThreadNet Desktop | `apps/desktop/axion1337/config.json` (ThreadNet-Web) | eigene Kopie derselben Themes — beim Ändern beide mitziehen |
|
||||
| BookStack | *Settings → Customization*, getrennt für hell und dunkel | liegt in der Datenbank, **nicht im Repo** — schriftlich hier und in `theme/sorbs-palette.md` |
|
||||
| BookStack (Feinschliff) | `theme/*.css` im Wiki-BookStack-Repo | nur Flächen, Text, Ränder — die sieben Farben oben gehören in die Oberfläche |
|
||||
| Docusaurus-Wiki | `src/css/custom.css` (homelab/wiki) | bislang nur Akzentfarbe |
|
||||
| Titelbild Login | `apps/web/res/themes/element/img/backgrounds/alpenglow.jpg` (ThreadNet-Web), gesetzt in `SdkConfig.ts` | siehe unten — Bilddatei kommt nur über einen Build in den Container |
|
||||
| Anmeldeseite Authentik | Brand-Blueprint in `apps/authentik/authentik-blueprints.yaml` (gitops) | Favicon und Hintergrund werden **von axion1337.chat referenziert**, nicht hochgeladen. **Logo ist noch Authentiks eigenes** → gitops#55 |
|
||||
|
||||
### Titelbild
|
||||
|
||||
Seit 2026-08-06 zeigt die Login-Seite ein Alpenglühen über einer Bergkette statt
|
||||
Elements See: **John Towner** ([@heytowner](https://unsplash.com/@heytowner)),
|
||||
[Unsplash](https://unsplash.com/photos/JgOeRuGD_Y4), *Unsplash License*.
|
||||
|
||||
Die Lizenz erlaubt kommerzielle Nutzung und Bearbeitung ohne Genehmigung und
|
||||
**verlangt keine Namensnennung**. Genannt wird er trotzdem — in *Einstellungen →
|
||||
Hilfe & Info* unter „Danksagungen". Verboten wäre nur der Weiterverkauf
|
||||
unbearbeiteter Bilder und das Nachbauen eines konkurrierenden Bilddienstes; beides
|
||||
trifft uns nicht.
|
||||
|
||||
⚠️ **Die Danksagung ist bewusst nicht übersetzt.** Elements Schlüssel
|
||||
`credits|default_cover_photo` liegt in 32 Sprachdateien, 31 davon nennen deren
|
||||
Fotografen namentlich. Nur `en`/`de` anzupassen hätte in 29 Sprachen eine **falsche
|
||||
Attribution** stehen lassen — und diese 29 pflegen wir nicht, sie kommen aus Elements
|
||||
Übersetzungsdienst. Deshalb steht die Zeile als fester Text im TSX, wie schon die
|
||||
„powered by Element"-Attribution.
|
||||
|
||||
⚠️ **Authentik hängt an dieser Datei.** Der Flow-Hintergrund dort zeigt auf
|
||||
`https://axion1337.chat/themes/element/img/backgrounds/alpenglow.jpg`. Wer das Bild im
|
||||
Client umbenennt oder entfernt, macht die Anmeldeseite grau — und merkt es nicht,
|
||||
weil im Client alles stimmt.
|
||||
|
||||
### Warum in Authentik kein PNG-Logo funktioniert
|
||||
|
||||
Der erste Versuch setzte `branding_logo` auf `vector-icons/512.png`. Ergebnis: das
|
||||
Logo rendert in der Anmeldemaske in **Naturgröße**. Authentiks Default ist ein SVG,
|
||||
das sich seiner Box anpasst — ein PNG tut das nicht, und der Slot begrenzt die Höhe
|
||||
nicht.
|
||||
|
||||
Zurückgesetzt am 2026-08-06 auf Authentiks eigenes Logo. Ein Ersatz braucht eine
|
||||
**Wortmarke im Querformat, am besten als SVG**; alles Vorhandene ist quadratisch,
|
||||
auch `threadnet-logo-wortmarke.png` (Bildmarke *über* Schriftzug). Offen in
|
||||
gitops#55.
|
||||
|
||||
⚠️ **Nicht über Authentiks Oberfläche einstellen.** Solange `branding_logo` im
|
||||
Blueprint steht, gewinnt der Blueprint: eine Auswahl in der UI hält bis zur nächsten
|
||||
Reconciliation und ist dann wieder weg.
|
||||
|
||||
⚠️ **Das BookStack-Schema lebt nur in der Datenbank.** Bei einem Volume-Verlust
|
||||
ist es weg — deshalb steht es oben in dieser Tabelle. Wiederherstellen heißt:
|
||||
sieben Felder in der Oberfläche neu eintragen.
|
||||
|
||||
Es steht bewusst an **zwei** Stellen schriftlich, und die Rollen sind verschieden:
|
||||
`theme/sorbs-palette.md` im BookStack-Repo ist die betriebsnahe Kopie mit den
|
||||
DB-Schlüsseln, liegt aber in der Gruppe `homelab` — die hat **keine Mirrors** und
|
||||
ist von außerhalb des Labs nicht lesbar. Diese Datei hier ist die gespiegelte
|
||||
und damit maßgebliche Fassung. Wer die Farben ändert, zieht beide mit; im
|
||||
Zweifel gilt, was in der laufenden Instanz eingestellt ist.
|
||||
|
||||
## Offen
|
||||
|
||||
Ob die Terrakotta-Richtung das Stammschema ablösen oder eine Alternative neben
|
||||
Gruvbox bleiben soll, ist nicht entschieden — das gehört in die Rebranding-Runde
|
||||
(→ [`vision/threadnet.md`](../vision/threadnet.md), ThreadNet-Web#10).
|
||||
@@ -0,0 +1,133 @@
|
||||
---
|
||||
type: wiki-page
|
||||
area: architecture
|
||||
related: []
|
||||
---
|
||||
|
||||
# Lab-Netzwerk (Heimnetz: Fritzbox + UDM Pro)
|
||||
|
||||
Themen rund um das Homelab-Netz selbst — Router-Kaskade, VLANs, VPN-Zugänge.
|
||||
Hosts im Lab: Overmind (git.lab, [hosts/overmind.md](../admin/overmind.md)),
|
||||
der Mac. Kaskade: **Fritzbox (WAN) → UDM Pro**, kein Doppel-NAT, statische
|
||||
Route in der Fritzbox für das Lab-VLAN.
|
||||
|
||||
> ✅ **Das VPN-Thema ist abgeschlossen und validiert** (sorb, 2026-08-02).
|
||||
> Beide Zugänge laufen und sind abgenommen, ADR-0004 steht auf *akzeptiert*
|
||||
> (Testreihe 1–7 in [#12](https://git.lab/axion1337.chat/management/-/issues/12)).
|
||||
> Es gibt dazu **keine offenen Issues mehr** — auch die Restpunkte #11
|
||||
> (MacBook-Profil) und #16 (LABNET-04, Feinschliff an den UniFi-Regeln) sind
|
||||
> geschlossen. Alles Folgende ist **Bestand und Historie**, keine offene Arbeit.
|
||||
|
||||
**Zwei WireGuard-Zugänge (Stand 2026-08-01, beide gelöst/abgenommen):**
|
||||
|
||||
| Zugang | Server | Port | Tunnelnetz | Zweck |
|
||||
|---|---|---|---|---|
|
||||
| Roadwarrior „Thore" | UDM | 51840 | 10.58.74.0/24 | Handy/MacBook ins Lab (LABNET-01) |
|
||||
| Site-to-Site „Matrix" | UDM | 51841 | 10.58.75.0/24 | Hetzner-Netz 10.0.0.0/24 ↔ Lab (LABNET-02, [ADR-0004](../../adr/0004-site-to-site-vpn-hetzner-lab.md)) |
|
||||
|
||||
### Verhältnis zu `homelab/docs`
|
||||
|
||||
Die Tabelle oben steht **absichtlich doppelt**. Maßgeblich für die
|
||||
Soll-Konfiguration ist
|
||||
[homelab/docs → MorninglightMountain](https://git.lab/homelab/docs/-/blob/main/netz/morninglightmountain.md)
|
||||
(dort auch Portfreigaben, Firewall-Zonen, Diagnose-Merksätze) — dieses Repo
|
||||
führt die **Historie**: was wann warum geändert wurde und mit welchem Issue.
|
||||
|
||||
Der Grund für die Doppelung ist der Mirror-Geltungsbereich aus der
|
||||
[CLAUDE.md](../../../AGENTS.md): Die Gruppe `homelab` hat bewusst **keine Mirrors** und
|
||||
ist von außerhalb des Labs nicht lesbar. Wer ohne Tunnel nachsehen muss, welcher
|
||||
Tunnel überhaupt auf welchem Port liegt, findet es nur hier. Deshalb hält dieses
|
||||
Dokument einen Kurzüberblick vor — Ports, Tunnelnetze, Zweck — und nichts
|
||||
darüber hinaus. **Bei Widerspruch gilt `homelab/docs`.**
|
||||
|
||||
---
|
||||
|
||||
## LABNET-01 — WireGuard-Roadwarrior ins Lab kaputt (seit einigen Monaten)
|
||||
|
||||
**Status:** GELÖST 2026-08-01 ~15:20 — `git.lab` lädt vom Handy über 5G/VPN. ✅
|
||||
Damit ist die Cutover-Voraussetzung für gitops#48 erfüllt.
|
||||
|
||||
**Drei gestapelte Ursachen (jede verdeckte die nächste):**
|
||||
1. **Privater Endpunkt** in jeder UDM-generierten Client-Config (UDM kennt hinter
|
||||
der Fritzbox ihre öffentliche IP nicht) → Fix: Endpunkt `178.25.213.70`;
|
||||
dauerhaft gelöst über UniFi-Option **„Alternate Address for Clients"**.
|
||||
2. **FritzOS reserviert UDP 51820 für seinen eigenen WireGuard-Stack** — die
|
||||
Portfreigabe 51820→UDM lief ins Leere (erklärt die „invalid response"-Stürme
|
||||
im Juli: zwei WG-Stacks auf einem Port) → Fix: UDM-WG auf **51840**.
|
||||
3. **Docker-Routen-Kollision auf Overmind**: Dokploys Bridge-Netze belegen zehn
|
||||
/20-Blöcke in 192.168.0.0/16; `192.168.0.0/20` verschluckte das VPN-Subnetz
|
||||
192.168.5.0/24 → Antworten an VPN-Clients endeten in der Bridge (SYN kam an,
|
||||
SYN-ACK verschwand — exakt der Chrome-Connection-Timeout, während Ping/DNS/
|
||||
fremde Hosts funktionierten) → Fix: **VPN-Subnetz auf 10.58.74.0/24** (Docker
|
||||
fasst 10.x nie an).
|
||||
|
||||
**Restarbeiten:** MacBook-WG-Profil → [Issue #11](https://git.lab/axion1337.chat/management/-/issues/11). ⚠️ Latente Wiederholungsgefahr
|
||||
notiert: Overminds Docker-Pool deckt auch `192.168.176.0/20` ab = kollidiert mit
|
||||
dem Fritzbox-Netz 192.168.178.x — aktuell folgenlos, aber bei künftigen Subnetz-
|
||||
Entscheidungen 192.168.x auf Overmind grundsätzlich meiden (oder Docker
|
||||
default-address-pools begrenzen).
|
||||
|
||||
**Bestätigte Ursachenkette (Diagnose-Session 2026-08-01):**
|
||||
1. Handy-Profil „@home" hatte seit 07.07. die **private** UDM-WAN-IP
|
||||
(192.168.178.20) als Endpunkt — die UDM kennt hinter der Fritzbox ihre
|
||||
öffentliche IP nicht und schreibt sie in jede generierte Config
|
||||
(⚠️ gilt für ALLE künftig exportierten Profile: Endpunkt manuell auf
|
||||
178.25.213.70 ändern!).
|
||||
2. Nach Endpunkt-Fix weiter tot: **FritzOS reserviert UDP 51820 für seinen
|
||||
EIGENEN WireGuard-Stack** — die alte Portfreigabe 51820→UDM lief ins Leere
|
||||
(erklärt auch die „invalid response"-Stürme im Juli: zwei WG-Stacks auf
|
||||
einem Port). Fix: UDM-WG auf **51840** umgezogen + Freigabe angepasst.
|
||||
3. Server + Schlüssel waren nie das Problem (WLAN-Handshake bewies beides).
|
||||
|
||||
Danach nur noch der ursprüngliche Blocker-Vermerk:
|
||||
blockierte gitops#48 (Erreichbarkeits-Entscheidung „WireGuard statt exponieren")
|
||||
|
||||
sorb hatte einen funktionierenden VPN-Zugang fürs Handy ins Lab; seit einigen
|
||||
Monaten „funktioniert das nicht mehr sauber" (Symptome noch zu präzisieren:
|
||||
Handshake? Routing nur teilweise? DNS?). Setup-Rahmen laut sorb (2026-08-01):
|
||||
UDM Pro hinter Fritzbox, ohne doppeltes NAT, statische Route in der Fritzbox
|
||||
für das VLAN.
|
||||
|
||||
**Diagnose-Plan von VOR der Lösung** — ⚠️ abgearbeitet und überholt, steht hier
|
||||
nur als Beleg, wie die Ursachen eingekreist wurden. Nichts davon ist zu tun:
|
||||
1. Symptom präzisieren: Handshake kommt zustande? (`wg show` auf der UDM /
|
||||
Client-Log) — trennt Portweiterleitungs- von Routing-Problemen
|
||||
2. Fritzbox: Portfreigabe UDP (WireGuard-Port) → UDM noch vorhanden/korrekt?
|
||||
(FritzOS-Updates werfen gern Freigaben/Exposed-Host-Einstellungen um)
|
||||
3. ~~DS-Lite~~ **ausgeschlossen** (sorb 2026-08-01: Dualstack + feste IPs) —
|
||||
damit auch kein DynDNS-Drift möglich. Verdacht konzentriert sich auf:
|
||||
FritzOS-Update warf die UDP-Portfreigabe um, UniFi-OS-Update veränderte
|
||||
WG-Server/Firewall, oder die statische Route griff nach Änderung nicht mehr.
|
||||
4. (entfällt — feste IP)
|
||||
5. UDM-Seite: WireGuard-Server-Config/Firewall-Regeln nach UniFi-OS-Updates
|
||||
prüfen; statische Route Fritzbox → VLAN gegenchecken
|
||||
6. Erst wenn 1–5 sauber: Client-Profil fürs Handy neu ausstellen, git.lab-DNS
|
||||
(Lab-Resolver) in die AllowedIPs/DNS-Konfig aufnehmen — Erfolgsbeweis =
|
||||
Issue-Board vom Handy über VPN erreichbar
|
||||
|
||||
**Verwandt:** gitops#48 (Cutover erst nach Lösung), perspektivisch ersetzt ein
|
||||
funktionierender Roadwarrior auch Ad-hoc-Wünsche wie „GitLab exponieren".
|
||||
|
||||
## Zugehörige Issues — alle geschlossen
|
||||
|
||||
Seit dem Framework-Umbau (2026-08-01) leben offene Punkte als Issues im
|
||||
[management-Projekt](https://git.lab/axion1337.chat/management/-/issues); die IDs bleiben in den Issue-Titeln erhalten.
|
||||
Dieses File hält nur noch Bestand und Historie.
|
||||
|
||||
Zum Netz/VPN ist **nichts mehr offen** (Stand 2026-08-02):
|
||||
|
||||
| Issue | Thema | Stand |
|
||||
|---|---|---|
|
||||
| [#11](https://git.lab/axion1337.chat/management/-/issues/11) | LABNET-01-Rest — MacBook-WireGuard-Profil | geschlossen |
|
||||
| [#12](https://git.lab/axion1337.chat/management/-/issues/12) | LABNET-02 — Site-to-Site-VPN (Design: [ADR-0004](../../adr/0004-site-to-site-vpn-hetzner-lab.md)) | geschlossen, Testreihe 1–7 protokolliert |
|
||||
| [#16](https://git.lab/axion1337.chat/management/-/issues/16) | LABNET-04 — Feinschliff UniFi-Regeln | geschlossen |
|
||||
|
||||
Zwei Punkte tragen zwar LABNET im Text, gehören aber **nicht** zum VPN-Thema und
|
||||
bleiben offen: [#13](https://git.lab/axion1337.chat/management/-/issues/13)
|
||||
(LABNET-03, Rückbau der Gitea-Ausnahme für Übergabe-Issues — durch den Tunnel
|
||||
erst möglich geworden, aber eine Repo-Frage) und
|
||||
[#15](https://git.lab/axion1337.chat/management/-/issues/15) (CFGMON-15,
|
||||
Widerruf der Einmal-Tokens aus der LABNET-02-Nacht — Credential-Hygiene, und der
|
||||
Widerruf kann still einen Push-Mirror brechen, solange dessen hinterlegtes Token
|
||||
unbekannt ist).
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
type: wiki-page
|
||||
area: architecture
|
||||
related:
|
||||
- "docs/adr/0001-gitlab-kanonisch-push-mirror.md"
|
||||
- "docs/adr/0002-issues-und-management-ins-lab.md"
|
||||
- "docs/adr/0004-site-to-site-vpn-hetzner-lab.md"
|
||||
- "docs/adr/0006-wikis-konsolidieren-docusaurus.md"
|
||||
---
|
||||
|
||||
# Mirror-Topologie: Das Lab ist die Quelle der Wahrheit
|
||||
|
||||
Begründungsprosa übernommen aus der alten `CLAUDE.md` (Abschnitt
|
||||
„Projektrealitäten", Wortlaut in der git-Historie vor der
|
||||
neckbeard-Migration); die verbindlichen Regeln stehen in `AGENTS.md` §6
|
||||
und den verlinkten ADRs. Erhalten per Feldtest-Befund F-013: Diese
|
||||
Begründung samt Gegenargument und Rettungspfad ist der Wert — sie
|
||||
erklärt, warum die Topologie so aussieht und so bleiben soll.
|
||||
|
||||
- Kanonische Repos liegen auf `git.lab/axion1337.chat/*` (nur im
|
||||
Lab/VPN auflösbar). Gitea/rohana wird per **Push-Mirror** beliefert
|
||||
und bleibt Flux-Source, Container-/npm-Registry und Release-Download
|
||||
([ADR-0001](../../adr/0001-gitlab-kanonisch-push-mirror.md)).
|
||||
- **Warum überhaupt zwei Orte — und warum das kein Altbestand ist:**
|
||||
Auf git.lab liegen die *Baupläne*, auf Gitea eine Kopie, die der
|
||||
Cluster **ohne verfügbares Lab** erreicht. Der Hetzner-Cluster muss
|
||||
sich bauen und neu ausrollen lassen, wenn das Homelab aus ist, im
|
||||
Umbau steckt oder niemand zu Hause ist — er darf deshalb nicht von
|
||||
einem Host abhängen, der nur im Lab antwortet.
|
||||
⚠️ **Die Flux-Quelle nicht „geradeziehen"** auf git.lab: Das sähe
|
||||
aufgeräumter aus und würde die Verfügbarkeit der Produktion an das
|
||||
Lab koppeln — genau das, was die Trennung verhindert.
|
||||
- **Gespiegelt wird nur die Gruppe `axion1337.chat`** (die Produkt-Repos
|
||||
und `management`). Die Gruppe **`homelab`** (`docs`, `wiki`,
|
||||
`wiki-bookstack`) hat bewusst **keine Mirrors**: Sie beschreibt und
|
||||
konfiguriert ausschließlich Lab-Infrastruktur, und seit dem
|
||||
Site-to-Site-VPN ([ADR-0004](../../adr/0004-site-to-site-vpn-hetzner-lab.md))
|
||||
erreichen auch Host-Sessions git.lab direkt — Tunnel einschalten
|
||||
genügt. Betriebslehren, die von außen lesbar sein müssen, gehören
|
||||
deshalb in die **AARs** unter `docs/aar/` (dieses Repo ist
|
||||
gespiegelt), nicht nur in die READMEs der Lab-Repos.
|
||||
- Landet doch ein Commit auf Gitea (z. B. aus einer Host-Session ohne
|
||||
Lab-Route): **Kanonisierungs-Verfahren** in
|
||||
[deploy-uebergabe](../deployment/deploy-uebergabe.md) — `.patch` von
|
||||
Gitea ziehen, `git am` (erhält Autorschaft), Push über git.lab.
|
||||
- ⚠️ gitops-Issue-Nummern haben sich beim Gitea-Umzug verschoben (Gitea
|
||||
zählte PRs mit; z. B. Gitea#48 → GitLab#46) — alte „gitops#N"-Verweise
|
||||
meinen die Gitea-Nummer; verbindlich ist der Migrations-Fußtext im
|
||||
Issue ([ADR-0002](../../adr/0002-issues-und-management-ins-lab.md)).
|
||||
- **Ausnahme** (bewusst entschieden, nur noch eine): der
|
||||
TURN-Rotations-CronJob schreibt weiter nach Gitea, weil er im Cluster
|
||||
läuft und git.lab nicht erreicht. **Die Rotation nicht von Hand
|
||||
nachziehen und den PR nie auf Gitea mergen** — das erledigt seit
|
||||
2026-08-02 der geplante CI-Job `canonize_rotation` im gitops-Repo
|
||||
täglich von git.lab aus. Scheitert er, bleibt die Pipeline rot; diese
|
||||
rote Pipeline **ist** der Alarm, einen zusätzlichen Termin gibt es
|
||||
bewusst nicht.
|
||||
- **Dokumentation** ([ADR-0006](../../adr/0006-wikis-konsolidieren-docusaurus.md)):
|
||||
Das gitops-Wiki liegt seit 2026-08-02 auf git.lab (*Wiki*-Reiter im
|
||||
Projekt); ⚠️ der `wiki`-**Branch** im gitops-Repo ist ein überholter
|
||||
Mai-Abzug von `docs/` und nicht die gepflegte Fassung. Alle Quellen
|
||||
zusammen erscheinen unter **axionwiki.lab**
|
||||
([`homelab/wiki`](https://git.lab/homelab/wiki), Docusaurus) —
|
||||
Inhalte werden beim Bau geholt, **Änderungen gehören ins Quell-Repo**.
|
||||
@@ -0,0 +1,148 @@
|
||||
---
|
||||
type: wiki-page
|
||||
area: architecture
|
||||
related: []
|
||||
---
|
||||
|
||||
# DNS-Zone `axion1337.de` und Mail-Policy
|
||||
|
||||
Übergreifend, weil die Zone alle Hosts abdeckt und die Mail-Policy sich nicht pro
|
||||
Host trennen lässt.
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **Registrar / DNS** | IONOS (`ns1098.ui-dns.biz`, `ns1022.ui-dns.com`, `ns1070.ui-dns.org`, `ns1059.ui-dns.de`) |
|
||||
| **Apex** | `217.160.0.140` / `2001:8d8:100f:f000::2e9` — IONOS-Hosting, nicht eigene Infrastruktur |
|
||||
| **Mail** | IONOS (`mx00.ionos.de`, `mx01.ionos.de`) |
|
||||
| **Stand** | 2026-08-06 (Mail-Records gemessen) |
|
||||
|
||||
**Ist-Stand der Mail-Härtung** (gemessen 2026-08-06 über DoH, um den Lab-Resolver
|
||||
zu umgehen):
|
||||
|
||||
| Name | `www` | MX | SPF | `_dmarc` | Bewertung |
|
||||
|---|---|---|---|---|---|
|
||||
| `rohana` | löst auf ❌ | gelöscht | **gelöscht** ⚠️ | fehlt | ⚠️ schwächer als vorher |
|
||||
| `selendis` | weg ✅ | IONOS ❌ | `~all` ❌ | fehlt | unangetastet |
|
||||
| `matrix` | löst auf ❌ | IONOS ❌ | `~all` ❌ | fehlt | offen |
|
||||
| `game` | löst auf ❌ | — | — | fehlt | teilweise |
|
||||
| **Apex** | legitim ✅ | IONOS (genutzt) | `~all` | **`p=none`** ⚠️ | siehe ZONE-02 |
|
||||
|
||||
Kein einziger Name trägt bisher `_dmarc`, alle erben damit `p=none` vom Apex.
|
||||
|
||||
> **Die Aufstellung ist nicht garantiert vollständig.** Zonentransfer ist verweigert,
|
||||
> DNS erlaubt kein Enumerieren. Die Records unten stammen aus gezielten Abfragen und
|
||||
> der IONOS-Oberfläche. Für eine vollständige Prüfung entweder die ungefilterte
|
||||
> IONOS-Liste durchgehen oder die Certificate-Transparency-Logs abfragen (zeigt alle
|
||||
> Namen, für die je ein Cert ausgestellt wurde).
|
||||
|
||||
## Bekannter Bestand
|
||||
|
||||
| Name | A | AAAA | Ziel |
|
||||
|---|---|---|---|
|
||||
| `axion1337.de` | `217.160.0.140` | `2001:8d8:100f:f000::2e9` | IONOS-Hosting |
|
||||
| `www` | `217.160.0.140` | dito | IONOS-Hosting — hier ist `www` **legitim** |
|
||||
| `rohana` | `188.245.193.243` | `2a01:4f8:c17:93eb::1` | CFGMON, Gitea |
|
||||
| `selendis` | `188.245.193.243` | `2a01:4f8:c17:93eb::1` | CFGMON, Grafana |
|
||||
| `game` | `157.90.155.206` | — | Pterodactyl |
|
||||
| `matrix` | `49.13.132.245` | — | Matrix-Homeserver |
|
||||
| `ftp` | `217.160.233.227` | `2001:8d8:1000:30f5:…` | IONOS-Default |
|
||||
| `www.rohana`, `www.selendis`, `www.game`, `www.matrix` | wie ohne `www` | teils | überflüssig, siehe ZONE-01 |
|
||||
|
||||
Mail-Records existieren auf `selendis` und `matrix` (MX ×2, SPF, DKIM-CNAMEs,
|
||||
`autodiscover`), auf `rohana` und `game` nicht.
|
||||
|
||||
## Was die Mail-Records eigentlich tun
|
||||
|
||||
Damit die Rezepte in [ZONE-01](https://git.lab/axion1337.chat/management/-/issues/5)
|
||||
nicht als Zahlensalat dastehen: Vier Mechanismen, die zusammenspielen. **Keiner
|
||||
schützt allein.**
|
||||
|
||||
### Das Grundproblem
|
||||
|
||||
Der Absender einer Mail (`From:`) ist frei wählbar — SMTP prüft ihn nicht. Jeder
|
||||
kann `rechnung@rohana.axion1337.de` in den Umschlag schreiben. Die folgenden
|
||||
Records sind die Möglichkeit, dem widersprechen, **bevor** jemand darauf hereinfällt.
|
||||
|
||||
### SPF — „diese Server dürfen für mich senden"
|
||||
|
||||
TXT-Record am Namen selbst. Listet die berechtigten Absender-IPs.
|
||||
|
||||
Entscheidend ist das **Ende** des Eintrags:
|
||||
|
||||
| Endung | Bedeutung | Wirkung beim Empfänger |
|
||||
|---|---|---|
|
||||
| `~all` | Softfail | „war nicht auf der Liste" → wird meist **trotzdem zugestellt**, evtl. markiert |
|
||||
| `-all` | Hardfail | „war nicht auf der Liste" → **ablehnen** |
|
||||
|
||||
`v=spf1 -all` ohne jeden Server davor heißt: *Für diesen Namen sendet niemand.*
|
||||
Genau die richtige Aussage für `rohana`, `selendis`, `matrix` — die verschicken keine
|
||||
Mail (für `matrix` verifiziert in MATRIX-01: weder Synapse noch MAS senden).
|
||||
|
||||
⚠️ **Es darf nur EIN SPF-Record je Name existieren.** Ein zweiter erzeugt
|
||||
`PermError`, und dann prüfen viele Empfänger **gar nicht mehr** — die Härtung
|
||||
schlägt ins Gegenteil um. Deshalb: bestehenden TXT **editieren**, nie einen zweiten
|
||||
anlegen.
|
||||
|
||||
### DKIM — „diese Mail wurde unterwegs nicht verändert"
|
||||
|
||||
Signatur mit einem privaten Schlüssel, öffentlicher Teil als CNAME/TXT im DNS
|
||||
(`s1-ionos._domainkey…`). Beweist Unversehrtheit und Herkunft.
|
||||
|
||||
Für Namen, die nicht senden, sind die DKIM-Einträge schlicht **Ballast** — sie
|
||||
signieren nichts. Sie können weg.
|
||||
|
||||
### DMARC — „und das tust du, wenn SPF oder DKIM nicht passen"
|
||||
|
||||
TXT unter `_dmarc.<name>`. SPF und DKIM stellen nur **fest**; DMARC sagt, welche
|
||||
**Konsequenz** das hat:
|
||||
|
||||
| Policy | Wirkung |
|
||||
|---|---|
|
||||
| `p=none` | nur beobachten — **kein Schutz**, Mail wird zugestellt |
|
||||
| `p=quarantine` | in den Spam-Ordner |
|
||||
| `p=reject` | ablehnen |
|
||||
|
||||
⚠️ **DMARC wird vererbt.** Fehlt `_dmarc.rohana`, gilt die Policy des
|
||||
organisatorischen Namens `axion1337.de`. Die steht heute auf **`p=none`**
|
||||
([ZONE-02](https://git.lab/axion1337.chat/management/-/issues/6)) — **damit erben
|
||||
alle Subdomains „kein Schutz"**, egal wie sauber ihr SPF ist.
|
||||
|
||||
Das ist der wichtigste Hebel der ganzen Zone: **Der Apex wirkt auf alle Namen
|
||||
gleichzeitig.** Mit `sp=` lässt sich für Subdomains sogar eine strengere Policy
|
||||
setzen als für den Apex selbst.
|
||||
|
||||
### Null-MX — „hier nimmt niemand Mail an" (RFC 7505)
|
||||
|
||||
Ein MX-Record mit dem Ziel `.` (Punkt) und Priorität 0.
|
||||
|
||||
Der Grund, warum **Löschen nicht reicht**: Findet ein Absender **keinen** MX,
|
||||
weicht er per RFC 5321 auf den **A/AAAA-Record** aus und versucht, direkt an den
|
||||
Webserver zuzustellen. Der Name sieht dann nach „nimmt vielleicht Mail an" aus.
|
||||
Null-MX sagt stattdessen ausdrücklich *nein* — Absender brechen sofort ab.
|
||||
|
||||
### Warum die Kombination
|
||||
|
||||
| Record | Beantwortet die Frage |
|
||||
|---|---|
|
||||
| **Null-MX** | Nimmt dieser Name Mail **an**? → nein |
|
||||
| **SPF `-all`** | Darf jemand für diesen Namen **senden**? → niemand |
|
||||
| **DMARC `p=reject`** | Was tun, wenn doch jemand behauptet, es zu dürfen? → ablehnen |
|
||||
|
||||
Erst zusammen ergeben sie eine Aussage, auf die sich ein Empfänger verlassen kann.
|
||||
Einzeln bleibt jeweils eine Lücke — und **ersatzloses Löschen** hinterlässt die
|
||||
größte: keine Aussage ist schwächer als eine schlechte Aussage.
|
||||
|
||||
**Real eingetreten:** Bei `rohana` sind MX und SPF gelöscht, die Ersatz-Records
|
||||
fehlen (gemessen 2026-08-06). Vorher gab es wenigstens ein Softfail-SPF, jetzt gar
|
||||
keine Aussage mehr — dazu die geerbte `p=none` vom Apex. Der Halbfertig-Zustand ist
|
||||
schwächer als der Ausgangszustand.
|
||||
|
||||
## Offene Punkte → git.lab-Issues
|
||||
|
||||
Seit dem Framework-Umbau (2026-08-01) leben offene Punkte als Issues im
|
||||
[management-Projekt](https://git.lab/axion1337.chat/management/-/issues); die IDs bleiben in den Issue-Titeln erhalten.
|
||||
Dieses File hält nur noch Bestand und Historie.
|
||||
|
||||
- [ZONE-01 — IONOS-Default-Records bereinigen (Rezepte im Issue; rohana/selendis in Arbeit)](https://git.lab/axion1337.chat/management/-/issues/5)
|
||||
- [ZONE-02 — Apex-DMARC ist `p=none` und schützt nichts](https://git.lab/axion1337.chat/management/-/issues/6)
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
type: wiki-page
|
||||
area: deployment
|
||||
related: []
|
||||
---
|
||||
|
||||
# Verfahren: Deploy-Übergabe
|
||||
|
||||
Für die Konstellation „einer baut, ein anderer rollt aus". Zweck ist nicht mehr
|
||||
Prozess, sondern **weniger Rückfragen und weniger stille Fehlschläge**.
|
||||
|
||||
Eingeführt am 2026-08-01 nach dem Deploy der CVE-Pipeline (`gitops#47`), siehe
|
||||
[aar/2026-08-01-cve-pipeline-gitops47.md](../../aar/2026-08-01-cve-pipeline-gitops47.md).
|
||||
|
||||
## Ablauf
|
||||
|
||||
1. Wer baut, öffnet **auf git.lab** ein Issue aus der Vorlage **Deploy-Übergabe**
|
||||
(`.gitlab/issue_templates/Deploy-Übergabe.md`, im Feld *Description template*).
|
||||
2. Wer ausrollt, arbeitet die Prüfliste unten ab und deployt.
|
||||
3. Wer ausrollt, hängt den **AAR** als Kommentar an dasselbe Issue
|
||||
(Vorlage: [docs/aar/template.md](../../aar/template.md)). Bei Befunden ab MEDIUM
|
||||
zusätzlich als Datei unter `docs/aar/`.
|
||||
|
||||
## Die vier Punkte, die den Unterschied machen
|
||||
|
||||
### 1. Mengengerüst vor dem Deploy
|
||||
|
||||
Bei allem, was etwas erzeugt — Nachrichten, Alarme, Zeitreihen, Requests —
|
||||
gehört die erwartete Anzahl beim **ersten** Lauf in die Übergabe. Geschätzt ist
|
||||
in Ordnung, gemessen ist besser; welches von beidem, muss dabeistehen.
|
||||
|
||||
Der Grund: „ein Alarm pro Fund" ist eine völlig unauffällige Zeile im Code und
|
||||
harmlos bei 5 Funden. Bei 126 ist es ein Ausfall. Der Unterschied steht nirgends
|
||||
im Diff — er ergibt sich erst aus den Daten, gegen die das Ding läuft.
|
||||
|
||||
Eine Stichprobe reicht: drei repräsentative Elemente von 29 messen und
|
||||
hochrechnen kostet Minuten und liefert die Größenordnung.
|
||||
|
||||
### 2. Verifikation dort, wo der Dienst liest
|
||||
|
||||
Ein grüner Linter belegt, dass eine Datei **gültig** ist — nicht, dass sie
|
||||
**geladen** wurde. Diese beiden Aussagen sind bei Bind-Mounts, Caches und
|
||||
Reload-Semantiken regelmäßig verschieden.
|
||||
|
||||
Also im Container prüfen, in der laufenden API, im tatsächlich geladenen
|
||||
Regelwerk. Ein Blick auf die Platte beweist nichts über den Prozess.
|
||||
|
||||
### 3. Deploy-Kommando vollständig übergeben
|
||||
|
||||
Inklusive Reload-, Restart- und Recreate-Schritten. Ein `docker compose up -d`,
|
||||
das `Running` meldet und dabei nichts aktiviert, ist der häufigste stille
|
||||
Fehlschlag: kein Fehler, kein Log, falscher Zustand.
|
||||
|
||||
Konkret auf dem Monitoring-Stack (CFGMON): Einzeldatei-Mounts hängen am Inode,
|
||||
`git pull` benennt beim Schreiben um und erzeugt damit einen neuen — der
|
||||
Container zeigt danach weiter auf die alte Datei. Es braucht
|
||||
`--force-recreate`. Details: `gitops#52`.
|
||||
|
||||
### 4. Zustellwege stumm schalten statt Deploy verschieben
|
||||
|
||||
Datensammlung und Außenwirkung lassen sich fast immer getrennt scharf schalten.
|
||||
Wenn der Zustellweg das Risiko ist, wird **er** abgeklemmt — nicht der ganze
|
||||
Deploy verschoben.
|
||||
|
||||
So läuft die Datensammlung ab sofort, das Dashboard steht, echte Zahlen
|
||||
ersetzen die Schätzung, und die Entscheidung über die Zustellung fällt auf
|
||||
Basis von Messwerten statt Vermutungen. Wichtig: die Stummschaltung gehört
|
||||
committet und dokumentiert, sonst ist sie in zwei Wochen ein Rätsel.
|
||||
|
||||
## Prüfliste für den Ausrollenden
|
||||
|
||||
<!-- pruefe-prosa:ok (Checkliste des Verfahrens, keine offene Aufgabe) -->
|
||||
- [ ] Diff gelesen, nicht nur die Beschreibung
|
||||
- [ ] Mengengerüst plausibel? Bei Zweifel an einer Stichprobe selbst messen
|
||||
- [ ] Configs mit den jeweiligen Werkzeugen validiert (`promtool`, `amtool`,
|
||||
`compose config`, `py_compile` …)
|
||||
- [ ] Außenwirkung identifiziert — was verlässt beim ersten Lauf das System?
|
||||
- [ ] Nach dem Deploy **im Container** verifiziert, dass die neue Config aktiv ist
|
||||
- [ ] Geprüft, ob vorher gesunde Dinge noch gesund sind (keine stille Regression)
|
||||
- [ ] AAR geschrieben, Folge-Issues angelegt, Stummschaltungen dokumentiert
|
||||
|
||||
## Abgrenzung
|
||||
|
||||
Das Verfahren gilt für Übergaben zwischen Personen. Wer baut **und** ausrollt,
|
||||
braucht kein Issue — der AAR lohnt trotzdem, sobald es Befunde ab MEDIUM gab.
|
||||
|
||||
## Kanonisierung nach CFGMON-Deploys (Topologie-Pflichtschritt)
|
||||
|
||||
CFGMON erreicht git.lab nicht — Commits aus Deploy-Sessions landen zwangsläufig
|
||||
direkt auf dem Gitea-Mirror und werden vom nächsten Mirror-Lauf **kommentarlos
|
||||
überschrieben** (zweimal passiert: dfe04c4→6ffab68 am 01.08. nachts,
|
||||
2b715ca→0bd77e2 am 01.08. nachmittags). Deshalb gehört zu jeder Übergabe:
|
||||
|
||||
1. **CFGMON-Seite** vermerkt den Commit-Hash im Übergabe-Issue (Feld „Stand").
|
||||
2. **Mac-Seite** kanonisiert zeitnah: Patch per
|
||||
`https://rohana.axion1337.de/sorb/<repo>/commit/<sha>.patch` ziehen
|
||||
(verwaiste Objekte bleiben eine Weile abrufbar), `git am`, Push nach git.lab.
|
||||
Der Hash ändert sich dabei — **Autorschaft und Inhalt bleiben erhalten**.
|
||||
3. **CFGMON** vor dem nächsten Pull: `git fetch && git reset --hard origin/main`
|
||||
(inhaltsgleich, nur neuer Hash).
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
type: wiki-page
|
||||
area: index
|
||||
related: []
|
||||
---
|
||||
|
||||
# Wiki-Index
|
||||
|
||||
Areas sind Ordner; leere Ordner werden nie angelegt — Struktur entsteht
|
||||
mit Inhalt. Projektfassung des neckbeard-Index (Original:
|
||||
`docs/sources/upstream/neckbeard-v0.1.1/`), erweitert um die Area
|
||||
`vision` (Alt-Wert „eine Datei je Linie", ADR-0005).
|
||||
|
||||
## Areas
|
||||
|
||||
| Area | Enthält | Stand |
|
||||
|---|---|---|
|
||||
| `admin/` | Betrieb: [cfgmon](admin/cfgmon.md) · [game](admin/game.md) · [matrix](admin/matrix.md) · [overmind](admin/overmind.md) · [Refinement & Retro](admin/refinement.md) · [Stillstandsprüfung](admin/stillstandspruefung.md) · [Textbausteine](admin/textbloecke.md) | belegt |
|
||||
| `deployment/` | [Deploy-Übergabe](deployment/deploy-uebergabe.md) (Definition of Done, Kanonisierungs-Verfahren) | belegt |
|
||||
| `architecture/` | [Mirror-Topologie](architecture/mirror-topologie.md) · [Lab-Netz](architecture/lab-netzwerk.md) · [DNS-Zone](architecture/zone-axion1337.md) · [Branding](architecture/branding.md) | belegt |
|
||||
| `vision/` | Eine Datei je Linie: [axion1337.chat](vision/axion1337-chat.md) · [Homelab](vision/homelab.md) · [ThreadNet](vision/threadnet.md) | belegt |
|
||||
| `user-guide/` | Für Nicht-Owner | entfällt — Gate 0: Publikum ist Owner + Sessions |
|
||||
| `requirements/` | Eigenständige Anforderungssicht | nur bei echtem Bedarf |
|
||||
| `faq/`, `stolpersteine/` | Nur aus AARs und geschlossenen Issues geerntet — nie auf Vorrat | leer, entsteht im Refinement |
|
||||
|
||||
## Seitenregeln
|
||||
|
||||
- Jede Seite trägt Frontmatter per `schema.yaml` (`type: wiki-page`,
|
||||
`area`, `related`, ggf. `sources`).
|
||||
- `sources` zitiert, worauf die Seite fußt — Dateien unter
|
||||
`docs/sources/` (unveränderlich, agentenschreibgeschützt) oder
|
||||
externe URLs.
|
||||
- Nur Standard-Markdown-Links, Diagramme als Mermaid (ADR-0003
|
||||
upstream); keine Wikilinks.
|
||||
- **Aufgaben gehören nicht ins Wiki:** offene Arbeitspunkte sind Issues
|
||||
(`docs/issues/`), Wiki-Seiten verweisen höchstens darauf
|
||||
(Lehre F-004; Prüfung: `scripts/pruefe_prosa.py`).
|
||||
- Widersprüche werden aufgelöst oder ausdrücklich als Konflikt markiert
|
||||
— nie stillschweigend nebeneinander stehen gelassen.
|
||||
- Kein „Stand:"-Etikett in Seitenkörpern — `git log` beantwortet das
|
||||
(Lehre F-010).
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
type: wiki-page
|
||||
area: vision
|
||||
related: []
|
||||
---
|
||||
|
||||
# Vision: aXion1337.chat — die Community
|
||||
|
||||
> **Getragene Fassung** — geschärft im Struktur-Workshop am 2026-08-06 (#17).
|
||||
> Leitplanke von sorb:
|
||||
> **„axion1337.chat ist die Community, ThreadNet ist das Tool."**
|
||||
|
||||
## Kern
|
||||
|
||||
Eine selbst betriebene, souveräne Kommunikationsplattform für die eigene
|
||||
Community: Matrix-Homeserver mit eigenem Client, eigener Identität (Authentik),
|
||||
eigenen Regeln — unabhängig von Discord & Co.
|
||||
|
||||
## Was dazugehört (Stand heute)
|
||||
|
||||
- Matrix/ESS-Stack mit Voice/Video (Element Call, 1440p-Defaults)
|
||||
- Gäste sollen unkompliziert, aber kontrolliert reinkommen
|
||||
(Invite-Workflow gitops-Issue, Freischaltung im Matrix-Raum, `@concierge`)
|
||||
- Community-Funktionen über Chat hinaus: Raidplaner mit Fotoalbum (HumHub-Kandidat)
|
||||
- Sicherheit als Feature: ClamAV beidseitig, CVE-Transparenz im Security-Raum
|
||||
|
||||
## Zielgruppe und Größe
|
||||
|
||||
**Kontrolliert wachsend** (entschieden 2026-08-06). Offen für Neue, aber **jeder
|
||||
Eintritt wird freigegeben** — genau das, was der Invite-Workflow mit `@concierge`
|
||||
und befristeten Gast-Accounts baut. Wachstum ist erwünscht, aber gedeckelt durch
|
||||
das, was eine Person moderieren kann; der Ein-Node-Stack setzt denselben Rahmen.
|
||||
|
||||
Verworfen: **geschlossener Kreis** (dann wäre der Invite-Workflow überdimensioniert)
|
||||
und **offene Registrierung** (verlangt Moderationsteam und Kapazität, die es nicht
|
||||
gibt).
|
||||
|
||||
Was daraus folgt: Der Invite-Workflow ist kein Nice-to-have, sondern das Mittel,
|
||||
mit dem diese Entscheidung durchgesetzt wird. Freie Registrierung bleibt aus.
|
||||
|
||||
## Verhältnis zum ThreadNet-Branding
|
||||
|
||||
Nicht mehr offen: Das Rebranding wird in **M4 zu Ende gebracht**, nicht separat
|
||||
terminiert — siehe [`threadnet.md`](threadnet.md).
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
type: wiki-page
|
||||
area: vision
|
||||
related: []
|
||||
---
|
||||
|
||||
# Vision: Homelab — die Plattform
|
||||
|
||||
> **Getragene Fassung** — geschärft im Struktur-Workshop am 2026-08-06 (#17).
|
||||
|
||||
## Kern
|
||||
|
||||
Das Lab (MorninglightMountain, Overmind, das Netz dazwischen) ist die
|
||||
**Quelle der Wahrheit** und die Werkbank: kanonische Repos, Build-CI,
|
||||
Verwaltung — alles, was nicht öffentlich erreichbar sein muss, lebt hier
|
||||
(ADR-0001/0002).
|
||||
|
||||
## Prinzipien
|
||||
|
||||
- Prod hängt nie vom Lab ab: Hetzner-Hosts laufen bei Lab-Ausfall weiter,
|
||||
nur Neues pausiert.
|
||||
- Verbindungen ins Lab sind schaltbar und minimal (Roadwarrior für Menschen,
|
||||
Site-to-Site für Server — ADR-0004), nie dauerhaft exponiert.
|
||||
- Bestand wird dokumentiert, wo er lebt: [homelab/docs](https://git.lab/homelab/docs)
|
||||
für Netz/Geräte, Betriebs-Repos je Host.
|
||||
|
||||
## Ausbaustufen
|
||||
|
||||
**Konsolidieren vor Ausbauen** (entschieden 2026-08-06). Kein neuer Dienst und
|
||||
kein weiterer Host, solange die Absicherung des Bestehenden nicht steht.
|
||||
|
||||
Der Maßstab ist nicht „läuft es", sondern „überlebt es den Verlust der Maschine,
|
||||
auf der es läuft". Ein Lab, das Quelle der Wahrheit ist, hat diese Frage zuerst zu
|
||||
beantworten — jeder zusätzliche Dienst vergrößert sonst die Angriffsfläche
|
||||
schneller als die Kontrolle.
|
||||
|
||||
**Nachtrag sorb (2026-08-06):** Die Git-Daten werden bereits in einen S3-Bucket
|
||||
auf sein NAS gesichert. Das entschärft den ursprünglichen Befund aus
|
||||
[#10](https://git.lab/axion1337.chat/management/-/issues/10) — offen bleibt
|
||||
jedoch, was diese Sicherung **nicht** umfasst (Registry-Blobs, npm-Pakete,
|
||||
Gitea-Datenbank). Siehe dort.
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
type: wiki-page
|
||||
area: vision
|
||||
related: []
|
||||
---
|
||||
|
||||
# Vision: ThreadNet — das Tool
|
||||
|
||||
> **Getragene Fassung** — geschärft im Struktur-Workshop am 2026-08-06 (#17).
|
||||
> Leitplanke: ThreadNet ist die Produkt-/Tool-Linie, axion1337.chat der Betrieb.
|
||||
|
||||
## Kern
|
||||
|
||||
Die Software-Artefakte, die die Community tragen — als eigenständige,
|
||||
wiederverwendbare Produkte gedacht: ThreadNet-Web (Element-Web-Fork mit
|
||||
Discord-artiger Raumliste), threadnet-call (Call-Fork), thread-net-git,
|
||||
threadnet-operating.
|
||||
|
||||
## Prinzipien
|
||||
|
||||
- **Reproduzierbar für Dritte:** Deployment-Arbeit so bauen, dass eine andere
|
||||
Community den Stack forken kann (stehendes Ziel von sorb, 2026-07-30) —
|
||||
Instanzwerte getrennt von generischer Struktur.
|
||||
- Fork-Pflege mit kleinem Delta: Upstream-Merges müssen billig bleiben,
|
||||
chirurgische Patches statt Umbauten.
|
||||
- CI beweist Releases: Tag → Pipeline → Artefakt, keine Handbuilds.
|
||||
|
||||
## Veröffentlichungsgrad
|
||||
|
||||
**Die Forks werden öffentlich** (entschieden 2026-08-06) — aber erst nach einem
|
||||
**History-Audit**, und in dieser Reihenfolge: zuerst gitops und Doku, die Clients
|
||||
später.
|
||||
|
||||
Der Grund für die Entscheidung steckt im Prinzip oben: „reproduzierbar für Dritte"
|
||||
zahlt sich nur öffentlich aus. Bliebe alles privat, würde dauerhaft für einen Zweck
|
||||
gebaut, den es nicht gibt — dann hätte das Prinzip gestrichen gehört.
|
||||
|
||||
⚠️ **Der Audit ist Bedingung, nicht Formsache.** In der Historie des gitops-Repos
|
||||
steht Commit `51ea513` — *„remove plaintext TURN shared secret, rotate leaked
|
||||
value"*. Der Wert ist rotiert und damit wertlos, aber er steht weiterhin in der
|
||||
Historie, und er ist vermutlich nicht der einzige Fund. Vor dem Umschalten auf
|
||||
public: Historie aller zu veröffentlichenden Repos auf Klartext-Geheimnisse prüfen
|
||||
und entscheiden, ob bereinigt (History-Rewrite) oder bewusst akzeptiert wird.
|
||||
|
||||
## Rebranding
|
||||
|
||||
**Wird in M4 zu Ende gebracht** (entschieden 2026-08-06), ohne eigenen Termin.
|
||||
|
||||
Begründung: Halbfertig ist der schlechteste Zustand — der Desktop-Client heißt
|
||||
seit `6b0261d` ThreadNet und trägt die eigene Marke, der Web-Client zeigt weiter
|
||||
Element. Der Rest gehört zusammen mit Signing und Installer-Branding in
|
||||
„Produktreife ThreadNet" (ThreadNet-Web#6, #7, #10).
|
||||
Reference in New Issue
Block a user