Files
2026-06-25 19:54:40 +02:00

57 lines
2.4 KiB
PL/PgSQL

-- GoBD-konformes Audit-Log: jede MA-Änderung wird mit Hash-Chain
-- gespeichert, manipulationssicher, nur INSERT erlaubt.
-- ====================================================================
-- Format: jede Zeile enthält content_hash = SHA256 über (prev_hash +
-- entity + entity_id + actor + timestamp + diff_json). Wenn ein
-- Eintrag nachträglich geändert wird, bricht die Kette und das ist
-- erkennbar.
--
-- entity: "employee" | "position" | "org_unit" | …
-- entity_id: UUID des betroffenen Records
-- action: "create" | "update" | "delete" | "activate" | "deactivate"
-- actor: E-Mail des Admin-Users (oder "system" für Bulk/Cron)
-- diff: JSON mit { field: { before, after } } — nur geänderte
-- Felder
--
-- Aufbewahrung: 10 Jahre laut GoBD; aktuell keine harte Retention,
-- App-Doku verweist auf manuelle Archivierung via CSV-Export.
create table if not exists public.change_log (
id uuid primary key default gen_random_uuid(),
occurred_at timestamptz not null default now(),
entity text not null,
entity_id uuid not null,
action text not null,
actor text not null,
diff jsonb not null default '{}'::jsonb,
prev_hash text, -- hash des vorherigen eintrags (kette)
content_hash text not null -- sha256 dieses eintrags
);
create index if not exists change_log_entity_idx
on public.change_log (entity, entity_id, occurred_at desc);
create index if not exists change_log_occurred_at_idx
on public.change_log (occurred_at desc);
-- Schreibschutz auf Updates/Deletes — service-role-only, aber
-- explizit als Trigger gegen Versehen.
create or replace function public.protect_change_log()
returns trigger language plpgsql as $$
begin
raise exception 'change_log ist immutable — keine Updates oder Deletes erlaubt';
end;
$$;
drop trigger if exists trg_protect_change_log_update on public.change_log;
create trigger trg_protect_change_log_update
before update on public.change_log
for each row execute function public.protect_change_log();
drop trigger if exists trg_protect_change_log_delete on public.change_log;
create trigger trg_protect_change_log_delete
before delete on public.change_log
for each row execute function public.protect_change_log();
alter table public.change_log enable row level security;
-- Service-Role-only — anon hat gar keinen Zugriff.