Was ein Löschkonzept enthalten muss
Die DSGVO verlangt kein formal definiertes „Löschkonzept" — aber die Kombination aus Artikel 5(1)(e) (Speicherbegrenzung), Artikel 17 (Recht auf Löschung) und Artikel 5(2) (Rechenschaftspflicht) macht ein dokumentiertes Verfahren faktisch notwendig.
Ein technisch vollständiges Löschkonzept für PostgreSQL umfasst:
- Dateninventar: Welche personenbezogenen Daten werden in welchen Tabellen gespeichert?
- Aufbewahrungsfristen: Wie lange darf jede Datenkategorie gespeichert werden?
- Löschverfahren: Wie wird gelöscht — automatisch oder manuell?
- Betroffenenanfragen: Wie werden Löschanfragen nach Artikel 17 bearbeitet?
- Nachweis: Wie wird dokumentiert, dass die Löschung tatsächlich erfolgt ist?
Schritt 1: Dateninventar erstellen
Bevor Sie löschen können, müssen Sie wissen, wo personenbezogene Daten liegen:
-- Automatische PII-Erkennung
SELECT pgcomply.quick_setup();
-- Ergebnis prüfen: Welche Tabellen enthalten PII?
SELECT table_name, column_name, pii_type
FROM pgcomply.classification_map()
WHERE level IN ('restricted', 'confidential');
Typisches Ergebnis für eine Webanwendung:
table_name | column_name | pii_type
------------+-------------+----------
users | email | email
users | name | person_name
users | phone | phone
profiles | address | address
orders | shipping_addr| address
sessions | ip_address | ip_address
Schritt 2: Aufbewahrungsfristen definieren
Deutsche Aufbewahrungspflichten nach Datenkategorie:
-- Sitzungsdaten: 30 Tage (kein gesetzliches Erfordernis)
SELECT pgcomply.retain('sessions', 'created_at', '30 days');
-- Bestelldaten: 10 Jahre (HGB §257)
SELECT pgcomply.retain('orders', 'created_at', '3650 days');
-- Rechnungen: 10 Jahre (AO §147)
SELECT pgcomply.retain('invoices', 'created_at', '3650 days');
-- Support-Tickets: 3 Jahre (allgemeine Verjährung §195 BGB)
SELECT pgcomply.retain('support_tickets', 'closed_at', '1095 days');
-- Marketing-Einwilligungen: bis Widerruf (kein automatisches Löschen)
-- → Diese Daten werden über Consent-Management gesteuert
-- Bewerberdaten: 6 Monate nach Absage (AGG §15)
SELECT pgcomply.retain('applications', 'rejected_at', '180 days');
Alle definierten Fristen einsehen:
SELECT * FROM pgcomply.retention_policies();
table_name | date_column | retention_days | retention_period | action | is_active
------------------+--------------+----------------+------------------+--------+-----------
public.sessions | created_at | 30 | 1 month(s) | delete | true
public.orders | created_at | 3650 | 10 year(s) | delete | true
public.invoices | created_at | 3650 | 10 year(s) | delete | true
public.support_tickets | closed_at | 1095 | 3 year(s) | delete | true
public.applications | rejected_at | 180 | 6 month(s) | delete | true
Schritt 3: Automatische Bereinigung einrichten
-- Tägliche Bereinigung um 03:00 Uhr
SELECT pgcomply.schedule_jobs(install := true);
-- Oder manuell:
SELECT pgcomply.enforce_retention();
Jede Bereinigung wird im Audit-Trail dokumentiert:
event_type | created_at | details
---------------------+---------------------+---------------------------------------------
retention_enforced | 2026-02-20 03:00:01 | {"table": "sessions", "deleted_rows": 847}
retention_enforced | 2026-02-20 03:00:02 | {"table": "applications", "deleted_rows": 12}
Schritt 4: Löschanfragen bearbeiten (Artikel 17)
Wenn eine betroffene Person die Löschung verlangt:
-- 1. Prüfen, welche Daten vorhanden sind
SELECT pgcomply.inspect('max.mustermann@example.de');
-- 2. Alle personenbezogenen Daten löschen
SELECT pgcomply.forget('max.mustermann@example.de');
-- 3. Nachweis, dass nichts mehr vorhanden ist
SELECT * FROM pgcomply.verify_forget('max.mustermann@example.de');
Wichtig: forget() respektiert gesetzliche Aufbewahrungspflichten. Wenn für eine Tabelle eine Aufbewahrungsfrist gilt (z.B. Rechnungen: 10 Jahre), werden die Daten dort nicht gelöscht, sondern anonymisiert. So bleiben die Buchhaltungsdaten erhalten, ohne dass sie einer Person zuordenbar sind.
Schritt 5: Löschung nachweisen
Die Rechenschaftspflicht (Artikel 5(2)) verlangt, dass Sie die Löschung dokumentieren können:
-- Löschhistorie für eine bestimmte Person
SELECT event_type, created_at, details
FROM pgcomply.audit_log
WHERE event_type IN ('forget_complete', 'forget_verified')
AND details->>'subject_id' = 'max.mustermann@example.de';
event_type | created_at | details
-----------------+---------------------+---------------------------------------------
forget_complete | 2026-02-20 10:15:03 | {"subject_id": "max.mustermann@example.de",
| | "tables_affected": 4, "rows_deleted": 23,
| | "rows_anonymized": 2}
forget_verified | 2026-02-20 10:15:04 | {"subject_id": "max.mustermann@example.de",
| | "remaining_records": 0}
Der Audit-Trail ist durch eine SHA-256-Hashkette gegen Manipulation geschützt:
SELECT pgcomply.verify_audit();
-- Ergebnis: "Audit trail integrity verified. 1,247 entries, chain intact."
Zusammenfassung: Löschkonzept-Vorlage
| Datenkategorie | Aufbewahrungsfrist | Rechtsgrundlage | Löschverfahren | |---|---|---|---| | Sitzungsdaten | 30 Tage | Keine Pflicht | Automatisch (retain + enforce) | | Benutzerdaten | Bis Löschantrag | Art. 6(1)(b) Vertrag | Auf Anfrage (forget) | | Bestelldaten | 10 Jahre | HGB §257 | Automatisch nach Ablauf | | Rechnungen | 10 Jahre | AO §147 | Automatisch nach Ablauf | | Support-Tickets | 3 Jahre | §195 BGB Verjährung | Automatisch nach Ablauf | | Bewerberdaten | 6 Monate | AGG §15 | Automatisch nach Absage | | Marketing-Daten | Bis Widerruf | Art. 6(1)(a) Einwilligung | Auf Widerruf (forget) |
Dieses Löschkonzept ist technisch durch pgcomply umgesetzt, automatisiert via pg_cron, und revisionsfest dokumentiert im Audit-Trail. Es kann dem Datenschutzbeauftragten und der Aufsichtsbehörde als Nachweis vorgelegt werden.