Files
nis2-agile/docs/sql/057_periodic_controls.sql
DevEnv nis2-agileandClaude Opus 4.8 4fdeae7cee [FEAT] Modulo Controlli periodici (control monitoring §9.1/A.8.16) — v1.23.0
Registro controlli ricorrenti (owner/frequenza/metodo/controllo SoA-NIS2 collegato)
+ registro esecuzioni come EVIDENZA (data/esito/note) con avanzamento automatico
della scadenza; da esito non conforme generazione NC o NC+azione correttiva
(riuso non_conformities/capa_actions, nuova source 'monitoring'); report
scheda+storico stampabile; scadenze nel Calendario unico.

mig.057: periodic_controls + periodic_control_executions (FK CASCADE, UNIQUE
(organization_id, code)). PeriodicControlController (slug periodic-controls) +
controlli-periodici.html + CalendarController.srcPeriodicControls.

Fix da flotta di verifica avversariale (9 finding confermati):
- advance(): correzione overflow strtotime '+1 month' (31/01 -> 28/02, no salto
  mese) via DateTimeImmutable con clamp all'ultimo giorno valido (mensile/
  trimestrale/semestrale/annuale); giornaliero/settimanale/custom invariati.
- create(): retry-on-duplicate del codice CTL-NNN con UNIQUE (org_id, code).
- update(): array_key_exists per azzerare owner_role_id / next_due_date.
- delete(): rimossa cleanup morta su review_schedule (il calendario legge diretto).
- CalendarController.srcReviewSchedule: esclude internal_audit/stakeholder_activity
  (gia' con sorgente diretta) -> fix doppia comparsa nel calendario.
- calendario.html: TYPE_META 'periodic_control' (chip filtro + label + colore).

Additivo. Cache-buster ?v= bump (sidebar) + sw cache nis2-shell-v1.23.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 09:21:03 +02:00

66 lines
3.9 KiB
SQL

-- =====================================================================
-- 057 — Controlli periodici (control monitoring con frequenza + esecuzioni + NC/AC)
-- =====================================================================
-- Registro dei controlli RICORRENTI con frequenza, owner e metodo; ogni
-- ESECUZIONE è registrata (data, esito, note, evidenze su evidence_files) =
-- EVIDENZA del monitoraggio periodico (ISO 27001 §9.1 / A.8.16; buona prassi,
-- non obbligo). Da un esito non conforme si genera una NC o un'azione correttiva
-- (riuso non_conformities/capa_actions). Distinto da: compliance_controls
-- (registro stato), review_schedule (cadenza generica), internal_audits (audit
-- puntuale). Vedi docs/DESIGN_CONTROLLI_PERIODICI.md.
--
-- Additivo, reversibile. Runner-safe: CREATE TABLE IF NOT EXISTS con FK inline;
-- l'ALTER dell'ENUM non_conformities.source è applicata dal seeder idempotente
-- (preservando i valori) — application/cli/seed_periodic_controls.php.
-- =====================================================================
CREATE TABLE IF NOT EXISTS periodic_controls (
id INT NOT NULL AUTO_INCREMENT,
organization_id INT NOT NULL,
code VARCHAR(20) NULL, -- CTL-NNN per org
title VARCHAR(255) NOT NULL,
description TEXT NULL,
category VARCHAR(100) NULL,
control_ref VARCHAR(32) NULL, -- codice SoA/NIS2 collegato (es. A.8.13)
owner_role_id INT NULL, -- responsabile (org_roles)
frequency ENUM('giornaliero','settimanale','mensile','trimestrale','semestrale','annuale','custom') NOT NULL DEFAULT 'mensile',
frequency_days INT NULL, -- usato se frequency='custom'
method TEXT NULL, -- metodologia di verifica
next_due_date DATE NULL,
last_executed_at DATE NULL,
status ENUM('active','suspended') 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_pctl_org (organization_id),
KEY idx_pctl_due (organization_id, next_due_date),
CONSTRAINT fk_pctl_org FOREIGN KEY (organization_id) REFERENCES organizations (id) ON DELETE CASCADE,
CONSTRAINT fk_pctl_role FOREIGN KEY (owner_role_id) REFERENCES org_roles (id) ON DELETE SET NULL,
CONSTRAINT fk_pctl_user FOREIGN KEY (created_by) REFERENCES users (id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS periodic_control_executions (
id INT NOT NULL AUTO_INCREMENT,
control_id INT NOT NULL,
executed_at DATE NOT NULL,
executed_by INT NULL,
outcome ENUM('conforme','non_conforme','parziale','non_applicabile') NOT NULL DEFAULT 'conforme',
notes TEXT NULL,
ncr_id INT NULL, -- NC eventualmente generata
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY idx_pcexec_control (control_id),
CONSTRAINT fk_pcexec_control FOREIGN KEY (control_id) REFERENCES periodic_controls (id) ON DELETE CASCADE,
CONSTRAINT fk_pcexec_user FOREIGN KEY (executed_by) REFERENCES users (id) ON DELETE SET NULL,
CONSTRAINT fk_pcexec_ncr FOREIGN KEY (ncr_id) REFERENCES non_conformities (id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ALTER non_conformities.source: aggiunge 'monitoring' (eseguita dal seeder, idempotente).
-- ALTER TABLE non_conformities MODIFY COLUMN source ENUM('assessment','audit','incident','supplier_review','management_review','external_audit','monitoring','other') NOT NULL DEFAULT 'assessment';
-- ROLLBACK (manuale):
-- DROP TABLE IF EXISTS periodic_control_executions
-- DROP TABLE IF EXISTS periodic_controls
-- (non_conformities.source: rimuovere 'monitoring' dall'ENUM dopo aver riclassificato le NC relative)