# CMP-07 – Prüfprotokoll: DSGVO-Löschantrag (Recht auf Löschung, Art. 17) Voraussetzung RET-03, RET-05, CMP-02, CMP-06 – alle bereits Fertig. ## Bekannten Fehler vermieden (Ticket-Vorgabe) `dsgvorequest.ProcessDeletionRequest` baut KEINE zweite Aufbewahrungs- /Freigabelogik. Es ruft ausschließlich auf: - `dpreport.SubjectReport` (CMP-02) für die Suche, - `deletionworkflow.IsOnLegalHold` (RET-03) für die Sperrprüfung, - `deletionapproval.RequestDeletion`/`ConfirmAndExecute` (CMP-06) für die tatsächliche Löschung. Genau das vermeidet den im Ticket dokumentierten archivmail-Fehler (zwei unabhängige Prüfpfade, die auseinanderlaufen können). ## Additive Erweiterung von CMP-02 (bereits Fertig) `dpreport.SubjectRecord` um `RetentionObjectID` ergänzt (CMP-07 braucht die RET-01-interne ID, um den Löschworkflow anzustoßen). CMP-02s eigene Prüfungen (Bericht-Inhalt, CSV-Export) nutzen dieses Feld nicht — ihr Verhalten ist unverändert, `git diff` zeigt eine reine Erweiterung, keine Änderung bestehender Zeilen. ## Umsetzung - `archive/migrations/0011_dsgvo_decision_log.up/down.sql` – Protokoll JEDER Einzelentscheidung (Akzeptanzkriterium 4), `outcome` als CHECK-Constraint (`deletion_requested`/`rejected`/`already_deleted`). - `archive/internal/dsgvorequest.ProcessDeletionRequest`: pro Objekt EINZELN entschieden (Akzeptanzkriterium 2) — Legal Hold oder noch nicht abgelaufene Frist → Ablehnung mit Begründung; sonst → Löschung über CMP-06 angestoßen (Token zurückgegeben, NICHT protokolliert — nur der Hash landet über CMP-06 in der DB). Jede Entscheidung wird vor Rückgabe protokolliert. ## Prüfungen | # | Prüfung | Ergebnis | |---|---|---| | 1 | Löschantrag für eine Testperson mit gemischtem Datenbestand liefert exakt eine Löschung und eine begründete Ablehnung | **bestanden** – `TestProcessDeletionRequest_MixedDatasetYieldsOneDeletionOneRejection`: genau 1 `deletion_requested` (richtiges Objekt) + 1 `rejected` mit Begründung. Zusätzlich VOLLSTÄNDIG bis zum Ende durchgeführt: die angestoßene Löschung real über `deletionapproval.ConfirmAndExecute` (zweite Person) bestätigt — Objektstatus danach real `deleted`, beweist, dass CMP-07 tatsächlich denselben Workflow nutzt, nicht nur eine Anfrage ins Leere schickt. Protokoll (`dsgvo_decision_log`) enthält beide Entscheidungen | | 2 | Aufbewahrungssperre (Legal Hold) verhindert die Löschung auch bei bereits abgelaufener regulärer Frist | **bestanden** – `TestProcessDeletionRequest_LegalHoldBlocksEvenExpiredObject`: Objekt mit Status `expired` (Frist bereits abgelaufen) UND aktiver Sperre → `rejected`, Status bleibt real unverändert `expired`, keine Löschung angestoßen | | 3 | Löschantrag für einen Tenant führt nachweislich zu keiner Aktion an Objekten eines anderen Tenants | **bestanden** – `TestProcessDeletionRequest_TenantIsolation`: real gegen zwei physisch getrennte Tenant-Datenbanken (`tenant_acme`/`tenant_globex`, wie schon bei CMP-02) — Objekt in Tenant A angelegt, Löschantrag für dieselbe `data_subject_ref` gegen Tenant B liefert 0 Entscheidungen, Tenant As Objekt bleibt real unverändert | ## 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. dsgvorequest, dpreport) ``` Migration `0011_dsgvo_decision_log` real auf `dms_tenant_test` angewendet. ## Gesamtergebnis **Bestanden.** Alle vier Akzeptanzkriterien und alle drei Pflichtprüfungen real erfüllt — inklusive einer vollständig bis zur tatsächlichen Vernichtung durchgeführten Löschung über den echten Vier-Augen-Workflow. Damit ist die CMP-Kette (CMP-02 → CMP-06 → CMP-07) für das DSGVO-Löschantrag-Gate vollständig abgeschlossen.