Zum Hauptinhalt springen

Backup & Restore (Point-in-Time) — OP-BACKUP-1

Status: Design (kein Code) — Kernentscheidungen ✅ (E-BACKUP-1/2/3, Sign-off 2026-06-27, §8); Slices B5-1…B5-5 offen (§7) · Bezug: OP-BACKUP-1 (Owning) · OP-SEED-1 (Purge = destruktiver Auslöser) · OP-AUDIT-1 (Zeitachse) · OP-DATA-1/S-SEED-5 · OP-TENANT · OP-COMPLIANCE-1 · Zielgruppe: IT-Dev/Architektur · True North: nur indirekt (Sicherheitsnetz für die Datenbasis der drei Leitfragen — beantwortet selbst keine davon)

Kernaussage. Taktano bekommt ein Sicherungs-/Wiederherstellungs-Konzept mit Point-in-Time-Restore (PITR) je Mandant — Auslöser: der Purge (OP-SEED-1) ist destruktiv & irreversibel, vor Produktivgang braucht es ein Sicherheitsnetz. Entschieden (§8): PITR kommt nativ aus DO-SQLite (E-BACKUP-1). Wichtig: der native Restore setzt die gesamte DO-Datenbank zurück (keine Tabellen-Selektivität) — die Leitlinie „das Audit-Log wird nie mitgerollt" (§5, append-only; der Restore ist selbst ein Audit-Event) verlangt daher ein explizites Audit-Handling beim Restore: Audit-Delta vor dem Rollback exportieren und danach re-appenden, oder das Audit in eine eigene Storage-Grenze legen (Festlegung im Restore-Slice). Die beiden Auftraggeber-Kernfragen sind beantwortet: (a) der Rollback-Zeitpunkt wird über die Audit-Timeline bestimmt (§4), (b) das Audit-Log bleibt beim Rollback unangetastet (§5). Als Sofort-Netz dient ein Pre-Purge-Snapshot nach R2 (B5-1); Retention 30 Tage rollierend (E-BACKUP-2).

1. Motivation & Geltungsbereich

  • Destruktive Aktionen ohne Netz: admin.purge (OP-SEED-1) löscht den gesamten Datenbestand eines Mandanten; heute geschützt nur durch Admin-Gate + Tipp-Bestätigung. Auch fehlerhafte Massen-Edits oder ein verkorkster Import brauchen einen Weg zurück.
  • Geltungsbereich: der fachliche Mandanten-Zustand (DO-State: Aufträge, Belegung, Stammdaten, Historien-Listen, Fotos-Metadaten). Das Audit-Log (OP-AUDIT-1) ist kein Backup-Ziel, sondern die Zeitachse, an der ein Restore ausgerichtet wird (§4/§5). Foto-Bytes (R2) sind versioniert/separat.
  • Je Mandant (tenant_id): Backup, Restore und Aufbewahrung sind tenant-skopiert (OP-TENANT).

2. Zwei Granularitäten — Snapshot vs. echtes PITR

Voll-SnapshotPoint-in-Time (PITR)
Ideeperiodische Komplettkopie des Zustandsjeden Zustand zwischen zwei Snapshots rekonstruierbar
MechanikDO-State serialisieren → AblageSnapshot + lückenloser Änderungs-Strom (Event-Log/WAL) zum Vorspulen
Restore-Ziel„Stand von Snapshot X"„Stand exakt vor Aktion Y / Zeit T"
Kostengeringhöher (Event-Strom + Replay/Reconstruct)

Der Auftraggeber-Wunsch ist PITR. Dafür gibt es zwei grundverschiedene Wege (§3).

3. Architektur-Wege (⮕ Entscheidung, hängt an OP-DATA-1)

  • (A) Snapshot-Kadenz (pragmatisch, sofort machbar). DO-State periodisch (Cron/Alarm) und vor jeder destruktiven Aktion (Purge/Tenant-Reset/Massen-Import) nach R2 (oder D1) sichern; Restore = Snapshot zurückspielen. „PITR" nur in Snapshot-Granularität (z. B. stündlich + pre-op). Einfach, robust, grob.
  • (B) Event-Sourcing/Replay (feinkörnig). Snapshot + append-only Mutations-Log → Restore spult bis zum Ziel-Zeitpunkt vor. Echtes PITR, aber jede DO-Mutation muss revisionssicher protokolliert werden (großer Eingriff; teilweise deckungsgleich mit OP-AUDIT-1 Slice 2 „breite Event-Erfassung").
  • (C) DO-SQLite-natives PITR (stärkste Option, hängt an OP-DATA-1 / E-DATA-1=B). Cloudflare Durable Objects mit SQLite-Storage bieten natives Point-in-Time-Recovery (Wiederherstellung auf einen Zeitpunkt innerhalb eines Retention-Fensters) — ohne eigenes Event-Log. Wenn der Live-State nach DO-SQLite wandert (Persistenz-Entscheidung E-DATA-1=B, docs/architektur/Persistenz.md §4), bekommt OP-BACKUP-1 PITR fast geschenkt. Das ist der stärkste Hebel und der Grund, OP-BACKUP-1 und OP-DATA-1 gemeinsam zu entscheiden.

Empfehlung: (A) als Sofort-Sicherheitsnetz (pre-Purge-Snapshot nach R2 — schließt die akute Irreversibilitäts-Lücke), und die PITR-Strategie an OP-DATA-1 koppeln: fällt E-DATA-1 auf DO-SQLite (B), dann (C) als PITR-Mechanik nutzen statt ein eigenes Event-Log (B-Variante) zu bauen.

4. Rollback-Zeitpunkt über das Audit-Log bestimmen (Frage a)

Das append-only Audit-Log (OP-AUDIT-1, D1) ist die fachliche Zeitachse: wer·was·wann (ts, event_type, actor_id, summary, resource_*). Der Restore-Dialog nutzt es als Auswahl-/Begründungsoberfläche:

  • Admin filtert die Audit-Timeline (je Mandant) und wählt „zurück auf den Stand vor Ereignis E" bzw. „… vor Zeit T". E.ts liefert den Ziel-Zeitstempel.
  • Der Ziel-Zeitstempel wird auf die Backup-Mechanik abgebildet: (A) nächster Snapshot ≤ T; (C) exakter PITR-Zeitpunkt T.
  • Vorschau vor Bestätigung: „dieser Restore verwirft N Audit-Ereignisse nach T" (rein informativ — die Ereignisse selbst bleiben, siehe §5) + Diff-Kurzfassung. Restore ist selbst eine destruktive Aktion → gleiche Schutzstufe wie Purge (Rollen-Gate, Bestätigung).

5. Was passiert mit dem Audit-Log beim Rollback? (Frage b) — Leitlinie festgezurrt

Das Audit-Log wird NICHT mitgerollt. Es bleibt append-only und unveränderlich.

Begründung (OP-AUDIT-1): das Audit-Log ist die revisionssichere, „nicht reverse-engineerbare" Historie (Compliance/TÜV/ISO, OP-COMPLIANCE-1). Würde man es mit zurückrollen, wäre es manipulierbar — der Rollback selbst würde unsichtbar. Das widerspräche dem Zweck.

Konsequenzen:

  • Mechanik-Randbedingung (07-12): Der native DO-SQLite-PITR setzt die gesamte DO-Datenbank zurück — eine tabellen-selektive Wiederherstellung gibt es nicht. Liegt das Audit-Log (per OP-TENANT-Entscheid) in derselben DO-Datenbank, muss der Restore-Slice das Audit vor dem Rollback exportieren und danach re-appenden (oder das Audit in eine eigene Storage-Grenze legen) — sonst wäre die Leitlinie verletzt.
  • Der Restore ist selbst ein neues Audit-Ereignis: event_type = 'state.restore', actor_id, Ziel-Zeitpunkt T, gewählter Snapshot/PITR-Punkt, betroffener tenant_id, Begründung. So bleibt lückenlos sichtbar: „Am … hat … auf den Stand von T zurückgesetzt."
  • Die Audit-Einträge zwischen T und jetzt bleiben erhalten (sie sind Tatsachen — sie sind passiert). Es entsteht also bewusst eine Divergenz: der fachliche Zustand ist auf T, das Audit-Log läuft durch. Das ist korrekt und gewollt (das Log dokumentiert die Realität inkl. des Rollbacks).
  • Reconciliation-Regel: nach einem Restore können Audit-Einträge auf Ressourcen verweisen, die im zurückgesetzten Zustand nicht (mehr) existieren. Lese-/Diff-Werkzeuge müssen gegen den state.restore- Marker robust sein (Ereignisse vor dem Restore-Marker beziehen sich auf einen verworfenen Zweig).
  • E-BACKUP-3 ✅ entschieden 06-27 = ja: verworfene Post-T-Ereignisse werden in Audit-Sichten als „durch Restore überholt" markiert — rein darstellungsseitig aus dem state.restore-Marker abgeleitet, kein Schreibzugriff aufs Log.
  • Restore-Vertrag „Fachzustand auf T, Audit unangetastet" (E-BACKUP-1, entschieden 06-27; Mechanik präzisiert 07-12): Da das Audit unter E-TENANT-1=C in derselben DO-SQLite liegt und der native PITR nur die ganze DO zurücksetzen kann, erfüllt der Restore-Slice den Vertrag zweistufig: Audit-Delta (alle Events, insbesondere nach T) vor dem Rollback exportieren → Whole-DO-PITR auf T → Audit-Delta re-appenden (append-only bleibt gewahrt, kein Event geht verloren). Alternative, falls der Re-Append-Weg im Slice B5-5 nicht trägt: Audit in eine eigene Storage-Grenze legen. §8/§3.

6. DSGVO / Residenz / Aufbewahrung

  • EU-Residenz für alle Backups (R2 eu / D1 weur), konsistent mit Audit/Foto (OP-COMPLIANCE-1).
  • Aufbewahrungsfrist = 30 Tage rollierend (E-BACKUP-2, deckt sich mit dem PITR-Fenster) + Recht-auf-Vergessen: Live-Daten sofort gelöscht, Backups altern aus → dokumentierte Lösch-SLA „aus Backups in ≤30 Tagen". PII im Audit ist bereits gescrubbt (delta_json); Snapshots enthalten Vollzustand inkl. PII → kurze Retention + Plattform-Verschlüsselung at-rest (per-Tenant-Krypto = E-TENANT-3, zurückgestellt).
  • Zugriff: Restore ist Owner-/Admin-rollen-gebunden (OP-AUTH-1; heute interim derselbe Gate wie Purge/Kosten).

7. Slices

  • B5-1 · Pre-Purge-Snapshot (Sofort-Netz). Vor admin.purge (und Tenant-Reset) den DO-State nach R2 sichern (tenant/<id>/pre-purge-<ts>.json, verschlüsselt, kurze Retention) + Audit-Event. Schließt die akute Irreversibilitäts-Lücke ohne die große PITR-Frage zu lösen.
  • B5-2 · Manueller Restore-Pfad. Admin-Aktion „Stand wiederherstellen" (Snapshot wählen → Vorschau → Bestätigung → state.restore-Audit-Event). Rollen-gegated.
  • B5-3 · Periodische Snapshots (Cron/Alarm) + Retention + Restore-Index (D1, tenant_id).
  • B5-4 · Audit-getriebene Auswahl (§4): Restore-Punkt aus der Audit-Timeline wählen.
  • B5-5 · Echtes PITR = native DO-SQLite-PITR (Whole-DO) + Audit-Export/Re-Append (E-BACKUP-1): Audit-Delta sichern → Whole-DO-PITR auf T → Audit re-appenden + state.restore-Event; Ergebnis-Vertrag: Fachzustand auf T, Audit lückenlos. Setzt die DO-SQLite-Migration (OP-DATA-1 D5-3 / OP-TENANT T-2) voraus.

8. Entscheidungen (Sign-off 2026-06-27)

  • E-BACKUP-1 ✅ = native DO-SQLite-PITR als Quelle; Vertrag „Fachzustand auf T, Audit unangetastet". PITR (≈30-Tage-Fenster) ist die Quelle. Mechanik-Präzisierung 07-12: der native PITR kann nur die gesamte DO zurücksetzen (keine Tabellen-Selektivität) — der Vertrag wird daher zweistufig erfüllt: Audit-Delta exportieren → Whole-DO-PITR auf T → Audit re-appenden (kein blinder Whole-DO-Rollback ohne Audit-Sicherung — der würde die Events zwischen T und jetzt vernichten, §5); Fallback = eigene Audit-Storage-Grenze. Plus B5-1 (Pre-Purge-Snapshot nach R2) als Sofort-Netz bis die DO-SQLite-Migration steht. Kein eigenes Event-Log nötig.
  • E-BACKUP-2 ✅ = 30 Tage rollierende Retention (deckt sich mit dem PITR-Fenster), Plattform- Verschlüsselung at-rest (per-Tenant-Krypto = E-TENANT-3, zurückgestellt). Recht-auf-Vergessen: Live-Daten sofort gelöscht, Backups altern aus → dokumentierte Lösch-SLA „aus Backups in ≤30 Tagen". Audit ist von der Löschung ausgenommen (Aufbewahrungspflicht/berechtigtes Interesse), enthält aber nur PII-gescrubbte Deltas.
  • E-BACKUP-3 ✅ = ja, rein darstellungsseitig. Audit-Einträge vor einem state.restore-Marker werden in Sichten als „durch Restore überholt" markiert — read-only aus dem Marker abgeleitet, kein Schreibzugriff aufs Log.

9. Bezüge

OP-SEED-1 (Purge = der destruktive Auslöser; B5-1 ist dessen Sicherheitsnetz) · OP-AUDIT-1 (Zeitachse

  • Unveränderlichkeit, state.restore-Event) · OP-DATA-1 / S-SEED-5 (docs/architektur/Persistenz.md — Heimat der Daten bestimmt die PITR-Mechanik) · OP-EXPORT-1 (Export ⊂ Backup) · OP-AUTH-1 (Rollen-Gate) · OP-TENANT (Tenant-Scope) · OP-COMPLIANCE-1 (DSGVO/Residenz/Retention). Tracking: HANDOFF §4 (OP-BACKUP-1).

↩ Zurück zur Doku-Landkarte · Lesepfade · Register (alle OPs)