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>
66 lines
2.4 KiB
SQL
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)
|
|
);
|