[DOCS] Manuale d'uso COMPLETO v1.14.0: accesso/registrazione/onboarding passo-passo + 18 moduli dall'help reale

Riscrittura completa: istruzioni concrete (login, registrazione 3 step, onboarding
4 step con campi reali, navigazione), per ogni modulo "cosa trovi e come si usa"
estratto dall'help contestuale del prodotto (help.js), FAQ, glossario. Rimosse le
interruzioni di pagina che lasciavano pagine vuote. Generatore self-contained
(estrae i contenuti da public/js/help.js via node).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile
2026-06-11 18:19:54 +02:00
co-authored by Claude Opus 4.8
parent 0a883b7cae
commit ae7bb072d7
2 changed files with 222 additions and 309 deletions
+222 -309
View File
@@ -1,287 +1,228 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Genera il Manuale d'uso di NIS2 Agile in .docx usando solo stdlib (zipfile+XML)."""
import zipfile, re, datetime
"""Manuale d'uso COMPLETO di NIS2 Agile (.docx, solo stdlib). Contenuti moduli da help.js reale."""
import zipfile, re, json, html as _html, subprocess, os
from xml.sax.saxutils import escape
OUT = "/projects/nis2-agile/docs/MANUALE_UTENTE_NIS2_AGILE.docx"
# ─────────────────────────────────────────────────────────────────────────
# CONTENUTO DEL MANUALE (DSL: lista di blocchi)
# ('title', titolo, sottotitolo, riga_meta)
# ('h1'|'h2'|'h3', testo) | ('p', testo) | ('note', testo)
# ('ul', [voci]) | ('ol', [voci])
# ('table', [intestazioni], [[riga],...])
# ('pb',) page break
# Nel testo: **grassetto** supportato.
# ─────────────────────────────────────────────────────────────────────────
BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # repo root
OUT = os.path.join(BASE, "docs", "MANUALE_UTENTE_NIS2_AGILE.docx")
HELP_JSON = "/tmp/help.json"
# Auto-estrae i contenuti dall'help reale del prodotto (public/js/help.js) via node.
_node = ('const fs=require("fs");let s=fs.readFileSync(process.argv[1],"utf8");'
'const a=s.indexOf("var _helpContent");const start=s.indexOf("{",a);'
'const end=s.indexOf("var _pageMap");let obj=s.slice(start,s.lastIndexOf("}",end)+1);'
'fs.writeFileSync(process.argv[2],JSON.stringify(eval("("+obj+")")));')
subprocess.run(["node","-e",_node, os.path.join(BASE,"public","js","help.js"), HELP_JSON], check=True)
HELP = json.load(open(HELP_JSON, encoding="utf-8"))
DATE = "11 giugno 2026"
C = []
def add(*b): C.append(b)
add('title', "NIS2 Agile", "Manuale d'uso del prodotto",
"Versione piattaforma 1.14.0 · Aggiornato all'%s" % DATE)
def html2mk(s):
"""Converte l'HTML dell'help nel markup interno (**bold**) + testo pulito."""
s = re.sub(r'</?strong>|</?b>', '**', s)
s = re.sub(r'<[^>]+>', '', s) # rimuovi altri tag (span/em/...)
s = _html.unescape(s) # &lt; &ge; &nbsp; ...
s = s.replace(' ', ' ')
s = re.sub(r'\s+', ' ', s).strip()
# bilancia eventuali ** dispari
if s.count('**') % 2: s += '**'
return s
# ===== INDICE (statico, i numeri di pagina non sono calcolati) =====
add('h1', "Indice dei contenuti")
for n in ["1. Introduzione","2. Primi passi (accesso, registrazione, onboarding)",
"3. Dashboard","4. Gap Analysis NIS2 (Art. 21)","5. Gap Analysis ACN (Determinazione 164179/2025)",
"6. Modello Organizzativo SGSI (ISO 27001/27017/27018)","7. Gestione dei Rischi",
"8. Gestione degli Incidenti (Art. 23)","9. Policy e procedure","10. Supply Chain (fornitori)",
"11. Formazione","12. Asset","13. Audit & Report","14. Whistleblowing (Art. 32)",
"15. Aggiornamenti normativi","16. Knowledge Base e Assistente AI","17. Segnalazioni (feedback)",
"18. Impostazioni","19. Amministrazione","20. Integrazioni e API","21. Glossario","22. Riferimenti normativi"]:
add('p', n)
def module_chapter(num, title, topic_key, lead=None):
t = HELP.get(topic_key, {})
add('h1', f"{num}. {title}")
if lead: add('p', lead)
if t.get('intro'): add('p', html2mk(t['intro']))
for sec in t.get('sections', []):
add('h3', html2mk(sec.get('heading','')))
items = [html2mk(x) for x in sec.get('items', [])]
if items: add('ul', items)
refs = [html2mk(x) for x in t.get('references', [])]
if refs:
add('h3', "Riferimenti normativi")
add('ul', refs)
# ══════════════════ COPERTINA ══════════════════
add('title', "NIS2 Agile", "Manuale d'uso del prodotto",
f"Guida operativa completa · Versione piattaforma 1.14.0 · {DATE}")
add('p', "Questo manuale spiega passo dopo passo come accedere alla piattaforma, registrarsi, completare l'onboarding aziendale e utilizzare ogni modulo. Per ogni schermata trovi cosa contiene, a cosa serve e come operare.")
add('pb')
# ===== 1. INTRODUZIONE =====
# ══════════════════ INDICE ══════════════════
add('h1', "Indice")
toc = ["1. Introduzione","2. Requisiti e accesso alla piattaforma","3. Registrazione di un nuovo utente",
"4. Onboarding: configurazione dell'azienda","5. Come muoversi nell'interfaccia","6. Dashboard",
"7. Gap Analysis NIS2 (Art. 21)","8. Gap Analysis ACN (Determinazione 164179/2025)",
"9. Modello Organizzativo SGSI (ISO 27001/27017/27018)","10. Gestione dei Rischi",
"11. Gestione degli Incidenti (Art. 23)","12. Policy e procedure","13. Supply Chain (fornitori)",
"14. Formazione","15. Asset","16. Audit & Report","17. Whistleblowing (Art. 32)",
"18. Aggiornamenti normativi","19. Knowledge Base","20. Compliance Journey","21. Segnalazioni (feedback)",
"22. Impostazioni","23. Gestione delle aziende (consulenti)","24. Domande frequenti (FAQ)",
"25. Glossario","26. Riferimenti normativi"]
for x in toc: add('p', x)
add('note', "I nomi delle voci e l'aspetto delle schermate possono variare leggermente con gli aggiornamenti. In ogni pagina è disponibile il pulsante di aiuto contestuale (icona ?) con la guida e i riferimenti normativi.")
# ══════════════════ 1. INTRODUZIONE ══════════════════
add('h1', "1. Introduzione")
add('h2', "1.1 Che cos'è NIS2 Agile")
add('p', "NIS2 Agile è una piattaforma SaaS multi-tenant che supporta le aziende nel percorso di conformità alla **Direttiva (UE) 2022/2555 (NIS2)** e al suo recepimento italiano (**D.Lgs. 138/2024**), comprese le **Determinazioni dell'Agenzia per la Cybersicurezza Nazionale (ACN)**. Integra l'intelligenza artificiale (Claude) per gap analysis, generazione di policy, classificazione degli incidenti e suggerimento dei rischi.")
add('p', "Dalla versione 1.14.0 la piattaforma include anche un modulo guidato per la costruzione del **Modello Organizzativo SGSI secondo ISO/IEC 27001:2022**, con estensioni cloud ISO/IEC 27017:2015 e 27018:2019.")
add('h2', "1.2 A chi è rivolto")
add('ul', ["**PMI** che devono adeguarsi agli obblighi NIS2 con risorse limitate;",
"**Grandi imprese / Enterprise** con processi di compliance strutturati;",
"**Consulenti e CISO** che gestiscono più organizzazioni clienti tramite uno studio (consulting firm)."])
add('h2', "1.3 Quadro normativo di riferimento")
add('table', ["Fonte","Ruolo"],
[["Direttiva (UE) 2022/2555 (NIS2)","Principi e obblighi europei di cibersicurezza"],
["D.Lgs. 138/2024","Recepimento italiano della NIS2 (obblighi operativi)"],
["Determinazione ACN 164179/2025","Misure di sicurezza di base, classificazione e notifica incidenti (Allegati)"],
["ISO/IEC 27001:2022","Requisiti del Sistema di Gestione della Sicurezza delle Informazioni (best practice)"],
["ISO/IEC 27017:2015 / 27018:2019","Controlli per servizi cloud / protezione PII in cloud (best practice)"]])
add('note', "Disclaimer: NIS2 Agile è uno strumento di supporto operativo e pre-audit. Non costituisce consulenza legale né parere professionale vincolante, e non rilascia certificazioni ISO. Le valutazioni proposte (perimetro, applicabilità, significatività) vanno confermate con il referente compliance/legale dell'organizzazione.")
add('p', "**NIS2 Agile** è una piattaforma web (SaaS) che accompagna le aziende nella conformità alla **Direttiva (UE) 2022/2555 (NIS2)**, al suo recepimento italiano (**D.Lgs. 138/2024**) e alle **Determinazioni dell'Agenzia per la Cybersicurezza Nazionale (ACN)**. Integra l'intelligenza artificiale per gap analysis, generazione di policy, classificazione degli incidenti e suggerimento dei rischi.")
add('p', "Dalla versione 1.14.0 include anche il **Modello Organizzativo SGSI** secondo **ISO/IEC 27001:2022**, con estensioni cloud ISO 27017/27018.")
add('h3', "A chi è rivolto")
add('ul', ["**PMI** che devono adeguarsi agli obblighi NIS2;",
"**Grandi imprese** con processi di compliance strutturati;",
"**Consulenti e CISO** che seguono più aziende clienti tramite uno studio."])
add('h3', "Come è organizzato il lavoro nella piattaforma")
add('p', "Il percorso tipico è: **(1)** accedi o registrati → **(2)** completa l'onboarding dell'azienda (che ne determina la classificazione NIS2) → **(3)** esegui la Gap Analysis NIS2 → **(4)** approfondisci con la Gap Analysis ACN e costruisci il Modello SGSI → **(5)** gestisci rischi, incidenti, policy, fornitori, formazione e audit nel tempo.")
add('note', "Disclaimer: NIS2 Agile è uno strumento di supporto operativo e pre-audit. Non costituisce consulenza legale né parere professionale vincolante e non rilascia certificazioni ISO. Le valutazioni proposte vanno confermate con il referente compliance/legale dell'organizzazione.")
# ===== 2. PRIMI PASSI =====
add('pb'); add('h1', "2. Primi passi")
add('h2', "2.1 Accesso e indirizzo")
add('p', "La piattaforma è raggiungibile all'indirizzo **https://nis2.agile.software/**. L'accesso avviene con email e password (autenticazione JWT). Se la tua organizzazione usa il Single Sign-On centralizzato (AgileHub), le credenziali sono condivise tra i prodotti della suite.")
add('h2', "2.2 Registrazione")
add('ol', ["Apri la pagina di **Registrazione** e inserisci i dati richiesti (email, password conforme alla policy di sicurezza).",
"Al termine vieni indirizzato automaticamente alla procedura di **onboarding** aziendale.",
"Se possiedi un **invito/licenza** (token `inv_...`) fornito da un partner, inseriscilo per attivare l'organizzazione pre-configurata."])
add('h2', "2.3 Recupero password")
add('p', "Dalla pagina di login usa **Password dimenticata** per ricevere un link di reset via email. Il cambio password effettuato da AgileHub si propaga automaticamente entro pochi minuti grazie al sync SSO.")
add('h2', "2.4 Onboarding dell'organizzazione")
add('p', "Il wizard di onboarding crea l'organizzazione e ne determina la classificazione NIS2. Si articola in quattro passi:")
add('ol', ["**Dati azienda** — inserimento manuale oppure precompilazione tramite **Partita IVA** (lookup automatico) o caricamento della **visura camerale** (estrazione AI dei dati).",
"**Verifica e completamento** — settore (ATECO → settore NIS2), numero dipendenti, fatturato, sede, contatti.",
"**Profilo utente** — nome, ruolo, telefono.",
"**Classificazione NIS2** — la piattaforma propone se il soggetto è **essenziale**, **importante** o **non applicabile** in base a settore e dimensione; è possibile aderire volontariamente."])
add('note', "La classificazione (essenziale/importante) determina il perimetro applicabile in più moduli, in particolare la Gap Analysis ACN e gli obblighi sugli incidenti. Puoi rivederla in Impostazioni › Classificazione NIS2.")
add('h2', "2.5 Ruoli e permessi")
add('table', ["Ruolo","Descrizione"],
[["super_admin","Amministratore di piattaforma (accesso a tutte le organizzazioni)"],
["org_admin","Amministratore dell'organizzazione"],
["compliance_manager","Responsabile compliance: gestisce assessment, rischi, policy, SGSI"],
["board_member","Organo direttivo: visione e approvazioni"],
["auditor","Revisore: lettura e compilazione evidenze/controlli"],
["employee","Dipendente: formazione, segnalazioni"],
["consultant","Consulente di studio che opera su più organizzazioni clienti"]])
add('h2', "2.6 Multi-organizzazione, lingua e aiuto")
add('ul', ["Chi appartiene a più organizzazioni (es. consulenti) può **cambiare contesto** dall'intestazione/menu.",
"L'interfaccia è disponibile in **Italiano** ed **Inglese** (selettore lingua).",
"Ogni pagina dispone di **Aiuto contestuale** (icona ?) con guida e riferimenti normativi certi."])
# ══════════════════ 2. ACCESSO ══════════════════
add('h1', "2. Requisiti e accesso alla piattaforma")
add('h3', "Requisiti")
add('ul', ["Un browser web aggiornato (Chrome, Edge, Firefox o Safari);",
"una connessione a Internet;",
"le credenziali di accesso (email e password) oppure un invito ricevuto dal proprio studio/partner."])
add('h3', "Indirizzo della piattaforma")
add('p', "Apri il browser e vai su **https://nis2.agile.software/**. Si apre la pagina di accesso.")
add('h3', "Come accedere (login)")
add('ol', ["Nel campo **Indirizzo Email** inserisci l'email con cui sei registrato (es. nome@azienda.it).",
"Nel campo **Password** inserisci la tua password. Puoi usare l'icona a forma di occhio per mostrarla/nasconderla.",
"Premi **Accedi**.",
"Se le credenziali sono corrette: se hai già un'azienda configurata vieni portato alla **Dashboard**, altrimenti alla procedura di **Onboarding**."])
add('p', "In caso di errore compare un messaggio in rosso sotto il titolo. Verifica email e password e riprova.")
add('h3', "Password dimenticata")
add('ol', ["Dalla pagina di accesso scegli **Password dimenticata**.",
"Inserisci l'email dell'account: riceverai un messaggio con un link per impostare una nuova password.",
"Apri il link, scegli la nuova password (rispettando i requisiti di sicurezza) e conferma."])
add('note', "Se la tua azienda usa il Single Sign-On della suite (AgileHub), la password è condivisa tra i prodotti: un cambio password si propaga automaticamente entro pochi minuti.")
add('h3', "Disconnessione e sessioni")
add('p', "Per uscire usa la voce **Esci/Logout** nel menu utente. Dalle Impostazioni puoi vedere i **dispositivi collegati** (sessioni attive) e revocarli singolarmente o tutti.")
# ===== 3. DASHBOARD =====
add('pb'); add('h1', "3. Dashboard")
add('p', "La Dashboard è la pagina iniziale dopo l'accesso e offre una visione d'insieme dello stato di conformità.")
add('ul', ["**Avanzamento implementazione misure Art. 21 NIS2** — indicatore complessivo (gauge);",
"**Scadenze imminenti** — adempimenti e revisioni in arrivo da più moduli;",
"**Attività recenti** — ultime azioni tracciate;",
"**Heatmap dei rischi** — distribuzione dei rischi su probabilità × impatto;",
"**Benchmark settoriale** (anonimizzato) — confronto con il proprio settore;",
"**Compliance Journey** — percorso guidato che indica i prossimi passi consigliati."])
# ══════════════════ 3. REGISTRAZIONE ══════════════════
add('h1', "3. Registrazione di un nuovo utente")
add('p', "Se non hai un account, dalla pagina di accesso scegli **Registrati**. La registrazione è una procedura guidata in tre passi, con un indicatore di avanzamento in alto.")
add('h3', "Passo 1 — Ruolo e (eventuale) codice invito")
add('p', "Scegli il **ruolo** con cui ti registri, selezionando una delle schede disponibili:")
add('table', ["Scheda ruolo","Quando sceglierlo"],
[["Responsabile compliance","Gestisci direttamente assessment, rischi, policy e SGSI dell'azienda"],
["Amministratore organizzazione","Amministri l'azienda, gli utenti e le impostazioni"],
["Consulente","Segui più aziende clienti per conto di uno studio"],
["Auditor","Esegui verifiche e compili evidenze/controlli (lettura prevalente)"],
["Membro del board","Organo direttivo: visione e approvazioni"]])
add('p', "Se hai ricevuto un **Codice Invito** da un partner o dal tuo studio (formato `inv_...`), inseriscilo nell'apposito campo: il sistema lo verifica e mostra l'azienda/piano associati. Premi **Avanti** per proseguire.")
add('h3', "Passo 2 — Dati personali e password")
add('ul', ["**Nome** e **Cognome** (es. Mario Rossi);",
"**Email** (sarà il tuo identificativo di accesso);",
"eventuale **Partita IVA** dell'azienda (verificata in tempo reale, dove richiesto);",
"**Password** (minimo 8 caratteri): un indicatore mostra la robustezza della password mentre la digiti;",
"**Conferma password**: ripeti la stessa password."])
add('h3', "Passo 3 — Conferma e avvio")
add('p', "Rivedi i dati, accetta le condizioni e completa la registrazione. Al termine vieni indirizzato automaticamente all'**Onboarding** per configurare l'azienda (se non sei entrato tramite un invito che la pre-configura).")
# ===== 4. GAP ANALYSIS NIS2 =====
add('pb'); add('h1', "4. Gap Analysis NIS2 (Art. 21)")
add('p', "Analisi di **primo livello** sulle 10 categorie di misure dell'Art. 21.2 NIS2, basata su un questionario di 80 domande (10 categorie), ciascuna collegata anche al controllo ISO 27001 corrispondente.")
add('h2', "4.1 Come si svolge")
add('ol', ["Crea un nuovo assessment: la piattaforma pre-popola tutte le domande.",
"Per ogni domanda indica lo stato: **Attuato**, **Parziale**, **Non attuato**, **Non applicabile**. Le risposte si salvano automaticamente.",
"Completa l'assessment per ottenere un **punteggio** per categoria e complessivo.",
"Avvia l'**analisi AI** per ricevere sintesi esecutiva, priorità, quick win e una roadmap di conformità."])
add('note', "Le risposte della Gap Analysis NIS2 alimentano automaticamente il Modello SGSI (capitolo 6): il loro stato pre-popola lo Statement of Applicability ISO 27001.")
# ══════════════════ 4. ONBOARDING ══════════════════
add('h1', "4. Onboarding: configurazione dell'azienda")
add('p', "L'onboarding crea l'organizzazione e ne stabilisce la **classificazione NIS2** (essenziale, importante o non applicabile), che determina gli obblighi e il perimetro applicabile negli altri moduli. È una procedura guidata con uno **stepper** in alto che mostra i passi.")
add('h3', "Passo 1 — Inserisci la Partita IVA")
add('p', "Nella prima schermata (\"Inserisci la Partita IVA dell'azienda\") digiti la **Partita IVA** (es. 12345678901) e premi il pulsante di ricerca: la piattaforma tenta di **recuperare automaticamente** i dati aziendali. In alternativa puoi caricare la **visura camerale** (i dati vengono estratti dall'AI) oppure proseguire e inserire tutto manualmente. Premi **Continua**.")
add('h3', "Passo 2 — Verifica e completa i dati aziendali")
add('p', "Nella schermata \"Verifica e Completa i Dati Aziendali\" un banner indica la fonte dei dati (visura, lookup P.IVA o inserimento manuale). Controlla e completa i campi:")
add('ul', ["**Ragione sociale** (es. Acme S.r.l.);",
"**Partita IVA** e **Codice Fiscale**;",
"**Indirizzo**, **Città**, **Sito web**;",
"**Email aziendale** e **Telefono aziendale**;",
"**Settore** — scegli dall'elenco il settore NIS2 (es. Energia, Trasporti, Sanità, Infrastrutture digitali, ecc.): è determinante per la classificazione;",
"**Numero di dipendenti** e **fatturato** annuo, usati per stabilire la dimensione dell'impresa."])
add('h3', "Passo 3 — Il tuo profilo")
add('p', "Inserisci i dati del tuo profilo utente: **nome completo**, **ruolo** in azienda e **telefono** di contatto.")
add('h3', "Passo 4 — Classificazione NIS2")
add('p', "In base a settore e dimensione, la piattaforma **propone la classificazione**: soggetto **essenziale**, **importante** oppure **non applicabile**. Se non rientri obbligatoriamente ma vuoi adeguarti, puoi indicare l'**adesione volontaria**. Conferma per completare l'onboarding e accedere alla Dashboard.")
add('note', "Puoi rivedere o aggiornare la classificazione in qualsiasi momento da Impostazioni › Classificazione NIS2. La classificazione filtra automaticamente, ad esempio, i requisiti applicabili nella Gap Analysis ACN e gli obblighi sugli incidenti.")
# ===== 5. GAP ANALYSIS ACN =====
add('pb'); add('h1', "5. Gap Analysis ACN (Determinazione 164179/2025)")
add('p', "Analisi di **secondo livello** sulle misure e i requisiti puntuali stabiliti dall'ACN, articolati secondo il **Framework Nazionale** (funzioni Governo GV, Identificazione ID, Protezione PR, Rilevamento DE, Risposta RS, Ripristino RC).")
add('table', ["Classificazione","Perimetro applicabile"],
[["Soggetto IMPORTANTE (Allegato 1)","37 misure / 87 requisiti"],
["Soggetto ESSENZIALE (Allegato 2)","43 misure / 116 requisiti"]])
add('ul', ["Il perimetro è filtrato automaticamente in base alla classificazione NIS2 dell'organizzazione;",
"scoring per funzione del Framework Nazionale e punteggio complessivo;",
"**piano d'azione** dei requisiti non conformi e **analisi AI** ancorata ai 203 requisiti ACN reali (nessun riferimento inventato);",
"**Catalogo requisiti** consultabile in sola lettura."])
# ══════════════════ 5. NAVIGAZIONE ══════════════════
add('h1', "5. Come muoversi nell'interfaccia")
add('p', "Dopo l'accesso l'interfaccia è composta da una **barra laterale** (sidebar) a sinistra con il menu, e dall'**area principale** a destra che mostra la pagina selezionata. In alto a destra di ogni pagina trovi il pulsante di **aiuto contestuale (?)** e le azioni della pagina.")
add('h3', "Le sezioni del menu")
add('table', ["Sezione","Voci"],
[["Principale","Dashboard, Compliance Journey, Gap Analysis (NIS2), Gap Analysis ACN, Modello SGSI (ISO 27001)"],
["Gestione","Rischi, Incidenti, Policy, Supply Chain, Segnalazioni (whistleblowing), Normative, AI Cross-Analysis, Knowledge Base"],
["Operativo","Formazione, Asset, Audit & Report"],
["Sistema","Guida all'uso, Impostazioni, Architettura, Simulazione Demo, Integrazioni Esterne"]])
add('h3', "Lingua e aiuto")
add('ul', ["L'interfaccia è disponibile in **Italiano** ed **Inglese** (selettore lingua).",
"Il pulsante **?** in ogni pagina apre la guida contestuale con spiegazioni e riferimenti normativi.",
"Chi appartiene a più aziende (consulenti) può **cambiare organizzazione** dal menu."])
# ===== 6. MODELLO SGSI ISO 27001 (NUOVO) =====
add('pb'); add('h1', "6. Modello Organizzativo SGSI (ISO 27001/27017/27018)")
add('p', "Procedura guidata per costruire il **Sistema di Gestione della Sicurezza delle Informazioni (SGSI / ISMS)** secondo **ISO/IEC 27001:2022** (clausole 4–10) e il relativo **Statement of Applicability (SoA)** sui 93 controlli dell'Annex A. È uno strumento di supporto e pre-audit, non una certificazione.")
add('h2', "6.1 Il wizard in 6 passi")
add('table', ["Passo","Clausola ISO 27001","Contenuto"],
[["1. Contesto e Ambito","cl. 4","Scope del SGSI, contesto interno/esterno, parti interessate, confini, esclusioni motivate, attivazione estensioni cloud"],
["2. Leadership","cl. 5","Ruoli e responsabilità con matrice RACI (Responsible, Accountable, Consulted, Informed)"],
["3. Risk","cl. 6","Metodologia di risk assessment e obiettivi del SGSI (il registro rischi resta nel modulo Rischi)"],
["4. Statement of Applicability","cl. 6.1.3","Applicabilità, stato e motivazione dei 93 controlli Annex A + estensioni cloud"],
["5. Documented Information","cl. 7–8","Policy e procedure, con bozze generabili dall'AI"],
["6. Monitoraggio e Miglioramento","cl. 9–10","Audit interni e non conformità (moduli Audit & Report e NCR/CAPA); checklist di completamento"]])
add('h2', "6.2 SoA pre-popolato dalla Gap Analysis NIS2")
add('p', "Ogni domanda della Gap Analysis NIS2 è collegata a un controllo ISO 27001 (es. A.5.1). Per questo lo Statement of Applicability viene **pre-compilato** a partire dalle risposte NIS2 già date: i controlli con corrispondenza riportano il badge **\"da NIS2\"** e uno stato proposto (Attuato = 100%, Parziale = 50%, Non attuato = 0%). I controlli non coperti dal NIS2 (es. parte dei controlli fisici A.7) restano da compilare manualmente.")
add('note', "Il pulsante \"Ri-deriva dal NIS2\" aggiunge soltanto i controlli mancanti e non sovrascrive le modifiche manuali già inserite.")
add('h2', "6.3 Estensioni cloud (condizionali)")
add('ul', ["**ISO/IEC 27017:2015** — attivala se usi servizi cloud pubblici o sei un fornitore cloud: aggiunge 7 controlli cloud (CLD.*) al SoA;",
"**ISO/IEC 27018:2019** — attivala se tratti dati personali (PII) in cloud pubblico come responsabile: aggiunge i controlli privacy (PII.*), sinergici con il GDPR.",
"Le sezioni cloud/PII compaiono nel SoA **solo** se attivi i relativi flag nel passo 1."])
add('h2', "6.4 Documenti e generazione AI")
add('p', "Nel passo 5 puoi generare bozze di policy e procedure (Policy SGSI, Dichiarazione di Applicabilità, controllo accessi, gestione incidenti, continuità, sicurezza fornitori). Le bozze sono prodotte dall'AI con ancoraggio alle fonti certe e richiedono **revisione umana** prima dell'approvazione.")
add('h2', "6.5 Esportazione")
add('p', "Il pulsante **Esporta SGSI** apre una versione stampabile del modello (ambito, metodologia, SoA con stato dei controlli), utile come evidenza in vista di un audit.")
# ══════════════════ 6..23 MODULI (da help.js) ══════════════════
module_chapter(6, "Dashboard", "dashboard")
module_chapter(7, "Gap Analysis NIS2 (Art. 21)", "assessment",
"Apri la voce **Gap Analysis** dal menu. È l'analisi di primo livello sulle 10 categorie di misure dell'Art. 21 NIS2.")
module_chapter(8, "Gap Analysis ACN (Determinazione 164179/2025)", "acn",
"Apri la voce **Gap Analysis ACN**. È l'analisi di secondo livello sui requisiti puntuali ACN.")
module_chapter(9, "Modello Organizzativo SGSI (ISO 27001/27017/27018)", "isms",
"Apri la voce **Modello SGSI (ISO 27001)**. Una procedura guidata in 6 passi costruisce il Sistema di Gestione della Sicurezza delle Informazioni; lo Statement of Applicability è pre-popolato dalle risposte della Gap Analysis NIS2.")
module_chapter(10, "Gestione dei Rischi", "risks", "Apri la voce **Rischi**.")
module_chapter(11, "Gestione degli Incidenti (Art. 23)", "incidents", "Apri la voce **Incidenti**.")
module_chapter(12, "Policy e procedure", "policies", "Apri la voce **Policy**.")
module_chapter(13, "Supply Chain (fornitori)", "supply-chain", "Apri la voce **Supply Chain**.")
module_chapter(14, "Formazione", "training", "Apri la voce **Formazione**.")
module_chapter(15, "Asset", "assets", "Apri la voce **Asset**.")
module_chapter(16, "Audit & Report", "reports", "Apri la voce **Audit & Report**.")
module_chapter(17, "Whistleblowing (Art. 32)", "whistleblowing", "Apri la voce **Segnalazioni**.")
module_chapter(18, "Aggiornamenti normativi", "normative", "Apri la voce **Normative**.")
module_chapter(19, "Knowledge Base", "kb", "Apri la voce **Knowledge Base**.")
module_chapter(20, "Compliance Journey", "workflow", "Apri la voce **Compliance Journey**: un percorso guidato che indica i prossimi passi consigliati.")
module_chapter(21, "Segnalazioni (feedback)", "feedback",
"Usa lo strumento di feedback per segnalare problemi o suggerimenti: ogni segnalazione cattura automaticamente versione e superficie del prodotto.")
module_chapter(22, "Impostazioni", "settings", "Apri la voce **Impostazioni**.")
module_chapter(23, "Gestione delle aziende (consulenti)", "companies",
"Disponibile per i consulenti: consente di gestire più aziende clienti da un unico accesso.")
# ===== 7. RISCHI =====
add('pb'); add('h1', "7. Gestione dei Rischi")
add('p', "Registro dei rischi con matrice **Probabilità × Impatto 5×5** e supporto AI, conforme all'Art. 21 NIS2 e alla metodologia ISO 27005.")
add('ul', ["Creazione del rischio con scala probabilità/impatto (dettagli ISO 27005);",
"**Piani di trattamento** (mitigare, accettare, trasferire, evitare) e stato di avanzamento;",
"**Suggerimento AI** dei rischi per settore e asset (dati anonimizzati);",
"Funzioni avanzate: registro quantitativo **FAIR** (calcolo ALE Monte Carlo) e dashboard **KRI**."])
# ══════════════════ 24. FAQ ══════════════════
add('h1', "24. Domande frequenti (FAQ)")
add('h3', "Non riesco ad accedere")
add('p', "Verifica email e password; usa **Password dimenticata** per reimpostarla. Se usi il SSO della suite, accedi con le credenziali centralizzate.")
add('h3', "Ho sbagliato la classificazione NIS2")
add('p', "Puoi correggerla in **Impostazioni › Classificazione NIS2**: il perimetro dei moduli (es. Gap Analysis ACN) si aggiorna di conseguenza.")
add('h3', "Lo Statement of Applicability del Modello SGSI è quasi vuoto")
add('p', "Viene pre-popolato dalle risposte della **Gap Analysis NIS2**: completa prima quell'assessment, poi usa **Ri-deriva dal NIS2** nel SoA. I controlli senza corrispondenza NIS2 (es. alcuni controlli fisici) vanno compilati manualmente.")
add('h3', "Le email non vengono inviate")
add('p', "Negli ambienti dimostrativi l'invio email può essere disattivato per sicurezza. In produzione le notifiche (CSIRT, formazione, inviti) vengono inviate regolarmente.")
add('h3', "Le bozze generate dall'AI sono definitive?")
add('p', "No: sono **bozze** da rivedere e approvare. Riportano sempre un avviso e citano le fonti normative.")
# ===== 8. INCIDENTI =====
add('pb'); add('h1', "8. Gestione degli Incidenti (Art. 23)")
add('p', "Gestione del ciclo di vita degli incidenti significativi e degli obblighi di notifica al CSIRT secondo l'Art. 23 e la Determinazione ACN 164179/2025.")
add('h2', "8.1 Tempistiche di notifica")
add('table', ["Adempimento","Termine"],
[["Pre-allarme (early warning)","entro 24 ore dalla conoscenza"],
["Notifica completa","entro 72 ore dalla conoscenza"],
["Relazione finale","entro 1 mese dalla notifica delle 72 ore"]])
add('h2', "8.2 Funzioni")
add('ul', ["**Albero decisionale** per valutare la significatività (utenti ≥ 500, durata > 4h, cross-border, attacco cyber, danni > €100k);",
"**timeline** dell'incidente e metriche (triage, contenimento, eradicazione, ripristino);",
"invio di **early warning, notifica e relazione finale** al CSIRT;",
"**classificazione AI** (tipo IS-1..IS-4, severità) con citazione della fonte (Allegato 3 = importanti, Allegato 4 = essenziali);",
"**PIR** (Post-Incident Review) per l'apprendimento."])
# ===== 9. POLICY =====
add('pb'); add('h1', "9. Policy e procedure")
add('ul', ["Creazione di policy da **template** o **generazione AI** (bozze marcate da revisionare);",
"flusso di **approvazione** e **versioning** con confronto delle versioni (diff);",
"**attestazione** di presa visione da parte del personale e relativo tracciamento."])
add('note', "Le bozze generate dall'AI riportano un banner di avviso: vanno riviste e approvate da un responsabile prima della pubblicazione.")
# ===== 10. SUPPLY CHAIN =====
add('pb'); add('h1', "10. Supply Chain (fornitori)")
add('p', "Gestione della sicurezza della catena di approvvigionamento (Art. 21.2.d).")
add('ul', ["Anagrafica fornitori, categorie e **import** massivo;",
"**questionari** configurabili (categorie, template, domande) inviati ai fornitori;",
"**portale fornitore** dedicato con accesso separato via OTP/magic-link (autosalvataggio risposte);",
"**campagne** di valutazione e cruscotto del rischio fornitori (risk overview)."])
# ===== 11. FORMAZIONE =====
add('pb'); add('h1', "11. Formazione")
add('p', "Gestione della formazione e dell'igiene informatica (Art. 21.2.g) e degli obblighi formativi per gli organi direttivi (Art. 20).")
add('ul', ["Catalogo **corsi** e **assegnazioni** al personale;",
"monitoraggio della **compliance formativa** e dei corsi obbligatori non completati."])
# ===== 12. ASSET =====
add('pb'); add('h1', "12. Asset")
add('p', "Inventario degli asset informativi e delle dipendenze.")
add('ul', ["Anagrafica asset e **import** (CMDB/cloud);",
"**scoring di rilevanza NIS2** (0–100, criterio GV.OC-04) e classificazione dei sistemi rilevanti;",
"**mappa delle dipendenze** tra asset."])
# ===== 13. AUDIT & REPORT =====
add('pb'); add('h1', "13. Audit & Report")
add('ul', ["Gestione dei **controlli di conformità** (framework NIS2 / ISO 27001) con stato ed evidenze;",
"caricamento **evidenze** e registro dei **log di audit**;",
"**mappature**: NIS2 ↔ ISO 27001 e NIST CSF 2.0; **registro dei sistemi rilevanti** (GV.OC-04);",
"**report esecutivo** stampabile ed **export CSV**;",
"**catena di integrità (hash chain SHA-256)**: ogni voce del log è concatenata alla precedente; verifica integrità ed **export certificato**."])
# ===== 14. WHISTLEBLOWING =====
add('pb'); add('h1', "14. Whistleblowing (Art. 32)")
add('p', "Canale per le segnalazioni, anche anonime.")
add('ul', ["Invio segnalazione (anche **anonima**, con codice di tracciamento);",
"assegnazione, gestione e chiusura della segnalazione;",
"consultazione anonima dello stato tramite codice di tracciamento."])
# ===== 15. NORMATIVE =====
add('pb'); add('h1', "15. Aggiornamenti normativi")
add('ul', ["Feed degli aggiornamenti **NIS2 / ACN / DORA**;",
"presa visione (**ACK**) tracciata per ciascun aggiornamento;",
"elenco aggiornamenti **in attesa** di presa visione e statistiche."])
# ===== 16. KB & AI =====
add('pb'); add('h1', "16. Knowledge Base e Assistente AI")
add('h2', "16.1 Knowledge Base (RAG)")
add('p', "La Knowledge Base alimenta le risposte dell'AI tramite ricerca semantica (RAG). Prevede tre livelli di visibilità:")
add('table', ["Livello","Chi possiede","Chi vede"],
[["SYSTEM","Fornitore della piattaforma","Tutti gli utenti"],
["FIRM","Studio di consulenza","Collaboratori dello studio + organizzazioni condivise"],
["ORG","Singola organizzazione","Solo gli utenti di quella organizzazione"]])
add('ul', ["Caricamento documenti (testo) con scelta dello scope;",
"ricerca semantica e cancellazione documenti;",
"le fonti normative certe (NIS2, D.Lgs. 138/2024, Determinazioni ACN) e i cataloghi **ISO 27001/27002/27017/27018** sono già indicizzati a livello SYSTEM."])
add('h2', "16.2 Assistente AI")
add('p', "L'assistente risponde alle domande pescando dalla Knowledge Base e **cita sempre la fonte normativa pertinente**, senza inventare riferimenti. Le risposte sono di orientamento operativo e non sostituiscono il parere legale.")
# ===== 17. FEEDBACK =====
add('pb'); add('h1', "17. Segnalazioni (feedback)")
add('p', "Strumento integrato per segnalare bug o suggerimenti di UX. Le segnalazioni vengono classificate dall'AI e, una volta risolte, l'esito può essere comunicato ai membri dell'organizzazione. Ogni segnalazione cattura automaticamente la **versione del prodotto** e la **superficie** (web/mobile) per facilitare la diagnosi.")
# ===== 18. IMPOSTAZIONI =====
add('pb'); add('h1', "18. Impostazioni")
add('ul', ["**Organizzazione** — dati, classificazione NIS2;",
"**Profilo** — dati personali, cambio password, preferenze;",
"**Membri** — invito e gestione degli utenti e dei ruoli;",
"**Sessioni** — gestione dei dispositivi collegati (multi-device) e revoca;",
"**Branding** (white-label per studi) — personalizzazione per lo studio di consulenza."])
# ===== 19. AMMINISTRAZIONE =====
add('pb'); add('h1', "19. Amministrazione")
add('p', "Area riservata al ruolo **super_admin**: gestione delle organizzazioni, degli utenti e statistiche di piattaforma.")
# ===== 20. INTEGRAZIONI E API =====
add('pb'); add('h1', "20. Integrazioni e API")
add('ul', ["**Services API** (autenticazione tramite API Key con scope) per integrazioni esterne, es. GRC/231: gap-analysis, misure, incidenti, formazione, scadenze e snapshot completo;",
"**Webhook** con firma HMAC-SHA256 e retry, per notifiche verso sistemi terzi;",
"**Licenze/inviti B2B** per provisioning di organizzazioni da parte di partner;",
"**SSO** centralizzato della suite AgileHub (sincronizzazione password)."])
# ===== 21. GLOSSARIO =====
add('pb'); add('h1', "21. Glossario")
# ══════════════════ 25. GLOSSARIO ══════════════════
add('h1', "25. Glossario")
add('table', ["Termine","Significato"],
[["NIS2","Direttiva (UE) 2022/2555 sulla cibersicurezza"],
["ACN","Agenzia per la Cybersicurezza Nazionale"],
["Soggetto essenziale / importante","Categorie NIS2 che determinano gli obblighi applicabili"],
["Gap Analysis","Analisi degli scostamenti tra stato attuale e requisiti"],
["SGSI / ISMS","Sistema di Gestione della Sicurezza delle Informazioni (ISO 27001)"],
["SoA","Statement of Applicability: dichiarazione di applicabilità dei controlli"],
["Annex A","Elenco dei 93 controlli di sicurezza di ISO/IEC 27001:2022"],
["Annex A","I 93 controlli di sicurezza di ISO/IEC 27001:2022"],
["RACI","Matrice di responsabilità: Responsible, Accountable, Consulted, Informed"],
["CSIRT","Computer Security Incident Response Team (autorità di notifica)"],
["CSIRT","Squadra nazionale di risposta agli incidenti (autorità di notifica)"],
["NCR / CAPA","Non conformità / azioni correttive e preventive"],
["PIR","Post-Incident Review (revisione post-incidente)"],
["RAG","Retrieval-Augmented Generation: AI con recupero da knowledge base"],
["PII","Personally Identifiable Information (dati personali)"],
["Soggetto essenziale / importante","Categorie NIS2 che determinano gli obblighi applicabili"]])
["RAG","Recupero da knowledge base a supporto delle risposte AI"],
["PII","Dati personali (Personally Identifiable Information)"]])
# ===== 22. RIFERIMENTI NORMATIVI =====
add('pb'); add('h1', "22. Riferimenti normativi")
# ══════════════════ 26. RIFERIMENTI ══════════════════
add('h1', "26. Riferimenti normativi")
add('ul', ["Direttiva (UE) 2022/2555 (NIS2);",
"Direttiva (UE) 2022/2557 (CER);",
"D.Lgs. 4 settembre 2024, n. 138;",
"Determinazione ACN n. 164179 del 14/04/2025 (misure di base, classificazione e notifica incidenti, Allegati);",
"Determinazione ACN n. 333017/2025 (piattaforma ACN, designazione rappresentanti);",
"Determinazione ACN n. 164179 del 14/04/2025 (misure di base, classificazione e notifica incidenti);",
"Determinazione ACN n. 333017/2025;",
"ISO/IEC 27001:2022, 27002:2022, 27017:2015, 27018:2019 (best practice, non vincolanti)."])
add('note', "Questo manuale descrive le funzionalità della piattaforma NIS2 Agile alla versione 1.14.0. Le schermate e le voci di menu possono variare con gli aggiornamenti. Per l'aiuto contestuale usa l'icona ? presente in ogni pagina.")
add('note', f"Manuale d'uso di NIS2 Agile — versione piattaforma 1.14.0, aggiornato all'{DATE}. Per assistenza usa il pulsante di aiuto (?) presente in ogni pagina o la voce \"Guida all'uso\" nel menu.")
# ─────────────────────────────────────────────────────────────────────────
# EMITTER OOXML
# ─────────────────────────────────────────────────────────────────────────
# ════════════════════════════════ EMITTER OOXML ════════════════════════════════
def runs(text):
"""Converte **bold** in run WordprocessingML."""
out = []
for i, part in enumerate(re.split(r'\*\*', text)):
if part == '':
continue
bold = (i % 2 == 1)
rpr = '<w:rPr><w:b/></w:rPr>' if bold else ''
if part == '': continue
rpr = '<w:rPr><w:b/></w:rPr>' if (i % 2 == 1) else ''
out.append('<w:r>%s<w:t xml:space="preserve">%s</w:t></w:r>' % (rpr, escape(part)))
return ''.join(out) or '<w:r><w:t/></w:r>'
@@ -294,62 +235,48 @@ def listitem(text, numid):
'<w:numPr><w:ilvl w:val="0"/><w:numId w:val="%d"/></w:numPr></w:pPr>%s</w:p>' % (numid, runs(text)))
def cell(text, header=False):
shd = '<w:shd w:val="clear" w:fill="1F3864"/>' if header else ''
t = ('**%s**' % text) if header else text
# nelle intestazioni il testo bianco
if header:
shd = '<w:shd w:val="clear" w:fill="1F3864"/>'
r = '<w:r><w:rPr><w:b/><w:color w:val="FFFFFF"/></w:rPr><w:t xml:space="preserve">%s</w:t></w:r>' % escape(text)
else:
r = runs(text)
return ('<w:tc><w:tcPr><w:tcW w:w="0" w:type="auto"/>%s</w:tcPr><w:p>%s</w:p></w:tc>' % (shd, r))
shd = ''; r = runs(text)
return '<w:tc><w:tcPr><w:tcW w:w="0" w:type="auto"/>%s</w:tcPr><w:p>%s</w:p></w:tc>' % (shd, r)
def table(headers, rows):
borders = ('<w:tblBorders>' + ''.join(
'<w:%s w:val="single" w:sz="4" w:space="0" w:color="BFBFBF"/>' % s
for s in ['top','left','bottom','right','insideH','insideV']) + '</w:tblBorders>')
tblpr = '<w:tblPr><w:tblW w:w="5000" w:type="pct"/>%s<w:tblLook w:firstRow="1"/></w:tblPr>' % borders
out = ['<w:tbl>', tblpr]
borders = '<w:tblBorders>' + ''.join('<w:%s w:val="single" w:sz="4" w:space="0" w:color="BFBFBF"/>'%s
for s in ['top','left','bottom','right','insideH','insideV']) + '</w:tblBorders>'
out = ['<w:tbl><w:tblPr><w:tblW w:w="5000" w:type="pct"/>%s<w:tblLook w:firstRow="1"/></w:tblPr>' % borders]
out.append('<w:tr>' + ''.join(cell(h, True) for h in headers) + '</w:tr>')
for row in rows:
out.append('<w:tr>' + ''.join(cell(c) for c in row) + '</w:tr>')
out.append('</w:tbl>')
out.append('<w:p/>') # spacing after table
for row in rows: out.append('<w:tr>' + ''.join(cell(c) for c in row) + '</w:tr>')
out.append('</w:tbl><w:p/>')
return ''.join(out)
def title_block(t, sub, meta):
return (para(t, 'Title') + para(sub, 'Subtitle') + para(meta, 'Meta'))
body = []
for b in C:
k = b[0]
if k == 'title': body.append(title_block(b[1], b[2], b[3]))
elif k == 'h1': body.append(para(b[1], 'Heading1'))
elif k == 'h2': body.append(para(b[1], 'Heading2'))
elif k == 'h3': body.append(para(b[1], 'Heading3'))
if k == 'title': body.append(para(b[1],'Title')+para(b[2],'Subtitle')+para(b[3],'Meta'))
elif k in ('h1','h2','h3'): body.append(para(b[1], {'h1':'Heading1','h2':'Heading2','h3':'Heading3'}[k]))
elif k == 'p': body.append(para(b[1]))
elif k == 'note': body.append(para(b[1], 'Note'))
elif k == 'ul': body.append(''.join(listitem(x, 1) for x in b[1]))
elif k == 'ol': body.append(''.join(listitem(x, 2) for x in b[1]))
elif k == 'note': body.append(para(b[1],'Note'))
elif k == 'ul': body.append(''.join(listitem(x,1) for x in b[1]))
elif k == 'ol': body.append(''.join(listitem(x,2) for x in b[1]))
elif k == 'table': body.append(table(b[1], b[2]))
elif k == 'pb': body.append('<w:p><w:r><w:br w:type="page"/></w:r></w:p>')
SECT = ('<w:sectPr><w:pgSz w:w="11906" w:h="16838"/>'
'<w:pgMar w:top="1417" w:right="1417" w:bottom="1417" w:left="1417" w:header="708" w:footer="708" w:gutter="0"/>'
'</w:sectPr>')
SECT = ('<w:sectPr><w:pgSz w:w="11906" w:h="16838"/><w:pgMar w:top="1417" w:right="1417" w:bottom="1417" w:left="1417" w:header="708" w:footer="708" w:gutter="0"/></w:sectPr>')
document = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
'<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">'
'<w:body>' + ''.join(body) + SECT + '</w:body></w:document>')
'<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:body>'
+ ''.join(body) + SECT + '</w:body></w:document>')
STYLES = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
'<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">'
'<w:docDefaults><w:rPrDefault><w:rPr><w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/><w:sz w:val="22"/></w:rPr></w:rPrDefault></w:docDefaults>'
'<w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/><w:pPr><w:spacing w:after="140" w:line="276" w:lineRule="auto"/></w:pPr></w:style>'
'<w:style w:type="paragraph" w:styleId="Title"><w:name w:val="Title"/><w:pPr><w:spacing w:before="2400" w:after="120"/></w:pPr><w:rPr><w:b/><w:color w:val="1F3864"/><w:sz w:val="72"/></w:rPr></w:style>'
'<w:style w:type="paragraph" w:styleId="Subtitle"><w:name w:val="Subtitle"/><w:pPr><w:spacing w:after="80"/></w:pPr><w:rPr><w:color w:val="2E74B5"/><w:sz w:val="36"/></w:rPr></w:style>'
'<w:style w:type="paragraph" w:styleId="Title"><w:name w:val="Title"/><w:pPr><w:spacing w:before="2600" w:after="120"/></w:pPr><w:rPr><w:b/><w:color w:val="1F3864"/><w:sz w:val="72"/></w:rPr></w:style>'
'<w:style w:type="paragraph" w:styleId="Subtitle"><w:name w:val="Subtitle"/><w:pPr><w:spacing w:after="80"/></w:pPr><w:rPr><w:color w:val="2E74B5"/><w:sz w:val="34"/></w:rPr></w:style>'
'<w:style w:type="paragraph" w:styleId="Meta"><w:name w:val="Meta"/><w:rPr><w:color w:val="808080"/><w:sz w:val="20"/></w:rPr></w:style>'
'<w:style w:type="paragraph" w:styleId="Heading1"><w:name w:val="heading 1"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:pPr><w:keepNext/><w:spacing w:before="320" w:after="120"/><w:outlineLvl w:val="0"/></w:pPr><w:rPr><w:b/><w:color w:val="1F3864"/><w:sz w:val="34"/></w:rPr></w:style>'
'<w:style w:type="paragraph" w:styleId="Heading2"><w:name w:val="heading 2"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:pPr><w:keepNext/><w:spacing w:before="240" w:after="80"/><w:outlineLvl w:val="1"/></w:pPr><w:rPr><w:b/><w:color w:val="2E74B5"/><w:sz w:val="28"/></w:rPr></w:style>'
'<w:style w:type="paragraph" w:styleId="Heading1"><w:name w:val="heading 1"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:pPr><w:keepNext/><w:spacing w:before="360" w:after="120"/><w:pBdr><w:bottom w:val="single" w:sz="6" w:space="3" w:color="2E74B5"/></w:pBdr><w:outlineLvl w:val="0"/></w:pPr><w:rPr><w:b/><w:color w:val="1F3864"/><w:sz w:val="32"/></w:rPr></w:style>'
'<w:style w:type="paragraph" w:styleId="Heading2"><w:name w:val="heading 2"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:pPr><w:keepNext/><w:spacing w:before="240" w:after="80"/><w:outlineLvl w:val="1"/></w:pPr><w:rPr><w:b/><w:color w:val="2E74B5"/><w:sz w:val="27"/></w:rPr></w:style>'
'<w:style w:type="paragraph" w:styleId="Heading3"><w:name w:val="heading 3"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:pPr><w:keepNext/><w:spacing w:before="200" w:after="60"/><w:outlineLvl w:val="2"/></w:pPr><w:rPr><w:b/><w:color w:val="404040"/><w:sz w:val="24"/></w:rPr></w:style>'
'<w:style w:type="paragraph" w:styleId="ListParagraph"><w:name w:val="List Paragraph"/><w:basedOn w:val="Normal"/><w:pPr><w:ind w:left="567"/><w:spacing w:after="60"/></w:pPr></w:style>'
'<w:style w:type="paragraph" w:styleId="Note"><w:name w:val="Note"/><w:basedOn w:val="Normal"/><w:pPr><w:pBdr><w:left w:val="single" w:sz="18" w:space="6" w:color="F59E0B"/></w:pBdr><w:ind w:left="227"/><w:spacing w:before="120" w:after="120"/><w:shd w:val="clear" w:fill="FFFBEB"/></w:pPr><w:rPr><w:i/><w:color w:val="7A5B00"/></w:rPr></w:style>'
@@ -359,49 +286,35 @@ NUMBERING = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
'<w:numbering xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">'
'<w:abstractNum w:abstractNumId="0"><w:lvl w:ilvl="0"><w:start w:val="1"/><w:numFmt w:val="bullet"/><w:lvlText w:val="•"/><w:lvlJc w:val="left"/><w:pPr><w:ind w:left="567" w:hanging="284"/></w:pPr><w:rPr><w:rFonts w:ascii="Symbol" w:hAnsi="Symbol" w:hint="default"/></w:rPr></w:lvl></w:abstractNum>'
'<w:abstractNum w:abstractNumId="1"><w:lvl w:ilvl="0"><w:start w:val="1"/><w:numFmt w:val="decimal"/><w:lvlText w:val="%1."/><w:lvlJc w:val="left"/><w:pPr><w:ind w:left="567" w:hanging="284"/></w:pPr></w:lvl></w:abstractNum>'
'<w:num w:numId="1"><w:abstractNumId w:val="0"/></w:num>'
'<w:num w:numId="2"><w:abstractNumId w:val="1"/></w:num>'
'</w:numbering>')
'<w:num w:numId="1"><w:abstractNumId w:val="0"/></w:num><w:num w:numId="2"><w:abstractNumId w:val="1"/></w:num></w:numbering>')
CONTENT_TYPES = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
CT = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
'<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">'
'<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>'
'<Default Extension="xml" ContentType="application/xml"/>'
'<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>'
'<Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>'
'<Override PartName="/word/numbering.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"/>'
'<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>'
'</Types>')
'<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/></Types>')
RELS = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
'<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>'
'<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>'
'</Relationships>')
DOC_RELS = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
'<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/></Relationships>')
DRELS = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
'<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>'
'<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering" Target="numbering.xml"/>'
'</Relationships>')
'<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering" Target="numbering.xml"/></Relationships>')
CORE = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
'<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" '
'xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
'<dc:title>Manuale d\'uso NIS2 Agile</dc:title><dc:creator>NIS2 Agile</dc:creator>'
'<cp:lastModifiedBy>NIS2 Agile</cp:lastModifiedBy>'
'<dcterms:created xsi:type="dcterms:W3CDTF">2026-06-11T00:00:00Z</dcterms:created>'
'<dcterms:modified xsi:type="dcterms:W3CDTF">2026-06-11T00:00:00Z</dcterms:modified>'
'</cp:coreProperties>')
'<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
'<dc:title>Manuale d\'uso NIS2 Agile</dc:title><dc:creator>NIS2 Agile</dc:creator><cp:lastModifiedBy>NIS2 Agile</cp:lastModifiedBy>'
'<dcterms:created xsi:type="dcterms:W3CDTF">2026-06-11T00:00:00Z</dcterms:created><dcterms:modified xsi:type="dcterms:W3CDTF">2026-06-11T00:00:00Z</dcterms:modified></cp:coreProperties>')
with zipfile.ZipFile(OUT, 'w', zipfile.ZIP_DEFLATED) as z:
z.writestr('[Content_Types].xml', CONTENT_TYPES)
z.writestr('[Content_Types].xml', CT)
z.writestr('_rels/.rels', RELS)
z.writestr('word/document.xml', document)
z.writestr('word/styles.xml', STYLES)
z.writestr('word/numbering.xml', NUMBERING)
z.writestr('word/_rels/document.xml.rels', DOC_RELS)
z.writestr('word/_rels/document.xml.rels', DRELS)
z.writestr('docProps/core.xml', CORE)
print("OK ->", OUT)
print("blocchi:", len(C))
print("OK ->", OUT, "| blocchi:", len(C))