Fondazione delle attività verso gli stakeholder (Simon C5 §4): - Questionari tipo (template): tipo questionario-da-compilare / firma-di-avvenuta-lettura, domande (JSON) + collegamento m2m a procedure (policies) E a misure/requisiti del framework (cfg_nis2_misure/requisiti). - Attività: basate (opz.) su un template, assegnabili a un CODICE stakeholder (tutti quelli di quel tipo) o a singoli stakeholder; pianificabili con data e scadenza. - Calendario NIS2: review_schedule esteso (ENUM entity_type += 'stakeholder_activity'); su create/update con scadenza la riga di calendario viene sincronizzata. - Invio: genera un magic-link per destinatario (token SHA-256) per il portale esterno (C5.2b). Email disattivate (kill-switch) -> i link si condividono manualmente. mig.052: stk_questionnaire_templates, stk_template_(procedures|misure|requisiti), stk_activities, stk_activity_targets, stk_activity_procedures + ALTER review_schedule. StakeholderActivityController + /api/stakeholder-activities/*; stakeholder-activities.html (2 tab: attività / questionari tipo + dettaglio invio); voce sidebar V2; help/i18n. Smoke prod OK (template m2m, attività by_code+calendario, assign, send magic-link, anti-IDOR individual, negativi 422; cleanup org 151 pulita). Additivo. v1.20.0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
141 lines
7.7 KiB
SQL
141 lines
7.7 KiB
SQL
-- =====================================================================
|
|
-- 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)
|