Merge branch 'main' of https://gitea.emsenhuber.net/admin/bf-infra
This commit is contained in:
30
CLAUDE.md
30
CLAUDE.md
@@ -6,7 +6,7 @@ DNS/DHCP-Ablösung, WLAN via **CAPsMAN auf dem Core** (TP28, 2026-08-17 — der
|
||||
|
||||
## Pflichtlektüre pro Sitzung (Reihenfolge)
|
||||
|
||||
1. **`docs/teilprojekte.md`** (Quick-Index-Block) — kanonischer Stand, Scope, Abhängigkeiten, **offene** TPs. **1 Read reicht.**
|
||||
1. **Status/Index = Gitea-Board** (seit TP36-Cutover 2026-09-07): [`admin/bf-infra` · Issues](https://gitea.emsenhuber.net/admin/bf-infra/issues) — TP = Issue, Status = Label `status:*`, Gruppierung = `thema:*`. Für den **Detail/Kontext** eines TP dann den `### TPnn`-Prosa-Abschnitt in **`docs/teilprojekte.md`** (aktiv) bzw. **`docs/teilprojekte-archiv.md`** lesen. *(Die frühere „Quick-Index-Block, 1 Read reicht"-Zeile ist überholt — Index/Status stehen nicht mehr in der Datei.)*
|
||||
2. **`docs/handoff-*.md`** (neueste) — wo die letzte Session aufgehört hat.
|
||||
3. Bei Live-Writes oder Inventur: **`docs/cf-tunnel-mapping.md`**, **`docs/teilprojekte-archiv.md`**.
|
||||
4. ✅ **TP16.3 §5 durch (2026-09-01):** [`docs/handoff-20260901-tp16.3-paragraph5-flip-durch.md`](docs/handoff-20260901-tp16.3-paragraph5-flip-durch.md)
|
||||
@@ -34,6 +34,21 @@ DNS/DHCP-Ablösung, WLAN via **CAPsMAN auf dem Core** (TP28, 2026-08-17 — der
|
||||
6. ap3-Bring-up 2026-08-30: [`docs/handoff-20260830-ap3.md`](docs/handoff-20260830-ap3.md) — sechs Funde zu Werks-MikroTiks, CAPsMAN und Golden-Config-Lücken.
|
||||
7. Inventur-Befund 2026-08-27: [`docs/handoff-20260827-inventur-und-architektur.md`](docs/handoff-20260827-inventur-und-architektur.md) — Master-Struktur, Asymmetrie, Drift.
|
||||
|
||||
## SSoT & Branch-Konvention (TP36-Cutover 2026-09-07)
|
||||
|
||||
- **SSoT-Dreiteilung:** **Index/Status = Gitea-Issues** (`admin/bf-infra`, Labels `status:*`/`thema:*`) ·
|
||||
**Prosa/Detail = Repo** (`docs/teilprojekte.md` aktiv + `teilprojekte-archiv.md`, `### TPnn`-Abschnitte) ·
|
||||
**Live-Gerätedaten = Nautobot** (Compliance-Zahl, RouterOS-Version …). Ein Status ändert sich **in Gitea**,
|
||||
nicht mehr in einer Repo-Datei. Sync-/Abgleich-Werkzeug fürs Archiv: `bin/gitea-tp-sync.py` (Dry-Run default,
|
||||
Token aus `~/.hermes/.env`, **nie ausgeben**).
|
||||
- **Branch-Konvention:** Branch `tpNN-kurz` **jederzeit** mitten in der Session möglich (`git switch -c`,
|
||||
uncommittete Arbeit wandert mit); für Multi-Session-TPs der Normalfall. **Merge nach `main`, sobald der
|
||||
Code/Config des TP steht.** Weil Steuerungs-Updates nach **Gitea** gehen (nicht in `teilprojekte.md`),
|
||||
kollidieren TP-Branches nicht mehr auf der Steuerungs-Doku — nur noch der eigene `### TPnn`-Prosa-Abschnitt
|
||||
wird angefasst.
|
||||
- **TP anlegen/schließen:** neues aktives TP = **direkt als Gitea-Issue** (Labels setzen), Prosa-Abschnitt
|
||||
im Repo dazu; abschließen = Issue `closed`, Prosa wandert bei Bedarf ins Archiv. **Keine Handtabelle mehr.**
|
||||
|
||||
## Was du sofort wissen musst (Inventur 2026-08-27)
|
||||
|
||||
- **`bf-infra`** ist aktiver Master **mit Gitea-Remote**: `origin` = `https://gitea.emsenhuber.net/admin/bf-infra.git` (live verifiziert 2026-08-30). ⚠️ **Die frühere Zeile „lokal, kein Gitea-Remote → verloren bei Festplattencrash" ist überholt** — sie stammt aus der Inventur vom 2026-08-27 und war damals richtig; das Remote existiert seit spätestens 2026-08-28 (`origin/main` = `b917691`). **Die Backup-Lücke ist damit keine Struktur-, sondern eine Disziplinfrage: `git push`.** Am 2026-08-30 lagen vier Commits nur lokal. 🔴 **Das Remote ist nur so viel wert wie der letzte Push** — der Backup-Guard (`~/dev/.bin/backup-guard.sh`, TP35 Schicht 5) bricht Commits ab, solange kein Backup markiert ist; **das ist die Erinnerung ans Pushen, kein Hindernis.** Nicht mit `--no-verify` umgehen. 🔴 **Merkregel:** diese Zeile hat eine Session dazu gebracht, „kein Remote" zu behaupten, statt `git remote -v` zu tippen — vor jeder Aussage über Remotes/Backups **live prüfen**.
|
||||
@@ -50,12 +65,15 @@ DNS/DHCP-Ablösung, WLAN via **CAPsMAN auf dem Core** (TP28, 2026-08-17 — der
|
||||
|
||||
Wenn während einer Session ein neues Teilprojekt, eine Abhängigkeit oder ein Querschnittsthema sichtbar wird, das bisher in keinem TP abgebildet ist:
|
||||
- Vorschlagen und mit dir abstimmen (nicht eigenmächtig anlegen).
|
||||
- Auf dein Okay hin anlegen: Quick-Index-Zeile + `### TP<n>`-Abschnitt mit Status `🔜`, Scope,
|
||||
Abhängigkeiten, Abgrenzung. Nächste freie Nummer vergeben (höchste vergebene + 1; Lücken aus
|
||||
verworfenen TPs bleiben frei).
|
||||
- Ist-Stand-Block mitziehen (Datum, betroffene Zeilen).
|
||||
- Auf dein Okay hin anlegen: **Gitea-Issue** `TPnn — <Kurztitel>` mit Labels `status:🔜`(todo) +
|
||||
passendem `thema:*` + Body (Anriss + Verweis auf den Prosa-Abschnitt) **und** einen
|
||||
`### TP<n>`-Prosa-Abschnitt in `docs/teilprojekte.md` (Scope, Abhängigkeiten, Abgrenzung).
|
||||
Nächste freie Nummer vergeben (höchste vergebene + 1; Lücken aus verworfenen TPs bleiben frei).
|
||||
- **Status/Reihenfolge/„was lief zuletzt" gehen ins Gitea-Issue** (Label ändern, Kommentar), **nicht**
|
||||
in eine Quick-Index-Tabelle oder einen Ist-Stand-Block — die gibt es seit dem TP36-Cutover (2026-09-07)
|
||||
nicht mehr in der Datei.
|
||||
|
||||
**Abgeschlossene TPs** stehen seit 2026-08-23 in `docs/teilprojekte-archiv.md` (Volltext, unverändert, mit Inhaltsverzeichnis). **Ein TP wandert erst ins Archiv, wenn nichts mehr daran zu tun ist — und wieder zurück, sobald doch etwas dazukommt.** Ein archiviertes TP ist ein *geschlossenes Ticket, kein versiegeltes*: bei neuer Arbeit an derselben Baustelle wandert der **Volltext zurück** nach `teilprojekte.md` (Zeiger bleibt im Archiv), **kein** Zwillings-TP mit neuer Nummer (Christoph-Direktive 2026-08-30, erster Fall TP28/`ap3`) — und der **Ist-Stand-Block wird bei jeder Änderung mitgezogen**, nicht nur der betroffene TP-Abschnitt.
|
||||
**Abgeschlossene TPs** stehen seit 2026-08-23 in `docs/teilprojekte-archiv.md` (Volltext, unverändert, mit Inhaltsverzeichnis) und ihr Gitea-Issue ist `closed` (Label `status:✅`/`❌`). **Ein TP wandert erst ins Archiv, wenn nichts mehr daran zu tun ist — und wieder zurück, sobald doch etwas dazukommt** (Issue dann `reopen`). Ein archiviertes TP ist ein *geschlossenes Ticket, kein versiegeltes*: bei neuer Arbeit an derselben Baustelle wandert der **Volltext zurück** nach `teilprojekte.md` (Zeiger bleibt im Archiv), **kein** Zwillings-TP mit neuer Nummer (Christoph-Direktive 2026-08-30, erster Fall TP28/`ap3`) — nur noch der betroffene `### TPnn`-Prosa-Abschnitt wird angefasst.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -3,11 +3,15 @@
|
||||
TP36 (reframed) — teilprojekte.md Index/Status → Gitea Issues (admin/bf-infra).
|
||||
|
||||
Idempotenter Sync (get-or-create, Match ueber "TPnn" im Titel):
|
||||
- Quick-Index-Tabelle in docs/teilprojekte.md -> aktive Issues (open/closed je Marker)
|
||||
- Archiv-Header in docs/teilprojekte-archiv.md -> closed Issues (nur TPs, die NICHT aktiv sind)
|
||||
- Archiv-Header in docs/teilprojekte-archiv.md -> closed Issues (nur TPs, die in Gitea
|
||||
NICHT offen sind; ein reopentes TP mit Archiv-Zeiger bleibt offen).
|
||||
- Labels status:* (Marker) + thema:* (Gruppierung) werden vorab get-or-create.
|
||||
|
||||
SSoT-Modell: Gitea fuehrt Index+Status; die per-TP-Prosa bleibt in docs/teilprojekte.md.
|
||||
SSoT-Modell (seit TP36-Cutover 2026-09-07): Gitea fuehrt Index+Status — aktive TPs werden
|
||||
DIREKT als Gitea-Issue angelegt/gepflegt, NICHT mehr aus einer Datei-Tabelle abgeleitet
|
||||
(die Quick-Index-Tabelle wurde aus teilprojekte.md entfernt). Dieses Werkzeug haelt nur noch
|
||||
die ARCHIVIERTEN (closed) TPs mit teilprojekte-archiv.md idempotent abgeglichen und fasst
|
||||
offene Issues nie an. Die per-TP-Prosa bleibt in docs/teilprojekte.md / teilprojekte-archiv.md.
|
||||
Token: ~/.hermes/.env (GITEA_ACCESS_TOKEN, GITEA_HOST) — wird NIE ausgegeben.
|
||||
|
||||
Aufruf:
|
||||
@@ -100,25 +104,9 @@ def api(method, path, body=None):
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- parse
|
||||
def parse_active():
|
||||
"""Quick-Index-Zeilen: > | TP44 | ⏳ | Kurztitel … | Datum |"""
|
||||
out = []
|
||||
row = re.compile(r"^>\s*\|\s*(TP[\d.]+)\s*\|\s*([^\s|]+)\s*\|\s*(.+?)\s*\|\s*(.*?)\s*\|\s*$")
|
||||
for line in ACTIVE.read_text().splitlines():
|
||||
m = row.match(line)
|
||||
if not m:
|
||||
continue
|
||||
tp, marker, title, date = m.groups()
|
||||
num = tp[2:]
|
||||
# Titel auf den Kern kuerzen (vor dem ersten " — " / " (" wenn lang)
|
||||
short = re.split(r"\s+—\s+|\s*\(", title)[0].strip()
|
||||
short = re.sub(r"\*\*|`", "", short)[:80]
|
||||
out.append({"tp": tp, "num": num, "marker": marker.strip(),
|
||||
"title": short, "date": date.strip(), "src": "active"})
|
||||
return out
|
||||
|
||||
|
||||
def parse_archiv(active_nums):
|
||||
def parse_archiv(exclude_nums):
|
||||
"""Archiv-Header -> archivierte TPs. exclude_nums = TP-Nummern, die in Gitea OFFEN sind
|
||||
(reopente TPs mit Archiv-Zeiger) -> die bleiben offen, nicht als closed abgleichen."""
|
||||
out = []
|
||||
hdr = re.compile(r"^#{2,4}\s*(TP[\d.\-A-Za-z]+)\s*—\s*(.+?)\s*▸", )
|
||||
seen = set()
|
||||
@@ -128,7 +116,7 @@ def parse_archiv(active_nums):
|
||||
continue
|
||||
tp, title = m.groups()
|
||||
num = tp[2:]
|
||||
if num in active_nums or num in seen:
|
||||
if num in exclude_nums or num in seen:
|
||||
continue
|
||||
seen.add(num)
|
||||
short = re.sub(r"\*\*|`", "", title).strip()[:80]
|
||||
@@ -164,22 +152,26 @@ def all_issues():
|
||||
|
||||
def main():
|
||||
print(f"Gitea {HOST} repo {OWNER_REPO} mode={'COMMIT' if COMMIT else 'DRY-RUN'}")
|
||||
active = parse_active()
|
||||
active_nums = {a["num"] for a in active}
|
||||
archiv = parse_archiv(active_nums)
|
||||
items = active + archiv
|
||||
print(f"Geparst: {len(active)} aktive + {len(archiv)} archivierte = {len(items)} TP\n")
|
||||
|
||||
st, existing_labels = api("GET", f"/repos/{OWNER_REPO}/labels?limit=100")
|
||||
label_id = ensure_labels(existing_labels if isinstance(existing_labels, list) else [])
|
||||
|
||||
issues = all_issues()
|
||||
by_tp = {}
|
||||
open_nums = set()
|
||||
for iss in issues:
|
||||
# Titel ist "TPxx — …"; volle ID inkl. Buchstaben/Bindestrich (TP14.2a, TP-R) bis zum " — "
|
||||
m = re.match(r"^(TP[\w.\-]*?)\s+—", iss["title"])
|
||||
if m:
|
||||
by_tp[m.group(1)] = iss
|
||||
if iss.get("state") == "open":
|
||||
open_nums.add(m.group(1)[2:])
|
||||
|
||||
# Aktive TPs sind seit dem TP36-Cutover SSoT direkt in Gitea -> nur das Archiv abgleichen,
|
||||
# und offene (reopente) TPs davon ausschliessen, damit sie nicht faelschlich geschlossen werden.
|
||||
items = parse_archiv(open_nums)
|
||||
print(f"Geparst: {len(items)} archivierte TP (aktive TPs = SSoT in Gitea: "
|
||||
f"{len(open_nums)} offen, nicht angetastet)\n")
|
||||
|
||||
created = updated = 0
|
||||
for it in items:
|
||||
|
||||
@@ -25,479 +25,24 @@ IP-Blöcke: `.1–10` Router/Gateways · `.11–20` Switches/APs. **GW je VLAN =
|
||||
Mgmt (VLAN99, Ist 2026-08-16): core `.99.1` · branch `.99.2` · ap1 `.99.11` · ap2 `.99.12`.
|
||||
*(Historisch, überholt: „ap1=.1, ap2=.2 · ALLNET=.11, Omada=.12" — aus der Zeit vor dem Core-Cutover.)*
|
||||
|
||||
## Ist-Stand (Kurz)
|
||||
## Status & Index → Gitea-Board (SSoT seit 2026-09-07, TP36-Cutover)
|
||||
|
||||
**Stand 2026-09-04 — live gegen die Geräte geprüft (MikroMCP/REST/SSH), nicht aus der Doku abgeschrieben.**
|
||||
**Compliance 140/140, 0 Drifts** (2026-09-04 nachmittags). Der TP25-Kanalplan ist **committed**:
|
||||
Template auf DFS-Frequenz-Listen umgestellt (`ch-5g-ap1=5260,5280`, `ch-5g-ap2=5300,5320`) + die
|
||||
ap1-Provisioning-Zeilen wieder aufgenommen → Transaktion `TP25-kanalplan-ap1-live` geschlossen und der
|
||||
`wifi-provisioning`-Drift weg. `wifi-security` gruen (`ft=no` auf `sec-main`).
|
||||
🔴 **Zusätzlich live behoben (nicht compliance-sichtbar):** ap3 trug auf `wifi1/wifi2` einen Werks-Inline
|
||||
`security.ft=yes` — gemischtes FT-ESS, das die 3/3-Strich-Abbrüche vom 09-04 erklärt. Unset → uniform
|
||||
`ft=no` on-air; Bring-up-Quelle `tp28-ap3-phase2-cap.rsc` um `!security.ft` ergänzt (s. Fund-E-Block).
|
||||
*(Die Fassung vom 2026-08-16 stand bis zum 18. hier und war an vier Stellen überholt. Wer diesen Block
|
||||
liest, liest ihn als Erstes: er wird bei jeder Änderung mitgezogen, nicht nur die TP-Abschnitte.)*
|
||||
- 🗺️ **TP37/34/36-Strang geplant + TP44-Drift bereinigt (2026-09-06, „erst planen, nichts bauen"):**
|
||||
Live gegen Nautobot geprüft — **TP37 Punkt 3 (CF-Connectoren) ist faktisch durch TP44 erledigt**
|
||||
(native `nautobot.cloud`-Modelle, Etappe 1 live: Account 1/ResType 6/Network 4/Service 14). Echt offen
|
||||
bleibt **TP37 Punkt 1+2** (Substrat: pve/NAS/macmini-Hosts + LXC/Docker als `virtualization.VM`, Dienste
|
||||
als `ipam.Service` — live **VM 0/Cluster 0/Service 0/CustomField 0**), und darauf sitzt **TP34** (Caddyfile
|
||||
via GC). **TP36** (Live-Daten-CustomFields + Datei-Split) ist davon **unabhängig** → parallel. Datenmodell-
|
||||
Entscheid: **native Modelle** (konsistent zu TP44), keine eigene App. **TP44 nachgezogen:** eigene
|
||||
Quick-Index-Zeile + Abschnitt, Seeder `nautobot/tp36-…` → `tp44-cf-estate-seed.py` umbenannt. Runbook:
|
||||
[`docs/handoff-20260906-tp37-34-36-plan.md`](handoff-20260906-tp37-34-36-plan.md). **Kein Nautobot-Write.**
|
||||
- ✅ **TP25 Multi-Pin-Konsole (2026-09-04):** die Klick-Konsole (`docs/tp6-marker/server.py`) ist auf
|
||||
**N Clients** generalisiert und hat eine **Pin-UI** bekommen. Sie liest die Client-Liste aus
|
||||
`geraete.txt` (schreibt `tp25-walk-messung.sh`), zeigt je Client AP/Signal/Ping-Verlust aus
|
||||
`sampler-<name>.csv`/`walk-ping-<name>.csv` (kein eigenes SSH mehr) und pinnt N Clients band-genau
|
||||
über `tp25-pin-multi.sh` direkt in der Konsole. Die alte 2-Client-Gegen-AP-Automatik ist entfernt.
|
||||
Handoff: [`docs/handoff-20260904-tp25-konsole-n-clients.md`](handoff-20260904-tp25-konsole-n-clients.md).
|
||||
- ✅ **TP25 Fund E GESCHLOSSEN (2026-09-02):** die vorgemerkte Abschlussmessung ist gelaufen —
|
||||
`reauthenticating` am 09-02 nur noch **4 in 8,6 h** (alle iPhone `F2:62`, isolierte Einzel, 0 Ausfälle)
|
||||
gegen Baseline 93 bzw. Hebel-1 **19/h**. Verlauf **218 → 40 → 4**; Vorbedingung geprüft (Core-Uptime
|
||||
1d18h, `caps joined=0` → keine Reboot-Artefakte). ⇒ **7.24.1 (TP27) war die Ursache/der Fix, nicht
|
||||
`ft-over-ds`.** Hebel 1 widerlegt+zurückgebaut, Hebel 2–4 entfallen, **kein Geräte-Write**. **Am
|
||||
2026-09-04 hat Christoph `ft=no` auf `sec-main` als Dauerzustand entschieden** (Hebel 2 doch gezogen,
|
||||
Template + bf-golden-config + Nautobot-Sync, `wifi-security` gruen). 🔴 **Nachtrag 2026-09-04:** „ohne FT"
|
||||
galt bis dahin **nur für Manager/ap1/ap2** — **ap3** trug einen Werks-Inline `security.ft=yes` auf
|
||||
`wifi1/wifi2` (Bring-up-Skript unset `!ft-over-ds`, aber nicht `!ft`; die Abnahme zählt nur benannte
|
||||
security-Objekte und sah den Inline-Wert nicht). Das ist ein **gemischtes FT-ESS** und erklärt den
|
||||
Abbruch bei 3/3 Strichen: Log zeigte wiederkehrende Strong-Signal-Disconnects (−43/−45 dBm) **nur auf
|
||||
ap3** (`cap-wifi2/4`, `dirtyvader-main`). Fix: `!security.ft` auf ap3 → uniform `ft=no`; Quelle
|
||||
korrigiert. **Merkregel: nach jeder `sec-main`-FT-Änderung jeden CAP einzeln auf `security.ft` prüfen —
|
||||
CAP-lokale Inline-Overrides sind compliance-unsichtbar.** Offen in
|
||||
TP25 bleibt nur der separate Punkt **ap2 unterperformt** (2 m/−80 dBm). Handoff:
|
||||
[`docs/handoff-20260902-tp25-fund-e-messung.md`](handoff-20260902-tp25-fund-e-messung.md).
|
||||
- ⏸️ **TP41 CF-Access-Reparatur — ZURÜCKGESTELLT 2026-09-01 (User-Entscheid; Rest wartet auf Info):** Session 720h,
|
||||
login_method-Loch zu (`bf-users` email-only), `zt-`-Gruppen, vw voll Bypass + `vw/admin` per WAF
|
||||
geblockt (Mobilfunk-verifiziert), API-Token auf vollständiges `…4148` konsolidiert. **T4 ✅**
|
||||
(ein Access-Service-Token `zt-svc`, Terpene-Worker per wrangler auf zt-svc umgestellt, Alt-Tokens
|
||||
gelöscht). **T3 ✅** (WARP Default-Profil fallback_domains `emsenhuber.net → .36/.37`). **T2 ✅**
|
||||
(WAF-Regel gelöscht, Caddy-Origin-404 für `/admin` via CF-Header; Edge=404, lokal=200).
|
||||
**T5 ✅** (GitHub- **und** Google-Login laufen, User-bestätigt 2026-09-01; Google via Consent-Fix §A).
|
||||
**Facebook/Meta für TP41 abgesagt** (optional, kein CF-IdP angelegt) — Geli über OTP
|
||||
`angelikahy@outlook.de` + Google `pillepalle670@gmail.com` voll gedeckt.
|
||||
**Token-Altlast geklärt:** `b00722`=live Caddy-DNS-Token, `d47435`=stale Kopie → **✅ d47435 revoked**,
|
||||
**✅ T3-WARP-Client-Verify** (User). **Geli CF-seitig fertig** (Enrollment via `zt-humans` + `geli`-Policy,
|
||||
2026-09-01 live geprüft) → verbleibt nur ein **Device-Handgriff bei Geli** (WARP-Client, Team `emsenhuber`).
|
||||
**Claude-/CF-Seite damit vollständig.** Handoff: [`docs/handoff-20260901-tp41.md`](handoff-20260901-tp41.md) · [Follow-up](handoff-20260901-tp41-followup.md).
|
||||
- ✅ **TP14.4 als in TP41 T4 aufgegangen markiert (2026-09-02):** kein eigenständiger `claude-mcp`-Token
|
||||
mehr — er wurde in TP41 T4 zu `zt-svc` konsolidiert, `mcp/cloudflare/.env` trägt jetzt
|
||||
`CF_ACCESS_CLIENT_ID`/`_SECRET`. Die TP14.4-Ist-Stand-Notiz („.env leer") war seit 09-01 stale;
|
||||
Quick-Index + TP-Abschnitt nachgezogen.
|
||||
- ✅ **TP31 abgeschlossen markiert (2026-09-02):** Schritt 5+6 sind über den Piloten TP16.3 (09-01)
|
||||
miterledigt — `bf-public` 12 conns, vier öffentliche Namen über Caddy, Alttunnel weg. Abnahme-Tool
|
||||
`caddy/cf-sync.py` von einem Fehlalarm befreit (prüfte nur `http://`, gebaut ist `https://…:443`) und
|
||||
**grün** (nur `ds-bf` als bewusst intern). Schritt-6-Teil „MCP auf FQDN" durch TP35 Schicht 1
|
||||
umgekehrt (LAN-IP), damit gegenstandslos.
|
||||
- ✅ **TP42 durch (2026-09-02):** interner Namensraum auf **einen** Suffix `bf.emsenhuber.net` vereinheitlicht.
|
||||
(A) DHCP-domain über die GC-Pipeline geflippt (Template + `push-gc-template.py` `7a4068c4` + neuer Job
|
||||
`tp42-dhcp-domain` + Deploy an core) → **7/7 live, Compliance 140/140**. Nebenbefund: Remote-GC-Template
|
||||
hing hinterher (`.bf.lan`), mit angeglichen. (B) `.16` (`adguard_bf1`) aus dem **mit FM geteilten** Stack
|
||||
195 getrimmt-redeployt — `.16` weg, `.17` (FM) läuft (kurzer ~40 s Blip). Nautobot-Doku-Teil (Scope 4)
|
||||
an TP37 gekoppelt.
|
||||
- 🔜 **TP42 Namens-Vereinheitlichung (2026-09-01, angelegt):** internes `.bf.lan` (Core-DNS, DHCP-Search-
|
||||
Domain) und die `.bf.emsenhuber.net`-Aliase (Caddyfile) auf **einen** Namensraum `emsenhuber.net`
|
||||
ziehen; stale `.16/.17`-Rewrites abbauen; Sollzustand in Nautobot. Handoff:
|
||||
[`docs/handoff-20260901-tp42-naming.md`](handoff-20260901-tp42-naming.md).
|
||||
- 🔜 **TP43 dw-Standort-DNS-Uplink (2026-09-01, angelegt):** dem dw-Standort einen eigenen Resolver/
|
||||
DNS-Uplink mit **site-spezifischen Overrides** geben (erster Fall `420.teilzeitladen.xyz` → BF-Caddy
|
||||
über WG), **inkl. Verhalten bei WG-Disconnect** (Override auf BF-interne IP fällt sonst aus). FritzBox
|
||||
standard kann keinen Per-Host-Override. Geli-Sofortlösung = **WARP** (nicht Teil von TP43). Cross-Projekt.
|
||||
- ✅ **TP16.3 ABGESCHLOSSEN (2026-09-01):** Flip **und** Abbau durch. Öffentlich laufen nur noch
|
||||
`bf-public` (12 Connectoren) und `fm` — die drei Alttunnel `bf-mm`/`bf-nas`/`bf-pve` **und** der
|
||||
projektfremde `terpene-db` sind gelöscht, **7 cloudflared-Container** entfernt (inkl.
|
||||
`terpene-cloudflared`, weil `420.teilzeitladen.xyz` nun über Caddy/CF läuft — vor der Löschung mit
|
||||
echtem Origin-Inhalt belegt). §6 wurde auf User-Entscheid vorgezogen. **TP wandert ins Archiv.**
|
||||
- 🆕 **TP16.3 §5 DURCH (2026-09-01): `n8n`/`gitea`/`hass`/`vw` laufen über `bf-public`** — der
|
||||
öffentliche Verkehr geht damit erstmals über **Caddy** statt an ihm vorbei, und die
|
||||
Host→Origin-Zuordnung lebt nur noch im `Caddyfile`. Je Name einzeln geflippt, dazwischen gemessen;
|
||||
Antwortzeiten vorher/nachher **unverändert** (Caddy im Pfad kostet nichts Messbares).
|
||||
Nachweise: `gitea` echte Gitea-Antwort · `hass` **WebSocket `101 Switching Protocols`** (= der
|
||||
Companion-App-Pfad, den das Runbook als „nur vom User prüfbar" führte) · `vw` `/alive` + `/api/config`
|
||||
200, WS-Hub `401` von Vaultwarden selbst · `n8n` von Christoph im Browser bestätigt.
|
||||
🚫 **§6 (Abbau) bewusst NICHT** — die drei Alttunnel bleiben als Rückfallebene (healthy/8).
|
||||
🔴 **Christoph hat den Flip ausdrücklich vorgezogen freigegeben** („aus Gründen"); die 7-Tage-Regel
|
||||
betrifft ohnehin §6, nicht den Flip.
|
||||
- 🆕 **TP39 ABGESCHLOSSEN + archiviert (2026-09-01):** letzter offener Punkt — der Resolver-Sweep —
|
||||
ist durch: **pve alle 13 LXCs** auf `10.40.20.1`, und die **DS923-Container via Portainer** (ep14)
|
||||
gegengeprüft — kein `.41.254`-Override, alle laufenden lösen in **66–110 ms** auf (inkl. Grenzfall
|
||||
`gitea`, erstellt 2026-07-10), kein eingefrorener Dead-Resolver, kein Recreate nötig. Die
|
||||
Abnahme-Regel („vor jedem LXC-Reboot `systemctl --failed` + Port-Vergleich") steht als
|
||||
CLAUDE.md-Gotcha, der Sweep ist als wiederkehrende Kontrolle dort verankert. **Volltext → Archiv.**
|
||||
🔴 Rest offen nur in **anderen** TPs: root-DB-PW-Rotation (→ TP30), HA-Recorder-Retention (→ TP40).
|
||||
- 🆕 **TP39 fast durch (2026-09-01):** `skip-name-resolve` auf der MariaDB **aktiviert** (mysql.user
|
||||
vorher geprüft — kein Hostname-Grant, gefahrlos; Wirkung: gitea/vw/hass 0 von 36 frischen Anfragen
|
||||
langsam). LXC 302 war **100 % voll** → `+30G` online (95 GB/69 %). 🔴 **root-DB-Passwort dabei ins
|
||||
Transkript geraten** (`.my.cnf` ohne `=`), zu rotieren (→ TP30).
|
||||
- 🆕 **TP40 angelegt (2026-09-01, User-Okay):** HA-Recorder-Retention — die `homeassistant`-DB frisst
|
||||
59 GB (`states.ibd` **41 GB**), unbegrenzt gewachsen. Das `+30G` aus TP39 ist ein Puffer; die
|
||||
dauerhafte Lösung (`purge_keep_days`, `exclude`, `purge repack`) ist HA-seitig und **Christophs
|
||||
Policy-Entscheidung** — kein eigenmächtiges Löschen.
|
||||
- 🆕 **TP39: `networking.service` in vier Containern repariert (2026-09-01).** Ursache war dieselbe
|
||||
Altlast wie beim Resolver: tote `auto`-Stanzas in `/etc/network/interfaces` aus dem VLAN1-Schema
|
||||
(`eth0` → `10.40.41.x`) und alten Versuchen — `ifup -a` scheiterte an Interfaces, die es nicht gibt,
|
||||
während `veth20` lief. **Abnahme war ein echter Reboot:** influxdb kam danach **von selbst** hoch
|
||||
(vorher gar kein Startversuch). Alle 13 LXCs stehen jetzt auf `dns=10.40.20.1`, `networking` überall
|
||||
sauber. **Offen in TP39: nur noch `skip-name-resolve` und der wiederkehrende Sweep.**
|
||||
- 🆕 **TP39 angelegt (2026-09-01, User-Okay):** LXC-Hygiene auf pve — die zwei Restpunkte aus dem
|
||||
Wartungsfenster unten (`skip-name-resolve` auf der MariaDB, kaputtes `networking.service` in vier
|
||||
Containern) plus Resolver-Sweep als wiederkehrende Kontrolle. **Ein** TP, weil beides dieselbe Ecke
|
||||
betrifft und in einem Fenster erledigt wird.
|
||||
- ✅ **GELÖST 2026-09-01: der 10-Sekunden-Zoll auf `gitea`/`vw`/`hass` — es war Reverse-DNS auf einen
|
||||
toten Resolver.** MariaDB (LXC **302**, `10.40.20.23`) hatte `skip-name-resolve` **auskommentiert**
|
||||
und machte damit bei **jeder neuen Verbindung** einen Reverse-Lookup; ihr `/etc/resolv.conf` zeigte
|
||||
auf **`10.40.41.254`** — den toten VLAN1-Resolver aus dem alten Schema (`nc` bestätigt tot).
|
||||
**Gemessen im Container: 10.010 ms je Lookup.** Bestehende Pool-Verbindungen waren schnell, neue
|
||||
kosteten 10 s — daher wirkte es sporadisch und unerklärlich.
|
||||
🔑 **Die Blast-Radius war größer als gedacht:** an derselben DB hängen **Vaultwarden (`.127`),
|
||||
Home Assistant (`.105`) und gitea (`.157`)** — belegt über die Verbindungstabelle, nicht vermutet.
|
||||
*(Die erste Zuschreibung „vaultwarden nutzt SQLite, also nicht betroffen" war eine **Annahme** und
|
||||
falsch — Christoph hat sie korrigiert, die Verbindungsliste hat es bewiesen.)*
|
||||
**Fix (Wartungsfenster, User-Freigabe):** `pct set <id> --nameserver 10.40.20.1` + Reboot für
|
||||
**fünf** LXCs — `302 mariadb`, `102 mqtt5`, `106 influxdb2`, `107 redis`, `150 iob-exposed`.
|
||||
**Nachher: Lookup 21–24 ms statt 10.010 ms; gitea 0 von 25 Proben langsam** (vorher ~10 % bei
|
||||
10,1 s), langsamste Probe 75 ms. Alle drei Dienste wieder verbunden.
|
||||
⚠️ **Strukturell offen:** `skip-name-resolve` ist weiterhin aus — der Lookup ist jetzt nur schnell,
|
||||
nicht abgeschafft. Ihn zu setzen bricht alle Grants, die auf **Hostnamen** statt IPs lauten; das
|
||||
gehört vorher gegen `mysql.user` geprüft (DB-Zugang fehlt: `root@localhost` ohne Passwort verweigert).
|
||||
- 🔴 **Latenter Fund aus demselben Wartungsfenster: `networking.service` und
|
||||
`ifupdown-wait-online.service` sind in `101`, `102`, `106`, `107` fehlgeschlagen.** Folge:
|
||||
Dienste mit `After=network-online.target` starten nach einem Reboot **nicht von selbst** —
|
||||
**influxdb2 kam nach dem Neustart nicht hoch**, Unit `enabled`, aber **kein einziger Startversuch
|
||||
im Journal**. Von Hand gestartet lief es sofort.
|
||||
🔑 **Nicht durch diese Session verursacht:** `101 iob-master` wurde nie angefasst und zeigt dieselben
|
||||
fehlgeschlagenen Units — die Container liefen nur 13+ Tage ohne Neustart, deshalb fiel es niemandem
|
||||
auf. **Merkregel: diese vier Container sind einen Reboot davon entfernt, still Dienste zu verlieren.**
|
||||
- 🔴 **Befund am Rand des Flips, NICHT von ihm verursacht: `gitea` hängt sporadisch exakt ~10,2 s.**
|
||||
~10 % der Anfragen, quer über Web-UI, **`/api/healthz`** und den **Git-Pfad** (`info/refs`) — also
|
||||
kein Rendering-Problem. `vw` und `hass` über **dieselbe** Strecke: **0 von 30**. Damit sind CF-Edge,
|
||||
AP-Connector, Firewall und Caddy entlastet; übrig bleibt **Caddy → `10.40.20.157:3000`** oder gitea
|
||||
selbst. **Immer ~10,15–10,43 s** = Timeout-Signatur (klassisch: ein toter Resolver, s. den
|
||||
VLAN20-Docker-DNS-Gotcha in der CLAUDE.md), kein Lastproblem. Weiter nur mit LAN-Zugriff.
|
||||
- 📎 **Drei Messfallen, die diese Session gekostet haben** (alle drei sind Standort-, keine Netzfehler):
|
||||
1. **Split-Horizon macht Tests von zuhause wertlos:** der Haus-Resolver liefert für alle vier Namen
|
||||
direkt `10.40.20.40`, die Anfrage sieht Cloudflare **nie**. Prüfen geht nur mit festgenagelter
|
||||
CF-Edge-IP (`curl --resolve <name>:443:188.114.96.10`) oder von außerhalb.
|
||||
2. **Access antwortet je nach Standpunkt verschieden:** `n8n` gibt aus dem Haus **200** (die
|
||||
`bf4`-Policy trägt die WAN-IP), von außen **302** zum Login. Beides gesund. Für die drei
|
||||
`bypass`-Namen (`hass`/`vw`/`gitea`) gibt es gar keinen Login — die Access-App heisst zu Recht
|
||||
`hass, vw, gitea`, sie führt alle drei in `self_hosted_domains` (das Feld `domain` zeigt nur den
|
||||
ersten). **Ein Rename wäre eine Verschlechterung gewesen.**
|
||||
3. 🔴 **„Der Host ist ausgefallen" war der eigene Standortwechsel.** Ping/SSH/Caddy waren tot,
|
||||
weil die Session-Maschine auf einen **Hotspot** gewandert war (Default-GW `172.20.10.1`) —
|
||||
dieselbe Klasse wie die WARP-Falle von 2026-08-13, nur ohne WARP. Es wurde daraufhin ein bereits
|
||||
erfolgreicher `n8n`-Flip **grundlos zurückgerollt**. **Merkregel: bevor ein Ausfall gemeldet wird,
|
||||
`route -n get default` lesen** — ein Standortwechsel sieht exakt aus wie ein Totalausfall.
|
||||
- ⚠️ **Nebenbefund: Caddy führt gar kein Access-Log.** Im `Caddyfile` steht keine `log`-Direktive, im
|
||||
Journal landen nur `info`/`warn`. Der Abnahmepunkt „Caddy sieht den Request" (Runbook §5.3) **kann
|
||||
nicht funktionieren** — ein erfolgreicher Request hinterlässt dort nichts, und leere Ausgabe liest
|
||||
sich wie „kam nie an". Dass der öffentliche Reverse Proxy keine Requests protokolliert, ist für sich
|
||||
eine Lücke (gehört zu TP31/TP34).
|
||||
- 🆕 **TP16.3: die sechs AP-Drifts sind ins Soll gehoben (2026-08-31) — Compliance 139/140.**
|
||||
`veth` / `ip address` / `ip firewall nat` der drei cloudflared-Connectoren stehen jetzt im
|
||||
**AP-Template** (Block `[7]`) und im ConfigContext `ap-common` (`ap.container`), **nicht** in einer
|
||||
`gc-transaktion`: ein Dauerzustand gehört ins Soll, eine Transaktion ist ein befristeter Versuch.
|
||||
**Kein Re-Baseline, kein Rückbau, keine Zeile aufs Gerät** — nur die SoT nachgezogen.
|
||||
🆕 **28. ComplianceRule `interface-veth`** (vorher gab es für `/interface veth` keine ⇒ ein
|
||||
gelöschtes veth hätte **nichts** gemeldet). 🔴 **Zwei Funde dabei:** (a) der veth-Export trägt
|
||||
**zwei gerätevergebene MACs** — eine nackte Regel hätte Dauer-Drift auf allen drei APs erzeugt;
|
||||
gelöst mit zwei eng auf die veth-Zeile verankerten `ConfigReplace`-Regeln (`60-`/`61-veth-*`,
|
||||
`nautobot/ingest-veth-rule.py`), bewusst mit der vorhandenen Maske `<<REDACTED>>`, weil die im
|
||||
Repo zugleich die **Push-Sperre** ist. (b) **Der erste Compliance-Lauf meldete `SUCCESS` und war
|
||||
trotzdem unvollständig** (139 statt 140 Einträge, `crs326-core`/`interface-veth` fehlte;
|
||||
Job-Log: `RENDER COMPLIANCE TASK GROUP failed: Broken pipe`). Zweiter Lauf sauber.
|
||||
⚠️ **Merkregel: nach einem Refresh nicht nur die Konformitätsquote lesen, sondern die ANZAHL der
|
||||
Einträge** — sie muss `Regeln × Geräte` sein. Eine fehlende Kombination sieht aus wie „die neue
|
||||
Regel greift nicht" und ist in Wahrheit ein halb gelaufener Job.
|
||||
*(Die damals übrige `crs326-core`/`wifi-security`-Drift = Transaktion `TP25-fund-e-ft-over-ds` ist mit
|
||||
dem Rückbau 2026-09-01 gegenstandslos; Fund E am 2026-09-02 geschlossen, Compliance 140/140.)*
|
||||
- 🆕 **MCP-Bestand 2026-08-28 korrigiert:** **9 MCPs identisch** in `~/.claude.json` und `~/.config/opencode/opencode.jsonc` (vorher Asymmetrie 7 vs. 11 — `portainer-mcp`/`shelly-mcp` raus, `gitea-mcp`/`n8n-mcp` rein). **Mac mini = n8n-Host, NICHT zentraler MCP-Host** (Performance-Restriktion); zentraler MCP-Host = **DS923** (`nas-bf`, Portainer Endpoint 14). Inventur-Stand `mcp/INVENTORY.md` + Policy `docs/mcp-host-policy.md`.
|
||||
- 🆕 **MCP-Migration FQDN→IP (2026-08-29, TP35 Schicht 1):** `gitea-mcp` und `n8n-mcp` in `~/.config/opencode/opencode.jsonc` von CF-FQDN auf LAN-IP umgestellt — `gitea-mcp` → `http://10.40.20.167:3000/mcp` (macmini, **ohne** Bearer, intern), `n8n-mcp` → `http://10.40.20.167:3001/mcp` (mit `Bearer {env:N8N_MCP_BEARER}`). **Befund dabei:** der Handoff 1.2 nannte für gitea-mcp die falsche IP `.157:3000` (das ist die Gitea-Web-UI, `400 Invalid CSRF`); der echte gitea-mcp läuft auf `.167:3000` (`serverInfo: gitea-mcp 0.0.10`). `cloudflare`-MCP bleibt auf dem offiziellen FQDN (User-Direktive).
|
||||
- 🆕 **TP16.3 §2/§3 durchgezogen (2026-08-31, Vor-Ort):** je ein `cloudflared`-Container auf
|
||||
**ap1/ap2/ap3**, `bf-public` **healthy mit 12 Connectoren** — der Tunnel hat damit zum ersten Mal
|
||||
überhaupt Connectoren. 🔴 **Zwei Runbook-Fehler dabei aufgedeckt:** die Flash-Rechnung war um Faktor
|
||||
2,5 zu optimistisch (entpacktes cloudflared = **69,5 MiB**, nicht 28 MB ⇒ das offizielle Image passt
|
||||
auf keinen der drei APs; Ersatz ist ein selbst gebautes `FROM scratch`-Image mit 35,3 MiB, Binary-SHA
|
||||
`e93824f6…` gepinnt), und `/container/envs` heisst `list=`, nicht `name=`.
|
||||
🔴 **Offen: Compliance 128/135.** §3.4 verlangt Direkt-Writes für `ip address`/`nat`, die unter
|
||||
GC-Kontrolle stehen ⇒ **sechs neue `extra`-Drifts** (zwei je AP), inhaltlich richtig, aber nicht im
|
||||
Soll. Braucht eine Entscheidung (ins Template heben), **kein Re-Baseline**. Details im TP16.3-Abschnitt.
|
||||
- 🆕 **TP37 angelegt (2026-08-30, User-Okay):** Nautobot soll durchgehende Netzwerkdoku werden, erster
|
||||
Anwendungsfall die CF-Connectoren. 🔴 **Befund dabei, live gegen die API:** Nautobot kennt heute
|
||||
**nur die 8 Netzgeräte** (4 aktiv, 4 decommissioned) — `ipam.Service`, `CustomField`, `Relationship`,
|
||||
`VirtualMachine` und `Tag` sind **alle 0**, installiert ist nur `golden-config`. Kein Host, kein
|
||||
Container, kein Dienst ist erfasst. **TP37 ist damit zuerst eine Datenmodell-Frage** und liefert das
|
||||
Fundament, das **TP34** (Caddyfile via GC) und **TP36** (SSoT für diese Datei) ebenfalls brauchen —
|
||||
Reihenfolge: **TP37 vor TP34**.
|
||||
- 🆕 **CF-Public-Strang eingedampft (2026-08-30, TP16.3 grosser Schnitt):** **12 Hostnames** aus Ingress
|
||||
**und** DNS entfernt — `pve`/`portainer`/`pve-mcp`/`ha-mcp`/`ds-bf`/`ccu`/`iobroker`/`z2m25`/`pbs`
|
||||
plus die drei CF-Access-SSH-Ziele. Ingress: `bf-mm` 6→4, `bf-nas` 6→3, `bf-pve` 9→2. **Öffentlich
|
||||
bleiben nur `vw`/`hass`/`n8n`/`gitea`** (weiterhin HTTP 200). Intern unverändert über AdGuard→Caddy
|
||||
(9× HTTP 200). ✅ **Nachtrag 2026-08-30 (F1 durch): `gitea-mcp`/`n8n-mcp` sind jetzt AUCH
|
||||
geschnitten** — damit **14 Hostnames** gesamt und `bf-mm` **4→2** (nur noch `n8n` + Catch-all).
|
||||
Möglich wurde das, weil zuvor **12 MCP-Client-Configs** auf LAN-IP migriert wurden (nicht 10 wie
|
||||
geschätzt: zwei Worktree-Kopien in `bf-network-r6{,.opencode}` kamen dazu). 🔴 **`bf-public` hat weiterhin 0 Connectoren** — er gehört
|
||||
laut Entscheid auf **ap1/ap2**, dort fehlen aber `container`-Paket **und** `device-mode container=yes`
|
||||
(physische Bestätigung nötig). Bis dahin stehen `bf-mm`/`bf-nas`/`bf-pve` mit **6 Containern**.
|
||||
Backups: `docs/cf-backup/*-20260830-vor-tp16.3-schnitt.json`.
|
||||
- 🆕 **TP16.3/TP31 Schritt 5 vorbereitet (2026-08-30):** Runbook für die Vor-Ort-Session geschrieben
|
||||
([`tp16.3-bf-public-ap-connector-runbook.md`](tp16.3-bf-public-ap-connector-runbook.md)), CF-Rollback-Snapshots
|
||||
unter `docs/cf-backup/*-20260830-vor-tp16.3-schnitt.json` **neu angelegt** (es gab sie vorher nicht).
|
||||
`docs/tp31-schritt5-runbook.md` ist damit **abgelöst** (read-only-Header): es kannte ap3 nicht,
|
||||
unterstellte einen Registry-Pull (`fetch: no` auf ap1/ap2) und enthielt eine **falsche**
|
||||
Firewall-Freigabe-Behauptung. **CF-Stand:** `bf-public` `inactive` / 0 Connectoren; die vier
|
||||
öffentlichen Namen laufen noch über bf-mm/bf-nas/bf-pve **an Caddy vorbei** direkt aufs Backend.
|
||||
- 🆕 **TP38 angelegt (2026-08-31):** OOB-Management — je ein untagged-VLAN99-Port auf beiden Switches.
|
||||
Auslöser: beim Core-Neustart war `crs326-branch` nicht erreichbar, weil sein Mgmt **ausschließlich**
|
||||
über den Core läuft (`vlan99` dort `tagged=ether1,ether24,bridge`, kein untagged-Member).
|
||||
🔴 **Nebenbefund mit eigenem Gewicht: `crs326-branch` hat gar keine `input`-Firewallregeln** — sein
|
||||
Schutz ist heute allein die Erreichbarkeit über den gehärteten Core. Das ist die Hauptauflage des TPs.
|
||||
- 🆕 **ROS-Upgrade 7.24.1 auf allen fünf (2026-08-31, User).** In Nautobot nachgezogen: **ap1** stand
|
||||
als einziges Gerät noch auf `7.24` (die anderen vier waren schon richtig) ⇒ auf `7.24.1` gesetzt.
|
||||
⚠️ **Korrektur (2026-08-31, nachträglich):** die dabei gesehene `wifi-security`-Drift auf
|
||||
`crs326-core` (`sec-main` `ft-over-ds=no` statt `yes`) hatte **nichts mit dem Upgrade zu tun** — sie
|
||||
ist **TP25 Fund E, Hebel 1**, um 08:09 bewusst gesetzt (Core-Upgrade war erst 14:36) und als
|
||||
**offene Transaktion `TP25-fund-e-ft-over-ds`** geführt (Scope `wifi-security`, Ablauf 2026-09-03).
|
||||
**Die 134/135 sind Absicht**, nicht Schaden: grün machen würde den laufenden Versuch unsichtbar
|
||||
machen, und `gc-transaktion.py` verweigert den Commit ohnehin, solange der Scope driftet.
|
||||
🔑 **Lehre:** vor jeder Drift-Bewertung `nautobot/gc-transaktion.py status` lesen — Drift aus einem
|
||||
laufenden Versuch sieht identisch aus wie ein Versehen, und genau dafür gibt es das Werkzeug.
|
||||
- 🆕 **TP16.3 §1-Blocker remote erledigt (2026-08-31):** Ingress von `bf-public` auf
|
||||
`https://10.40.20.40:443` + `originServerName`; Firewall-Freigabe `vlan99 → vlan20:443` **über
|
||||
Nautobot GC** (Plan `Completed`, Re-Baseline `ingest-core-firewall.py --apply`, danach
|
||||
**135/135 compliant / 0 Drifts**); `ROUTER_AP3_PASS` in `~/.secrets`. **Offen bleibt nur die
|
||||
Vor-Ort-Session** (§2/§3: `container.npk`, `device-mode`, Container) und danach Flip + Abbau.
|
||||
- 🆕 **Globale Verhaltensregeln konsolidiert (2026-08-29, TP35 Schicht 3):** `~/.config/opencode/AGENTS.md` ist jetzt die **SSoT** für globale Verhaltensregeln (Secrets, VLAN-Schema, 5 Lessons, SoC, Übergabe-Mechanik, Mid-Action-Checkpoint, Commit-Hinweis, Backup-Guard). `~/.claude/CLAUDE.md` hält denselben Block als Claude-Code-Spiegelung mit Verweis auf die SSoT. opencode liest AGENTS.md mit Vorrang vor `~/.claude/CLAUDE.md`.
|
||||
|
||||
- **Alle fünf MikroTik laufen auf RouterOS `7.24.1`** (🆕 **Angleichung am 2026-08-31 von Christoph
|
||||
selbst durchgezogen, TP27 damit erledigt** — ap2 08:56, core 14:36, ap1 14:50, branch 14:52;
|
||||
ap3 kam bereits so. RouterBOOT jeweils = `upgrade-firmware` = `7.24.1`, live gegengelesen).
|
||||
Vorher: vier auf 7.24 (08-17), nur ap3 auf 7.24.1. Neu in der Flotte **`ap3`**
|
||||
(cAP ax `cAPGi-5HaxD2HaxD`, **`10.40.99.13`**, Uplink core `ether21`).
|
||||
✅ **Folge für TP16.3:** die versionsgebundene `container.npk` ist damit **eine** Datei für alle drei
|
||||
APs (alle `arm64`) — die Zwei-Dateien-Regel vom 08-30 war rein versionsbedingt und ist erledigt.
|
||||
*(Hier stand bis 08-29 „Alle vier MikroTik … 7.24" — durch ap3 und das Upgrade zweifach überholt.)*
|
||||
- **L3 + WAN-Edge = `crs326-core`** (CRS326-24G-2S+, Technik UG): Routing, DHCP (7 Server,
|
||||
54 Reservierungen), DNS, NAT, **NTP-Server für den Standort** und der WG-Hub (TP10, Peers `fm`/`dw`)
|
||||
laufen hier. Mgmt-SVI **`10.40.99.1`** (vlan99), Gateway `.1` je VLAN. **WAN = `vlan100`** — DHCP-Client
|
||||
hält die öffentliche Liwest-IP **`90.146.33.177/24`** direkt vom Arris (Bridge-Mode) → kein Double-NAT.
|
||||
**DNS-Upstream = DoH zum CF-Gateway mit `verify-doh-cert=yes`** (TP23 Stufe 1 ✅ 08-18);
|
||||
`servers=1.1.1.1` steht nur noch als Bootstrap für den DoH-Hostnamen.
|
||||
- 🔥 **Die Firewall ist deny-by-default — in BEIDEN Ketten** (TP5 E3/E4 ✅ 08-18). `TP10-seal-lan` ist
|
||||
`disabled`; Mgmt-Input kommt nur noch aus VLAN10, von HA (`8728`), von Nautobot (`22`) und über
|
||||
`cf-mesh`. Ein neuer Dienst über eine VLAN-Grenze braucht ab jetzt eine explizite Regel.
|
||||
- **L2-Branch = `crs326-branch`** (Technik OG): reiner L2-Switch, Mgmt **`10.40.99.2`**,
|
||||
Uplink `ether1` → core `ether8`.
|
||||
- **WLAN = CAPsMAN auf dem Core** (TP28 ✅ 08-17, GC-Modell nachgezogen 08-18): ap1 **`10.40.99.11`**
|
||||
(an core `ether15`), ap2 **`10.40.99.12`** (an branch `ether24`), beide **reine CAPs** —
|
||||
`cap enabled=yes`, `discovery-interfaces=vlan99`. Die APs halten **keine eigene WLAN-Config** mehr;
|
||||
Kanäle, SSIDs, Security und Steering kommen vom Manager. 802.11k/v aktiv; **802.11r (FT) aus** —
|
||||
`ft=no` auf allen SSIDs (sec-main seit 2026-09-04, User-Entscheid).
|
||||
🆕 **Dritter AP `ap3` (cAP ax) ✅ LIVE seit 2026-08-30** (TP28 dafür wieder geöffnet):
|
||||
`10.40.99.13`, Uplink `ether1` → **core `ether21`** (Trunk), reiner CAP, **RouterOS 7.24.1**
|
||||
(🆕 **seit 2026-08-31 die ganze Flotte** — die frühere Versionsdifferenz ist aufgelöst). Kanäle
|
||||
**`5180/ax/Ce/I`** + **`2437/ax`** (ch6) nach dem TP25-Plan vom 2026-08-24, am Gerät nachgemessen.
|
||||
🔴 **ap1 ist funkstill** — es steht bis zu seinem Umzug ans Sideboard direkt neben ap3 und würde
|
||||
auf 5180 kollidieren; es hat deshalb bewusst **keine Provisioning-Regel** am Manager, bleibt aber
|
||||
erreichbar. Beim Umzug: ap1 → `5260/Ce` (Band B, DFS, **Frequenz-Liste statt Einzelwert**),
|
||||
ap2 → `5300/Ce`, Uplink ap1 → `core ether3`.
|
||||
**Compliance jetzt 130/130 / 0 Drifts über 5 Geräte** (vorher 104/104 über 4).
|
||||
- **SSDP-Relay** (TP7.1, **nachgebessert 08-25**): LXC **108 `mcast-relay`** auf pve, zweibeinig
|
||||
`10.40.10.21` (VLAN10) + `10.40.40.21` (VLAN40) — dafür trägt `core ether13` beide VLANs; mDNS macht
|
||||
weiterhin der Core. **Läuft seit 08-25 ohne `--ssdpUnicastAddr`** — die Flagge verwarf die M-SEARCH
|
||||
der App auf dem Weg nach VLAN40 (Messung: **0 Pakete `via eth1` gegen 308 `via eth0`** in 20 min,
|
||||
**0×** `Received SSDP Unicast` im ganzen Journal seit 08-18). Der Rückweg läuft jetzt **nativ geroutet**
|
||||
über die längst offene Regel `TP5: MEDIA->MAIN`; nachgemessen kommen `HTTP/1.1 200 OK` von
|
||||
`10.40.40.193/.195` an beiden MacBook-Beinen an. Unit liegt im Repo: **`mcast-relay/multicast-relay.service`**,
|
||||
Details als Gotcha in `CLAUDE.md`. ⚠️ **Der Fall hatte zwei unabhängige Ursachen** — nach der
|
||||
Relay-Reparatur suchte die **App** immer noch nicht (macOS-Local-Network-Gate stand auf „an" und
|
||||
griff nicht; Fix war Schalter aus/ein + Neustart, User-bestätigt 08-25). **Beide sind erledigt.**
|
||||
- **Reverse Proxy = `caddy-bf1`** (LXC 130 auf pve, **`10.40.20.40`**, TP31 ✅ Schritt 1–3 seit
|
||||
2026-08-25, **`hass` 400 behoben 2026-08-26, Split-Horizon seit 2026-08-26**): Caddy 2.11.4,
|
||||
**16 Sites** (4 public, 12 intern mit `.bf.`-Suffix), Zertifikate ausschliesslich
|
||||
per **DNS-01** mit einem eng geschnittenen `Zone:DNS:Edit`-Token (`CF_DNS_API_TOKEN`, **nicht** das
|
||||
account-weite). Abnahme über den Host-Header von einem zweiten Host: 11× 200, `nautobot` 302.
|
||||
Offen: **Schritt 5–6** (Connector für `bf-public`, CNAME-Flip, Abbau der sechs Container) —
|
||||
**Runbook steht: [`tp16.3-bf-public-ap-connector-runbook.md`](tp16.3-bf-public-ap-connector-runbook.md)**,
|
||||
Vor-Ort-Session an ap1/ap2/ap3. ✅ **Die drei §1-Blocker sind am 2026-08-31 remote erledigt** —
|
||||
**(a)** Ingress auf `https://10.40.20.40:443` + `originServerName` je Regel umgestellt (die alte
|
||||
`:80`-Zeile hätte über CF eine Redirect-Schleife gebaut, weil Caddy dort 308 auf https antwortet);
|
||||
**(b)** Freigabe `vlan99 → vlan20:443` **über Nautobot GC** deployt (`ip-firewall-filter` steht unter
|
||||
Drift-Kontrolle, TP26 ⇒ kein Direkt-Write), Position vor `TP5: log-only` verifiziert, **135/135
|
||||
compliant, 0 Drifts**; **(c)** `ROUTER_AP3_PASS` in `~/.secrets` nachgetragen (REST-Auth 200).
|
||||
⇒ **Vor Ort startet die Arbeit bei §2/§3** (Pakete, `device-mode`, Container).
|
||||
- **DNS/Resolver = AdGuard-Paar `agh-bf1`/`agh-bf2`** (LXC 110/111 auf pve, **`10.40.20.36`/`.37`**,
|
||||
TP23 Stufe 2 + TP31 Schritt 4 ✅ seit 2026-08-26): Upstream DoH zum CF-Gateway, conditional
|
||||
`[/bf.emsenhuber.net/] → 10.40.20.1`, 47 Rewrites (16 Service → Caddy `.20.40` + 10 Host-Namen
|
||||
mit `.bf.`-Suffix + alte suffixlose parallel). DHCP liefert `.36`/`.37` als DNS in allen 7 VLANs
|
||||
(`domain=emsenhuber.net`), Firewall forward UDP+TCP/53 auf beide. Der Core-Resolver (`10.40.X.1`)
|
||||
bleibt als Bootstrap unverändert (DoH, `allow-remote-requests=yes`, `mdns-repeat-ifaces`).
|
||||
🆕 **TP23 Stufe 4+5 ✅ 2026-09-04:** `clients.persistent` = 7 VLAN-CIDR-Gruppen + `dns-bypass-exempt`
|
||||
(Policy-Matrix, INFRA/MEDIA/MGMT `filtering=aus`), API-User `automation`, Sync-Tool + redigierte
|
||||
Repo-SSoT unter `adguard/`. HA-Self-Service (Button → JIT-Domain-Freigabe, nativer Timer-Revert) live.
|
||||
Offen nur **Stufe 6** (Bypass-Sperre, TP5). Werkzeuge/Doku: `adguard/{agh-sync,agh-exception}.py`,
|
||||
`adguard/{README,ha-self-service}.md`.
|
||||
- **Ausgebaut / gelöscht:** ALLNET-`sw1` und Omada-`sw2` sind **physisch weg** (2026-08-08 bzw. 2026-07-23,
|
||||
in Nautobot *Decommissioned*); Omada-Controller + `omada-mcp` gelöscht (2026-07-16); FritzBox 6660 raus
|
||||
seit 2026-07-01 (Liwest-Tausch auf Arris). **VLAN1 ist leer** (`/ip arp` auf `bridge` = 0 Einträge,
|
||||
08-18) — TP19 ist geschlossen; `cudy1` hängt stromlos an core `ether11`, physischer Ausbau ist hands-on.
|
||||
- 🆕 **WLAN-Logging persistent seit 2026-08-30 (TP25 Fund E):** `wireless` + `caps` gehen vom Core
|
||||
in den TP5-Kollektor (`10.40.20.18:514`); `/system logging` steht unter der **27. ComplianceRule**
|
||||
`system-logging`. Vorher nur Ringpuffer → ein seit Wochen gemeldeter iPhone-Abbruch war rückwirkend
|
||||
nicht diagnostizierbar.
|
||||
- ⚖️ **TP25 Fund E — Hebel 1 ZURÜCKGEBAUT, Entscheidung faellt am 2026-09-02 (Stand 09-01 09:2x):**
|
||||
Zwei Sessions haben denselben Fall bewertet und kamen zu entgegengesetzten Schluessen. **Aufgeloest
|
||||
zugunsten der Kollektor-Messung:**
|
||||
- Die Nacht-Session las `get_log … sinceMinutes=1440` → `total 0` und schloss auf „geheilt". Das ist
|
||||
der **fluechtige Ringpuffer des Routers**: live nachgemessen **1000 Zeilen, aeltester Eintrag
|
||||
01.09. 00:38:58** — keine 9 h Tiefe. Der Core-Reboot 14:36 hatte ihn geleert, der 31.08. Vormittag
|
||||
war darin **nicht sichtbar**. 🔴 Genau die Falle, wegen der am 30.08. der persistente Kollektor
|
||||
eingerichtet wurde.
|
||||
- Im **Kollektor** stehen fuer 08:09–14:36 (Hebel 1 **allein**, vor dem Upgrade) **124×
|
||||
`reauthenticating`**, Stundenverteilung 09h=1 · 11h=2 · 12h=20 · 13h=31 · 14h=70, **alle vom
|
||||
iPhone allein** (= Client-Befund nach der eigenen Merkregel „viele MACs = Infrastruktur"), dazu
|
||||
Christophs **zwei erlebte Ausfaelle** um 13:16 und 14:23. Zwischen 09:00 und 14:36 gab es
|
||||
**keinen Reboot**, der sie erklaeren koennte.
|
||||
- ⇒ Hebel 1 hat im upgrade-freien Fenster **nichts** bewirkt; der Einbruch faellt exakt auf 7.24.1.
|
||||
**Deshalb am 2026-09-01 zurueckgebaut** (`ft-over-ds=yes`, Provisionierung nachgezogen, frische
|
||||
DHCP-Lease abgenommen, Transaktion **`zurueckgebaut`**, **Compliance 140/140**). Der Rueckbau **ist
|
||||
das Experiment**: bleibt es ruhig, war 7.24.1 die Ursache; kehrt das Haemmern zurueck, hatte die
|
||||
Nacht-Session recht und Hebel 1 wird als neue Transaktion erneut gezogen. **Bis zur Messung am
|
||||
2026-09-02 frueh committet niemand.** Handoff:
|
||||
[`handoff-20260901-fund-e-hebel1-zurueckgebaut.md`](handoff-20260901-fund-e-hebel1-zurueckgebaut.md).
|
||||
- 🔴 **ABER: neuer Teilbefund am 23:02 (2026-08-31) — `ap2` unterperformt, NICHT FT.** Christoph am
|
||||
Schreibtisch, 5G, kein Telefonat. Log: iPhone `F2:62:4C:E1:AF:09` ping-pongt im Sekundentakt
|
||||
`cap-wifi5 ↔ cap-wifi6` = **beide Radios von ap2** (5G 5220 ↔ 2,4G ch11/2462, Band-Steering-Thrash
|
||||
auf demselben AP), `disconnected, not responding` um 22:37:40 und 23:01:00. Feldstärke **−75…−88 dBm
|
||||
— bei laut Christoph 2 m Abstand** (ap2 auf 2,3 m, gleicher Raum). Bei 2 m wären −35…−45 normal.
|
||||
Aktuell **0 Clients auf ap2**, alle 29 auf ap3. ⇒ kein Coverage-/FT-Problem, sondern **ap2s Funk
|
||||
selbst** (RF/Antenne/HW) und/oder die **DTU-Störung auf ap2/ch11** (Transaktion `TP17.1-dtu-pin-ap2`,
|
||||
−59 dBm auf ap2s 2,4-Radio). Als eigener 🔬-Unterpunkt geführt, In-situ zu messen. Handoff:
|
||||
[`handoff-20260901-tp25-ap2-verdacht.md`](handoff-20260901-tp25-ap2-verdacht.md).
|
||||
- 🔴 **TP25 Fund E — Hebel 1 ist GESCHEITERT (Stand 2026-08-31 nachmittags):** `sec-main` steht am
|
||||
Core auf **`ft=yes ft-over-ds=no`** (seit 08:09), aber das Symptom blieb: **124× `reauthenticating`
|
||||
nach dem Eingriff** und **zwei von Christoph erlebte Ausfälle** — 13:16 (Videocall bricht ab,
|
||||
7 min ohne WLAN) und 14:23 (5,5 min, nur durch WLAN-Toggle beendet). Stundenvergleich auf
|
||||
gleicher Firmware: **07:00–08:00 = 79 · 14:00–15:00 = 70**. Erfolgskriterium war „~0" ⇒ nicht
|
||||
eingetreten. Gewertet wird bewusst nur **08:09–14:36** (danach kommt das TP27-Upgrade als zweite
|
||||
Variable dazu; Christoph-Entscheid: „Vormittag als Ergebnis werten").
|
||||
⇒ Transaktion **`TP25-fund-e-ft-over-ds` bleibt OFFEN** (Ablauf **2026-09-03**), **Compliance
|
||||
weiter bewusst 134/135**; Rollback oder Commit ist eine Entscheidung, kein Aufräumen.
|
||||
Geräte-Backup `pre-tp25-funde-ftoverds.backup` liegt auf dem Core.
|
||||
**Nächste Entscheidung:** Hebel 2 (`ft=no`) **oder** `authentication-types=wpa2-psk,wpa3-psk` —
|
||||
`sec-main` ist auch die einzige SSID ohne `wpa2-psk`, und `association rejected, no cached PMK`
|
||||
(157× am 31.08., 0× am 30.08.) ist eine SAE/PMKSA-Meldung. **Vorher prüfen, ob 7.24.1 auf dem
|
||||
Manager das Verhalten schon verändert hat** — zwischen 14:37 und 15:12 stand nur **1**
|
||||
`reauthenticating` im Log, keines vom iPhone (35 min = noch keine Aussage).
|
||||
Details: [`handoff-20260831-tp27-upgrade-und-hebel1-befund.md`](handoff-20260831-tp27-upgrade-und-hebel1-befund.md).
|
||||
- ⚠️ **Messfalle, die diese Session fast erwischt hat:** die 13 CAP-`joined`/`activity timeout` vom
|
||||
31.08. sahen nach CAPWAP-Instabilität aus — es waren die **Reboots des TP27-Upgrades**. Und die
|
||||
**`cap-wifiN`-Karte hat sich an einem Tag zweimal verschoben** (08:09, 14:36), womit die im
|
||||
Vorgänger-Handoff festgehaltene Tabelle nach sechs Stunden falsch war. Interface-Namen in
|
||||
Logzeilen sind ohne zeitnahen Karten-Snapshot **nicht zuschreibbar**.
|
||||
- **Kontrolle / Governance:** MikroMCP für Reads/Debug (alle 5 Geräte in der Registry),
|
||||
**Config-Änderungen ausschließlich über Nautobot Golden Config** (TP21/TP22 — Deploy-Pipeline scharf,
|
||||
**135/135 Compliance-Checks grün, 0 Drifts** bei **27 Rules × 5 Geräten** (Stand 2026-08-30;
|
||||
**seit 2026-08-31 vorübergehend 134/135 — der eine Drift ist die offene Transaktion
|
||||
`TP25-fund-e-ft-over-ds`, s. oben, kein Fehler**) — live gegen die API
|
||||
geprüft am **2026-08-23**; zuletzt dazugekommen: **`wifi-access-list`** (08-22), **`queue`**
|
||||
(08-23, TP6) und **`ip-firewall-mangle`** (08-23, TP6.1), s. TP22-Nachtrag im Archiv).
|
||||
*(Hier stand bis zum 08-23 „100/100 bei 25 Rules" — eine Zählung, die TP6.1 am selben Tag überholt
|
||||
hat. Die Merkregel gilt: der Ist-Stand-Block wird bei jeder Änderung mitgezogen, nicht nur der TP.)*
|
||||
|
||||
<details><summary>📜 Historische Fassung (Stand bis 2026-08-08, Topologie <b>vor</b> dem Core-Cutover — bewusst erhalten, nicht als Ist lesen)</summary>
|
||||
|
||||
> ALLNET-Core `.11` (FW2.2.1, VLANs 10/20/30/40/50/90/99/100; GE1/GE2/GE8 Trunk; **TP1 ✅ 2026-06-15**). Omada-Switch `.12` (adopted, **TP2 ✅ 2026-06-15**; Trunk-ALL auf P1+P2, Access-Profile auf P3-P8; Profile noch PVID=1 bis Omada-PVID-Fix).
|
||||
> Omada-Controller **`.175`** (DS923/macvlan, mbentley 6.2, 🟢 live). omada-mcp **`.176`** (pve-LXC, StreamableHTTP, 🟢 live, 84 read-Tools; Controller-API v2 intern via christoph@emsenhuber.com).
|
||||
> 2× hAP ax² (7.23.1): ap1 `.1` (ALLNET P1) — **TP4 ✅ 2026-07-01: Router + WAN-Edge** (VLAN-Subinterfaces, DHCP, DNS, NAT, Public-Edge). ap2 `.2` (Omada P2 — Trunk).
|
||||
> **Edge-Cutover ✅ 2026-07-01:** FB6660 physisch entfernt (Liwest-Kabelmodemtausch, kein Zurück), Arris-Kabelmodem im Bridge-Mode; WAN = `sw1 gi16 Access VLAN100 → gi15 Trunk → ap1 ether2 → vlan100 auf bridge` (**NICHT** ether1); ap1 hält Public-IP direkt (Liwest, kein CGNAT), Double-NAT weg. Telefonie war auf der FB und wird nicht weitergeführt. Vorarbeit: TP10-Kern durch (2026-06-27, WG-Hub live) → Bridge-Gate vorher gelöst. Runbook: `routeros/wan-cutover-runbook.md`.
|
||||
> Kontrolle: MikroMCP (MikroTik) live · ALLNET = Klickanleitungen · Omada → Controller + omada-mcp 🟢.
|
||||
|
||||
</details>
|
||||
|
||||
**Nächster Schritt (Stand 2026-08-30): Vor-Ort-Session ap1/ap2** — sie ist der einzige Weg, den
|
||||
Public-Strang auf `bf-public` zu heben und die drei Alt-Tunnel samt sechs Containern abzubauen
|
||||
(TP16.3 Follow-up F2). ✅ **F1 ist am 2026-08-30 durch** (12 Client-Configs auf LAN-IP, danach
|
||||
`gitea-mcp`/`n8n-mcp` aus Ingress+DNS geschnitten) — davor unabhängig machbar bleibt nur noch die
|
||||
**Announcement-Doku (TP35 Schicht 4)**, die den anderen Projekten die neuen MCP-URLs mitteilt.
|
||||
|
||||
**Vorherige Fassung (Stand 2026-08-28): drei Folge-Sessions parallel** (siehe `docs/handoff-20260828-mcp-bestand-und-performance.md`):
|
||||
> - ✅ **Session A** — `/projektstatus`-Skill global für opencode (TP35 Schicht 6). Funktionsbeweis erbracht 2026-08-28.
|
||||
> - 🔜 **Session B** — shelly-mcp-Container auf DS923 (`10.40.20.10`) deployen (live, ssh). Repo-Materialien committed (`mcp/shelly/{Dockerfile,BUILD.md,requirements.txt,.gitignore}`); `.env` und Tunnel-Secret lokal — kein MCP-Client (User-Direktive).
|
||||
> - 🔜 **Session C** — `caddy/cf-sync.py`-Drift-Check + Backup-Guard (`~/dev/.bin/backup-guard.sh`, TP35 Schicht 5).
|
||||
> 🧭 **Ist-Stand, kritischer Pfad und Quick-Index leben ab jetzt als Gitea-Issues**, nicht mehr in
|
||||
> dieser Datei: **[admin/bf-infra · Issues](https://gitea.emsenhuber.net/admin/bf-infra/issues)**.
|
||||
> **TP = Issue · Status = Label `status:*`** (todo/wip/paused/idea/concept/done/dropped) ·
|
||||
> **Gruppierung = Label `thema:*`**. Filtern über die Label-Chips der Issue-Liste, z.B.
|
||||
> [nur offene](https://gitea.emsenhuber.net/admin/bf-infra/issues?type=issue&state=open).
|
||||
>
|
||||
> 🆕 **Dazu seit 2026-08-30: TP16.3/TP31 Schritt 5 = Vor-Ort-Session** an ap1/ap2/**ap3**
|
||||
> ([Runbook](tp16.3-bf-public-ap-connector-runbook.md)). **Reihenfolge beachten:** die drei Blocker in
|
||||
> §1 sind **remote** zu erledigen, *bevor* jemand in den Keller geht — sonst steht man vor einem
|
||||
> Connector, der `healthy` meldet, während die Seite eine Redirect-Schleife dreht.
|
||||
> **Diese Datei führt nur noch die per-TP-Prosa** — die `### TPnn`-Abschnitte unten; Abgeschlossenes im
|
||||
> **[Archiv](teilprojekte-archiv.md)**. **Live-Gerätedaten** (Compliance-Zahl, RouterOS-Version …) kommen
|
||||
> aus **Nautobot**, nicht von hier. Sync-Werkzeug Datei/Archiv → Gitea (idempotent, Dry-Run default):
|
||||
> `bin/gitea-tp-sync.py`.
|
||||
>
|
||||
> 🆕 **Strukturelle Folge = TP36:** SSoT für `teilprojekte.md`-Live-Daten via Nautobot (eigene Session, nicht heute). Befund 2026-08-28: manuell gepflegte Datei verliert gegen die Realität, sobald sie lang wird. Quickref-Index, TP-Abschnitt und Ist-Stand-Block müssen bei jedem Edit mitgezogen werden — keine schlägt die andere. **Merkregel im Lessons-Block.**
|
||||
> *(TP36-Cutover 2026-09-07: die frühere Quick-Index-Tabelle und der chronologische „Ist-Stand (Kurz)"-Block
|
||||
> sind aus dieser Datei entfernt, damit TP-Branches nicht mehr auf der Steuerungs-Doku kollidieren — Status-
|
||||
> Updates gehen nach Gitea statt in diese Datei. Die alte Ist-Stand-Historie steht in der Git-Historie.)*
|
||||
|
||||
> 🆕 **Neu am 2026-08-24/25:** [TP31](#tp31) löst **TP16** und **TP16.2** ab und dampft cloudflared
|
||||
> von **sechs Containern auf einen** ein; [TP32](#tp32) gibt die Nummern- und Adress-Systematik vor
|
||||
> (und hat nebenbei die **falsche Startreihenfolge auf pve repariert** — HA startete vor seiner
|
||||
> Datenbank). **TP16 ✅, TP25 ✅ und TP16.3 (Pilot) ✅** sind am 24./25. durchgezogen worden.
|
||||
|
||||
**Vorherige Fassung (Stand 2026-08-23): Christoph entscheidet — der kritische Pfad ist LEER.**
|
||||
> 🎯 **Das Projekt ist in seinem Kern fertig.** deny-by-default steht (TP5), Golden Config steht und
|
||||
> meldet **104/104 compliant bei 0 Drifts** (live geprüft 2026-08-23), WLAN steht über CAPsMAN auf dem
|
||||
> Core (TP28), VLAN1 ist leer (TP19) — und **TP6 ist beantwortet statt offengelassen**: CAKE gebaut,
|
||||
> gemessen, wieder ausgebaut. **Nichts blockiert mehr etwas.**
|
||||
> 🟢 **Was zuletzt wirklich etwas gebracht hat, war TP6.1** (2026-08-23): nicht Shapen, sondern
|
||||
> **Klassentrennung** — NAS-Bulk `priority=8` gegen interaktiv `priority=1` drückt dieselbe Strecke
|
||||
> unter derselben Sättigung von **40,8 auf 11,0 ms (−73 %)**. Die zuerst notierte DOCSIS-Erklärung aus
|
||||
> TP6 ist damit **widerlegt**; der Fehler lag in der Messmethode (Last und Messung vom selben Host).
|
||||
> 📋 **Offen und ohne Blockadewirkung:** **TP25** (Fund F = 5:05-Takt bei IoT, plus die Entscheidung
|
||||
> „5 GHz auf 20 MHz") · **TP16** (CF-Tunnel-HA degradiert, vier tote Alt-Tunnel) · **TP16.2/16.3** ·
|
||||
> **TP23 Stufe 2** · **TP24** (DC-USV) · **TP13/TP14.4** (beide mit fertigem Runbook) ·
|
||||
> ❌ **TP17.1 VERWORFEN 2026-08-23** (Zigbee-Weg bewiesen, Ziel damit nicht erreichbar — das Gerät
|
||||
> bleibt WLAN-Client; `s9` zurückgebaut) · ✅ **TP17.3 ERLEDIGT** (Ursache **`eco_mode`** bewiesen;
|
||||
> `s23` + `s26` repariert; **`eco_mode` flottenweit aus**, 22/22 außer `s24`) ·
|
||||
> ➡️ **TP17.2 ist am 2026-08-24 in TP30 aufgegangen** (Shelly-Gerätepasswort = Erstvergabe eines
|
||||
> Credentials; TP30 ist das Sammelbecken dafür) ·
|
||||
> 🔑 **Alle Passwort-/Token-Rotationen sind seit 2026-08-24 TP30** (Sammel-TP) — **bewusst
|
||||
> gebündelt gegen Projektende**, User-Entscheid. Damit ist die ältere Einreihung „hinter TP17.1"
|
||||
> gegenstandslos (TP17.1 ist verworfen). **Etappe 1 — die Service-Accounts — ist durch;**
|
||||
> das `admin`-Passwort selbst ist **nicht rotiert** und bleibt es bis dahin bewusst.
|
||||
> 📌 **Einstieg für die nächste Session:
|
||||
> [`handoff-20260825-agh-dns-cutover.md`](handoff-20260825-agh-dns-cutover.md)** — AdGuard als
|
||||
> Resolver + Split-Horizon (TP23 Stufe 2 ∥ TP31 Schritt 4). **Bewusst eigene Session:** der Schritt
|
||||
> verschiebt die DNS-Auflösung des ganzen Standorts in einen Container.
|
||||
> 📜 Älter: [`handoff-20260824-session.md`](handoff-20260824-session.md)
|
||||
> — ⚠️ dessen Empfehlung „Start bei der Passwort-Rotation Etappe 2" ist durch den TP30-Entscheid
|
||||
> **überholt**; der Rest der Übergabe gilt. Ältere Sitzungsvorschläge:
|
||||
> [`handoff-20260822-naechste-schritte.md`](handoff-20260822-naechste-schritte.md).
|
||||
> ✅ **`crs326-core` ist transaktionsfrei** (seit 2026-08-22, geprüft): ein gemeldeter Drift ist ab
|
||||
> jetzt **echt**, nicht beabsichtigt — `python3 nautobot/gc-transaktion.py status`.
|
||||
|
||||
<details><summary>📜 Vorherige Fassungen dieses Absatzes (2026-07-22 → 2026-08-21, bewusst erhalten)</summary>
|
||||
|
||||
> *Fassung 2026-08-21 abends (erledigt — TP25s Dead Spot ist am 08-22 repariert, TP6 am 08-23 geschlossen):*
|
||||
> **Nächster Schritt: TP25 — Steering-Test in den Schlafräumen.**
|
||||
> 📋 **Einstieg: [`handoff-tp25-session-20260821.md`](handoff-tp25-session-20260821.md)** — dort steht
|
||||
> der verifizierte Ist-Stand, die Messfallen und der nächste Test.
|
||||
> ✅ **`crs326-core` ist transaktionsfrei (2026-08-22).** `TEST-ether3-trunk-ap1-sideboard` und
|
||||
> `TEST-infra-ssid-matter-pairing` sind beide zurückgerollt und geschlossen; ap1 hängt wieder auf
|
||||
> `ether15`, `ether3` ist wieder untagged VLAN40. Ein gemeldeter Drift ist ab jetzt **echt**, nicht
|
||||
> beabsichtigt — `python3 nautobot/gc-transaktion.py status`.
|
||||
> 🆕 **TP29** (Anwesenheitserkennung fürs Energiesparen) ist als Idee angelegt, nicht auf dem Pfad.
|
||||
> 📌 **Die TP6-Prämisse ist am 2026-08-20/21 gemessen** (Runbook §5): formal Fall B (+28…+47 ms unter
|
||||
> Dauer-Upload), aber im Videocall **nicht wahrnehmbar** — kein einziger Problem-Klick über sechs
|
||||
> Lastphasen. Laut war stattdessen der Funk: **Sticky Client + Band-Ping-Pong, zwölf Wechsel in neun
|
||||
> Minuten**, je Wechsel bis zu 4 s ohne Durchsatz →
|
||||
> [`tp25-wlan-roaming-messung-20260820.md`](tp25-wlan-roaming-messung-20260820.md). Deshalb steht jetzt
|
||||
> **TP25 vor TP6**; TP6 bleibt offen und begründet, aber nachrangig.
|
||||
>
|
||||
> *Vorherige Fassung (Stand 2026-08-18, erledigt):*
|
||||
TP6 wird hier seit Monaten als „DAS Ziel" geführt, aber `docs/call-quality-diagnosis.md` hat den
|
||||
Bufferbloat 2026-06-16 bereits gemessen (**A/A+**, „CAKE wäre marginal, nicht deployt"). Die Messung
|
||||
stammt aus der FritzBox-Ära, der Edge ist seither getauscht — also **einmal gegen den heutigen Edge
|
||||
nachmessen und dann entscheiden**. Blocker gibt es keine mehr. TP5 ist in der Nacht auf den 18. abgeschlossen worden (Etappe 3 + 4: deny-by-default in `forward` **und** `input`, MGMT isoliert, `seal-lan` abgeschaltet), TP23 Stufe 1 (DoH auf dem Core) ebenfalls. Nebenher offen, blockiert nichts: **TP25** (Signal-Boden + Re-Walk), **TP28-Rest** (die fünf `wifi-*`-Features vom AP-Scope auf den Core umhängen — die einzigen verbliebenen Compliance-Drifts), **TP7.1** (SSDP-Relay für die macOS-Sonos-App), **TP16.3**, **TP24**.
|
||||
> *Vorherige Fassung (Stand 2026-08-14, überholt): „TP5 — Deny-by-default am Ende von `forward`." Alles Davorliegende ist durch:* CRS326-Bring-up + L3-Umzug ap1→`crs326-core` (TP15/TP21.1 ✅ 2026-08-08), WLAN-Neuprovisionierung ohne CAPsMAN (TP3 ✅ 2026-08-08), Nautobot-Plattform + Fleet-Adoption + Deploy-Pipeline (TP21/TP22 ✅ 2026-08-13). Danach **TP6 (CAKE) = das Projektziel**. Kleine Follow-ups nebenher: DoH-Cloudflare auf core, DC-USV (**TP24**, seit 2026-08-16 eigener TP). ⚪ **Omada-PVID-Fix ist obsolet** (User-Entscheid 2026-07-22 — Omada spielt seit der TP15-Korrektur keine Rolle mehr im Netz, nie mehr aufgreifen).
|
||||
> *Vorherige Fassung (Stand 2026-07-22, erledigt): „TP15 CRS326-Bring-up als neuer L3-Core, danach WLAN-Neuprovisionierung ohne CAPsMAN; TP5 folgt nach TP21/CRS326-Adoption."*
|
||||
|
||||
</details>
|
||||
## Governance & genehmigte Ausnahmen (stehende Regeln — kein Status)
|
||||
|
||||
> 🎯 **Ziel: sauberes System „from scratch", keine Leichen/Altlasten.** Migrations-Session-Endstand = **VLAN1 + altes cudy-WLAN komplett weg** (VLAN1 nur noch Mgmt, `defconf`-Client-DHCP zurückgezogen, cudy-Uplinks aufs Ziel-Client-VLAN getaggt oder cudy abgebaut). **Unterpunkte/Aufräum-Liste bei Migration:** (a) die Interim-Härtung ap2 `wifi1/wifi2 frame-types=admit-only-vlan-tagged` (TP3.1, 2026-07-06) bleibt gültig — verschwindet automatisch mit VLAN1; (b) ~~`st-main rrm/wnm` = reines Roaming-Provisorium~~ → **kein Provisorium mehr (2026-08-13, TP3.3): Steering ist fester Bestandteil des Golden-Config-Templates + ComplianceFeature `wifi-steering`** — es war die Neuprovisionierung, die es stillschweigend verloren hatte; (c) ~~**cudy1 = verbleibender aktiver VLAN1-Leak**~~ → **ERLEDIGT (User-bestätigt + verifiziert 2026-08-14): cudy1 ist offline.** `core ether11` trägt **kein Link** (kein `R`-Flag), Nautobot-Status *Offline* (TP22 Schritt 5). Damit existiert kein aktiver VLAN1-Leak mehr; der Dual-DHCP-Race aus `project_vlan1_dhcp_incident` ist Historie. Der formale Teardown (Gerät ausbauen, Doku/Inventar) bleibt TP19.
|
||||
> ⚠️ **HW-Constraint hAP ax²:** 1 GB RAM, aber nur **128 MB Flash + KEIN USB** → **Container auf dem Router NICHT praktikabel**.
|
||||
@@ -522,44 +67,7 @@ nachmessen und dann entscheiden**. Blocker gibt es keine mehr. TP5 ist in der Na
|
||||
> ~~**TP17.2** ↔ TP17~~ *(TP17.2 ist am 2026-08-24 in **TP30** aufgegangen und kein eigenes TP mehr)*
|
||||
> und **TP20.1** ↔ TP20).
|
||||
>
|
||||
> ### 📊 Quick-Index (nur dieser Block ist für den Statusbaum nˆtig — 1 Read)
|
||||
>
|
||||
> | # | Status | Kurztitel | Abschluss |
|
||||
> |---|---|---|---|
|
||||
> | TP5.1 | ⏸️ | DNS-Visibility Airfryer | — |
|
||||
> | TP8 | ⏸️ | Identity / 802.1X | — |
|
||||
> | TP11 | ⏸️ | Monitoring | — |
|
||||
> | TP12 | ⏸️ | IPv6 (3 Standorte) | — |
|
||||
> | TP12.1 | 🔜 | IPv6 ULA + v6-Firewall | — |
|
||||
> | TP13 | 🔜 | Botschafts-WLANs | — |
|
||||
> | TP14.4 | ✅ | CF-Access-Token — **in TP41 T4 aufgegangen** (`claude-mcp`→`zt-svc`, `.env` geschrieben) | 2026-09-01 |
|
||||
> | TP16 | ✅ | CF-Tunnel HA wieder voll | 2026-08-24 |
|
||||
> | TP16.2 | 🔜 | Härtung bypass-Dienste | — |
|
||||
> | TP16.3 | ✅ | cloudflared-Reduktion — Flip + Abbau durch; nur noch `bf-public`+`fm`, 7 Container weg | 2026-09-01 |
|
||||
> | TP17.1 | ❌ | Shelly Gen4 → Zigbee | 2026-08-23 |
|
||||
> | TP17.3 | ✅ | Shelly-Regression behoben | 2026-08-23 |
|
||||
> | TP18 | 🔜 | Garage-Objektspeicher | — |
|
||||
> | TP20.1 | 🔜 | Vaultwarden → Platform-PG | — |
|
||||
> | TP23 | ⏳ | DNS-Policy (Stufe 1–5 ✅ 09-04) — offen nur Stufe 6 (Bypass-Sperre, in TP5) | 2026-09-04 |
|
||||
> | TP24 | 🔜 | DC-USV | — |
|
||||
> | TP25 | ⏳ | WLAN-Stabilisierung (Kern ✅) — **Fund E ✅ geschlossen 09-02: 7.24.1 war die Ursache, nicht `ft-over-ds` (4/8,6 h, 0 Ausfälle)**; **`ft=no` auf `sec-main` als Dauerzustand ✅ 09-04**; **Konsole auf N Clients + Pin-UI ✅ 09-04**; offen nur ap2 unterperformt (2 m/−80, In-situ) | 2026-09-04 |
|
||||
> | TP28 | ✅ | WLAN/CAPsMAN — dritter AP `ap3` (cAP ax) **live** | 2026-08-30 |
|
||||
> | TP29 | 💡 | Anwesenheitserkennung (Idee) | — |
|
||||
> | TP30 | 🔜 | Credentials (Etappe 1 ✅, Rest gebündelt) | — |
|
||||
> | TP31 | ✅ | Reverse Proxy Caddy — 1–4 ✅ (08-25/26), **5+6 via TP16.3 (09-01)**; Abnahme-Tool `cf-sync.py` grün | 2026-09-01 |
|
||||
> | TP32 | 🟢 | Nummern-Systematik (Konzept) | — |
|
||||
> | TP33 | 💡 | Sonos fern (Idee, zurückgestellt) | — |
|
||||
> | TP34 | 🔜 | Caddyfile via Nautobot/GC (Stub, Inventur-Handoff 2026-08-27) | — |
|
||||
> | TP35 | ⏳ | MCP-Schichtung + 3-Schicht-CLAUDE.md + Backup-Guard (Schicht 1+3+6 ✅) | — |
|
||||
> | TP36 | 🔜 | SSoT via Nautobot für teilprojekte.md-Live-Daten + Datei-Aufteilung | — |
|
||||
> | TP37 | 🔜 | Nautobot als Netzwerkdoku: Hosts/Container/Dienste + CF-Connectoren (Okay 08-30) | — |
|
||||
> | TP38 | 🔜 | OOB-Mgmt: untagged-VLAN99-Port je Switch | — |
|
||||
> | TP40 | 🔜 | HA-Recorder-Retention: 41 GB `states` beschneiden (Okay 09-01) | — |
|
||||
> | TP41 | ⏸️ | CF-Access-Reparatur **zurückgestellt 2026-09-01** (User): **T2/T3/T4/T5 ✅** (GitHub+Google-Login live); **Facebook abgesagt**; **Geli CF-seitig fertig** (zt-humans+geli-Policy) → offen nur noch WARP-Client auf Gelis Gerät, wartet auf User-Info | — |
|
||||
> | TP42 | ✅ | Namens-Vereinheitlichung: ein interner Suffix **`bf.emsenhuber.net`** — DHCP-domain via GC geflippt (140/140), `.16` abgebaut (`.17`=FM bleibt); Nautobot-Doku-Teil an TP37 | 2026-09-02 |
|
||||
> | TP43 | 🔜 | dw-Standort-DNS-Uplink: eigener Resolver mit site-Overrides (`420.teilzeitladen.xyz`→BF-Caddy/WG), WG-Disconnect bedacht; Geli sofort per WARP | — |
|
||||
> | TP44 | ⏳ | CF-Estate als Doku-SSoT in Nautobot — **Etappe 1 ✅ live** (`nautobot.cloud`: Account 1/ResType 6/Network 4/Service 14/Assign 3); offen Etappe 2 (CF-API→Nautobot-Sync) + IPAM-Prefixe | — |
|
||||
> | — | — | **35 archivierte TPs** in `teilprojekte-archiv.md` (inkl. TP39 ✅ 2026-09-01) | — |
|
||||
> 📊 **Index/Statustabelle → [Gitea-Board](https://gitea.emsenhuber.net/admin/bf-infra/issues)** (siehe Kopf dieser Datei). Hier unten folgt nur noch die per-TP-Prosa.
|
||||
|
||||
### TP5.1 — DNS-Visibility & Flow-Observability für Low-Trust-Geräte (Airfryer-Fall) ▸ vorgemerkt
|
||||
- **Kontext (2026-07-08/09):** Airfryer „airschreier" (Philips/Versuni, ESP, `10.40.30.180`) bekam per DHCP-Option 6 `dns 1.1.1.1` als Override, weil das OTA-Update über den ap1-DoH-Gateway-Pfad nicht durchging (DoH-Latenz beim primitiven ESP-Stack — **kein** Content-Block, via Gateway-Logs bewiesen, s. `memory/ref_esp_ota_doh_not_block`). Nebenwirkung: public **1.1.1.1 = anonymer Consumer-Resolver ≠ accountgebundener Gateway-DoH** (`px35ynlol3.cloudflare-gateway.com`) → **DNS-Sicht auf das Gerät weg**, Gerät umgeht zudem die Filterung.
|
||||
@@ -2874,18 +2382,17 @@ kann in Ruhe nachziehen.
|
||||
|
||||
---
|
||||
|
||||
### TP36 — SSoT via Nautobot für `teilprojekte.md`-Live-Daten + Datei-Aufteilung ▸ 🔜 ANGELEGT 2026-08-28, Scope-Ausarbeitung eigene Session
|
||||
- **Auslöser:** Skill-Run 2026-08-28 (`docs/handoff-20260828-session-a-projektstatus.md`) lieferte „Nächster Schritt (2026-08-26): TP31 Schritt 5" als Output, obwohl seit dem 26. drei Folge-Sessions parallel offen waren. **Manuell gepflegte Doku mit Live-Daten verliert gegen die Realität, sobald sie lang wird.**
|
||||
- **Befund:** Drei Stellen pro Edit berücksichtigen müssen — Quick-Index (Tabelle), TP-Abschnitt, Ist-Stand-Block. Keine schlägt die andere. Wer eine ändert, **muss** die anderen mitlesen. Die Datei hat aktuell 1940 Zeilen, der Ist-Stand-Block steht bei Z. 28, das Archiv-Cover bei Z. 1771. Strukturelles Risiko, kein Einzelfall.
|
||||
- **Scope (Skizze, eigene Session):**
|
||||
1. **Nautobot Custom Fields für Live-Daten** — RouterOS-Version, Compliance-Zahl (104/104, 26 Rules × 4 Geräte), DHCP-Server-Anzahl, MGMT-IPs, DNS-Upstream-Modus. Script `nautobot/gc-snapshot.py` rendert `docs/teilprojekte.md` (oder einen schmaleren Ersatz) als **read-only Snapshot**.
|
||||
2. **Datei-Aufteilung** — `docs/teilprojekte-index.md` (1 Seite: nur aktive TPs, Titel + Status + Datum), `docs/teilprojekte-aktuell.md` (Live-Snapshot aus Nautobot), `docs/teilprojekte-archiv.md` (bleibt Volltext). `/projektstatus`-Skill liest Index + Archiv, nicht die Snapshot-Datei.
|
||||
3. **Archiv-Anzeige im Quick-Index** — die heute 34 Namen stehen heute in *einer* Zeile am Ende. Sichtbarkeit = „Geschichte zählt". Quick-Index-Block bekommt eine zweite Tabelle mit „abgeschlossen seit …" und Link aufs Archiv.
|
||||
4. **Migrationspfad** — kompatibel mit bestehendem Workflow (`/projektstatus`-Skill konsumieren, niemand außer mir editiert Live-Markdown). Testphase = beide Dateien parallel führen.
|
||||
- **Abgrenzung:** TP36 ist Querschnitt, nicht Kern-BF. Eigene Session, eigener Handoff. Nicht heute.
|
||||
- 🔴 **Klarstellung 2026-09-06:** **unabhängig vom TP37-Substrat** — die Live-Daten-CustomFields (Punkt 1) hängen an den **4 bestehenden `dcim.Device`**, nicht an neuen VM/Service-Objekten → TP36 kann **parallel/vorgezogen** laufen. Datenmodell: native `extras.CustomField` (Compliance-Zahl kommt aus GC selbst). ⚠️ **Namensfalle bereinigt:** das Skript `nautobot/tp36-cf-estate-seed.py` gehörte **nie** zu TP36 — es ist die TP44-CF-Estate-Befüllung und heißt seit 2026-09-06 `tp44-cf-estate-seed.py`. TP36 hat **noch kein** Skript (`gc-snapshot.py` ist zu bauen).
|
||||
- **Verzahnt mit:** TP22 (Nautobot-GC als Vorbild), TP35 (geht Hand in Hand — beide sind „SSoT + Konsolidierung"), `bf-infra/CLAUDE.md`-Lessons.
|
||||
- **Referenzen:** Lessons-Block-Eintrag „Manuell gepflegte Doku mit Live-Daten verliert gegen die Realität" · Handoff Session A 2026-08-28.
|
||||
### TP36 — Index/Status als SSoT nach Gitea (Steuerung aus der branchbaren Datei herauslösen) ▸ ⏳ **CUTOVER 2026-09-07** — Index/Status = Gitea-Issues, Prosa bleibt Datei
|
||||
- **Auslöser:** Skill-Run 2026-08-28 (`docs/handoff-20260828-session-a-projektstatus.md`) lieferte einen überholten „Nächster Schritt"-Output; **manuell gepflegte Doku mit Live-Daten verliert gegen die Realität, sobald sie lang wird.** Verschärft 2026-09-06: `docs/teilprojekte.md` wurde in **40/40** letzten Commits angefasst — jeder TP editierte Quick-Index **und** Ist-Stand-Block → **Merge-Konflikt-Magnet**, der Branch-pro-TP verhinderte (ein Parallel-Branch hatte so die TP37-Doppelvergabe verursacht).
|
||||
- 🔄 **Reframe 2026-09-06 (Christoph):** von „SSoT via **Nautobot**" auf „SSoT via **Gitea**". Grund: Index+Status sind **kuratierte Steuerung** (Reihenfolge, Marker, Abhängigkeiten), kein Geräte-Live-Zustand — die gehören auf ein **Issue-Board**, nicht in Custom Fields. **Nautobot bleibt nur für Live-Gerätedaten** relevant (Compliance-Zahl, RouterOS-Version …) → als optionaler Rest unten, entkoppelt von diesem TP.
|
||||
- **Modell (umgesetzt):** TP = **Gitea-Issue** in [`admin/bf-infra`](https://gitea.emsenhuber.net/admin/bf-infra/issues) · Status = Label `status:*` (todo/wip/paused/idea/concept/done/dropped) · Gruppierung = Label `thema:*`. Seeder `bin/gitea-tp-sync.py` (idempotent, Dry-Run default, `--commit` schreibt; Token aus `~/.hermes/.env`, **nie ausgeben**). Erstlauf: **68 Issues (25 open/43 closed) + 15 Labels**.
|
||||
- ✅ **Erledigt (A1–A3):** Labels/Modell · 68 TPs → Issues · Board = Index (Label-Filter statt Handtabelle).
|
||||
- ⏳ **Cutover 2026-09-07 (diese Session):**
|
||||
- **A4** — Quick-Index-Tabelle + „Ist-Stand (Kurz)"-Block aus dieser Datei entfernt; Header zeigt aufs Gitea-Board; die vier **Genehmigten Ausnahmen** unter eigenem Governance-Header behalten. Alle `### TPnn`-Prosa bleibt.
|
||||
- **A5** — `/projektstatus` liest Baum+Status aus der **Gitea-API** (Issues + `status:*`/`thema:*`), Transaktionen weiter aus `nautobot/gc-transaktion.py status`, Prosa-Detail bei Bedarf aus dem Repo. Beide Skill-Kopien (`~/.claude/skills/…` **und** `~/.config/opencode/skills/…`, `cp`, kein Symlink).
|
||||
- **A6** — Projekt-`CLAUDE.md`: Pflichtlektüre = Gitea-Board (Status) + Prosa-Datei (Detail); Branch-Konvention (`tpNN-kurz` jederzeit, Merge nach `main` wenn Code/Config steht, Steuerungs-Updates nach Gitea); SSoT-Notiz.
|
||||
- 🔜 **Optionaler Rest (entkoppelt, „TP36-Live"):** Live-Daten-CustomFields auf den **4 `dcim.Device`** (`ros_version`, `compliance_pct`, `dhcp_server_count`, `mgmt_ip`, `dns_upstream_mode`) + Snapshot-Skript `nautobot/gc-snapshot.py` (existiert noch nicht). Unabhängig von diesem Cutover; nur relevant, wenn die Doku Live-Zahlen tragen soll. ⚠️ **Namensfalle bereinigt:** `nautobot/tp36-cf-estate-seed.py` gehörte **nie** zu TP36 → seit 2026-09-06 `tp44-cf-estate-seed.py`.
|
||||
- **Verzahnt mit:** TP35 (SSoT + Konsolidierung), TP44 (native Nautobot-Modelle), `bf-infra/CLAUDE.md`-Lessons. Plan: `~/.claude/plans/geht-das-los-auch-reflective-lark.md`.
|
||||
|
||||
<a id="tp37"></a>
|
||||
### TP38 — Out-of-Band-Management: ein untagged-VLAN99-Port je Switch ▸ 🔜 **ANGELEGT 2026-08-31**
|
||||
|
||||
Reference in New Issue
Block a user