-- 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) );