Files
breakpilot-compliance/ai-compliance-sdk/migrations/011_vendor_compliance_schema.sql
Benjamin Boenisch 504dd3591b feat: Add Academy, Whistleblower, Incidents, Vendor, DSB, SSO, Reporting, Multi-Tenant and Industry backends
Go handlers, models, stores and migrations for all SDK modules.
Updates developer portal navigation and BYOEH page.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 21:11:27 +01:00

357 lines
17 KiB
SQL

-- ============================================================================
-- Migration 011: Vendor Compliance Schema
-- Vendor Management, Contract/AVV Management, Findings, Templates
--
-- Implements DSGVO Art. 28 (Auftragsverarbeitung) requirements:
-- - Vendor registry with risk scoring and classification
-- - Contract/AVV document management with AI-assisted review
-- - Compliance findings from contract analysis
-- - Control instances for vendor-level control assessments
-- - Pre-filled templates for vendors, processing activities, and TOMs
-- ============================================================================
-- ============================================================================
-- Vendors (Service Provider Registry)
-- ============================================================================
CREATE TABLE IF NOT EXISTS vendor_vendors (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES compliance_tenants(id) ON DELETE CASCADE,
-- Basic info
name VARCHAR(255) NOT NULL,
legal_form VARCHAR(100),
country VARCHAR(10) NOT NULL DEFAULT 'DE', -- ISO 3166-1 alpha-2
address JSONB, -- {street, city, postalCode, country, state}
website VARCHAR(500),
-- Contact
contact_name VARCHAR(255),
contact_email VARCHAR(255),
contact_phone VARCHAR(100),
contact_department VARCHAR(255),
-- Role & Classification
role VARCHAR(50) NOT NULL DEFAULT 'PROCESSOR', -- PROCESSOR, CONTROLLER, JOINT_CONTROLLER, SUB_PROCESSOR, THIRD_PARTY
service_category VARCHAR(50), -- HOSTING, CRM, ERP, ANALYTICS, etc. (19 categories)
service_description TEXT,
data_access_level VARCHAR(50) DEFAULT 'NONE', -- NONE, POTENTIAL, ADMINISTRATIVE, CONTENT
-- Processing & Compliance
processing_locations JSONB DEFAULT '[]', -- [{country, region, isPrimary, isEU, isAdequate}]
certifications JSONB DEFAULT '[]', -- ["ISO 27001", "SOC 2", etc.]
-- Risk Scoring (0-100)
inherent_risk_score INT DEFAULT 0,
residual_risk_score INT DEFAULT 0,
manual_risk_adjustment INT,
-- Contract & Review
review_frequency VARCHAR(50) DEFAULT 'ANNUAL', -- QUARTERLY, SEMI_ANNUAL, ANNUAL, BIENNIAL
last_review_date TIMESTAMPTZ,
next_review_date TIMESTAMPTZ,
-- Links
processing_activity_ids JSONB DEFAULT '[]', -- UUIDs of linked processing activities
-- Status
status VARCHAR(50) DEFAULT 'ACTIVE', -- ACTIVE, INACTIVE, PENDING_REVIEW, TERMINATED
-- Template reference (if created from template)
template_id VARCHAR(100),
-- Audit
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID NOT NULL
);
-- ============================================================================
-- Contracts (including AVV/DPA)
-- ============================================================================
CREATE TABLE IF NOT EXISTS vendor_contracts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES compliance_tenants(id) ON DELETE CASCADE,
vendor_id UUID NOT NULL REFERENCES vendor_vendors(id) ON DELETE CASCADE,
-- Document info
file_name VARCHAR(500),
original_name VARCHAR(500),
mime_type VARCHAR(100),
file_size BIGINT,
storage_path VARCHAR(1000), -- MinIO path
-- Classification
document_type VARCHAR(50) NOT NULL, -- AVV, MSA, SLA, SCC, NDA, TOM_ANNEX, CERTIFICATION, SUB_PROCESSOR_LIST
-- Metadata (extracted or manual)
parties JSONB, -- [{name, role, address}]
effective_date DATE,
expiration_date DATE,
auto_renewal BOOLEAN DEFAULT FALSE,
renewal_notice_period VARCHAR(100),
-- Review Status
review_status VARCHAR(50) DEFAULT 'PENDING', -- PENDING, IN_PROGRESS, COMPLETED, FAILED
review_completed_at TIMESTAMPTZ,
compliance_score INT, -- 0-100
-- Versioning
version VARCHAR(50) DEFAULT '1.0',
previous_version_id UUID REFERENCES vendor_contracts(id),
-- Content (extracted text for analysis)
extracted_text TEXT,
page_count INT,
-- Audit
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID NOT NULL
);
-- ============================================================================
-- Findings (from contract reviews)
-- ============================================================================
CREATE TABLE IF NOT EXISTS vendor_findings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES compliance_tenants(id) ON DELETE CASCADE,
contract_id UUID REFERENCES vendor_contracts(id) ON DELETE CASCADE,
vendor_id UUID NOT NULL REFERENCES vendor_vendors(id) ON DELETE CASCADE,
-- Classification
finding_type VARCHAR(20) NOT NULL, -- OK, GAP, RISK, UNKNOWN
category VARCHAR(50) NOT NULL, -- AVV_CONTENT, SUBPROCESSOR, INCIDENT, AUDIT_RIGHTS, DELETION, TOM, TRANSFER, LIABILITY, SLA, DATA_SUBJECT_RIGHTS, CONFIDENTIALITY, INSTRUCTION, TERMINATION, GENERAL
severity VARCHAR(20) NOT NULL, -- LOW, MEDIUM, HIGH, CRITICAL
-- Content
title VARCHAR(500) NOT NULL,
description TEXT,
recommendation TEXT,
-- Citations (from contract text)
citations JSONB DEFAULT '[]', -- [{documentId, page, startChar, endChar, quotedText, quoteHash}]
-- Workflow
status VARCHAR(50) DEFAULT 'OPEN', -- OPEN, IN_PROGRESS, RESOLVED, ACCEPTED, FALSE_POSITIVE
assignee VARCHAR(255),
due_date DATE,
resolution TEXT,
resolved_at TIMESTAMPTZ,
resolved_by UUID,
-- Audit
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ============================================================================
-- Control Instances (applied controls per vendor)
-- ============================================================================
CREATE TABLE IF NOT EXISTS vendor_control_instances (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES compliance_tenants(id) ON DELETE CASCADE,
vendor_id UUID NOT NULL REFERENCES vendor_vendors(id) ON DELETE CASCADE,
-- Control reference
control_id VARCHAR(100) NOT NULL, -- e.g., VND-TRF-01
control_domain VARCHAR(50), -- TRANSFER, AUDIT, DELETION, INCIDENT, SUBPROCESSOR, TOM, CONTRACT, DATA_SUBJECT, SECURITY, GOVERNANCE
-- Assessment
status VARCHAR(50) DEFAULT 'PLANNED', -- PASS, PARTIAL, FAIL, NOT_APPLICABLE, PLANNED
evidence_ids JSONB DEFAULT '[]',
notes TEXT,
-- Timing
last_assessed_at TIMESTAMPTZ,
last_assessed_by UUID,
next_assessment_date TIMESTAMPTZ,
-- Audit
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(tenant_id, vendor_id, control_id)
);
-- ============================================================================
-- Templates (pre-filled templates for various entity types)
-- ============================================================================
CREATE TABLE IF NOT EXISTS compliance_templates (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID REFERENCES compliance_tenants(id) ON DELETE CASCADE, -- NULL for system templates
-- Template info
template_type VARCHAR(50) NOT NULL, -- VENDOR, PROCESSING_ACTIVITY, TOM, CONTROL_SET
template_id VARCHAR(100) NOT NULL UNIQUE, -- e.g., tpl-vendor-cloud-iaas
category VARCHAR(100), -- HR, SALES, MARKETING, CLOUD_INFRASTRUCTURE, etc.
-- Content
name_de VARCHAR(500) NOT NULL,
name_en VARCHAR(500) NOT NULL,
description_de TEXT,
description_en TEXT,
-- Template data (full template content as JSONB)
template_data JSONB NOT NULL,
-- Organization
industry VARCHAR(100), -- IT, HEALTHCARE, FINANCE, MANUFACTURING, RETAIL, etc.
tags JSONB DEFAULT '[]',
-- Metadata
is_system BOOLEAN DEFAULT FALSE, -- true = pre-installed, false = user-created
is_active BOOLEAN DEFAULT TRUE,
usage_count INT DEFAULT 0,
-- Audit
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ============================================================================
-- Indexes: Vendors
-- ============================================================================
CREATE INDEX IF NOT EXISTS idx_vendor_vendors_tenant ON vendor_vendors(tenant_id);
CREATE INDEX IF NOT EXISTS idx_vendor_vendors_status ON vendor_vendors(tenant_id, status);
CREATE INDEX IF NOT EXISTS idx_vendor_vendors_role ON vendor_vendors(tenant_id, role);
CREATE INDEX IF NOT EXISTS idx_vendor_vendors_service_category ON vendor_vendors(tenant_id, service_category);
CREATE INDEX IF NOT EXISTS idx_vendor_vendors_next_review ON vendor_vendors(next_review_date)
WHERE next_review_date IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_vendor_vendors_template_id ON vendor_vendors(template_id)
WHERE template_id IS NOT NULL;
-- ============================================================================
-- Indexes: Contracts
-- ============================================================================
CREATE INDEX IF NOT EXISTS idx_vendor_contracts_tenant ON vendor_contracts(tenant_id);
CREATE INDEX IF NOT EXISTS idx_vendor_contracts_vendor ON vendor_contracts(vendor_id);
CREATE INDEX IF NOT EXISTS idx_vendor_contracts_document_type ON vendor_contracts(tenant_id, document_type);
CREATE INDEX IF NOT EXISTS idx_vendor_contracts_review_status ON vendor_contracts(tenant_id, review_status);
CREATE INDEX IF NOT EXISTS idx_vendor_contracts_expiration ON vendor_contracts(expiration_date)
WHERE expiration_date IS NOT NULL;
-- ============================================================================
-- Indexes: Findings
-- ============================================================================
CREATE INDEX IF NOT EXISTS idx_vendor_findings_tenant ON vendor_findings(tenant_id);
CREATE INDEX IF NOT EXISTS idx_vendor_findings_vendor ON vendor_findings(vendor_id);
CREATE INDEX IF NOT EXISTS idx_vendor_findings_contract ON vendor_findings(contract_id)
WHERE contract_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_vendor_findings_severity ON vendor_findings(tenant_id, severity);
CREATE INDEX IF NOT EXISTS idx_vendor_findings_status ON vendor_findings(tenant_id, status);
CREATE INDEX IF NOT EXISTS idx_vendor_findings_category ON vendor_findings(tenant_id, category);
-- ============================================================================
-- Indexes: Control Instances
-- ============================================================================
CREATE INDEX IF NOT EXISTS idx_vendor_control_instances_tenant ON vendor_control_instances(tenant_id);
CREATE INDEX IF NOT EXISTS idx_vendor_control_instances_vendor ON vendor_control_instances(vendor_id);
CREATE INDEX IF NOT EXISTS idx_vendor_control_instances_control_id ON vendor_control_instances(control_id);
CREATE INDEX IF NOT EXISTS idx_vendor_control_instances_status ON vendor_control_instances(tenant_id, status);
-- ============================================================================
-- Indexes: Templates
-- ============================================================================
CREATE INDEX IF NOT EXISTS idx_compliance_templates_type ON compliance_templates(template_type);
CREATE INDEX IF NOT EXISTS idx_compliance_templates_category ON compliance_templates(category)
WHERE category IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_compliance_templates_industry ON compliance_templates(industry)
WHERE industry IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_compliance_templates_system ON compliance_templates(is_system);
CREATE INDEX IF NOT EXISTS idx_compliance_templates_active ON compliance_templates(is_active);
CREATE INDEX IF NOT EXISTS idx_compliance_templates_template_id ON compliance_templates(template_id);
-- ============================================================================
-- Triggers
-- ============================================================================
-- Reuse existing update_updated_at_column function
-- Vendors trigger
DROP TRIGGER IF EXISTS update_vendor_vendors_updated_at ON vendor_vendors;
CREATE TRIGGER update_vendor_vendors_updated_at
BEFORE UPDATE ON vendor_vendors
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- Contracts trigger
DROP TRIGGER IF EXISTS update_vendor_contracts_updated_at ON vendor_contracts;
CREATE TRIGGER update_vendor_contracts_updated_at
BEFORE UPDATE ON vendor_contracts
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- Findings trigger
DROP TRIGGER IF EXISTS update_vendor_findings_updated_at ON vendor_findings;
CREATE TRIGGER update_vendor_findings_updated_at
BEFORE UPDATE ON vendor_findings
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- Control instances trigger
DROP TRIGGER IF EXISTS update_vendor_control_instances_updated_at ON vendor_control_instances;
CREATE TRIGGER update_vendor_control_instances_updated_at
BEFORE UPDATE ON vendor_control_instances
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- Templates trigger
DROP TRIGGER IF EXISTS update_compliance_templates_updated_at ON compliance_templates;
CREATE TRIGGER update_compliance_templates_updated_at
BEFORE UPDATE ON compliance_templates
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- ============================================================================
-- Comments
-- ============================================================================
-- Table comments
COMMENT ON TABLE vendor_vendors IS 'Service provider registry for vendor compliance management (DSGVO Art. 28)';
COMMENT ON TABLE vendor_contracts IS 'Contract and AVV/DPA document management with AI-assisted review';
COMMENT ON TABLE vendor_findings IS 'Compliance findings from contract reviews and vendor assessments';
COMMENT ON TABLE vendor_control_instances IS 'Applied controls per vendor with assessment tracking';
COMMENT ON TABLE compliance_templates IS 'Pre-filled templates for vendors, processing activities, TOMs, and control sets';
-- Vendor column comments
COMMENT ON COLUMN vendor_vendors.role IS 'DSGVO role: PROCESSOR (Art. 28), CONTROLLER, JOINT_CONTROLLER (Art. 26), SUB_PROCESSOR, THIRD_PARTY';
COMMENT ON COLUMN vendor_vendors.data_access_level IS 'Level of access to personal data: NONE, POTENTIAL, ADMINISTRATIVE, CONTENT';
COMMENT ON COLUMN vendor_vendors.processing_locations IS 'JSONB array: Data processing locations with EU/adequacy status for transfer assessment';
COMMENT ON COLUMN vendor_vendors.certifications IS 'JSONB array: Vendor certifications (ISO 27001, SOC 2, etc.)';
COMMENT ON COLUMN vendor_vendors.inherent_risk_score IS 'Risk score (0-100) before controls are applied';
COMMENT ON COLUMN vendor_vendors.residual_risk_score IS 'Risk score (0-100) after controls are applied';
COMMENT ON COLUMN vendor_vendors.review_frequency IS 'How often the vendor must be reviewed: QUARTERLY, SEMI_ANNUAL, ANNUAL, BIENNIAL';
COMMENT ON COLUMN vendor_vendors.processing_activity_ids IS 'JSONB array: UUIDs linking to dsgvo_processing_activities entries';
COMMENT ON COLUMN vendor_vendors.template_id IS 'Reference to compliance_templates.template_id if vendor was created from a template';
-- Contract column comments
COMMENT ON COLUMN vendor_contracts.document_type IS 'Contract type: AVV (Auftragsverarbeitungsvertrag), MSA, SLA, SCC (Standard Contractual Clauses), NDA, TOM_ANNEX, CERTIFICATION, SUB_PROCESSOR_LIST';
COMMENT ON COLUMN vendor_contracts.storage_path IS 'MinIO object storage path for the uploaded document';
COMMENT ON COLUMN vendor_contracts.compliance_score IS 'AI-assessed compliance score (0-100) from contract review';
COMMENT ON COLUMN vendor_contracts.extracted_text IS 'Full text extracted from the document for AI analysis';
COMMENT ON COLUMN vendor_contracts.previous_version_id IS 'Self-referencing FK for contract version history';
-- Finding column comments
COMMENT ON COLUMN vendor_findings.finding_type IS 'Classification: OK (compliant), GAP (missing clause), RISK (problematic clause), UNKNOWN (could not determine)';
COMMENT ON COLUMN vendor_findings.category IS 'DSGVO Art. 28 requirement category the finding relates to';
COMMENT ON COLUMN vendor_findings.citations IS 'JSONB array: References to specific contract text passages with page/character offsets';
COMMENT ON COLUMN vendor_findings.status IS 'Workflow status: OPEN, IN_PROGRESS, RESOLVED, ACCEPTED (risk accepted), FALSE_POSITIVE';
-- Control instance column comments
COMMENT ON COLUMN vendor_control_instances.control_id IS 'Control identifier (e.g., VND-TRF-01 for transfer controls)';
COMMENT ON COLUMN vendor_control_instances.control_domain IS 'Control domain: TRANSFER, AUDIT, DELETION, INCIDENT, SUBPROCESSOR, TOM, CONTRACT, DATA_SUBJECT, SECURITY, GOVERNANCE';
COMMENT ON COLUMN vendor_control_instances.status IS 'Assessment result: PASS, PARTIAL, FAIL, NOT_APPLICABLE, PLANNED';
COMMENT ON COLUMN vendor_control_instances.evidence_ids IS 'JSONB array: References to evidence documents or contract IDs';
-- Template column comments
COMMENT ON COLUMN compliance_templates.template_type IS 'Template category: VENDOR, PROCESSING_ACTIVITY, TOM, CONTROL_SET';
COMMENT ON COLUMN compliance_templates.template_id IS 'Human-readable unique identifier (e.g., tpl-vendor-cloud-iaas)';
COMMENT ON COLUMN compliance_templates.template_data IS 'JSONB: Full template content including all pre-filled fields';
COMMENT ON COLUMN compliance_templates.is_system IS 'true = pre-installed system template, false = user-created tenant template';
COMMENT ON COLUMN compliance_templates.usage_count IS 'Number of times this template has been used to create entities';