# Update-/Rollback-Protokoll — Probe in der isolierten Umgebung (Issue #221) Nachweis für Maßnahmenplan P1-3 (ADR 0024): der Update-Pfad inklusive Migrationen und geprobtem Fehlschlag-Rollback, ausgeführt in derselben netzisolierten Umgebung wie der Isolationslauf (`97-isolationslauf-protokoll.md` — Compose-Projekt `dorfteich-isolated`, alle Netze `internal: true`, kein Egress-Pfad). Belegstufe: **live verifiziert**. Die daraus destillierte Prozedur steht in `docs/operations/update-runbook.md`. - **Datum:** 2026-07-31 - **Ausgangsstand („v1"):** Images `dorfteich-iso-*:isolated` (`main@a758c9d`, backup mit #288-Fix aus `4f6596e`), Instanz mit Inhalt aus dem Isolationslauf. - **Update-Ziel („v2"):** Images `dorfteich-iso-*:isolated-v2`, gebaut aus dem Kettenstand `ccffcaa` (#288 + #220) — als Stellvertreter eines regulären Release-Bundles; die Beschaffung/Digest-Prüfung eines echten Bundles ist das Mirror-Verfahren (#218, `95-mirror-protokoll.md`) und wurde dort bereits nachgewiesen. - **Fehlschlag-Kandidat („bad"):** api-Image mit einer absichtlich fehlschlagenden Migration (`20260731230000_deliberately_failing_update`: `ALTER TABLE` + `SELECT 1/0`), nur für die Probe gebaut, nie committet. ## Phase A — reguläres Update | Schritt | Ergebnis | | ------------------- | --------------------------------------------------------------------------------------------- | | Pre-Update-Backup | ✅ Set `20260731-150833` über die Admin-API erzeugt und in der Set-Liste bestätigt | | `TAG` → v2, `up -d` | ✅ alle vier eigenen Services zusammen ersetzt (Ausfallfenster Sekunden, kein Rolling Update) | | Migrationen | ✅ migrate-on-start läuft durch (dieses „Release" enthält keine neuen Migrationen) | | `/readyz` | ✅ vollständig grün | | Inhalt | ✅ Seite „Isolationstest Seite" unverändert vorhanden | ## Phase B — geprobter Fehlschlag + Rollback 1. **Bad-Update einspielen** (`TAG` → bad, `up -d`): api scheitert beim Boot in `migrate deploy` — **P3018**, `ERROR: division by zero` bei `20260731230000_deliberately_failing_update`; Container geht in den Restart-Loop, jeder Folge-Boot meldet **P3009** („migrate found failed migrations"). 2. **Datenbank-Zustand geprüft:** die Migration steht als `failed` in `_prisma_migrations` (Logs erfasst), aber `broken_column` existiert **nicht** — die per-Migration-Transaktion hat den Schema-Eingriff zurückgerollt. Genau das dokumentierte Verhalten. 3. **Image-Rollback allein reicht nicht** (bewusst vorgeführt): `TAG` zurück auf v2, `up -d` — der alte Stand scheitert weiter mit **P3009** („The 20260731230000_deliberately_failing_update migration started at 2026-07-31 15:10:50 UTC failed"). 4. **Recovery wie im Runbook:** `migrate resolve --rolled-back 20260731230000_deliberately_failing_update` (im api-Image ausgeführt) → „marked as rolled back" → api-Neustart: `/readyz` vollständig grün, Inhalt unverändert, Migrations-Row trägt `rolled_back_at`. 5. **Alternativer Weg zurück** (für semantisch irreversible, aber erfolgreich gelaufene Migrationen): Restore des Pre-Update-Sets — der Restore-Pfad selbst ist im Isolationslauf verifiziert (`97-isolationslauf-protokoll.md`, Fix #288). ## Versions-Skew (Akzeptanzkriterium) Ein Compose-Stage kennt **kein Rolling Update**: `docker compose up -d` ersetzt web/api/collab/backup zusammen; Mischbetrieb alter und neuer Versionen ist kein unterstützter Betriebszustand und dauert nur die Container-Ersetzung selbst (Sekunden). Für VS-Zonen heißt das: Update im angekündigten Wartungsfenster; die Migrationen wendet ausschließlich der neue api-Container beim Start an (`MIGRATE_ON_START`). ## Rückfluss - **`docs/operations/update-runbook.md`** — die Prozedur (Beschaffen, Prüfen, Sichern, Einspielen, Verifizieren, Rollback) inkl. explizitem Migrationsverhalten; aus dieser Probe destilliert. - **`docs/operations/restore-runbook.md`** — Querverweis: Restore als einziger Weg zurück nach irreversiblen Migrationen. - **#229** — Betriebshandbuch §1 (Airgap) und §2 (Update/Rollback) verweisen auf Runbook und dieses Protokoll.