# 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 riga `non_conformities` con `source_entity_type='internal_audit_item'` + `source_entity_id` (polimorfico già esistente, `004`); **calendario** → riga `review_schedule` (estendo ENUM con `internal_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_soa` dove applicable=1) — riuso del dataset `038`. 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 a `capa_actions` se diventa azione), ord. - Riuso: decisioni con scadenza → riga `review_schedule` e/o `capa_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`): 1. stato azioni dal riesame precedente (`management_review_decisions` + CAPA); 2. cambiamenti contesto/parti interessate (ISMS context + stakeholder); 3. **risultati audit interni** (Modulo A); 4. stato NC/azioni correttive (`non_conformities`/`capa_actions`); 5. risultati monitoraggio/KPI (dashboard score, SoA `implementation_pct`); 6. raggiungimento **obiettivi** SGSI (`isms_objectives`); 7. risultati valutazione rischi e stato trattamento (Risk + treatments); 8. feedback parti interessate (attività stakeholder/feedback); 9. aggiornamenti normativi e ACK (`normative_*`); 10. 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 (filtro `organization_id` su ogni sorgente), stato calcolato live (come `review_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.