-- ========================================================= -- Migration 147: Compliance Template Rules — profilbasierte Empfehlungs-Regeln -- mit Versionierung, Approval-Workflow und Tenant-Overrides. -- -- Ersetzt langfristig die hartcodierten Regeln in -- admin-compliance/app/sdk/document-generator/templateRecommendations.ts. -- ========================================================= -- compliance_template_rules: Regel-Hülle (eine Regel = eine document_type-Empfehlung) CREATE TABLE IF NOT EXISTS compliance_template_rules ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), rule_key VARCHAR(150) NOT NULL UNIQUE, -- z.B. "whistleblower_required_50plus" document_type VARCHAR(100) NOT NULL, -- z.B. "whistleblower_policy" title VARCHAR(300) NOT NULL, -- kurzer Anzeigename current_version_id UUID, -- pointet auf published Version, null bis erste Freigabe created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- compliance_template_rule_versions: Versionen mit Lifecycle + Approval-Trail CREATE TABLE IF NOT EXISTS compliance_template_rule_versions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), rule_id UUID NOT NULL REFERENCES compliance_template_rules(id) ON DELETE CASCADE, version_number INT NOT NULL, -- Lifecycle (analog compliance_legal_document_versions) status VARCHAR(20) NOT NULL DEFAULT 'draft', -- draft|review|approved|published|archived|rejected is_live SMALLINT NOT NULL DEFAULT 0, -- 1 = aktuell published Version dieser Regel -- Klassifikation der Empfehlung classification VARCHAR(20) NOT NULL, -- required | recommended | optional -- Bedingung als strukturiertes JSONB -- Format: { "kind": "all"|"any", "clauses": [{ "field": "...", "op": "...", "value": ... }] } conditions JSONB NOT NULL DEFAULT '{"kind":"all","clauses":[]}'::jsonb, -- Editorial-Pflichtfelder source_citation TEXT NOT NULL DEFAULT '', -- "§ 12 HinSchG", "EuGH C-311/18", "DSK Kurzpapier Nr. 18" rationale TEXT, -- Freitext-Begründung des Anwalts change_summary TEXT, -- Pflicht beim Einreichen (was wurde geändert) -- Approval-Trail (vereinfacht; volle Action-Liste in approvals-Tabelle) created_by VARCHAR(200), submitted_by VARCHAR(200), submitted_at TIMESTAMPTZ, approved_by VARCHAR(200), approved_at TIMESTAMPTZ, published_by VARCHAR(200), published_at TIMESTAMPTZ, rejected_by VARCHAR(200), rejected_at TIMESTAMPTZ, rejection_reason TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE (rule_id, version_number), CHECK (classification IN ('required', 'recommended', 'optional')), CHECK (status IN ('draft', 'review', 'approved', 'published', 'archived', 'rejected')), CHECK (is_live IN (0, 1)) ); -- Genau eine published/live Version pro Regel CREATE UNIQUE INDEX IF NOT EXISTS idx_rule_versions_one_live ON compliance_template_rule_versions(rule_id) WHERE is_live = 1; -- compliance_template_rule_approvals: Audit-Trail aller Lifecycle-Aktionen CREATE TABLE IF NOT EXISTS compliance_template_rule_approvals ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), version_id UUID NOT NULL REFERENCES compliance_template_rule_versions(id) ON DELETE CASCADE, action VARCHAR(50) NOT NULL, -- submitted|approved|rejected|published|archived approver VARCHAR(200), comment TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- compliance_tenant_rule_overrides: Pro Kanzlei/Tenant Override einer globalen Regel CREATE TABLE IF NOT EXISTS compliance_tenant_rule_overrides ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id VARCHAR(100) NOT NULL, rule_id UUID NOT NULL REFERENCES compliance_template_rules(id) ON DELETE CASCADE, override_classification VARCHAR(20), -- null = Regel komplett für Tenant deaktiviert reason TEXT NOT NULL, -- Pflicht: warum dieser Override created_by VARCHAR(200), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), CONSTRAINT chk_override_classification CHECK ( override_classification IS NULL OR override_classification IN ('required', 'recommended', 'optional') ) ); -- Indizes CREATE INDEX IF NOT EXISTS idx_template_rules_type ON compliance_template_rules(document_type); CREATE INDEX IF NOT EXISTS idx_rule_versions_rule ON compliance_template_rule_versions(rule_id); CREATE INDEX IF NOT EXISTS idx_rule_versions_status ON compliance_template_rule_versions(status); CREATE INDEX IF NOT EXISTS idx_rule_approvals_version ON compliance_template_rule_approvals(version_id); CREATE INDEX IF NOT EXISTS idx_tenant_overrides_tenant ON compliance_tenant_rule_overrides(tenant_id); CREATE UNIQUE INDEX IF NOT EXISTS idx_tenant_overrides_unique ON compliance_tenant_rule_overrides(tenant_id, rule_id);