-- ===================================================================== -- 052 — Attività stakeholder: questionari tipo + attività + calendario (Epic C / C5.2a) -- ===================================================================== -- Simon C5 §4: a ogni stakeholder si possono assegnare ATTIVITA' (questionari -- da compilare, richieste di firma di avvenuta lettura, o azioni), pianificabili -- su un calendario NIS2. Questa migrazione (C5.2a) crea la FONDAZIONE: -- - questionari tipo (template) con domande + m2m a procedure e misure/requisiti -- - attività + assegnazione (per codice stakeholder o per singoli) -- - destinatari (target) con token magic-link per il portale esterno (C5.2b) -- La sotto-dashboard feedback (risposte/firma, commenti, allegati) e il portale -- esterno arrivano in C5.2b (mig.053). -- -- Calendario: si RIUSA review_schedule (mig.044) aggiungendo il valore -- 'stakeholder_activity' all'ENUM entity_type (ALTER MODIFY, idempotente in -- effetto: re-eseguibile senza errore). -- -- Ancoraggio: GV.SC-02 (ruoli/responsabilità verso terze parti), GV.SC-05/07 -- (requisiti negli accordi, monitoraggio nel tempo) -> art. 24 D.Lgs. 138/2024. -- -- Additivo, reversibile. Runner-safe: CREATE TABLE IF NOT EXISTS con FK dentro -- il CREATE; nessun DELIMITER/stored-procedure; nessun ';' nei commenti. -- Dati: nessun seed di sistema (i template sono per-org). DDL eseguita dal CLI -- idempotente application/cli/seed_stakeholder_activities.php. -- ===================================================================== -- 1) Questionari tipo (template) CREATE TABLE IF NOT EXISTS stk_questionnaire_templates ( id INT NOT NULL AUTO_INCREMENT, organization_id INT NOT NULL, name VARCHAR(255) NOT NULL, kind ENUM('questionnaire','read_ack') NOT NULL DEFAULT 'questionnaire', description TEXT NULL, content TEXT NULL, -- testo da leggere (per kind=read_ack) questions JSON NULL, -- per kind=questionnaire: [{code,text,type,options,required}] status ENUM('draft','active','archived') NOT NULL DEFAULT 'active', created_by INT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_stkqt_org (organization_id), CONSTRAINT fk_stkqt_org FOREIGN KEY (organization_id) REFERENCES organizations (id) ON DELETE CASCADE, CONSTRAINT fk_stkqt_user FOREIGN KEY (created_by) REFERENCES users (id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 2) m2m template -> procedure (policies) CREATE TABLE IF NOT EXISTS stk_template_procedures ( template_id INT NOT NULL, policy_id INT NOT NULL, PRIMARY KEY (template_id, policy_id), KEY idx_stktp_policy (policy_id), CONSTRAINT fk_stktp_tpl FOREIGN KEY (template_id) REFERENCES stk_questionnaire_templates (id) ON DELETE CASCADE, CONSTRAINT fk_stktp_policy FOREIGN KEY (policy_id) REFERENCES policies (id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 3) m2m template -> misure (cfg_nis2_misure.misura_code) CREATE TABLE IF NOT EXISTS stk_template_misure ( template_id INT NOT NULL, misura_code VARCHAR(16) NOT NULL, PRIMARY KEY (template_id, misura_code), KEY idx_stktm_misura (misura_code), CONSTRAINT fk_stktm_tpl FOREIGN KEY (template_id) REFERENCES stk_questionnaire_templates (id) ON DELETE CASCADE, CONSTRAINT fk_stktm_misura FOREIGN KEY (misura_code) REFERENCES cfg_nis2_misure (misura_code) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 4) m2m template -> requisiti (cfg_nis2_requisiti.id) CREATE TABLE IF NOT EXISTS stk_template_requisiti ( template_id INT NOT NULL, requisito_id INT NOT NULL, PRIMARY KEY (template_id, requisito_id), KEY idx_stktr_req (requisito_id), CONSTRAINT fk_stktr_tpl FOREIGN KEY (template_id) REFERENCES stk_questionnaire_templates (id) ON DELETE CASCADE, CONSTRAINT fk_stktr_req FOREIGN KEY (requisito_id) REFERENCES cfg_nis2_requisiti (id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 5) Attività CREATE TABLE IF NOT EXISTS stk_activities ( id INT NOT NULL AUTO_INCREMENT, organization_id INT NOT NULL, title VARCHAR(255) NOT NULL, type ENUM('questionnaire','read_ack','action') NOT NULL DEFAULT 'questionnaire', template_id INT NULL, description TEXT NULL, assign_mode ENUM('by_code','individual') NOT NULL DEFAULT 'individual', stak_code VARCHAR(16) NULL, -- quando assign_mode=by_code planned_date DATE NULL, due_date DATE NULL, status ENUM('draft','scheduled','sent','in_progress','completed','cancelled') NOT NULL DEFAULT 'draft', created_by INT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_stka_org (organization_id), KEY idx_stka_tpl (template_id), CONSTRAINT fk_stka_org FOREIGN KEY (organization_id) REFERENCES organizations (id) ON DELETE CASCADE, CONSTRAINT fk_stka_tpl FOREIGN KEY (template_id) REFERENCES stk_questionnaire_templates (id) ON DELETE SET NULL, CONSTRAINT fk_stka_user FOREIGN KEY (created_by) REFERENCES users (id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 6) Destinatari dell'attività (target) — un record per stakeholder coinvolto CREATE TABLE IF NOT EXISTS stk_activity_targets ( id INT NOT NULL AUTO_INCREMENT, activity_id INT NOT NULL, stakeholder_id INT NOT NULL, access_token_hash CHAR(64) NULL, -- SHA-256 del magic-link (portale esterno C5.2b) state ENUM('pending','sent','responded','acknowledged','expired') NOT NULL DEFAULT 'pending', sent_at DATETIME NULL, responded_at DATETIME NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uq_stkat (activity_id, stakeholder_id), KEY idx_stkat_stk (stakeholder_id), KEY idx_stkat_token (access_token_hash), CONSTRAINT fk_stkat_act FOREIGN KEY (activity_id) REFERENCES stk_activities (id) ON DELETE CASCADE, CONSTRAINT fk_stkat_stk FOREIGN KEY (stakeholder_id) REFERENCES stakeholders (id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 7) m2m attività -> procedure (policies) — collegamento all'elenco procedure (§4.1) CREATE TABLE IF NOT EXISTS stk_activity_procedures ( activity_id INT NOT NULL, policy_id INT NOT NULL, PRIMARY KEY (activity_id, policy_id), KEY idx_stkap_policy (policy_id), CONSTRAINT fk_stkap_act FOREIGN KEY (activity_id) REFERENCES stk_activities (id) ON DELETE CASCADE, CONSTRAINT fk_stkap_policy FOREIGN KEY (policy_id) REFERENCES policies (id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 8) Calendario NIS2: estende l'ENUM di review_schedule (mig.044). -- ALTER MODIFY e' idempotente in effetto (re-eseguibile senza errore). ALTER TABLE review_schedule MODIFY COLUMN entity_type ENUM('role','skill','inventory','procedure','risk','supplier','measure','custom','stakeholder_activity') NOT NULL; -- ROLLBACK (manuale): -- DROP TABLE IF EXISTS stk_activity_procedures -- DROP TABLE IF EXISTS stk_activity_targets -- DROP TABLE IF EXISTS stk_activities -- DROP TABLE IF EXISTS stk_template_requisiti -- DROP TABLE IF EXISTS stk_template_misure -- DROP TABLE IF EXISTS stk_template_procedures -- DROP TABLE IF EXISTS stk_questionnaire_templates -- (review_schedule: rimettere l'ENUM senza 'stakeholder_activity' dopo aver eliminato le righe relative)