Mandanten können jetzt selbst festlegen, wer bei welcher abgeleiteten Bedingung (Anforderung/Einstufung/Datenklasse) zusätzlich zur Fachebene-Entscheidung zustimmen muss (z. B. Datenschutzbeauftragter, Geschäftsführung) - Genehmiger-Rollen sind orthogonal zu den fünf bestehenden Zugriffsrollen. Alle ausgelösten Rollen müssen zustimmen, eine Ablehnung kippt kaskadierend den gesamten Antrag. Mandanten ohne Freigabe-Regeln (aktuell alle) sind unverändert vom alten Direktpfad betroffen, siehe TestOhneFreigabeRegelnVerhaeltSichWieVorher. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
60 lines
2.9 KiB
SQL
60 lines
2.9 KiB
SQL
-- Konfigurierbarer Mehrfach-Freigabe-Workflow (2026-08-31): manche
|
|
-- Anträge brauchen zusätzlich zur normalen Fachebene-Entscheidung eine
|
|
-- Freigabe durch bestimmte Personen (z. B. Datenschutzbeauftragte bei
|
|
-- dsfa_erforderlich, Geschäftsführung bei hochrisiko). Bewusst additiv
|
|
-- zur bestehenden app_user.role (Zugriffskontrolle) — eine
|
|
-- Genehmiger-Rolle ist eine reine Freigabe-Funktion, keine Berechtigung,
|
|
-- und eine Person kann mehrere davon gleichzeitig innehaben.
|
|
|
|
-- Stammdaten wie abteilung, pro Mandant frei benennbar.
|
|
CREATE TABLE genehmiger_rolle (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
account_id UUID NOT NULL REFERENCES account (id),
|
|
name TEXT NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
UNIQUE (account_id, name)
|
|
);
|
|
|
|
-- Welche Personen eine Genehmiger-Rolle innehaben (n:m).
|
|
CREATE TABLE nutzer_genehmiger_rolle (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
app_user_id UUID NOT NULL REFERENCES app_user (id),
|
|
genehmiger_rolle_id UUID NOT NULL REFERENCES genehmiger_rolle (id),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
UNIQUE (app_user_id, genehmiger_rolle_id)
|
|
);
|
|
|
|
-- "Wenn Bedingung X zutrifft, ist zusätzlich eine Freigabe durch
|
|
-- Genehmiger-Rolle Y nötig." Bedingung ist bewusst eine der bereits vom
|
|
-- Regelwerk abgeleiteten Größen (Anforderungs-ID, Einstufungs-ID,
|
|
-- Datenklasse-ID) — kein freier Regel-Editor, keine beliebige Logik.
|
|
CREATE TABLE freigabe_regel (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
account_id UUID NOT NULL REFERENCES account (id),
|
|
bedingung_typ TEXT NOT NULL CHECK (bedingung_typ IN ('anforderung', 'einstufung', 'datenklasse')),
|
|
bedingung_wert TEXT NOT NULL,
|
|
genehmiger_rolle_id UUID NOT NULL REFERENCES genehmiger_rolle (id),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- Pro Antrag ein Eintrag je durch eine Regel ausgelöster nötiger
|
|
-- Freigabe. Nicht append-only (wie werkzeug) — ein Freigabeschritt ist
|
|
-- eine einzelne Aufgabe, die von ausstehend in einen Endzustand
|
|
-- übergeht, keine Historie mehrerer Entscheidungen zum selben Schritt.
|
|
CREATE TABLE freigabeschritt (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
antrag_id UUID NOT NULL REFERENCES antrag (id),
|
|
genehmiger_rolle_id UUID NOT NULL REFERENCES genehmiger_rolle (id),
|
|
status TEXT NOT NULL DEFAULT 'ausstehend' CHECK (status IN ('ausstehend', 'genehmigt', 'abgelehnt')),
|
|
entschieden_von UUID REFERENCES app_user (id),
|
|
entschieden_am TIMESTAMPTZ,
|
|
kommentar TEXT NOT NULL DEFAULT '',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- Ein Antrag, der auf zusätzliche Freigaben wartet, ist weder "nur
|
|
-- eingereicht" noch schon "entschieden" — eigener Zwischenzustand.
|
|
ALTER TABLE antrag DROP CONSTRAINT antrag_status_check;
|
|
ALTER TABLE antrag ADD CONSTRAINT antrag_status_check
|
|
CHECK (status IN ('entwurf', 'eingereicht', 'wartet_auf_freigabe', 'entschieden'));
|