-- ============================================================================ -- Migration 043 — A4 Fase 4.3: Matrice RACI + link molti-a-molti tra -- inventario (assets), procedure (policies), rischi (risks) e misure ACN. -- ---------------------------------------------------------------------------- -- 5 tabelle ADDITIVE. Idempotente (CREATE TABLE IF NOT EXISTS). Applicare con la -- STESSA connessione PDO dell'app (container nis2-db via TCP+TLS), via runner. -- -- Ancoraggio normativo (docs/DESIGN_A4_RELATIONAL.md): la matrice RACI collega i -- RUOLI dell'organigramma (mig.041, org_roles) agli OGGETTI di compliance -- (inventario/procedure/rischi/fornitori) con responsabilita R/A/C/I. -- - GV.RR-02 (NIST CSF 2.0): ruoli, responsabilita e poteri stabiliti/comunicati -- - ID.AM (asset management): inventario dei sistemi rilevanti -- - GV.PO (policy/governance): procedure -- - art. 24 D.Lgs. 138/2024 + ID.RA (risk assessment): rischi -- -- NOTE strutturali (verificate sul codice reale): -- - 'inventario' nel prodotto = tabella `assets` (mig.001 riga 363). -- - 'procedure' = tabella `policies` (mig.001 riga 256). -- - rischi = `risks` (riga 141); fornitori = `suppliers` (riga 286). -- - org_roles = mig.041 (id + organization_id). -- - misure ACN = catalogo JSON application/data/acn_measures.json (campo 'code', -- es. GV.OC-04) — NON e una tabella DB: 'risk_measure.measure_code' NON ha FK. -- - raci_assignments.object_id e POLIMORFICO (punta a assets/policies/risks/ -- suppliers a seconda di object_type) -> NON puo avere FK; l'esistenza e -- verificata in PHP (RaciController::assertObjectExists), org-scoped. -- -- Multi-tenancy: ogni tabella ha organization_id NOT NULL (FK organizations, -- ON DELETE CASCADE) e ogni query del controller filtra organization_id. -- ============================================================================ -- Assegnazione RACI: per ogni (ruolo, oggetto) una sola responsabilita R/A/C/I. -- object_id e polimorfico (vedi nota sopra) -> nessuna FK su object_id. CREATE TABLE IF NOT EXISTS raci_assignments ( id INT AUTO_INCREMENT PRIMARY KEY, organization_id INT NOT NULL, role_id INT NOT NULL, object_type ENUM('inventory','procedure','risk','supplier') NOT NULL, object_id INT NOT NULL, raci ENUM('R','A','C','I') NOT NULL, created_by INT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE, FOREIGN KEY (role_id) REFERENCES org_roles(id) ON DELETE CASCADE, FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL, UNIQUE KEY uk_raci (role_id, object_type, object_id), INDEX idx_raci_org (organization_id), INDEX idx_raci_object (object_type, object_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Link m2m: procedura (policy) <-> inventario (asset). CREATE TABLE IF NOT EXISTS procedure_inventory ( id INT AUTO_INCREMENT PRIMARY KEY, organization_id INT NOT NULL, policy_id INT NOT NULL, asset_id INT NOT NULL, created_by INT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE, FOREIGN KEY (policy_id) REFERENCES policies(id) ON DELETE CASCADE, FOREIGN KEY (asset_id) REFERENCES assets(id) ON DELETE CASCADE, FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL, UNIQUE KEY uk_proc_inv (policy_id, asset_id), INDEX idx_pi_org (organization_id), INDEX idx_pi_asset (asset_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Link m2m: procedura (policy) <-> rischio (risk). CREATE TABLE IF NOT EXISTS procedure_risk ( id INT AUTO_INCREMENT PRIMARY KEY, organization_id INT NOT NULL, policy_id INT NOT NULL, risk_id INT NOT NULL, created_by INT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE, FOREIGN KEY (policy_id) REFERENCES policies(id) ON DELETE CASCADE, FOREIGN KEY (risk_id) REFERENCES risks(id) ON DELETE CASCADE, FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL, UNIQUE KEY uk_proc_risk (policy_id, risk_id), INDEX idx_pr_org (organization_id), INDEX idx_pr_risk (risk_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Link m2m: inventario (asset) <-> rischio (risk). CREATE TABLE IF NOT EXISTS inventory_risk ( id INT AUTO_INCREMENT PRIMARY KEY, organization_id INT NOT NULL, asset_id INT NOT NULL, risk_id INT NOT NULL, created_by INT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE, FOREIGN KEY (asset_id) REFERENCES assets(id) ON DELETE CASCADE, FOREIGN KEY (risk_id) REFERENCES risks(id) ON DELETE CASCADE, FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL, UNIQUE KEY uk_inv_risk (asset_id, risk_id), INDEX idx_ir_org (organization_id), INDEX idx_ir_risk (risk_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Link m2m: rischio (risk) <-> misura ACN (codice del catalogo JSON, non FK). CREATE TABLE IF NOT EXISTS risk_measure ( id INT AUTO_INCREMENT PRIMARY KEY, organization_id INT NOT NULL, risk_id INT NOT NULL, measure_code VARCHAR(20) NOT NULL, created_by INT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE, FOREIGN KEY (risk_id) REFERENCES risks(id) ON DELETE CASCADE, FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL, UNIQUE KEY uk_risk_measure (risk_id, measure_code), INDEX idx_rm_org (organization_id), INDEX idx_rm_measure (measure_code) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;