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-Snapshot | Point-in-Time (PITR) | |
|---|---|---|
| Idee | periodische Komplettkopie des Zustands | jeden Zustand zwischen zwei Snapshots rekonstruierbar |
| Mechanik | DO-State serialisieren → Ablage | Snapshot + lückenloser Änderungs-Strom (Event-Log/WAL) zum Vorspulen |
| Restore-Ziel | „Stand von Snapshot X" | „Stand exakt vor Aktion Y / Zeit T" |
| Kosten | gering | hö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.tsliefert 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, betroffenertenant_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/ D1weur), 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)