Files
breakpilot-compliance/backend-compliance/migrations/068_tom_control_mappings.sql
Benjamin Admin 4b1eede45b feat(tom): audit document, compliance checks, 25 controls, canonical control mapping
Phase A: TOM document HTML generator (12 sections, inline CSS, A4 print)
Phase B: TOMDocumentTab component (org-header form, revisions, print/download)
Phase C: 11 compliance checks with severity-weighted scoring
Phase D: MkDocs documentation for TOM module
Phase E: 25 new controls (63 → 88) in 13 categories

Canonical Control Mapping (three-layer architecture):
- Migration 068: tom_control_mappings + tom_control_sync_state tables
- 6 API endpoints: sync, list, by-tom, stats, manual add, delete
- Category mapping: 13 TOM categories → 17 canonical categories
- Frontend: sync button + coverage card (Overview), drill-down (Editor),
  belegende Controls count (Document)
- 20 tests (unit + API with mocked DB)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 11:56:53 +01:00

66 lines
2.4 KiB
SQL

-- Migration 068: TOM ↔ Canonical Control Mappings
-- Bridge table connecting TOM measures (88) to Canonical Controls (10,000+)
-- Enables three-layer architecture: TOM → Mapping → Canonical Controls
-- ============================================================================
-- 1. Mapping table (TOM control code → Canonical control)
-- ============================================================================
CREATE TABLE IF NOT EXISTS tom_control_mappings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
project_id UUID,
-- TOM side (references the embedded TOM control code, e.g. 'TOM-AC-01')
tom_control_code VARCHAR(20) NOT NULL,
tom_category VARCHAR(50) NOT NULL,
-- Canonical control side
canonical_control_id UUID NOT NULL,
canonical_control_code VARCHAR(20) NOT NULL,
canonical_category VARCHAR(50),
-- Mapping metadata
mapping_type VARCHAR(20) NOT NULL DEFAULT 'auto'
CHECK (mapping_type IN ('auto', 'manual')),
relevance_score NUMERIC(3,2) DEFAULT 1.00
CHECK (relevance_score >= 0 AND relevance_score <= 1),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
-- No duplicate mappings per tenant+project+TOM+canonical
UNIQUE (tenant_id, project_id, tom_control_code, canonical_control_id)
);
CREATE INDEX IF NOT EXISTS idx_tcm_tenant_project
ON tom_control_mappings (tenant_id, project_id);
CREATE INDEX IF NOT EXISTS idx_tcm_tom_code
ON tom_control_mappings (tom_control_code);
CREATE INDEX IF NOT EXISTS idx_tcm_canonical_id
ON tom_control_mappings (canonical_control_id);
CREATE INDEX IF NOT EXISTS idx_tcm_tom_category
ON tom_control_mappings (tom_category);
-- ============================================================================
-- 2. Sync state (tracks when the last sync ran + profile hash)
-- ============================================================================
CREATE TABLE IF NOT EXISTS tom_control_sync_state (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
project_id UUID,
-- Profile hash to detect changes (SHA-256 of serialized company profile)
profile_hash VARCHAR(64),
-- Stats from last sync
total_mappings INTEGER DEFAULT 0,
canonical_controls_matched INTEGER DEFAULT 0,
tom_controls_covered INTEGER DEFAULT 0,
last_synced_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
-- One sync state per tenant+project
UNIQUE (tenant_id, project_id)
);