Datenaufbewahrung und Anonymisierungskonzept
Aktueller Stand
Dieses Dokument füllt eine Lücke, die beim Abgleich von PROCUREX-PLANUNGSENTSCHEIDUNGEN.md
gegen den tatsächlichen Repo-Zustand identifiziert wurde (2026-08-17): Confluence Seite 10 nennt
unter [ANNAHME] ein „Lösch-/Anonymisierungskonzept für Supplier-Kontaktdaten und
ApprovalRequest-Begründungen nach fiktiver Aufbewahrungsfrist von 24 Monaten“, ohne dass dieses
Konzept bisher irgendwo ausformuliert war. PROCUREX ist ein fiktives Lernprojekt ohne echte
Personendaten (siehe README.md); dieses Dokument ist entsprechend eine konzeptionelle
Übung, keine Umsetzung einer realen Compliance-Anforderung.
Umsetzungsstatus: implementiert (seit 2026-08-29). SupplierRetentionJob
(procurex-supplier/.../retention/) und ApprovalRetentionJob
(procurex-approval/.../retention/) setzen die unten beschriebene Fristlogik als
@Scheduled-Jobs um, analog zu den bestehenden Outbox-Relays. Keine Flyway-Migration nötig, da
kein neues Spaltenschema entsteht — nur bestehende Felder werden überschrieben. Beide Jobs sind
per procurex.retention.enabled abschaltbar (Standard: an) und in Tests deaktiviert, damit
Integrationstests nicht mit dem periodischen Lauf um dieselbe Testcontainers-Datenbank
konkurrieren.
Betroffene Daten
| Entität | Feld(er) | Schema.Tabelle | Fristbeginn |
|---|---|---|---|
Supplier |
contact_email |
supplier.supplier |
updated_at (letzte Statusänderung) |
ApprovalRequest |
reason |
approval.approval_request |
decided_at |
Beide Felder enthalten die einzigen personenbezogen wirkenden Freitext-/Kontaktdaten im
Datenmodell (siehe procurex-supplier/.../domain/Supplier.java und
procurex-approval/.../domain/ApprovalRequest.java). Alle übrigen Entitäten (Katalogartikel,
Bestellungen, Wareneingänge, Rechnungen) enthalten ausschließlich Geschäftsdaten ohne
Personenbezug.
Konzept: Anonymisierung statt Löschung
Vollständiges Löschen der Datensätze würde die revisionssichere Nachvollziehbarkeit von
Bestellungen und Genehmigungsentscheidungen zerstören (siehe ApprovalRequest-Klassenkommentar:
„Revisionssicherer Beleg einer Genehmigungsentscheidung“, PRX-5/PRX-8). Deshalb: Anonymisierung
statt Löschung.
Supplier.contactEmail: nach Ablauf der Frist wird der Wert durch einen Platzhalter
(anonymized@procurex.invalid) ersetzt. name, taxId und status bleiben erhalten, da sie
für die Nachvollziehbarkeit historischer Bestellungen (welcher Lieferant war zum Zeitpunkt X
aktiv) benötigt werden und keinen direkten Personenbezug haben (Firmendaten, keine
Kontaktperson).
ApprovalRequest.reason: nach Ablauf der Frist wird der Freitext durch einen Platzhalter
([anonymisiert nach Aufbewahrungsfrist]) ersetzt. orderId, decision und decidedAt
bleiben erhalten — die revisionssichere Kernaussage („wer hat wann wie entschieden“) bleibt
damit auch nach Anonymisierung nachvollziehbar, nur der potenziell personenbezogene Freitext
entfällt.
Fristlogik (konzeptionell)
IF Supplier.updatedAt < now() - 24 Monate
AND Supplier.contactEmail != 'anonymized@procurex.invalid'
THEN Supplier.contactEmail = 'anonymized@procurex.invalid'
IF ApprovalRequest.decidedAt < now() - 24 Monate
AND ApprovalRequest.reason != '[anonymisiert nach Aufbewahrungsfrist]'
THEN ApprovalRequest.reason = '[anonymisiert nach Aufbewahrungsfrist]'
Tatsächliche Umsetzung: ein @Scheduled-Job je Modul (analog zu den bestehenden Outbox-Relays,
siehe ADR-0003 und AbstractOutboxRelay), der periodisch (Standard: alle 24h,
procurex.retention.check-interval-ms) prüft und in Batches von 200 Datensätzen anonymisiert, um
Lock-Contention mit dem laufenden Betrieb zu vermeiden. Bewusst kein hartes DELETE, damit
referentielle Integrität zu PurchaseOrder bzw. Fremdschlüsseln erhalten bleibt. Die 24-Monats-
Frist wird als 730 Tage angenähert (procurex.retention.supplier-contact-email-days /
procurex.retention.approval-reason-days, je Standard 730) — eine bewusste, dokumentierte
Vereinfachung für einfache Instant-Arithmetik ohne Kalendermonate.
Bewusste Grenze
- Keine Betroffenenrechte-Workflows (Auskunft, Widerspruch) beschrieben, da es sich um fiktive
Übungsdaten ohne echte betroffene Personen handelt (siehe Lernprojekt-Hinweis auf
Confluence-Seiten 01/02/07).
- Die 24-Monats-Frist ist eine
[ANNAHME]aus der ursprünglichen Planung, keine aus einer echten
Rechtsgrundlage abgeleitete Vorgabe; die Umsetzung nähert sie als feste 730-Tage-Dauer an statt
echter Kalendermonate.
- Kein Anonymisierungskonzept für Kafka-Event-Payloads oder den Audit-Log
(audit.audit_log_entry) — Events und Audit-Einträge enthalten orderId/decision, aber
keine Kontaktdaten, daher aktuell kein zusätzlicher Bedarf identifiziert.
- Keine Testcontainers-Integrationstests für die Jobs gegen eine echte PostgreSQL-Instanz — nur
Unit-Tests mit gemocktem Repository (SupplierRetentionJobTest, ApprovalRetentionJobTest)
plus Domain-Tests für die Anonymisierungs-Methoden selbst.
Weitere Informationen
Siehe Confluence Seite 10 „APIs, Events, Daten und Security“ (CONFIRMED, Abschnitt „Daten“) sowie
docs/runbooks/backup-restore.md für die verwandte Frage der Datensicherung (nicht Löschung).