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>
This commit is contained in:
65
backend-compliance/migrations/068_tom_control_mappings.sql
Normal file
65
backend-compliance/migrations/068_tom_control_mappings.sql
Normal file
@@ -0,0 +1,65 @@
|
||||
-- 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)
|
||||
);
|
||||
Reference in New Issue
Block a user