-- DSGVO Art. 17 (Recht auf Vergessenwerden) fuer Empfangs-Audit-Daten. -- ==================================================================== -- Problem: reception_visit_audit ist per Trigger append-only (GoBD). -- Bei einem Loeschanspruch nach DSGVO muessen aber personenbezogene -- Daten aus dem `payload`-JSON entfernt werden — die strukturelle -- Zeile (id, occurred_at, event_kind, actor_kind, actor_id, lead_id) -- bleibt fuer den Audit-Trail erhalten. -- -- Loesung: -- 1. Spalte `redacted_at` markiert anonymisierte Eintraege. -- 2. UPDATE-Trigger erlaubt EINEN spezifischen UPDATE-Pfad: das -- Setzen von `redacted_at` UND gleichzeitiges Nullen / Redacten -- der payload-PII. Alle anderen UPDATEs werden weiterhin geblockt. -- 3. card_leads bekommt auch `redacted_at` — Anonymisierung sowohl -- im Hauptdatensatz als auch im Audit-Log. alter table public.reception_visit_audit add column if not exists redacted_at timestamptz; alter table public.card_leads add column if not exists redacted_at timestamptz; -- Trigger neu definieren: erlaubt UPDATEs die NUR redacted_at + payload -- ändern (Anonymisierungs-Pfad). Aenderungen anderer Spalten bleiben -- blockiert. create or replace function public.reject_reception_audit_modify() returns trigger as $$ begin if tg_op = 'DELETE' then raise exception 'reception_visit_audit ist append-only — DELETE nicht erlaubt'; end if; -- UPDATE: nur erlauben wenn redacted_at von NULL auf NOT NULL gesetzt -- wird UND keine anderen identitaetsrelevanten Felder geaendert werden. if tg_op = 'UPDATE' then if old.redacted_at is not null then raise exception 'Eintrag wurde bereits anonymisiert — keine weiteren UPDATEs'; end if; if new.redacted_at is null then raise exception 'reception_visit_audit-UPDATE nur fuer DSGVO-Anonymisierung erlaubt (redacted_at muss gesetzt werden)'; end if; if new.id <> old.id or new.lead_id is distinct from old.lead_id or new.occurred_at <> old.occurred_at or new.event_kind <> old.event_kind or new.actor_kind <> old.actor_kind or new.actor_id is distinct from old.actor_id then raise exception 'reception_visit_audit-Anonymisierung darf nur payload + redacted_at aendern'; end if; return new; end if; return new; end; $$ language plpgsql; -- Index fuer schnelle Filterung "noch nicht anonymisiert". create index if not exists reception_visit_audit_active_idx on public.reception_visit_audit (occurred_at desc) where redacted_at is null;