# RET-01 – Prüfprotokoll: Generisches Retention-Objektmodell Keine Vorbedingungen (Welle 1 des RET-Epics). ## Grundsatzentscheidung: Adapter-Muster, keine Fremdschlüssel auf Modul-Tabellen `retention_objects.object_type`/`object_reference` sind reine Textfelder — Archive importiert weder DMS- noch Mail-Code (eigene Go-Module, physisch getrennte Verantwortung, dieselbe Disziplin wie BAK-05s `reconcile`-Paket gegenüber `file_revisions`). Ein neues Modul kann retention-pflichtige Objekte einbinden, ohne dieses Paket zu ändern — nur `RegisterObject(objectType, objectReference)` aufrufen. Aufbewahrungsklassen-Zuordnung ist historisiert: `AssignClass` fügt IMMER eine neue Zeile hinzu, ändert nie eine bestehende — die "aktuelle" Klasse ist die mit dem jüngsten `assigned_at`. Damit bleibt nachvollziehbar, wann und wie oft sich die Klasse eines Objekts geändert hat, ohne eigene Audit-Tabelle. ## Umsetzung - `migrations/0002_retention.up.sql`/`.down.sql` — `retention_objects`, `retention_class_assignments`. - `internal/retention.RegisterObject` — idempotent (`ON CONFLICT`). - `internal/retention.AssignClass`/`CurrentClass`/`ClassHistory`. ## Prüfungen | # | Prüfung | Ergebnis | |---|---|---| | 1 | Migration vorwärts und rückwärts getestet | **bestanden** — `TestMigration_ForwardAndBackward`: real gegen die tatsächlichen Migrationsdateien (nicht nachgebaut), vorwärts→Tabellen vorhanden, rückwärts→Tabellen weg, erneut vorwärts→sauber (kein Rest blockiert erneuten Lauf) | | 2 | Testobjekt aus fiktivem DMS- und Mail-Adapter beide korrekt abgebildet | **bestanden** — `TestRegisterObject_MapsDMSAndMailAdapterObjectsIdentically`: `dms_document`/`mail_message` beide ohne modulspezifische Spalten abgebildet, zusätzlich Idempotenz bewiesen (erneute Registrierung liefert dieselbe ID) | | 3 | Tenant-Isolation der Kern-Tabellen durch Negativtest belegt | **bestanden** — `TestTenantIsolation_Negativtest`: reales zweites Tenant-DB (`ret01_tenant_test_b`), Objekt aus Tenant A über Verbindung zu Tenant B abgefragt, `count=0` — technisch nicht sichtbar, keine gemeinsame Tabelle mit `tenant_id`-Filter (Modell C, TEN-01) | Zusätzlich: `TestAssignClass_IsHistoricized` — zwei Klassen-Zuordnungen, `CurrentClass` liefert die jüngste, `ClassHistory` beide chronologisch. ## Echte Verdrahtung auf 192.168.1.131 - Migration real gegen `dms_tenant_test` angewendet (`psql -f migrations/0002_retention.up.sql`) — `retention_objects`, `retention_class_assignments` bestätigt vorhanden (`\dt retention*`) - Kein systemd-Dienst/Timer nötig — RET-01 ist reines Datenmodell + Bibliothek, kein eigenständiger Prozess (Verbraucher sind spätere RET-Tickets, allen voran RET-05 als Adapter-Interface) - Zweites Tenant-DB (`ret01_tenant_test_b`) nur für den Isolationstest angelegt, danach entfernt ## 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 -> 8/8 Pakete mit Tests ok (backup, objectbackup, reconcile, restore, restoretest, retention, scrub, tenantbackup), 0 Fehlschläge ``` ## Gesamtergebnis **Bestanden.** Alle drei Akzeptanzkriterien und alle drei Pflichtprüfungen real erfüllt — Migration gegen die tatsächlichen `.sql`-Dateien (nicht nachgebaut) getestet, Mandantentrennung gegen ein echtes zweites Tenant-DB bewiesen. Grundlage für RET-05 (Adapter- Interface, als Nächstes) und RET-02 gelegt.