Files
breakpilot-compliance/backend-compliance/migrations/111_org_roles_reviews.sql
T
Benjamin Admin 9b4be663f7 feat: Rollenkonzept backend + SOP template (Phase 1-3)
- Migration 111: 3 new tables (org_roles, document_reviews, document_role_mapping)
  with seed data mapping all 71 doc types to 7 compliance roles
- org_role_routes.py: CRUD for roles, seed defaults, test email, mapping API
- document_review_routes.py: Review lifecycle (create→send→approve/reject)
  with approval notification to all affected roles
- Migration 112: SOP template (ISO 9001 structure, 21 placeholders)
- Added standard_operating_procedure to TemplateType, doc-labels, presets

[migration-approved]

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-03 13:03:38 +02:00

178 lines
8.4 KiB
PL/PgSQL

-- Migration 111: Organizational Compliance Roles + Document Review Workflow
-- Creates tables for:
-- 1. compliance_org_roles — role assignments per project (DSB, GF, IT-Leiter, etc.)
-- 2. compliance_document_reviews — review tracking for generated documents
-- 3. compliance_document_role_mapping — which roles review which document types
BEGIN;
-- =============================================================================
-- Table 1: Organizational Compliance Roles
-- =============================================================================
CREATE TABLE IF NOT EXISTS compliance_org_roles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
project_id UUID,
role_key VARCHAR(50) NOT NULL,
role_label VARCHAR(200) NOT NULL,
person_name VARCHAR(300),
person_email VARCHAR(300),
department VARCHAR(200),
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(tenant_id, project_id, role_key)
);
CREATE INDEX IF NOT EXISTS idx_org_roles_tenant ON compliance_org_roles(tenant_id);
CREATE INDEX IF NOT EXISTS idx_org_roles_project ON compliance_org_roles(tenant_id, project_id);
-- =============================================================================
-- Table 2: Document Reviews
-- =============================================================================
CREATE TABLE IF NOT EXISTS compliance_document_reviews (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
project_id UUID,
document_type VARCHAR(100) NOT NULL,
document_title VARCHAR(500) NOT NULL,
document_content_hash VARCHAR(64),
reviewer_role_key VARCHAR(50) NOT NULL,
reviewer_name VARCHAR(300),
reviewer_email VARCHAR(300),
status VARCHAR(20) NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending', 'in_review', 'approved', 'rejected')),
submitted_at TIMESTAMPTZ,
submitted_by VARCHAR(200),
reviewed_at TIMESTAMPTZ,
review_comment TEXT,
review_link TEXT,
email_sent BOOLEAN NOT NULL DEFAULT FALSE,
email_sent_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_doc_reviews_tenant ON compliance_document_reviews(tenant_id);
CREATE INDEX IF NOT EXISTS idx_doc_reviews_status ON compliance_document_reviews(tenant_id, status);
CREATE INDEX IF NOT EXISTS idx_doc_reviews_doctype ON compliance_document_reviews(document_type);
-- =============================================================================
-- Table 3: Document-to-Role Mapping (seed defaults)
-- =============================================================================
CREATE TABLE IF NOT EXISTS compliance_document_role_mapping (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
document_type VARCHAR(100) NOT NULL,
role_key VARCHAR(50) NOT NULL,
is_primary BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(tenant_id, document_type, role_key)
);
CREATE INDEX IF NOT EXISTS idx_role_mapping_tenant ON compliance_document_role_mapping(tenant_id);
-- =============================================================================
-- Seed: Default document-to-role mapping (tenant_id = '__default__')
-- Every document type has at least one primary reviewer.
-- Tenants get a copy on first use; editable per tenant.
-- =============================================================================
-- DSB — Datenschutzbeauftragter
INSERT INTO compliance_document_role_mapping (tenant_id, document_type, role_key) VALUES
('__default__', 'privacy_policy', 'dsb'), ('__default__', 'vvt_register', 'dsb'),
('__default__', 'tom_documentation', 'dsb'), ('__default__', 'dsfa', 'dsb'),
('__default__', 'loeschkonzept', 'dsb'), ('__default__', 'dpa', 'dsb'),
('__default__', 'pflichtenregister', 'dsb'), ('__default__', 'data_protection_concept', 'dsb'),
('__default__', 'data_protection_policy', 'dsb'), ('__default__', 'data_retention_policy', 'dsb'),
('__default__', 'data_transfer_policy', 'dsb'), ('__default__', 'data_classification_policy', 'dsb'),
('__default__', 'privacy_incident_policy', 'dsb'), ('__default__', 'informationspflichten', 'dsb'),
('__default__', 'verpflichtungserklaerung', 'dsb'), ('__default__', 'consent_texts', 'dsb'),
('__default__', 'dsr_process_art15', 'dsb'), ('__default__', 'dsr_process_art16', 'dsb'),
('__default__', 'dsr_process_art17', 'dsb'), ('__default__', 'dsr_process_art18', 'dsb'),
('__default__', 'dsr_process_art19', 'dsb'), ('__default__', 'dsr_process_art20', 'dsb'),
('__default__', 'dsr_process_art21', 'dsb')
ON CONFLICT DO NOTHING;
-- GF — Geschaeftsfuehrung
INSERT INTO compliance_document_role_mapping (tenant_id, document_type, role_key) VALUES
('__default__', 'agb', 'gf'), ('__default__', 'terms_of_use', 'gf'),
('__default__', 'nda', 'gf'), ('__default__', 'sla', 'gf'),
('__default__', 'impressum', 'gf'), ('__default__', 'widerruf', 'gf'),
('__default__', 'whistleblower_policy', 'gf'),
('__default__', 'cloud_service_agreement', 'gf'),
('__default__', 'standard_operating_procedure', 'gf'),
('__default__', 'data_usage_clause', 'gf')
ON CONFLICT DO NOTHING;
-- IT-Leiter / CISO
INSERT INTO compliance_document_role_mapping (tenant_id, document_type, role_key) VALUES
('__default__', 'it_security_concept', 'it_leiter'),
('__default__', 'isms_manual', 'it_leiter'),
('__default__', 'backup_recovery_concept', 'it_leiter'),
('__default__', 'logging_concept', 'it_leiter'),
('__default__', 'incident_response_plan', 'it_leiter'),
('__default__', 'access_control_concept', 'it_leiter'),
('__default__', 'risk_management_concept', 'it_leiter'),
('__default__', 'information_security_policy', 'it_leiter'),
('__default__', 'access_control_policy', 'it_leiter'),
('__default__', 'password_policy', 'it_leiter'),
('__default__', 'encryption_policy', 'it_leiter'),
('__default__', 'logging_policy', 'it_leiter'),
('__default__', 'backup_policy', 'it_leiter'),
('__default__', 'incident_response_policy', 'it_leiter'),
('__default__', 'change_management_policy', 'it_leiter'),
('__default__', 'patch_management_policy', 'it_leiter'),
('__default__', 'asset_management_policy', 'it_leiter'),
('__default__', 'cloud_security_policy', 'it_leiter'),
('__default__', 'devsecops_policy', 'it_leiter'),
('__default__', 'secrets_management_policy', 'it_leiter'),
('__default__', 'vulnerability_management_policy', 'it_leiter'),
('__default__', 'cybersecurity_policy', 'it_leiter'),
('__default__', 'business_continuity_policy', 'it_leiter'),
('__default__', 'disaster_recovery_policy', 'it_leiter'),
('__default__', 'crisis_management_policy', 'it_leiter')
ON CONFLICT DO NOTHING;
-- HR-Leitung
INSERT INTO compliance_document_role_mapping (tenant_id, document_type, role_key) VALUES
('__default__', 'employee_dsi', 'hr_leitung'),
('__default__', 'applicant_dsi', 'hr_leitung'),
('__default__', 'employee_security_policy', 'hr_leitung'),
('__default__', 'security_awareness_policy', 'hr_leitung'),
('__default__', 'remote_work_policy', 'hr_leitung'),
('__default__', 'offboarding_policy', 'hr_leitung'),
('__default__', 'byod_policy', 'hr_leitung')
ON CONFLICT DO NOTHING;
-- Marketing-Leitung
INSERT INTO compliance_document_role_mapping (tenant_id, document_type, role_key) VALUES
('__default__', 'cookie_banner', 'marketing_leitung'),
('__default__', 'cookie_policy', 'marketing_leitung'),
('__default__', 'social_media_dsi', 'marketing_leitung'),
('__default__', 'community_guidelines', 'marketing_leitung'),
('__default__', 'acceptable_use', 'marketing_leitung'),
('__default__', 'media_content_policy', 'marketing_leitung'),
('__default__', 'copyright_policy', 'marketing_leitung'),
('__default__', 'video_conference_dsi', 'marketing_leitung')
ON CONFLICT DO NOTHING;
-- Compliance-Beauftragter
INSERT INTO compliance_document_role_mapping (tenant_id, document_type, role_key) VALUES
('__default__', 'ai_usage_policy', 'compliance_beauftragter')
ON CONFLICT DO NOTHING;
-- Einkauf / Vendor Management
INSERT INTO compliance_document_role_mapping (tenant_id, document_type, role_key) VALUES
('__default__', 'vendor_risk_management_policy', 'einkauf'),
('__default__', 'third_party_security_policy', 'einkauf'),
('__default__', 'supplier_security_policy', 'einkauf'),
('__default__', 'transfer_impact_assessment', 'einkauf'),
('__default__', 'scc_companion', 'einkauf')
ON CONFLICT DO NOTHING;
COMMIT;