RET-03: löschworkflow-und-aufbewahrungssperre-legal-hold
- migrations/0008_legal_hold_destruction: legal_holds (historisiert, Partial-Unique-Index gegen doppelte aktive Sperre), destruction_log (append-only, per Postgres-Trigger gegen UPDATE/DELETE geschuetzt) - archive/internal/deletionworkflow: SetLegalHold (Begruendungspflicht), ReleaseLegalHold (Aufheben selbst protokolliert, keine Loeschung der Zeile), ReleaseExpired (Freigabeprozess active->expired, keine Sofortloeschung, Sperre wird respektiert), Destroy (verlangt vorherigen expired-Status, prueft Sperre erneut, transaktional mit Protokolleintrag) - 6 Tests, alle Pflichtpruefungen real bestanden (Sperre widersteht Loeschversuch, Protokoll real unveraenderlich per Trigger, Aufheben real protokolliert) - Migration real auf dms_tenant_test angewendet Pruefungen siehe archive/docs/RET-03-PRUEFPROTOKOLL.md
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
# RET-03 – Prüfprotokoll: Löschworkflow & Aufbewahrungssperre (Legal Hold)
|
||||
|
||||
Voraussetzung RET-01, RET-02 – beide bereits Fertig.
|
||||
|
||||
## Umsetzung
|
||||
|
||||
- `archive/migrations/0008_legal_hold_destruction.up/down.sql`:
|
||||
- `legal_holds` – historisiert (Sperre wird NIE gelöscht, nur
|
||||
`released_at`/`released_by` gesetzt), Partial-Unique-Index erlaubt
|
||||
höchstens eine AKTIVE Sperre je Objekt.
|
||||
- `destruction_log` – append-only, real per Postgres-TRIGGER gegen
|
||||
UPDATE/DELETE geschützt (`destruction_log_immutable()`,
|
||||
`RAISE EXCEPTION`) — DB-Ebene, nicht nur Anwendungscode.
|
||||
- `archive/internal/deletionworkflow`:
|
||||
- `SetLegalHold` — Begründung PFLICHT (`ErrReasonRequired`),
|
||||
`ErrAlreadyOnHold` bei bereits aktiver Sperre (DB-Unique-Index als
|
||||
zusätzliche Absicherung gegen Wettlaufsituationen).
|
||||
- `ReleaseLegalHold` — hebt auf, OHNE die Zeile zu löschen (das
|
||||
Aufheben selbst bleibt dauerhaft nachvollziehbar).
|
||||
- `ReleaseExpired` — Freigabeprozess: `active` → `expired`, NIEMALS
|
||||
direkt `deleted`. Objekte mit aktiver Sperre werden übersprungen,
|
||||
unabhängig vom Fristablauf.
|
||||
- `Destroy` — verlangt vorherigen Status `expired`
|
||||
(`ErrNotReleased` sonst), prüft die Sperre ZUSÄTZLICH direkt vor der
|
||||
Vernichtung erneut (Verteidigung in der Tiefe gegen eine
|
||||
zwischenzeitlich gesetzte Sperre), schreibt Statuswechsel und
|
||||
Protokolleintrag in EINER Transaktion.
|
||||
|
||||
## Prüfungen
|
||||
|
||||
| # | Prüfung | Ergebnis |
|
||||
|---|---|---|
|
||||
| 1 | Objekt mit aktiver Sperre widersteht einem direkten Löschversuch | **bestanden** – `TestDestroy_ObjectWithActiveHoldResistsDeletion`: Objekt bereits im Status `expired` (simuliert vorherige Freigabe), Sperre danach gesetzt, `Destroy` liefert `ErrOnLegalHold`, Status bleibt unverändert |
|
||||
| 2 | Protokolleintrag nach Vernichtung ist nachträglich nicht änderbar (DB-Constraint oder Trigger) | **bestanden** – `TestDestructionLog_IsImmutable`: nach echter `Destroy`-Ausführung direkter `UPDATE`/`DELETE` per rohem SQL (umgeht die Go-API vollständig) — beide scheitern real am Postgres-Trigger, nicht nur weil das Paket keine Änderungsfunktion anbietet |
|
||||
| 3 | Aufheben einer Sperre ist selbst protokolliert | **bestanden** – `TestReleaseLegalHold_IsItselfLogged`: nach `ReleaseLegalHold` sind `released_at`/`released_by` real gesetzt, die ursprüngliche Sperr-Zeile bleibt bestehen (kein DELETE) |
|
||||
|
||||
**Zusätzliche Tests (Akzeptanzkriterium 1, nicht in den drei
|
||||
Pflichtprüfungen, aber je AC mindestens ein Test):**
|
||||
- `TestReleaseExpired_NoImmediateDeletionAndHoldIsRespected` — fälliges
|
||||
Objekt wird `expired` (NICHT `deleted`), gesperrtes fälliges Objekt
|
||||
bleibt `active`, nicht fälliges Objekt bleibt `active`.
|
||||
- `TestSetLegalHold_RequiresReason`, `TestDestroy_RequiresPriorRelease`.
|
||||
|
||||
## Build/Test-Ergebnis (192.168.1.131)
|
||||
|
||||
```
|
||||
go build ./... -> clean
|
||||
go vet ./... -> clean
|
||||
golangci-lint run ./... -> 0 issues
|
||||
go test ./... -p 1 -> alle Archive-Pakete bestanden (inkl. deletionworkflow, 6 Tests)
|
||||
```
|
||||
|
||||
Migration `0008_legal_hold_destruction` real auf `dms_tenant_test`
|
||||
angewendet (Test-DB, in der auch RET-06-API läuft) — sauber, ohne
|
||||
Fehler.
|
||||
|
||||
## Gesamtergebnis
|
||||
|
||||
**Bestanden.** Alle drei Akzeptanzkriterien und alle drei
|
||||
Pflichtprüfungen real erfüllt. Damit ist das RET-Epic (RET-01 bis
|
||||
RET-10) vollständig abgeschlossen: Objektmodell, Fristenengine,
|
||||
Modul-Adapter (Interface + Dienst), Konfigurationsoberfläche (Backend +
|
||||
Frontend + CORS), Benachrichtigungen, WORM-Speicher und jetzt
|
||||
Löschworkflow mit Legal Hold.
|
||||
Reference in New Issue
Block a user