Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
12 KiB
Design + Stima — Moduli "Audit Interni" (9.2) e "Riesame di Direzione" (9.3)
Proposta progettuale (NON ancora implementata) · 2026-06-17 · obiettivo: chiudere i 2 gap gestionali emersi dalla valutazione ISO 27001 (
docs/Agile 27000/VALUTAZIONE_COPERTURA_NIS2AGILE_vs_ISO27001.md) e rendere NIS2 Agile audit-ready end-to-end sul lato SGSI (clausole 4–10 complete). Vale anche per NIS2: il riesame periodico e gli audit interni sono buona prassi di governance (GV.PO-02/DE).
Perché questi due
La valutazione ha mostrato che il software copre bene SoA, rischi, NC/CAPA, formazione, asset, evidenze e audit-trail, ma lascia scoperti due output formali che l'auditor chiede sempre:
- 9.2 Audit interni — manca il ciclo programma → checklist → report.
- 9.3 Riesame di direzione — il software pianifica la scadenza (
review_schedule) ma non produce il verbale con input/output. Entrambi sono gestionali (non controlli tecnici), quindi pienamente realizzabili in-app.
MODULO A — Audit Interni (ISO 27001 §9.2)
Cosa deve produrre (richiesta auditor)
Procedura audit interni (documento) + programma annuale + checklist di conduzione + report con esiti, il tutto come registrazioni tracciate. Le non conformità rilevate confluiscono nel modulo NC/CAPA esistente.
Modello dati (mig.055, additivo, runner-safe)
internal_audits: id, organization_id, code (AUD-NNN), title, scope (TEXT), criteria (TEXT: es. "ISO 27001:2022 cl.4-10 + Annex A"), planned_date, executed_date, status ENUM('planned','in_progress','completed','cancelled'), lead_auditor_user_id NULL, lead_auditor_role_id NULL (org_roles), conclusion TEXT, created_by, ts.internal_audit_items(checklist): id, audit_id FK CASCADE, ref_type ENUM('clause','annex_control','nis2_measure','custom'), ref_code VARCHAR (es. '9.2', 'A.8.13', 'ID.AM-01'), checkpoint TEXT, result ENUM('conforme','non_conforme','osservazione','opportunita','non_applicabile','da_verificare') DEFAULT 'da_verificare', note TEXT, ord INT.- Riuso: evidenze su
evidence_files(entity_type='internal_audit'); finding NC → crea riganon_conformitiesconsource_entity_type='internal_audit_item'+source_entity_id(polimorfico già esistente,004); calendario → rigareview_schedule(estendo ENUM coninternal_audit).
Seed checklist (valore chiave: "checklist pronta")
Al create di un audit con criteria ISO, pre-popolare gli item da:
- clausole 4–10 (28 punti) — lista statica in config,
- controlli Annex A applicabili dal SoA dell'org (
isms_soadove applicable=1) — riuso del dataset038. Così l'auditor interno parte con la checklist già compilabile, non da foglio bianco.
Endpoint — InternalAuditController (slug internal-audits)
GET list·GET {id}(con item) ·POST create(genera code + seed checklist) ·PUT {id}·DELETE {id}GET {id}/items·PUT {id}/items/{subId}(esito/note) ·POST {id}/items(item custom)POST {id}/items/{subId}/raise-ncr(finding → NC/CAPA)GET {id}/report(report HTML stampabile via ReportService)- Ruoli scrittura:
org_admin/compliance_manager/auditor. Anti-IDOR + audit log (hash-chain).
Frontend — internal-audits.html
Lista programma (con stato/scadenza dal calendario) + dettaglio audit: intestazione (scope/criteri/auditor), checklist raggruppata per area (clausole / Annex A / NIS2) con esito per riga, pulsante "apri NC" sui non-conformi, export report. Voce sidebar in common-bi.js + common.js (sezione Audit & Report o Gestione). Help/i18n/KB.
MODULO B — Riesame di Direzione (ISO 27001 §9.3)
Cosa deve produrre
Il verbale del riesame, ad intervalli pianificati, con INPUT e OUTPUT previsti dalla norma. Punto di forza possibile: aggregare automaticamente gli input dai moduli esistenti (enorme risparmio + coerenza).
Modello dati (mig.056, additivo)
management_reviews: id, organization_id, code (RD-AAAA-NN), review_date, period_label, chair_user_id, attendees (JSON), status ENUM('draft','approved'), approved_by NULL, approved_at NULL, snapshot (JSON: gli input aggregati congelati al momento del verbale), conclusions TEXT, created_by, ts.management_review_decisions: id, review_id FK CASCADE, decision TEXT, owner_role_id NULL, due_date NULL, status ENUM('open','in_progress','done'), capa_id NULL (link acapa_actionsse diventa azione), ord.- Riuso: decisioni con scadenza → riga
review_schedulee/ocapa_actions; export via ReportService; immutabilità via audit-log all'approve.
Aggregazione automatica degli input (il valore vero)
GET /api/management-reviews/gather raccoglie e propone (l'utente rivede/edita prima di congelare nello snapshot):
- stato azioni dal riesame precedente (
management_review_decisions+ CAPA); - cambiamenti contesto/parti interessate (ISMS context + stakeholder);
- risultati audit interni (Modulo A);
- stato NC/azioni correttive (
non_conformities/capa_actions); - risultati monitoraggio/KPI (dashboard score, SoA
implementation_pct); - raggiungimento obiettivi SGSI (
isms_objectives); - risultati valutazione rischi e stato trattamento (Risk + treatments);
- feedback parti interessate (attività stakeholder/feedback);
- aggiornamenti normativi e ACK (
normative_*); - opportunità di miglioramento. OUTPUT: decisioni → diventano azioni (CAPA) e/o scadenze (calendario).
Endpoint — ManagementReviewController (slug management-reviews)
GET list·GET {id}·POST create·PUT {id}·GET gather(input aggregati) ·POST {id}/decisions·PUT {id}/decisions/{subId}·POST {id}/approve(congela snapshot + audit log) ·GET {id}/report(verbale stampabile).- Ruoli:
org_admin/compliance_manager(approve:org_admin).
Frontend — management-review.html
Form/wizard del verbale: sezioni INPUT pre-compilate da gather (editabili), tabella DECISIONI (con owner/scadenza→calendario), stato draft→approvato, export verbale. Sidebar + help/i18n/KB.
Integrazione e principi
- Config-driven dove sensato (checklist clausole 4–10 in config/JSON di sistema; controlli da SoA org).
- Riuso massimo: NC/CAPA, review_schedule (ENUM +=
internal_audit,management_review), evidence_files, ReportService, AuditService (hash-chain), ISMS SoA/objectives, dashboard score. - Convenzioni note: migrazioni runner-safe (CREATE IF NOT EXISTS + FK inline), deploy via host SSH + reload php-fpm host (il prod gira su fpm host), cache-buster, version bump, smoke su org 151 con cleanup, giro help/i18n/KB.
- Chiude i gap #1 e #2 della valutazione; gli altri (#3 A.8 tecnici, #4 A.7 fisici, #5 KPI/6.3) restano per natura fuori software (resta lo slot SoA+evidenza).
Fasi e stima (riferimento: C5.1/C5.2a già fatti, complessità simile)
| Fase | Contenuto | Stima |
|---|---|---|
| A1 | mig.055 + InternalAuditController + seed checklist + router/api | ~0,5 sessione |
| A2 | internal-audits.html (programma+checklist+report) + sidebar/help/i18n/KB + deploy+smoke |
~0,5 sessione |
| B1 | mig.056 + ManagementReviewController + gather (aggregazione input) + router/api |
~0,5–1 sessione (il gather è il pezzo ricco) |
| B2 | management-review.html (verbale + decisioni + export) + sidebar/help/i18n/KB + deploy+smoke |
~0,5 sessione |
| V | verifica flotta multi-agente + correzioni + doc | ~0,5 sessione |
| Totale | due moduli completi, deployati, collaudati | ~2,5–3 sessioni |
Ogni fase è committata+pushata e LIVE in autonomia (1 sola istanza L1). Prossima migrazione libera: 055.
Esito atteso
Con questi due moduli l'auditor ISO troverebbe in-app: SoA, rischi, NC/CAPA, formazione, asset, evidenze, programma+report audit interni e verbale del riesame — cioè tutte le registrazioni gestionali delle clausole 4–10. Resterebbe solo da dimostrare i controlli tecnici A.7/A.8 sull'infrastruttura reale (non delegabili ad alcun software).
MODULO C — Calendario unico delle scadenze (richiesta utente 2026-06-17)
Obiettivo
Una vista calendario unica che raccoglie ogni scadenza del sistema in un solo posto (griglia mensile + lista + filtri), con stato (in ritardo / in scadenza / futura) e link diretto all'elemento. Oggi le scadenze sono sparse in molti moduli e aggregate solo in parte (dashboard "prossime scadenze" a 30 gg + Scadenziario revisioni periodiche): manca la vista d'insieme completa.
Analisi — sorgenti di scadenza già presenti (verificate nel codice/DB)
| Sorgente | Campo data | Modulo |
|---|---|---|
| Incidenti Art.23 | early_warning_due / notification_due / final_report_due (calcolati) |
incidents |
| Revisione policy/procedure | policies.next_review_date |
Policy |
| Trattamenti rischio | risk_treatments.due_date |
Rischi |
| Revisione controlli | compliance_controls.next_review_date |
Audit/Controlli |
| Non conformità / azioni | non_conformities.target_close_date, capa_actions.due_date |
NCR/CAPA |
| Formazione | training_assignments.due_date |
Formazione |
| Attività stakeholder | stk_activities.due_date / planned_date |
Stakeholder (C5) |
| Scadenziario revisioni | review_schedule.next_review_date (ricorrenti) |
Scadenziario (A4 4.4) |
| Audit interni (nuovo) | internal_audits.planned_date |
Modulo A |
| Decisioni riesame (nuovo) | management_review_decisions.due_date |
Modulo B |
Esistente da riusare: DashboardController::deadlines (union incidenti/policy/trattamenti/formazione a 30 gg) — ne generalizzo il pattern. review_schedule resta per le revisioni ricorrenti (ha frequency_months); il calendario lo include come una delle sorgenti.
Decisione architetturale — aggregatore READ-ONLY (nessuna tabella nuova)
Le scadenze vivono già nei moduli sorgente, ciascuna col proprio ciclo di vita: duplicarle in una tabella calendario creerebbe disallineamenti. Quindi: endpoint aggregatore in sola lettura che fa UNION live di tutte le sorgenti e normalizza gli eventi. Niente migrazione per il calendario (mig. solo per A/B). Vantaggi: sempre coerente, additivo, zero rischio dato.
Endpoint — CalendarController (slug calendar)
GET /api/calendar/events?from=YYYY-MM-DD&to=YYYY-MM-DD&types=...→ lista eventi normalizzati:{ source, type, title, date, status (overdue|due_soon|upcoming|done), severity, entity_type, entity_id, link }. org-scoped, anti-IDOR (filtroorganization_idsu ogni sorgente), stato calcolato live (comereview_schedule).GET /api/calendar/summary→ conteggi per stato/tipo (per badge dashboard).- Riusa/centralizza la logica di
DashboardController::deadlines(che può poi delegare a questo). - Sola lettura →
requireOrgAccess().
Frontend — calendario.html
- Griglia mensile (HTML/CSS puro, dependency-free) con pallini colorati per tipo + navigazione mese prec./succ.; vista lista alternativa (ordinata per data, in ritardo in cima); filtri per tipo (incidenti, policy, rischi, formazione, NC/CAPA, stakeholder, audit, riesame, revisioni) e per stato.
- Click su evento → deep-link al modulo sorgente (es. incidente, policy, audit…).
- Legenda + badge "in ritardo / in scadenza". Voce sidebar ("Calendario") in
common-bi.js+common.js; help/i18n/KB. - La dashboard mostra già "prossime scadenze": aggiungere un link "Apri calendario".
Ancoraggio
Strumento operativo trasversale; supporta direttamente la buona prassi di monitoraggio scadenze e revisioni periodiche (ISO 9.1/9.3, NIS2 GV.PO-02/GV.SC-07/DE.CM). Non è un obbligo specifico: è gestione.
Stima Modulo C
| Fase | Contenuto | Stima |
|---|---|---|
| C1 | CalendarController (aggregatore union tutte le sorgenti + summary) + router/api |
~0,5 sessione |
| C2 | calendario.html (griglia mensile + lista + filtri + deep-link) + sidebar/help/i18n/KB + deploy+smoke |
~0,5–1 sessione |
Nessuna migrazione per C (solo lettura). Le scadenze di A e B vi confluiscono automaticamente.
Stima complessiva aggiornata (A + B + C)
- Modulo A (Audit interni): ~1 sessione · Modulo B (Riesame): ~1–1,5 · Modulo C (Calendario): ~1 · Verifica flotta finale: ~0,5.
- Totale ~3,5–4 sessioni, tutto additivo/runner-safe, committato e LIVE a fasi.
Ordine consigliato
A → B → C: il calendario (C) per ultimo così ingloba subito anche le scadenze di Audit interni e Riesame. In alternativa C si può fare per primo come quick-win trasversale (aggrega già tutto l'esistente) e poi A/B vi si agganciano.