# Handoff 2026-08-27 — Inventur + Asymmetrie + Architektur-Vorschlag > Bezug: TP34 (Caddyfile via Nautobot/GC, neu, Stub-Eintrag in `docs/teilprojekte.md`). > Inventur-Session mit Christoph, alles Read-Only geprüft (CF-API live, MikroMCP-ARP live, > Gitea-REST live). ## TL;DR - `bf-infra` ist **aktiver Fork** von `bf-network-r6`; aktiv gepflegt, **kein Gitea-Remote** → Backup-Lücke. - 🔴 **Korrektur 2026-08-30 (Befund steht, Schlussfolgerung überholt):** das Remote existiert inzwischen — `origin` = `https://gitea.emsenhuber.net/admin/bf-infra.git`, `origin/main` = `b917691` (2026-08-28). Der Satz oben war am 08-27 zutreffend und ist **bewusst erhalten**; er darf aber nicht mehr als Ist gelesen werden. Die Backup-Lücke schließt ein `git push`, kein neues Repo. - `admin/bf-network-r6` (Gitea) = historischer Master, letzte aktive Commits 2026-08-25 → auf read-only stellen (deine Aktion). - `admin/bf-golden-config` (Gitea) = Bot-Master (Nautobot BACKUP/GENERATE 2×/Tag) → kein lokaler Mirror. - `admin/blaueblueten-n8n` (Gitea) = Master für terpene-Repo, aktiv. - Inventar-Pipeline gelöscht (XLSX stale seit 2025-06-05, vor Core-Cutover; Live-Daten via MikroMCP/CF/Portainer). - Architektur-Vorschlag: **Caddyfile als Generated aus Nautobot/GC**, nicht handgeschrieben (TP34). ## Drift-Befund (Phase 0) | # | Quelle A | Quelle B | Konflikt | Einschätzung „wahrscheinlich richtig" | |---|---|---|---|---| | **D1** | `inventory/bf.csv`/`bf.md` (219× `10.40.41.x`) | CLAUDE.md / teilprojekte.md (`10.40.20.x`) | Inventar führt altes VLAN1-Subnetz | Inventar war tot; **gelöscht**. CLAUDE.md ist richtig. | | **D2** | Caddyfile → `10.40.20.167:5678` | Mac mini ARP-reachable | Konsistent | Caddyfile ist richtig, Tunnel ist nur Ingress für CF-CNAMEs. | | **D3** | `cf-tunnel-mapping.md` §15-Tabelle: `terpene-db` 1 Connector | Live CF-API: `terpene-db` 4 Connectoren | Doku-Drift | Live ist richtig, Doku-Stand 08-25. | | **D4** | `STATUS.md` Z.47: „Ingress `terpene.teilzeitladen.xyz` → `macmini:8890`" | Live: kein Tunnel hat diesen Hostname | Doku-Lüge | STATUS.md ist veraltet; **kein CNAME, kein Ingress**. Worker läuft nur über CF-Workers-Custom-Domain `420.teilzeitladen.xyz`. | | **D5** | `~/.claude.json` enthält `terpene-pg` MCP | `pg_hba.conf` blockiert `10.40.10.0/24` | Geistereintrag | MCP konfiguriert, scheitert aber. Entscheidung offen (Fix oder Austragen). | | **D6** | `~/.claude.json` 9 MCPs vs. `mcp/INVENTORY.md` 4 | Unterschiedlicher Scope | Beide richtig | `~/.claude.json` = globaler Werkzeugkasten, INVENTORY = BF-Netz-SSoT. Keine Synchronisation nötig, Notiz reicht. | | **D7** | `memory/project_tp2_topology.md` | TP2 RETIRED (Omada) | Tote Memory-Datei | **Gelöscht** (im selben Commit mit Inventar). | | **D8** | `handoff.md` im Root | Konvention: `docs/handoff-YYYYMMDD-thema.md` | Konventionsbruch | **Verschoben** zu `docs/handoff-20260827-hubert-und-altlasten.md`. | | **D9** | `cf-tunnel-mapping.md` §10: `bf-nas = 70d6a4cf` | Live: `bf-nas = 220c9958` | §10 stale, §15-Nachtrag korrigiert | §15 hat es; §10 nicht. Kosmetik. | | **D10** | Gitea `bf-network-r6/docs/cf-tunnel-mapping.md` | Lokal `~/dev/bf-infra/docs/cf-tunnel-mapping.md` | Gitea ist 1 Comm voraus, lokal ist Import-Stand | Gitea ist Master; Lokal ist veraltet (kein Sync). | ## Veraltet / tot (bereits aufgelöst) | # | Was | Aktion | |---|---|---| | T1 | `inventory/bf.csv`, `bf.md`, `IPs.xlsx`, `build.py`, `bf-core-ports.*` | gelöscht (Commit 1) | | T2 | `memory/project_tp2_topology.md` | gelöscht | | T3 | `handoff.md` im Root | verschoben nach `docs/handoff-20260827-…` | | T4 | `STATUS.md` Z.47 (Mac-mini-Ingress) | offen, manuelle Edit (nächste terpene-Session) | | T5 | `bf-public` Tunnel (inactive, 0 Connector) | bewusst aufgehoben, Teil von TP31 Schritt 5/6 | ## Asymmetrie (Repo-Struktur) | Repo | Lokal? | Gitea? | Master? | |---|---|---|---| | `bf-infra` | ✅ Working-Copy | ❌ kein Remote | **lokal** (Sicherheitsrisiko) | | `bf-network-r6` | ✅ Mirror | ✅ Master (read-only geplant) | Gitea | | `bf-golden-config` | ❌ kein Mirror | ✅ Master (Nautobot-Bot) | Gitea | | `blaueblueten-n8n` | ✅ Mirror | ✅ Master | Gitea + lokal synchron | **Dringlichkeit:** `bf-infra` ohne Remote = alle Edits nur lokal, kein Backup. **Festplattencrash = Datenverlust.** ## Inventar-Entscheidung - Pipeline war seit **2025-06-05** tot: `IPs.xlsx` (Quelle) ist nicht aktualisiert, `build.py` rendert nur. - Inventar ist seit Core-Cutover (2026-08-08) **inhaltlich falsch** (alle IPs `10.40.41.x`). - Live-Daten kommen jetzt aus **MikroMCP** (ARP/DHCP/Interface je Router), **CF-API** (Tunnel/Ingress), **pve-mcp** (VM/LXC), **Portainer/Komodo** (Container). - **Entscheidung: Inventar-Datei löschen.** Live-Tooling deckt den Bedarf. ## Architektur-Vorschlag (TP34 — Caddyfile via Nautobot/GC) ### Warum Heute ist der Caddyfile (16 Sites, `bf-infra/caddy/Caddyfile`) **manuell gepflegt**. Problem: - **Manuelle Edits** erlauben Drift. - **Keine generische Schnittstelle**: andere Projekte (terpene, blaueblueten-n8n) können keine Sites anlegen, ohne Christoph zu fragen. - **Kein Compliance-Check**: ein fehlerhafter Block bleibt stehen, bis jemand manuell vergleicht. - **Keine Transaktionen**: ein kaputter Eintrag bricht die ganze Datei. ### Zielbild Caddyfile wird **generated** aus einem **Nautobot-Datenmodell** + **Golden Config Pipeline**, identisch zum bestehenden Workflow für Router-Configs. ### Datenmodell (Skizze) Nautobot-Entities: - **Site**: `bf`, `fm`, `dw` (Standort, gehört zu ggf. `cf-public` Catch-all) - **Host**: `vw.bf.emsenhuber.net` — mit Attributen `site`, `public` (boolean), `access_policy` (optional) - **Backend**: `10.40.20.127` (Vaultwarden) — mit Attributen `protocol` (http/https), `tls_insecure` (bool), `host_header` (optional) - **SiteBinding**: Host ↔ Backend (m:n, falls mehrere Backends pro Host) ### GC-Workflow (Skizze) 1. **Generate**: Golden Config rendert aus Nautobot-Daten den Caddyfile. 2. **Diff**: gegen die Live-Version auf `caddy-bf1` (Caddy-Admin-API `:2019/config/`). 3. **Compliance**: Pflichtfelder (jeder Host braucht Backend, jeder Backend braucht Protokoll), keine hardcoded IPs in Caddyfile, keine `tls_insecure_skip_verify` ohne Annotation. 4. **Transaktion**: Snapshot vor Deploy, Rollback bei Fehler. ### Erster Anwendungsfall: terpene.teilzeitladen.xyz - Backend: `http://10.40.20.167:8890` (Mac mini, Caddy dort bedient PostgREST + sync + web) - Access: CF-Access mit Service-Token `terpene-verify-v2` - **Vorteil**: terpene-Caddyfile-Block wird in 30 Sekunden via `nautobot/gc-configplan.py` deployed, mit Diff und Rollback. Backfill-SQL ist dann via `admin/migrate` callbar. ### Abhängigkeiten - **TP22** (Golden Config Pipeline) ✅ vorhanden - **TP23** (DNS-Policy + Caddy-Schnittstelle-Voraussetzungen) ✅ Stufe 1 - Hängt an **nichts** außer der Implementierung. ### Status 🔜 Stub. Implementierung in eigenem Runbook, nach terpene-Caddy-Block (Quick-Win). ## Übergangsplan bf-network-r6 → bf-infra | Schritt | Wer | Wann | |---|---|---| | bf-infra lokal Master (dieser Commit) | ich | ✅ | | bf-network-r6 im Gitea: read-only + Header mit Verweis | du | offen | | bf-infra bekommt Gitea-Remote (`admin/bf-infra` neu) | offen, „später" | nach terpene-Caddy-Block | | Caddyfile-Master wandert zu Nautobot/GC (TP34) | nach terpene | nach Quick-Win | ## Offene Punkte (für nächste Session) - **terpene-Caddy-Block** (zeitkritisch): Quick-Win vor TP34, manueller Eintrag in `bf-infra/caddy/Caddyfile` für `terpene.teilzeitladen.xyz → http://10.40.20.167:8890`. Mit Commit-Kommentar, dass das nicht das Pattern ist. - **`STATUS.md` Z.47** korrigieren: Streichen oder Realität einarbeiten. - **`~/.claude.json` `terpene-pg`**: deine Aktion (pg_hba-Erweiterung oder austragen). - **TP34 Implementierung**: Runbook + Nautobot-Datenmodell-Skizze, sobald terpene-Caddy-Block committed ist. ## Selbstkritik / Lessons Learned für Sessions - **Bestandsaufnahme vor Plan.** Erst was ist da, wo ist der Schaden — dann Vorschläge. Nicht umgekehrt. - **Eine große Fragenrunde statt vieler kleiner.** Wenn der Plan von Annahmen abhängt, sammle die Annahmen in einer Runde, nicht in 3–4 Mikrorunden. - **Master-Frage früh stellen.** Bei jedem Repo, jeder Datei, jedem Tooling: „Was ist die SSoT, wo lebt der Master, was ist Mirror?" — bevor du eine Lösung vorschlägst. - **Drift zuerst, Lösungen später.** Drift-Tabelle posten + fragen, was richtig ist. Keine Lösungen vor dem Befund. ## Stand - 2026-08-27 - Inventur-Session mit Christoph - Commits: `8d2b4a7` (Aufräumen) + dieser Handoff-Commit