Files
nexarch/archive/docs/BAK-04-PRUEFPROTOKOLL.md
T
sysops 80b0ca9176 feat(archive): BAK-04 Tenant-Backup & -Restore einzelner Mandant
internal/tenantbackup: datenbank-scharfes pg_dump/pg_restore statt
BAK-01s Cluster-weitem pg_basebackup - bei Modell C (TEN-01, physisch
isolierte DB je Mandant) wuerde ein Cluster-Restore zwangslaeufig ALLE
Mandanten ueberschreiben. Objekt-Seite nutzt BAK-02 direkt (Mandanten
haben eigene Buckets/Pfad-Roots). Eigene Postgres-Rolle
nexarch_tenantbackup (CREATEDB, kein Superuser, getrennt von
nexarch_backup). Zwei-Tenant-Isolation real in beide Richtungen
bewiesen (Markerwert-Nachweis), JSONL-Protokoll fuer Sicherung UND
Restore. Realer End-zu-Ende-Lauf ueber tenantbackup-cli auf 131.
2026-08-30 00:41:48 +02:00

124 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# BAK-04 Prüfprotokoll: Tenant-Backup & -Restore (einzelner Mandant)
Voraussetzung BAK-03 erledigt, siehe eigenes Protokoll.
## Grundsatzentscheidung: eigenes Verfahren, NICHT auf BAK-01/BAK-03 aufgesetzt
Nutzer-Rückfrage vor Implementierungsbeginn bestätigte einen realen
Architekturkonflikt: `pg_basebackup` (BAK-01) sichert den GESAMTEN
Postgres-Cluster. Bei Modell C (TEN-01: eine physisch isolierte
Datenbank je Mandant) liegen ALLE Mandanten-Datenbanken im selben
Cluster — ein Restore der BAK-01-Sicherung würde zwangsläufig ALLE
Mandanten gleichzeitig überschreiben, das Gegenteil von
Mandanten-Isolation. `internal/tenantbackup` verwendet daher ein
DATENBANK-SCHARFES logisches Verfahren (`pg_dump -Fc`/`pg_restore` für
GENAU EINE benannte Datenbank), keine physische Cluster-Sicherung.
Objekt-Storage-Seite: da jeder Mandant bereits einen eigenen
Bucket/Pfad-Root hat (`STORAGE-KONZEPT.md` Abschnitt 3), genügt ein
`objectbackup`-Aufruf pro Mandanten-Root — keine neue Objekt-Storage-Logik
nötig, das bestehende BAK-02-Paket direkt wiederverwendet.
## Zweite Rückfrage geklärt: OPS-03/`metrics_sources` kennt keine
## Tenant-Label-Dimension auf Schema-Ebene
`metrics_sources` ist `module_name TEXT PRIMARY KEY, metrics_url TEXT`
ein Eintrag pro DIENST, kein Tenant-Feld. Labels (z. B. `tenant="..."`)
sind ein Prometheus-Textformat-Konzept INNERHALB der von einem Dienst
exportierten Metrik, nicht Teil von `metrics_sources`. Ein
`tenant_restore_failed_total{tenant="..."}`-Export wäre daher technisch
möglich, ohne OPS-03s Schema zu ändern (derselbe Mechanismus wie
BAK-06s `{kind="database"}`-Labels). **Bewusst nicht umgesetzt** in
diesem Ticket: BAK-04s Akzeptanzkriterien fordern "vollständig
protokolliert" (JSONL-Log, siehe unten), keine OPS-05-Alarmierung — eine
`/metrics`-Anbindung wäre zusätzlicher Scope über das Ticket hinaus und
bleibt als dokumentierter, leicht nachziehbarer Folgeschritt offen
(gleiches Muster wie zuvor bei BAK-05s Meldeweg-Frage).
## Reale Betriebsrollen-Grenze gefunden (dokumentiert, nicht verschwiegen)
Die für BAK-04 nötige Postgres-Rolle braucht `CREATEDB` (isolierte
Zieldatenbanken anlegen) — bewusst NICHT `nexarch_backup` erweitert
(jene Rolle hat nur `REPLICATION`, Prinzip geringster Rechte aus BAK-01).
Neue, eigene Rolle `nexarch_tenantbackup` angelegt. Beim ersten echten
Restore-Versuch schlug `pg_restore` mit `permission denied for schema
public` fehl (Versuch, Tabellen auf den URSPRÜNGLICHEN Tenant-Eigentümer
umzueignen) — behoben mit `pg_restore --no-owner` (Standardpraxis beim
Restore in eine andere Umgebung/Rolle, Eigentümerschaft ist für den
Restore-Nachweis irrelevant). Für PRODUKTIVE Mandanten-Datenbanken (nach
echter TEN-01-Provisionierung) muss `nexarch_tenantbackup` je Mandant
Lesezugriff erhalten (z. B. Rollenmitgliedschaft) — hier für den
Testnachweis exemplarisch für `dms_tenant_test` eingerichtet, echte
Automatisierung dieses Zugriffs ist TEN-01/TEN-07-Folgearbeit.
## Umsetzung
- `internal/tenantbackup.Backup``pg_dump -Fc` für genau eine
Datenbank.
- `internal/tenantbackup.Verify``pg_restore -l`, volle
Inhaltslisten-Prüfung (nicht nur Dateikopf).
- `internal/tenantbackup.CreateEmptyDatabase` — schlägt fehl, wenn
Zieldatenbank bereits existiert (kein stiller Overwrite, dieselbe
Disziplin wie BAK-03s `internal/restore`).
- `internal/tenantbackup.Restore``pg_restore --no-owner`.
- `internal/tenantbackup.AppendLog`/`ReadLog` — JSONL,
Sicherung UND Restore beide protokolliert (Akzeptanzkriterium 3).
- `cmd/tenantbackup-cli``backup <tenant-db> <storage-root>` /
`restore <tenant-db> <ziel-db> <dump> [<snapshot-id> <objekt-ziel>]`.
## Prüfungen
| # | Prüfung | Ergebnis |
|---|---|---|
| 1 | Sicherung von Tenant A enthält keine Datensätze von Tenant B (Stichprobe) | **bestanden**`TestBackupRestore_RecoversExactTenantData`: Tenant A mit eindeutigem Markerwert gesichert und in isolierte Zieldatenbank wiederhergestellt, Markerwert stimmt exakt; strukturell ist ein Cross-Tenant-Leck ausgeschlossen, weil `pg_dump` ausschließlich mit der EINEN übergebenen Datenbankverbindung spricht (Modell C, TEN-01) |
| 2 | Wiederherstellung von Tenant A in eine Testumgebung verändert Tenant B dort nicht | **bestanden**`TestRestore_DoesNotAffectOtherTenant`: reales zweites Tenant-DB mit eigenem Markerwert angelegt, nach Restore von Tenant A unverändert (Markerwert UND Datenbank-Existenz geprüft) |
| 3 | Tenant-Sicherung und -Restore vollständig protokolliert | **bestanden**`TestLog_BackupAndRestoreFullyLogged`; real auf 131: `tenantbackup.log` zeigt beide Operationen (`backup_database`, `backup_objects`, `restore_database`, `restore_objects`) mit Zeitstempel/Quelle/Ziel/Ergebnis |
Zusätzlich: `TestVerify_DetectsCorruptedDump` (absichtlich beschädigtes
Dump-Archiv wird erkannt).
## Echte Verdrahtung auf 192.168.1.131
- `tenantbackup-cli` gebaut nach `/opt/nexarch-archive/bin/`
- Eigene Postgres-Rolle `nexarch_tenantbackup` (`CREATEDB`, kein
Superuser) angelegt — getrennt von `nexarch_backup` (Prinzip
geringster Rechte)
- `/etc/nexarch/archive-tenantbackup.env` (0600)
- Realer End-zu-Ende-Lauf über `tenantbackup-cli` (nicht nur Testcode):
Sicherung von `dms_tenant_test` (DB-Dump + Objekt-Snapshot eines
Demo-Verzeichnisses) → Restore in isolierte Zieldatenbank
(`dms_tenant_test_restore_demo`) UND isoliertes Zielverzeichnis →
Objektinhalt real gelesen und bestätigt (`demo-tenant-objekt-inhalt`)
→ Protokolldatei zeigt alle vier Operationen korrekt → Testartefakte
anschließend entfernt (Zieldatenbank gedroppt, Demo-Verzeichnisse
gelöscht)
- `nexarch-archive-tenantbackup.{service,timer}.tmpl` als Vorlage
bereitgestellt (unabhängiger Zeitplan, Akzeptanzkriterium 3) — bewusst
NICHT auf einen festen Mandanten scharf geschaltet installiert, da
TEN-01s echte Tenant-Registry auf 192.168.1.131 noch nicht produktiv
befüllt ist (nur die Test-Tenant-DB `dms_tenant_test` existiert); reale
Aktivierung pro Mandant folgt, sobald eine echte Registry-Abfrage dafür
vorliegt (dokumentierter, kein stiller Gap)
## Build/Test-Ergebnis (192.168.1.131, `make check`)
```
go build ./... -> clean
go vet ./... -> clean
golangci-lint run ./... -> 0 issues
go test ./... -p 1 -count=1 -> 7/7 Pakete mit Tests ok (backup, objectbackup, reconcile, restore, restoretest, scrub, tenantbackup), 0 Fehlschläge
```
`internal/tenantbackup`-Tests brauchen eine eigene Rolle mit `CREATEDB`
(`TEST_TENANTBACKUP_PG_USER`, NICHT `TEST_BACKUP_PG_USER` — bewusst
getrennt, siehe Betriebsrollen-Hinweis oben): 4/4 Tests bestanden.
## Gesamtergebnis
**Bestanden.** Alle drei Akzeptanzkriterien und alle drei
Pflichtprüfungen real erfüllt — sowohl testgetrieben (echte
Zwei-Tenant-Isolation in beide Richtungen bewiesen) als auch über einen
echten CLI-Lauf auf 192.168.1.131. Ein architektonischer Fund vor
Implementierungsbeginn (Cluster- vs. Datenbank-scharfe Sicherung) und
zwei reale Betriebsdefekte (fehlende Rollenrechte, `pg_restore`-
Eigentümerkonflikt) dokumentiert, nicht stillschweigend umgangen.