[FORMAZIONE] Avatar di prodotto — mappa-logica COMPLETA (22 viste) + SELETTORI_DEMO + tassonomia corso + fix kb.js
Deliverable formazione-first (DESIGN_AVATAR_FORMAZIONE / product-demo-complete):
- docs/mappa-logica/01..22_*.md: tutte le viste app V2 mappate (formato canonico standard §2),
selettori VERIFICATI sul DOM reale, endpoint verificati su api.js/script, gate ruolo dai controller
- docs/mappa-logica/SELETTORI_DEMO.md: registry canonico (22 viste, 131 visualizzazione + 89 azioni)
+ worklist consolidata 132 id stabili da aggiungere (modifiche chirurgiche future)
- docs/formazione/TASSONOMIA_CORSO_NIS2.{md,json}: 10 moduli / 28 lezioni / ~7h45, prerequisiti+durate,
esame con soglia 80%, sandbox 'prova tu' org 996002
- fix kb.js: ingest scope=ORG ora invia organization_id (prima 422 KB_ORG_REQUIRED) — bug trovato da A2
Prodotto con 4 trittici di agenti (A1 esecutore -> A2 revisore -> A3 controllore avversariale):
A2: ~14 correzioni (cross-ref, gate ruolo, comportamenti); A3 PASS: 38 selettori campionati 0 rotti,
18 endpoint reali, 0 violazioni normative (Allegati 3/4, IS-4, '1 mese', PII.* interna), 9 claim verificati.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
e1ab0b3ea0
commit
4dfab2a391
@@ -1,6 +1,6 @@
|
||||
# Avatar di prodotto NIS2 — Demo + Formazione (standard product-demo-complete)
|
||||
|
||||
> Stato: **Fase 1 (DEMO) in costruzione**. Owner prodotto: NIS2. Owner persona/voce/collaudo: AgileHub.
|
||||
> Stato: **FORMAZIONE-FIRST (decisione utente 2026-06-12): la formazione è l'obiettivo primario; la demo riusa i mattoni.** Owner prodotto: NIS2. Owner persona/voce/collaudo: AgileHub.
|
||||
> Persona già LIVE: `ARIA_SUPPORT_NIS2` (id=4). Voce ARIA riusata (niente consenso voce).
|
||||
> Modalità **A** (prodotto live: l'avatar pilota la SPA reale).
|
||||
|
||||
@@ -22,10 +22,12 @@
|
||||
- [ ] **Manifest** `public/demo/nis2-tour-2026.json` (~10 step IT; EN dopo).
|
||||
- [ ] **Mappe** `docs/mappa-logica/*.md` (1 per vista) + `SELETTORI_DEMO.md` + anchor `data-demo-action` + id stabili nel DOM.
|
||||
|
||||
## Deliverable IN PIÙ — FORMAZIONE (punti 6–7, dopo la demo)
|
||||
- [ ] Mappa-logica **COMPLETA** (tutte le viste, non solo le 10 della demo).
|
||||
- [ ] **Tassonomia corso** (moduli → lezioni → argomenti, prerequisiti, durata). *Formato JSON da definire (lo standard non lo fissa).*
|
||||
- [ ] (opz.) banca esercizi/domande per modulo + sandbox scrivibile isolata.
|
||||
## Deliverable FORMAZIONE (priorità primaria — punti 6–7(+8) del brief)
|
||||
- [ ] **Mappa-logica COMPLETA** `docs/mappa-logica/*.md` — TUTTE le ~22 viste app (in produzione con agenti, formato canonico standard §2).
|
||||
- [ ] **`SELETTORI_DEMO.md`** — registry campo→selettore compilato dalle mappe, selettori VERIFICATI nel DOM reale.
|
||||
- [x] **Tassonomia corso** `docs/formazione/TASSONOMIA_CORSO_NIS2.md` + `.json` (moduli→lezioni→argomenti, prerequisiti, durate). Formato JSON definito da noi (lo standard non lo fissa) — da validare con AgileHub.
|
||||
- [ ] **Banca esercizi/domande** per modulo (punto 8, la forniamo noi: conosciamo il prodotto) — dopo la tassonomia.
|
||||
- [ ] **Sandbox scrivibile isolata**: org **996002** (dataset finto SCRIVIBILE con reset, per i "prova tu"), distinta dall'org demo read-only 996001. Scope JWT dedicato `training:sandbox` (scritture consentite SOLO su org 996002).
|
||||
|
||||
## Endpoint (route shape scelta)
|
||||
Per non combattere il router NIS2 (path-param numerici), il `session_id` (stringa `demo-<uuid>`) viaggia in **query/body**, non in path. Le URL esatte che userà il widget sono quelle che ritorno io in `session-start` (`manifest_url`, `credentials_url`), quindi è conforme.
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
{
|
||||
"course_id": "formazione:nis2-agile",
|
||||
"course_title": "Corso completo NIS2 Agile — compliance NIS2 operativa",
|
||||
"version": "1.0",
|
||||
"language": "it",
|
||||
"persona_key": "ARIA_SUPPORT_NIS2",
|
||||
"exam": { "type": "soglia", "passing_score": 80, "certificate": true },
|
||||
"total_duration_min": 465,
|
||||
"modules": [
|
||||
{
|
||||
"id": "M1", "title": "Fondamenti NIS2 e accesso alla piattaforma",
|
||||
"duration_min": 45, "prerequisites": [],
|
||||
"lessons": [
|
||||
{ "id": "M1.L1", "title": "La direttiva NIS2 e il D.Lgs. 138/2024", "duration_min": 15,
|
||||
"topics": ["Soggetti essenziali e importanti", "Obblighi Art.21 (misure) e Art.23 (notifiche)", "Determine ACN 164179/2025 e 333017/2025", "Allegati 1/2 (misure) e 3/4 (incidenti)"],
|
||||
"views": [], "kb_refs": ["nis2_sources"] },
|
||||
{ "id": "M1.L2", "title": "Registrazione, login e onboarding organizzazione", "duration_min": 15,
|
||||
"topics": ["Registrazione e login", "Wizard onboarding 5 step (visura/CertiSource/manuale)", "Classificazione NIS2 dell'organizzazione"],
|
||||
"views": ["onboarding"], "kb_refs": ["mappa:18_onboarding"] },
|
||||
{ "id": "M1.L3", "title": "Ruoli, multi-tenancy e impostazioni", "duration_min": 15,
|
||||
"topics": ["Ruoli (org_admin, compliance_manager, auditor, employee, consultant)", "Organizzazione attiva e membri", "Impostazioni profilo"],
|
||||
"views": ["settings"], "kb_refs": ["mappa:16_settings"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "M2", "title": "Dashboard e governance",
|
||||
"duration_min": 30, "prerequisites": ["M1"],
|
||||
"lessons": [
|
||||
{ "id": "M2.L1", "title": "Dashboard: score, scadenze e heatmap", "duration_min": 15,
|
||||
"topics": ["Compliance score (avanzamento misure Art.21)", "Scadenze imminenti", "Heatmap rischi", "Attività recente"],
|
||||
"views": ["dashboard"], "kb_refs": ["mappa:01_dashboard"] },
|
||||
{ "id": "M2.L2", "title": "Gestione membri e organizzazione", "duration_min": 15,
|
||||
"topics": ["Invito membri", "Ruoli e permessi", "Dati organizzazione e classificazione"],
|
||||
"views": ["settings"], "kb_refs": ["mappa:16_settings"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "M3", "title": "Assessment e Gap Analysis",
|
||||
"duration_min": 60, "prerequisites": ["M2"],
|
||||
"lessons": [
|
||||
{ "id": "M3.L1", "title": "Assessment NIS2 (Art.21)", "duration_min": 20,
|
||||
"topics": ["80 domande, 10 categorie Art.21", "Livelli di risposta (implemented/partial/not_implemented/n.a.)", "Progress e completamento"],
|
||||
"views": ["assessment"], "kb_refs": ["mappa:02_assessment"] },
|
||||
{ "id": "M3.L2", "title": "Report assessment e analisi AI", "duration_min": 15,
|
||||
"topics": ["Punteggio per categoria", "Raccomandazioni AI (gap analysis)", "Creazione NCR da assessment"],
|
||||
"views": ["assessment"], "kb_refs": ["mappa:02_assessment"] },
|
||||
{ "id": "M3.L3", "title": "Gap Analysis ACN di 2° livello", "duration_min": 25,
|
||||
"topics": ["Misure/requisiti Det. ACN 164179/2025", "Importanti (37/87) vs essenziali (43/116)", "Stato requisito e evidenze"],
|
||||
"views": ["acn-gap"], "kb_refs": ["mappa:03_acn-gap", "reference:acn_allegati"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "M4", "title": "Gestione dei rischi",
|
||||
"duration_min": 45, "prerequisites": ["M3"],
|
||||
"lessons": [
|
||||
{ "id": "M4.L1", "title": "Registro rischi e matrice 5x5", "duration_min": 15,
|
||||
"topics": ["Censimento rischi", "Likelihood/Impact (scala ISO 27005)", "Matrice 5x5 e score inerente/residuo"],
|
||||
"views": ["risks"], "kb_refs": ["mappa:04_risks"] },
|
||||
{ "id": "M4.L2", "title": "Trattamenti e piani di mitigazione", "duration_min": 15,
|
||||
"topics": ["Piani di trattamento", "Responsabili e scadenze", "Stati (planned/in_progress/completed)"],
|
||||
"views": ["risks"], "kb_refs": ["mappa:04_risks"] },
|
||||
{ "id": "M4.L3", "title": "Suggerimenti AI e collegamento ai controlli", "duration_min": 15,
|
||||
"topics": ["AI suggest rischi per settore", "Collegamento rischi-controlli Art.21"],
|
||||
"views": ["risks"], "kb_refs": ["mappa:04_risks"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "M5", "title": "Incidenti e notifiche Art.23",
|
||||
"duration_min": 60, "prerequisites": ["M2"],
|
||||
"lessons": [
|
||||
{ "id": "M5.L1", "title": "Classificazione degli incidenti", "duration_min": 20,
|
||||
"topics": ["Incidente significativo (5 criteri)", "Tassonomia IS-1..IS-4 (IS-4 solo essenziali)", "Allegato 3 = importanti, Allegato 4 = essenziali"],
|
||||
"views": ["incidents"], "kb_refs": ["mappa:05_incidents", "reference:acn_allegati"] },
|
||||
{ "id": "M5.L2", "title": "Ciclo di notifica 24h/72h/1 mese", "duration_min": 20,
|
||||
"topics": ["Preallarme 24h", "Notifica completa 72h", "Relazione finale entro 1 mese dalla notifica 72h", "Invio al CSIRT (ACN)"],
|
||||
"views": ["incidents"], "kb_refs": ["mappa:05_incidents"] },
|
||||
{ "id": "M5.L3", "title": "Timeline, metriche e PIR", "duration_min": 20,
|
||||
"topics": ["Timeline incidente", "Metriche TTD/TTC/TTR", "Post-Incident Review (5 whys)"],
|
||||
"views": ["incidents"], "kb_refs": ["mappa:05_incidents"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "M6", "title": "Policy e Modello Organizzativo SGSI",
|
||||
"duration_min": 60, "prerequisites": ["M3"],
|
||||
"lessons": [
|
||||
{ "id": "M6.L1", "title": "Policy: creazione, AI e approvazione", "duration_min": 20,
|
||||
"topics": ["Template policy", "Generazione bozza con AI (revisione obbligatoria)", "Flusso approvazione e versioni"],
|
||||
"views": ["policies"], "kb_refs": ["mappa:06_policies"] },
|
||||
{ "id": "M6.L2", "title": "SGSI ISO 27001: wizard del modello organizzativo", "duration_min": 20,
|
||||
"topics": ["Wizard 6 step", "Contesto, ruoli, documenti SGSI", "Pre-popolamento da dati NIS2"],
|
||||
"views": ["isms"], "kb_refs": ["mappa:11_isms"] },
|
||||
{ "id": "M6.L3", "title": "SoA e controlli ISO 27001/27017/27018", "duration_min": 20,
|
||||
"topics": ["Statement of Applicability", "111 controlli (93 ISO 27001:2022 + cloud/PII)", "Applicabilità e giustificazioni"],
|
||||
"views": ["isms"], "kb_refs": ["mappa:11_isms"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "M7", "title": "Supply chain e asset",
|
||||
"duration_min": 45, "prerequisites": ["M2"],
|
||||
"lessons": [
|
||||
{ "id": "M7.L1", "title": "Fornitori: censimento e valutazione", "duration_min": 15,
|
||||
"topics": ["Anagrafica fornitori", "Valutazione sicurezza e risk score", "Import CSV", "Categorie e template"],
|
||||
"views": ["supply-chain"], "kb_refs": ["mappa:07_supply-chain"] },
|
||||
{ "id": "M7.L2", "title": "Asset: inventario e dipendenze", "duration_min": 15,
|
||||
"topics": ["Censimento asset (tipo, criticità, owner)", "Mappa dipendenze"],
|
||||
"views": ["assets"], "kb_refs": ["mappa:08_assets"] },
|
||||
{ "id": "M7.L3", "title": "Rilevanza NIS2 degli asset (GV.OC-04)", "duration_min": 15,
|
||||
"topics": ["Scoring rilevanza 0-100 (6 criteri)", "Classi critico/alto/medio", "Registro sistemi rilevanti stampabile"],
|
||||
"views": ["assets"], "kb_refs": ["mappa:08_assets"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "M8", "title": "Formazione, segnalazioni e aggiornamenti normativi",
|
||||
"duration_min": 45, "prerequisites": ["M2"],
|
||||
"lessons": [
|
||||
{ "id": "M8.L1", "title": "Corsi e assegnazioni formative (Art.20)", "duration_min": 15,
|
||||
"topics": ["Creazione corsi", "Assegnazioni e scadenze", "Stato compliance formativa"],
|
||||
"views": ["training"], "kb_refs": ["mappa:09_training"] },
|
||||
{ "id": "M8.L2", "title": "Whistleblowing: segnalazioni e gestione", "duration_min": 15,
|
||||
"topics": ["Segnalazione anonima e tracking", "Presa in carico e chiusura", "Timeline riservata"],
|
||||
"views": ["whistleblowing"], "kb_refs": ["mappa:13_whistleblowing"] },
|
||||
{ "id": "M8.L3", "title": "Aggiornamenti normativi e Knowledge Base", "duration_min": 15,
|
||||
"topics": ["Feed NIS2/ACN/DORA con ACK tracciato", "KB multi-livello (SYSTEM/FIRM/ORG)", "Upload documenti e ricerca semantica"],
|
||||
"views": ["normative", "kb"], "kb_refs": ["mappa:12_normative", "mappa:14_kb"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "M9", "title": "Report, audit e assistente AI",
|
||||
"duration_min": 45, "prerequisites": ["M4", "M5", "M6"],
|
||||
"lessons": [
|
||||
{ "id": "M9.L1", "title": "Report esecutivo e export", "duration_min": 15,
|
||||
"topics": ["Report esecutivo per il CdA (Art.20)", "Export CSV (rischi, incidenti, controlli, asset)"],
|
||||
"views": ["reports"], "kb_refs": ["mappa:10_reports"] },
|
||||
{ "id": "M9.L2", "title": "Audit trail e controlli", "duration_min": 15,
|
||||
"topics": ["Audit log con hash-chain (integrità)", "Controlli di compliance e evidenze", "Mapping NIST CSF / ISO 27001"],
|
||||
"views": ["reports"], "kb_refs": ["mappa:10_reports"] },
|
||||
{ "id": "M9.L3", "title": "ARIA: l'assistente AI con fonti certe", "duration_min": 15,
|
||||
"topics": ["Domande su normativa e prodotto (RAG)", "Principio fonti certe (mai riferimenti inventati)", "Cross-analysis AI"],
|
||||
"views": ["cross-analysis"], "kb_refs": ["mappa:15_cross-analysis"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "M10", "title": "Percorsi per ruolo: consulente e amministratore",
|
||||
"duration_min": 30, "prerequisites": ["M2"], "optional": true, "target_roles": ["consultant", "super_admin"],
|
||||
"lessons": [
|
||||
{ "id": "M10.L1", "title": "Vista consulente: portafoglio aziende", "duration_min": 15,
|
||||
"topics": ["Elenco clienti e score", "Switch organizzazione", "Connettori evidence automation"],
|
||||
"views": ["companies"], "kb_refs": ["mappa:17_companies"] },
|
||||
{ "id": "M10.L2", "title": "Amministrazione piattaforma", "duration_min": 15,
|
||||
"topics": ["Gestione organizzazioni", "Gestione utenti", "Statistiche piattaforma"],
|
||||
"views": ["admin/index", "admin/organizations", "admin/users"], "kb_refs": ["mappa:20_admin-index", "mappa:21_admin-organizations", "mappa:22_admin-users"] }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
# Tassonomia corso — Formazione con avatar NIS2 Agile
|
||||
|
||||
> Deliverable punto 7 dello standard `product-demo-complete` / `DESIGN_AVATAR_FORMAZIONE.md`.
|
||||
> Macchina: `TASSONOMIA_CORSO_NIS2.json` (formato definito da noi: lo standard non lo fissa — da validare con AgileHub).
|
||||
> Completamento: **esame con soglia 80%** (decisione utente 2026-06-12) → attestato solo se superato.
|
||||
|
||||
## Struttura: 10 moduli · 28 lezioni · ~7h45m
|
||||
|
||||
| Mod | Titolo | Durata | Prerequisiti | Viste |
|
||||
|---|---|---|---|---|
|
||||
| M1 | Fondamenti NIS2 e accesso | 45' | — | onboarding, settings |
|
||||
| M2 | Dashboard e governance | 30' | M1 | dashboard, settings |
|
||||
| M3 | Assessment e Gap Analysis | 60' | M2 | assessment, acn-gap |
|
||||
| M4 | Gestione dei rischi | 45' | M3 | risks |
|
||||
| M5 | Incidenti e notifiche Art.23 | 60' | M2 | incidents |
|
||||
| M6 | Policy e SGSI (ISO 27001) | 60' | M3 | policies, isms |
|
||||
| M7 | Supply chain e asset | 45' | M2 | supply-chain, assets |
|
||||
| M8 | Formazione, whistleblowing, normative | 45' | M2 | training, whistleblowing, normative, kb |
|
||||
| M9 | Report, audit e ARIA | 45' | M4+M5+M6 | reports, cross-analysis |
|
||||
| M10 | Percorsi per ruolo (opz.) | 30' | M2 | companies, admin/* |
|
||||
|
||||
## Principi
|
||||
- Ogni lezione referenzia le **mappe-logiche** (`kb_refs: mappa:NN_vista`) → l'avatar insegna sulla vista REALE coi selettori verificati.
|
||||
- **Fonti certe**: i contenuti normativi citano `nis2_sources.php` (Dir. 2022/2555, D.Lgs. 138/2024, Det. ACN); mai riferimenti inventati.
|
||||
- Punti delicati codificati nei topics: Allegato 3=importanti / 4=essenziali; IS-4 solo essenziali; relazione finale **1 mese dalla notifica 72h** (non "30 giorni dal rilevamento").
|
||||
- **Sandbox "prova tu"**: org 996002 scrivibile isolata con reset (vs demo read-only 996001).
|
||||
- M10 è opzionale e per ruolo (consultant/super_admin).
|
||||
|
||||
## Banca esercizi (punto 8 — prossimo deliverable)
|
||||
Per ogni modulo: 5-8 domande chiuse + 1-2 esercizi pratici in sandbox ("crea un rischio con score ≥12 e un trattamento", "registra un incidente significativo e invia il preallarme"). Da produrre dopo la verifica delle mappe.
|
||||
@@ -0,0 +1,58 @@
|
||||
# MAPPA-LOGICA · Dashboard
|
||||
|
||||
⟦ INIZIO · U-DASHBOARD · Videata "Dashboard" ⟧
|
||||
File: public/dashboard.html · URL: /dashboard.html · Scopo: panoramica iniziale della compliance NIS2 dell'organizzazione (score, KPI, scadenze, attività) · Profili: tutti gli utenti autenticati con organizzazione (org_admin, compliance_manager, board_member, auditor, employee, consultant; super_admin)
|
||||
|
||||
• U-DASHBOARD.1 — Intestazione pagina
|
||||
Mostra: titolo "Dashboard" e data corrente in italiano (es. "giovedì 12 giugno 2026"), valorizzata da JS.
|
||||
Azioni: nessuna.
|
||||
Dati da: data locale del browser (`new Date().toLocaleDateString('it-IT')`), nessuna API.
|
||||
Confine: `#header-date` (riga ~23); header = `.content-header` (riga ~20).
|
||||
|
||||
• U-DASHBOARD.2 — Gauge "Avanzamento implementazione misure Art.21 NIS2"
|
||||
Mostra: gauge circolare con percentuale di avanzamento implementazione delle misure Art.21 NIS2. Nota sotto il gauge: "Misura l'implementazione tecnica, non la conformita' legale". Il valore preferisce la % controlli implementati (`avg_implementation`); se assente ripiega sul punteggio assessment (`score`).
|
||||
Azioni: nessuna (solo visualizzazione).
|
||||
Dati da: `GET /api/dashboard/overview` (campo `compliance_score`) poi raffinato da `GET /api/dashboard/compliance-score` (campi `avg_implementation`, `score`).
|
||||
Confine: `#compliance-gauge` (riga ~33).
|
||||
|
||||
• U-DASHBOARD.3 — Card statistiche (4 KPI)
|
||||
Mostra: 4 stat-card con etichette reali: "Rischi Aperti" (totale rischi), "Incidenti Attivi", "Policy Approvate" (somma policy con status approved/published), "Formazione" (percentuale completamento corsi assegnati).
|
||||
Azioni: nessuna (solo visualizzazione).
|
||||
Dati da: `GET /api/dashboard/overview` — campi `risks.total`, `active_incidents`, `policies[]` (status+count), `training.total`/`training.completed`.
|
||||
Confine: griglia `#stats-grid` (riga ~43); valori in `#stat-risks` (riga ~50), `#stat-incidents` (riga ~59), `#stat-policies` (riga ~68), `#stat-training` (riga ~77).
|
||||
|
||||
• U-DASHBOARD.4 — Azioni Rapide
|
||||
Mostra: card "Azioni Rapide" con 3 bottoni: "Nuovo Assessment", "Registra Incidente", "Genera Policy AI".
|
||||
Azioni: "Nuovo Assessment" → naviga a assessment.html; "Registra Incidente" → naviga a incidents.html; "Genera Policy AI" → apre la modale di generazione policy AI (vedi U-DASHBOARD.7).
|
||||
Dati da: nessuna API in questa area (solo navigazione/apertura modale).
|
||||
Confine: card alle righe ~85-105; bottoni con classe `.quick-action-btn` dentro `.quick-actions` (riga ~90). Nessun id stabile sui singoli bottoni (vedi sezione ID mancanti).
|
||||
|
||||
• U-DASHBOARD.5 — Prossime Scadenze
|
||||
Mostra: lista delle prossime 5 scadenze con giorno/mese, titolo, categoria; badge "Urgente" se ≤3 giorni, "Prossima" se ≤7 giorni. Empty state: "Nessuna scadenza imminente".
|
||||
Azioni: nessuna.
|
||||
Dati da: `GET /api/dashboard/upcoming-deadlines` (campi `due_date`, `title`/`description`, `category`/`type`).
|
||||
Confine: `#deadlines-list` (riga ~114).
|
||||
|
||||
• U-DASHBOARD.6 — Attività Recenti
|
||||
Mostra: lista delle ultime 8 attività con descrizione e tempo relativo ("x minuti fa"). Empty state: "Nessuna attivita' recente".
|
||||
Azioni: nessuna.
|
||||
Dati da: `GET /api/dashboard/recent-activity` (campi `description`/`message`/`action`, `created_at`).
|
||||
Confine: `#activity-list` (riga ~124).
|
||||
|
||||
• U-DASHBOARD.7 — Modale "Genera Policy con AI" (generata via JS)
|
||||
Mostra: select "Categoria Policy" con 8 opzioni: Gestione del Rischio, Risposta agli Incidenti, Continuita' Operativa, Sicurezza Supply Chain, Controllo degli Accessi, Crittografia, Sicurezza del Personale, Gestione degli Asset.
|
||||
Azioni: "Genera" → chiama l'AI, notifica "Generazione policy in corso...", a successo redirige a policies.html; "Annulla" → chiude la modale.
|
||||
Dati da: `POST /api/policies/ai-generate` (body `{category}`).
|
||||
Confine: modale iniettata da `showModal()` in `#modal-overlay` (creato da common.js); select `#ai-policy-category` (definito nel JS, riga ~310 dello script inline).
|
||||
|
||||
⟦ FINE · U-DASHBOARD ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Bottone "Nuovo Assessment" (azioni rapide) | ~91 | `nis2-dashboard-qa-assessment` |
|
||||
| Bottone "Registra Incidente" (azioni rapide) | ~95 | `nis2-dashboard-qa-incidente` |
|
||||
| Bottone "Genera Policy AI" (azioni rapide) | ~99 | `nis2-dashboard-qa-policy-ai` |
|
||||
| Card "Azioni Rapide" | ~85 | `nis2-dashboard-quick-actions` |
|
||||
| Card "Prossime Scadenze" (wrapper card, il body ha già `#deadlines-list`) | ~110 | `nis2-dashboard-card-scadenze` |
|
||||
| Card "Attivita' Recenti" (wrapper card, il body ha già `#activity-list`) | ~120 | `nis2-dashboard-card-attivita` |
|
||||
@@ -0,0 +1,54 @@
|
||||
# MAPPA-LOGICA · Gap Analysis NIS2 (Assessment)
|
||||
|
||||
⟦ INIZIO · U-ASSESSMENT · Videata "Gap Analysis NIS2" ⟧
|
||||
File: public/assessment.html · URL: /assessment.html · Scopo: condurre l'assessment di conformità NIS2 (80 domande, 10 categorie Art.21), vedere i risultati per categoria, lanciare l'analisi AI e generare NCR dai gap · Profili: tutti gli utenti autenticati con organizzazione (org_admin, compliance_manager, board_member, auditor, employee, consultant; super_admin)
|
||||
|
||||
• U-ASSESSMENT.1 — Intestazione con bottone "Analisi AI"
|
||||
Mostra: titolo "Gap Analysis NIS2"; bottone "Analisi AI" nascosto finché non si è nella vista risultati.
|
||||
Azioni: "Analisi AI" → lancia l'analisi AI sull'assessment corrente (vedi U-ASSESSMENT.6).
|
||||
Dati da: `POST /api/assessments/{id}/ai-analyze`.
|
||||
Confine: `#btn-ai-analyze` (riga ~23).
|
||||
|
||||
• U-ASSESSMENT.2 — Schermata iniziale "Assessment di Conformita' NIS2"
|
||||
Mostra: card introduttiva con testo "Valuta il livello di conformita' della tua organizzazione rispetto ai requisiti della direttiva NIS2"; tabella "Assessment Esistenti" (colonne: Data, Stato, Punteggio, Azioni) con badge "Completato"/"In Corso"; bottone primario "Nuovo Assessment".
|
||||
Azioni: "Nuovo Assessment" → crea un assessment e apre il wizard; per riga esistente: "Risultati" (se completato) → vista risultati; "Riprendi" (se in corso) → riapre il wizard.
|
||||
Dati da: lista: `GET /api/assessments/list`; creazione: `POST /api/assessments/create` (body `{title}`).
|
||||
Confine: `#assessment-start` (riga ~32); tabella in `#existing-assessments` (riga ~37); bottone `#btn-new-assessment` (riga ~39).
|
||||
|
||||
• U-ASSESSMENT.3 — Wizard: indicatore step e barra avanzamento
|
||||
Mostra: step cliccabili numerati per categoria (10 categorie Art.21, generati via JS con classe `.step`); barra "Avanzamento risposta domande" con percentuale e contatore "N di M domande con risposta".
|
||||
Azioni: click su uno step → salta alla categoria (consentito solo verso categorie già visitate o la successiva).
|
||||
Dati da: `GET /api/assessments/{id}/questions` (struttura: array di `{category_id, category_title, questions[]}`).
|
||||
Confine: wizard `#assessment-wizard` (riga ~47); step `#steps-indicator` (riga ~49); barra `#progress-bar-fill` (riga ~58), percentuale `#progress-pct` (riga ~55), contatori `#progress-answered` / `#progress-total` (riga ~61).
|
||||
|
||||
• U-ASSESSMENT.4 — Wizard: card domanda corrente
|
||||
Mostra: titolo categoria, contatore "n/totale"; testo domanda con eventuale guida (`guidance_it`) e tag "Art. <articolo NIS2>" e "ISO <controllo 27001>"; 4 radio "Livello di Conformita'": Non Implementato, Parziale, Implementato, Non Applicabile; slider "Livello di Maturita' (0-5)" da "0 - Inesistente" a "5 - Ottimizzato"; campo "Note"; campo "Descrizione Evidenza".
|
||||
Azioni: "Precedente" → domanda precedente; "Salva Progresso" → salva la risposta corrente con notifica; "Successiva" → salva in background e avanza; sull'ultima domanda il bottone diventa "Completa Assessment" e chiude l'assessment.
|
||||
Dati da: salvataggio risposta: `POST /api/assessments/{id}/respond` (body `{question_code, response_value, maturity_level, notes, evidence_description}`); completamento: `POST /api/assessments/{id}/complete`.
|
||||
Confine: header categoria `#category-title` (riga ~68), contatore `#question-counter` (riga ~69), area domanda `#question-area` (riga ~71); bottoni `#btn-prev` (riga ~76) e `#btn-next` (riga ~83). Campi generati via JS dentro `#question-area`: `#maturity-slider`, `#maturity-value`, `#question-notes`, `#question-evidence`. Il bottone "Salva Progresso" non ha id (vedi ID mancanti).
|
||||
|
||||
• U-ASSESSMENT.5 — Risultati: punteggio complessivo e per categoria
|
||||
Mostra: gauge con punteggio complessivo (`overall_score`); sezione "Punteggio per Categoria" con barre percentuali colorate (verde ≥60%, giallo ≥40%, rosso <40%) per ciascuna delle categorie Art.21.
|
||||
Azioni: bottone "Analisi AI" nell'header della card (stesso flusso di U-ASSESSMENT.6).
|
||||
Dati da: `GET /api/assessments/{id}/report` (campi `overall_score`, `category_scores`).
|
||||
Confine: contenitore `#assessment-results` (riga ~93); gauge `#results-gauge` (riga ~104); barre `#category-scores` (riga ~108).
|
||||
|
||||
• U-ASSESSMENT.6 — Card "Analisi AI"
|
||||
Mostra: (visibile dopo l'analisi) sezioni Riepilogo, Punti di Forza, Aree di Miglioramento, Raccomandazioni generate dall'AI; badge "Intelligenza Artificiale".
|
||||
Azioni: nessuna interna; viene popolata dai bottoni "Analisi AI".
|
||||
Dati da: `POST /api/assessments/{id}/ai-analyze` (risposta con `summary`, `strengths[]`, `weaknesses[]`, `recommendations[]`).
|
||||
Confine: card `#ai-analysis-card` (riga ~113); contenuto `#ai-analysis-content` (riga ~118).
|
||||
|
||||
• U-ASSESSMENT.7 — Card "Non Conformita'" (generazione NCR dai gap)
|
||||
Mostra: testo esplicativo: i controlli "Non Implementato" generano NCR major, quelli "Parzialmente Implementato" generano NCR minor; dopo la generazione mostra il riepilogo "N non conformita' generate" con conteggio major/minor.
|
||||
Azioni: "Genera Non Conformita' dai Gap" → crea le NCR dall'assessment; il bottone si nasconde a successo.
|
||||
Dati da: `POST /api/ncr/from-assessment` (body `{assessment_id}`).
|
||||
Confine: card `#ncr-generation-card` (riga ~122); bottone `#btn-generate-ncr` (riga ~132); esito `#ncr-generation-result` (riga ~136).
|
||||
|
||||
⟦ FINE · U-ASSESSMENT ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Bottone "Salva Progresso" (footer card domanda) | ~80 | `nis2-assessment-btn-salva` |
|
||||
| Bottone "Analisi AI" nell'header della card Risultati (duplicato di #btn-ai-analyze, senza id) | ~97 | `nis2-assessment-btn-ai-risultati` |
|
||||
@@ -0,0 +1,48 @@
|
||||
# MAPPA-LOGICA · Gap Analysis ACN (misure di base)
|
||||
|
||||
⟦ INIZIO · U-ACN-GAP · Videata "Gap Analysis ACN (misure di base)" ⟧
|
||||
File: public/acn-gap.html · URL: /acn-gap.html · Scopo: assessment di secondo livello sulla conformità puntuale alla Determinazione ACN 164179/2025 — misure e requisiti specifici per soggetti NIS importanti o essenziali, organizzati per funzione del Framework Nazionale (GV/ID/PR/DE/RS/RC) · Profili: tutti gli utenti autenticati con organizzazione (org_admin, compliance_manager, board_member, auditor, employee, consultant; super_admin). Richiede che l'organizzazione sia già classificata come importante o essenziale.
|
||||
|
||||
• U-ACN-GAP.1 — Intro normativa e bottone "Analisi AI dei gap"
|
||||
Mostra: box introduttivo "Conformità puntuale alla Determinazione ACN 164179/2025" — spiega che l'analisi va oltre le 10 misure generiche dell'Art. 21 e che il perimetro dipende dalla classificazione (importante o essenziale). Nell'header un bottone "Analisi AI dei gap", visibile solo nella vista risultati.
|
||||
Azioni: "Analisi AI dei gap" → lancia l'analisi AI dei requisiti non conformi (vedi U-ACN-GAP.6).
|
||||
Dati da: `POST /api/acn-gap/{id}/aiAnalyze`.
|
||||
Confine: intro `#acn-intro` (riga ~62); bottone `#btn-ai-analyze` (riga ~56).
|
||||
|
||||
• U-ACN-GAP.2 — Schermata START: classificazione, perimetro, assessment esistenti
|
||||
Mostra: badge "Soggetto IMPORTANTE" (giallo) o "Soggetto ESSENZIALE" (rosso) con il perimetro applicabile "N misure, M requisiti" (importanti: 37 misure/87 requisiti; essenziali: 43/116). Se l'organizzazione non è classificata: messaggio "Classifica prima il soggetto come importante o essenziale (Impostazioni › Classificazione NIS2)" (error_code ENTITY_LEVEL_REQUIRED). Elenco "Assessment esistenti" con badge Completato (con punteggio) / In corso.
|
||||
Azioni: "Nuova Gap Analysis ACN" → crea l'assessment e apre il wizard; "Consulta il catalogo dei requisiti" → mostra il catalogo read-only (U-ACN-GAP.3); per ogni assessment esistente: "Vedi" (completato) → risultati, "Riprendi" (in corso) → wizard.
|
||||
Dati da: catalogo+livello: `GET /api/acn-gap/catalog` (campi `entity_level`, `totals.measures`, `totals.requirements`, `functions[]`); lista: `GET /api/acn-gap/list`; creazione: `POST /api/acn-gap/create`.
|
||||
Confine: card `#acn-start` (riga ~68); info livello `#acn-level-info` (riga ~70); esistenti `#acn-existing` (riga ~71); bottone `#btn-new-acn` (riga ~72). Il bottone "Consulta il catalogo" non ha id (vedi ID mancanti).
|
||||
|
||||
• U-ACN-GAP.3 — Catalogo requisiti ACN (read-only)
|
||||
Mostra: card "Catalogo requisiti ACN applicabili": accordion per funzione del Framework Nazionale — Governo (GV), Identificazione (ID), Protezione (PR), Rilevamento (DE), Risposta (RS), Ripristino (RC) — con misure (codice + titolo) e requisiti numerati, testo integrale.
|
||||
Azioni: click sull'intestazione di una funzione → espande/comprime la sezione.
|
||||
Dati da: `GET /api/acn-gap/catalog` (cache in `window._acnCatalog`).
|
||||
Confine: card `#acn-catalog` (riga ~82); contenuto `#acn-catalog-body` (riga ~84).
|
||||
|
||||
• U-ACN-GAP.4 — Wizard di valutazione requisiti
|
||||
Mostra: barra sticky con titolo "Gap Analysis ACN", badge livello (IMPORTANTE/ESSENZIALE), progress bar, contatore "N / M requisiti con risposta" e hint di salvataggio ("Salvataggio…" / "Salvato HH:MM" / "Salvataggio in sospeso"). Sotto: accordion per funzione con misure (codice + titolo) e per ogni requisito 4 bottoni-pillola: "Attuato" (verde), "Parziale" (giallo), "Non attuato" (rosso), "Non applic." (grigio).
|
||||
Azioni: click su una pillola → seleziona la risposta e salva in autosave batch con debounce 700ms; "Calcola punteggio e completa" → se mancano risposte mostra alert "Mancano N risposte", altrimenti completa e mostra i risultati.
|
||||
Dati da: domande: `GET /api/acn-gap/{id}/requirements`; salvataggio: `POST /api/acn-gap/{id}/respond` (body `{responses:[{requirement_key, response_value}]}`); completamento: `POST /api/acn-gap/{id}/complete`.
|
||||
Confine: contenitore `#acn-wizard` (riga ~88); titolo `#acn-wizard-title` (riga ~92); livello `#acn-wizard-level` (riga ~93); barra `#acn-bar-fill` (riga ~95); contatori `#acn-answered` / `#acn-total` (riga ~96); hint `#acn-savehint` (riga ~97); requisiti `#acn-functions` (riga ~101); messaggio `#acn-wizard-msg` (riga ~105); bottone `#btn-acn-complete` (riga ~106). Le pillole risposta sono generate via JS con classe `.acn-opt` e attributi `data-key`/`data-val`.
|
||||
|
||||
• U-ACN-GAP.5 — Risultati: punteggio complessivo e per funzione
|
||||
Mostra: card "Esito Gap Analysis ACN" con punteggio complessivo 0-100 (colore: verde ≥80, lime ≥60, ambra ≥40, rosso <40) e didascalia "Punteggio complessivo di conformità (0-100)"; sezione "Punteggio per funzione (Framework Nazionale)" con pill colorate per GV/ID/PR/DE/RS/RC; card "Requisiti non conformi (piano d'azione)" con codice misura, badge "Non attuato"/"Parziale" e testo del requisito (oppure "Nessun gap: pienamente conforme."); bottone "Torna all'inizio".
|
||||
Azioni: "Torna all'inizio" → ricarica la pagina (vista START).
|
||||
Dati da: `GET /api/acn-gap/{id}/report` (campi `assessment.overall_score`, `assessment.function_scores`, `gaps[]`, `assessment.ai_summary`).
|
||||
Confine: contenitore `#acn-results` (riga ~113); punteggio `#acn-overall` (riga ~118); funzioni `#acn-func-scores` (riga ~122); gap `#acn-gaps` (riga ~131). Il bottone "Torna all'inizio" non ha id (vedi ID mancanti).
|
||||
|
||||
• U-ACN-GAP.6 — Card "Analisi AI dei gap"
|
||||
Mostra: testo dell'analisi AI dei requisiti non conformi (`ai_summary`, pre-formattato). Visibile se l'assessment ha già un riepilogo AI o dopo aver lanciato l'analisi.
|
||||
Azioni: popolata dal bottone `#btn-ai-analyze` (header); durante l'analisi il bottone mostra "Analisi in corso…".
|
||||
Dati da: `POST /api/acn-gap/{id}/aiAnalyze` (risposta `ai_summary`); in lettura da `GET /api/acn-gap/{id}/report`.
|
||||
Confine: card `#acn-ai-card` (riga ~125); contenuto `#acn-ai-body` (riga ~127).
|
||||
|
||||
⟦ FINE · U-ACN-GAP ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Bottone "Consulta il catalogo dei requisiti" | ~75 | `nis2-acn-gap-btn-catalogo` |
|
||||
| Bottone "Torna all'inizio" (vista risultati) | ~134 | `nis2-acn-gap-btn-restart` |
|
||||
@@ -0,0 +1,71 @@
|
||||
# MAPPA-LOGICA · Gestione Rischi
|
||||
|
||||
⟦ INIZIO · U-RISKS · Videata "Gestione Rischi" ⟧
|
||||
File: public/risks.html · URL: /risks.html · Scopo: risk register NIS2 — censimento rischi (probabilità x impatto), matrice 5x5, analisi quantitativa FAIR (ALE/Monte Carlo), dashboard KRI, trattamenti e suggerimenti AI · Profili: tutti gli utenti autenticati con organizzazione (org_admin, compliance_manager, board_member, auditor, employee, consultant; super_admin)
|
||||
|
||||
• U-RISKS.1 — Intestazione: toggle viste + azioni globali
|
||||
Mostra: titolo "Gestione Rischi"; toggle a 4 viste: "Tabella", "Matrice", "Quantitativo (FAIR)", "KRI"; bottoni "AI Suggerisci" e "+ Nuovo Rischio".
|
||||
Azioni: click sul toggle → `switchView()` mostra la vista corrispondente; "AI Suggerisci" → modale con rischi suggeriti dall'AI (U-RISKS.9); "+ Nuovo Rischio" → modale creazione rischio (U-RISKS.7).
|
||||
Dati da: "AI Suggerisci": `POST /api/risks/ai-suggest`.
|
||||
Confine: toggle `#view-toggle` (riga ~310); bottone `#btn-ai-suggest` (riga ~316). I singoli bottoni del toggle e "+ Nuovo Rischio" non hanno id (vedi ID mancanti).
|
||||
|
||||
• U-RISKS.2 — Vista Tabella: filtri + registro rischi
|
||||
Mostra: filtri "Tutte le categorie" (Cyber, Operativo, Compliance, Supply Chain, Fisico, Umano) e "Tutti gli stati" (Identificato, In Analisi, In Trattamento, Monitorato, Chiuso); tabella con colonne Codice, Titolo, Categoria, Probabilita' (n/5), Impatto (n/5), Score (badge circolare colorato: low<10, medium 10-14, high 15-19, critical ≥20), Stato, Azioni (matita=Modifica, cestino=Elimina). Righe cliccabili.
|
||||
Azioni: cambio filtro → ricarica lista; click riga → dettaglio rischio (U-RISKS.6); matita → modale modifica (U-RISKS.7); cestino → modale conferma eliminazione (U-RISKS.8).
|
||||
Dati da: `GET /api/risks/list?category=&status=` (risposta `data.items`).
|
||||
Confine: contenitore `#view-table` (riga ~326); filtri `#filter-category` (riga ~328) e `#filter-status` (riga ~337); corpo tabella `#risks-table-body` (riga ~362).
|
||||
|
||||
• U-RISKS.3 — Vista Matrice di Rischio 5x5
|
||||
Mostra: card "Matrice di Rischio 5x5" (sottotitolo "Rischi inerenti (esclusi chiusi)"): griglia Probabilita' (asse Y, 5→1) x Impatto (asse X, 1→5), celle colorate dal verde al rosso secondo score P×I; dot bianco con il numero di rischi nella cella (tooltip con i titoli). Legenda: Basso (1-4), Medio (5-9), Alto (10-14), Elevato (15-19), Critico (20-25).
|
||||
Azioni: hover sulle celle (tooltip); nessun click.
|
||||
Dati da: `GET /api/risks/matrix` (risposta `data.risks` con `likelihood`, `impact`, `title`).
|
||||
Confine: contenitore `#view-matrix` (riga ~375); griglia `#risk-matrix-grid` (riga ~386).
|
||||
|
||||
• U-RISKS.4 — Vista Quantitativo (FAIR): simulatore ALE + registro
|
||||
Mostra: card "Analisi Quantitativa del Rischio (FAIR)" — "Perdita Annua Attesa (ALE) in EUR — simulazione Monte Carlo". Form: select Rischio, TEF min/probabile/max (eventi/anno), Vulnerabilita (0-1), Perdita min/probabile/max (EUR). Risultati: 4 stat-box "ALE P10 (ottimistico)", "ALE Mediana (P50)", "ALE P90 (pessimistico)", "ALE Media", LEF medio e istogramma della distribuzione delle perdite simulate. Seconda card "Registro Quantitativo" con "ALE di portafoglio" e tabella (Codice, Titolo, Categoria, ALE Min/Mediana/Max/Media).
|
||||
Azioni: "Calcola ALE" → esegue la simulazione FAIR sul rischio selezionato e aggiorna il registro.
|
||||
Dati da: select rischi: `GET /api/risks/list?per_page=200`; calcolo: `POST /api/risks/{id}/fair` (body `tef_min, tef_ml, tef_max, vuln, lm_min, lm_ml, lm_max`); registro: `GET /api/risks/fairRegister` (campi `portfolio_ale_mean`, `risks[]`).
|
||||
Confine: contenitore `#view-fair` (riga ~420); select `#fair-risk-select` (riga ~429); input `#fair-tef-min` (~430), `#fair-tef-ml` (~431), `#fair-tef-max` (~432), `#fair-vuln` (~433), `#fair-lm-min` (~434), `#fair-lm-ml` (~435), `#fair-lm-max` (~436); bottone `#btn-run-fair` (riga ~438); risultati `#fair-result` (~439) con `#fair-p10`/`#fair-p50`/`#fair-p90`/`#fair-mean` (~441-444), `#fair-lef` (~446), `#fair-histogram` (~447), `#fair-histogram-labels` (~448); portafoglio `#fair-portfolio` (~454); registro `#fair-register-body` (~458).
|
||||
|
||||
• U-RISKS.5 — Vista KRI: indicatori chiave di rischio
|
||||
Mostra: 4 stat-box riepilogo per stato (Critico/rosso, Attenzione/ambra, OK/verde, N/D/grigio); tabella KRI con colonne Stato (semaforo), Indicatore (nome + descrizione), Categoria, Valore (con unità), Soglia Warning, Soglia Critica, Azioni (Modifica).
|
||||
Azioni: "+ Nuovo KRI" → modale creazione (U-RISKS.8); "Modifica" su riga → stessa modale precompilata.
|
||||
Dati da: `GET /api/risks/kri` (campi `summary{red,amber,green,unknown}`, `kris[]`).
|
||||
Confine: contenitore `#view-kri` (riga ~464); riepilogo `#kri-summary` (riga ~466); corpo tabella `#kri-table-body` (riga ~473). Il bottone "+ Nuovo KRI" non ha id (vedi ID mancanti).
|
||||
|
||||
• U-RISKS.6 — Vista Dettaglio rischio (generata via JS)
|
||||
Mostra: bottone "Torna alla lista"; card principale con codice + titolo, blocco score "Probabilita' x Impatto = Rischio Inerente" (+ "Rischio Residuo" se presente), Descrizione, Categoria, Stato, Trattamento (Mitigare/Accettare/Trasferire/Evitare), Sorgente Minaccia, Vulnerabilita', Responsabile, Data Revisione, Articolo NIS2; card "Trattamenti" con elenco azioni (descrizione, stato, responsabile, scadenza, note); card laterale "Riepilogo" (Codice, Creato il, Aggiornato il, numero Trattamenti).
|
||||
Azioni: "Torna alla lista" → ripristina la vista precedente; "Modifica" → modale modifica; "Elimina" → modale conferma; "+ Aggiungi" trattamento → modale trattamento (U-RISKS.8).
|
||||
Dati da: `GET /api/risks/{id}` (include `treatments[]`).
|
||||
Confine: contenitore `#view-detail` (riga ~479); contenuto interno generato via JS senza id propri (bottone back con classe `.detail-back`).
|
||||
|
||||
• U-RISKS.7 — Modale "Nuovo Rischio" / "Modifica Rischio" (generata via JS)
|
||||
Mostra: campi Titolo*, Descrizione, Categoria, Trattamento, Sorgente Minaccia, Vulnerabilita', slider Probabilita' 1-5 (con scala ISO 27005: da "1 - Remota: <1% probabilità annua" a "5 - Quasi Certa: >70%"), slider Impatto 1-5 (da "1 - Minimo: <€10k danno" a "5 - Catastrofico: >€10M"), anteprima live "Rischio Inerente" (P×I, colore dinamico), Responsabile (ID utente), Data Revisione, Articolo NIS2 di riferimento.
|
||||
Azioni: "Crea Rischio"/"Salva Modifiche" → crea o aggiorna il rischio e ricarica lista/dettaglio; "Annulla" → chiude.
|
||||
Dati da: creazione: `POST /api/risks/create`; modifica: `PUT /api/risks/{id}`; precompilazione: `GET /api/risks/{id}`.
|
||||
Confine: modale in `#modal-overlay` (common.js); campi JS: `#risk-title`, `#risk-description`, `#risk-category`, `#risk-treatment`, `#risk-threat-source`, `#risk-vulnerability`, `#risk-likelihood`, `#risk-impact`, `#likelihood-value`, `#impact-value`, `#likelihood-detail`, `#impact-detail`, `#score-preview-value`, `#risk-owner`, `#risk-review-date`, `#risk-nis2-article` (script righe ~1080-1156).
|
||||
|
||||
• U-RISKS.8 — Modali secondarie: KRI, Trattamento, Eliminazione (generate via JS)
|
||||
Mostra: (a) Modale "Nuovo KRI"/"Modifica KRI": Nome indicatore*, Descrizione, Categoria, Unita (%, count, EUR...), Valore corrente, Obiettivo, Soglia Warning, Soglia Critica, Direzione (Valori alti = peggio / Valori bassi = peggio). (b) Modale "Aggiungi Trattamento": Descrizione Azione*, Responsabile (ID utente), Data Scadenza, Stato (Pianificato/In Corso/Completato), Note. (c) Modale "Conferma Eliminazione": testo con titolo del rischio.
|
||||
Azioni: (a) "Salva" → crea/aggiorna KRI; (b) "Aggiungi" → crea trattamento e ricarica il dettaglio; (c) "Elimina" → cancella il rischio.
|
||||
Dati da: KRI: `POST /api/risks/kri` (create) e `PUT /api/risks/kri/{id}` (update); trattamento: `POST /api/risks/{id}/treatments`; eliminazione: `DELETE /api/risks/{id}`.
|
||||
Confine: tutte in `#modal-overlay`; campi KRI: `#kri-name`, `#kri-desc`, `#kri-cat`, `#kri-unit`, `#kri-cur`, `#kri-target`, `#kri-warn`, `#kri-crit`, `#kri-dir` (script righe ~764-777); campi trattamento: `#treatment-description`, `#treatment-responsible`, `#treatment-due-date`, `#treatment-status`, `#treatment-notes` (script righe ~1264-1291).
|
||||
|
||||
• U-RISKS.9 — Modale "Rischi Suggeriti dall'AI" (generata via JS)
|
||||
Mostra: elenco scrollabile di rischi suggeriti dall'AI in base al settore/asset dell'organizzazione: titolo, descrizione, tag categoria, badge "P:n" e "I:n".
|
||||
Azioni: "Chiudi" → chiude la modale (i suggerimenti non vengono inseriti automaticamente nel registro).
|
||||
Dati da: `POST /api/risks/ai-suggest` (risposta array o `data.suggestions[]`).
|
||||
Confine: modale in `#modal-overlay`; trigger `#btn-ai-suggest` (riga ~316).
|
||||
|
||||
⟦ FINE · U-RISKS ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Bottone toggle "Tabella" | ~311 | `nis2-risks-toggle-tabella` |
|
||||
| Bottone toggle "Matrice" | ~312 | `nis2-risks-toggle-matrice` |
|
||||
| Bottone toggle "Quantitativo (FAIR)" | ~313 | `nis2-risks-toggle-fair` |
|
||||
| Bottone toggle "KRI" | ~314 | `nis2-risks-toggle-kri` |
|
||||
| Bottone "+ Nuovo Rischio" (header) | ~320 | `nis2-risks-btn-nuovo` |
|
||||
| Bottone "+ Nuovo KRI" (vista KRI) | ~467 | `nis2-risks-btn-nuovo-kri` |
|
||||
| Bottone "Torna alla lista" nel dettaglio (classe `.detail-back`, generato via JS) | script ~918 | `nis2-risks-btn-back` |
|
||||
@@ -0,0 +1,55 @@
|
||||
# MAPPA-LOGICA · Gestione Incidenti
|
||||
|
||||
⟦ INIZIO · U-INCIDENTS · Videata "Gestione Incidenti" ⟧
|
||||
File: public/incidents.html · URL: /incidents.html · Scopo: registro incidenti di sicurezza con gestione completa degli obblighi di notifica NIS2 Art. 23 (Early Warning 24h, Notifica 72h, Report Finale 1 mese al CSIRT/ACN), decision tree di significatività e timeline eventi · Profili: tutti gli utenti autenticati con organizzazione (org_admin, compliance_manager, board_member, auditor, employee, consultant; super_admin)
|
||||
|
||||
• U-INCIDENTS.1 — Intestazione
|
||||
Mostra: titolo "Gestione Incidenti"; bottone "+ Nuovo Incidente".
|
||||
Azioni: "+ Nuovo Incidente" → apre la modale di registrazione (U-INCIDENTS.3).
|
||||
Dati da: nessuna API diretta.
|
||||
Confine: header `.content-header` (riga ~268). Il bottone "+ Nuovo Incidente" non ha id (vedi ID mancanti).
|
||||
|
||||
• U-INCIDENTS.2 — Vista Lista: filtri + registro incidenti
|
||||
Mostra: 3 filtri: classificazione (Attacco Cyber, Data Breach, Guasto Sistema, Errore Umano, Disastro Naturale, Supply Chain, Altro), severità (Critico, Alto, Medio, Basso), stato (Rilevato, In Analisi, Contenimento, Eradicazione, Ripristino, Chiuso, Post Mortem). Tabella con colonne: Codice, Titolo (con badge rosso "SIGNIFICATIVO" se applicabile), Classificazione, Severita', Stato, Rilevato (data/ora), "NIS2 Art. 23" (3 dot compatti per Early Warning 24h / Notifica 72h / Report Finale 1 mese: verde=inviato, rosso=scaduto, giallo=in scadenza <6h, grigio=in attesa; icona warning pulsante se c'è uno scaduto; "N/A" se non significativo), Azioni (matita=Aggiorna). Righe cliccabili.
|
||||
Azioni: cambio filtro → ricarica la lista; click riga → dettaglio incidente (U-INCIDENTS.4); matita → modale aggiornamento (U-INCIDENTS.5).
|
||||
Dati da: `GET /api/incidents/list?classification=&severity=&status=` (campi per i dot: `early_warning_due/sent_at`, `notification_due/sent_at`, `final_report_due/sent_at`, `is_significant`).
|
||||
Confine: contenitore `#view-list` (riga ~277); filtri `#filter-classification` (riga ~279), `#filter-severity` (riga ~289), `#filter-status` (riga ~296); corpo tabella `#incidents-table-body` (riga ~323).
|
||||
|
||||
• U-INCIDENTS.3 — Modale "Registra Nuovo Incidente" con decision tree Art. 23 (generata via JS)
|
||||
Mostra: campi Titolo*, Descrizione*, Classificazione, Severita' (default Medio), "Data e ora rilevamento"* (preimpostata ad adesso). Box "Criteri Art. 23 NIS2 — Incidente Significativo" (rif. Considerando 101 NIS2 / D.Lgs. 138/2024 art. 25) con 5 checkbox: interruzione grave per ≥500 utenti; durata interruzione >4 ore; impatto transfrontaliero su altri Stati Membri UE; attacco cyber o data breach con dati personali; perdita finanziaria stimata >€100.000. Esito automatico: con ≥1 criterio "l'incidente e' probabilmente SIGNIFICATIVO" (box rosso, auto-spunta la checkbox), con 0 criteri "appare NON significativo" (box verde). Checkbox "Incidente significativo (richiede notifica CSIRT/ACN ai sensi dell'Art. 23 NIS2)"; poi Servizi interessati, Utenti coinvolti, Impatto transfrontaliero, Azione dolosa / malevola.
|
||||
Azioni: ogni checkbox criterio → `evalSignificance()` ricalcola l'esito e la spunta di significatività; "Registra Incidente" → crea l'incidente (se significativo: notifica "Scadenze NIS2 Art. 23 attivate"); "Annulla" → chiude.
|
||||
Dati da: `POST /api/incidents/create` (body `{title, description, classification, severity, detected_at, is_significant, affected_services, affected_users_count, cross_border_impact, malicious_action}`).
|
||||
Confine: modale in `#modal-overlay` (common.js); campi JS: `#inc-title`, `#inc-description`, `#inc-classification`, `#inc-severity`, `#inc-detected-at`, criteri `#crit-users`, `#crit-duration`, `#crit-crossborder`, `#crit-attack`, `#crit-financial`, esito `#significance-result`, `#inc-significant`, `#inc-affected-services`, `#inc-affected-users`, `#inc-cross-border`, `#inc-malicious` (script righe ~500-595).
|
||||
|
||||
• U-INCIDENTS.4 — Vista Dettaglio incidente (generata via JS)
|
||||
Mostra: bottone "Torna alla lista"; card principale: codice + titolo, Classificazione, Severita', Stato, Descrizione, Data Rilevamento, Segnalato da, Assegnato a, Servizi Interessati, Utenti Coinvolti, Incidente Significativo (Si/No), Impatto Transfrontaliero, Azione Malevola, Causa Radice, Azioni di Rimedio, Lezioni Apprese. Card "NIS2 Art. 23 - Obblighi di Notifica" (solo se significativo, badge "Incidente Significativo") con timeline a 3 step: "Early Warning (24h)" (allerta iniziale al CSIRT nazionale ACN entro 24 ore), "Notifica Incidente (72h)", "Report Finale (1 mese)" — ogni step con scadenza, countdown ("N ore e M min rimanenti" / "Scaduto da..."), stato colorato (verde inviato, giallo in scadenza, rosso scaduto) e bottone di invio (con suffisso "(URGENTE)" se scaduto). Se non significativo: testo "Le notifiche NIS2 Art. 23 non sono richieste". Card "Timeline Eventi" con eventi cronologici (data/ora, descrizione, autore). Card laterale "Riepilogo" (Codice, Creato il, Aggiornato il, Chiuso il, n. Eventi Timeline) e card "Azioni Rapide" (solo se significativo) con i 3 bottoni di invio/stato notifiche.
|
||||
Azioni: "Torna alla lista"; "Aggiorna" → modale aggiornamento (U-INCIDENTS.5); "+ Aggiungi Evento" → modale evento (U-INCIDENTS.6); "Invia Early Warning (24h)" / "Invia Notifica (72h)" / "Invia Report Finale (1 mese)" → modali di conferma (U-INCIDENTS.7).
|
||||
Dati da: `GET /api/incidents/{id}` (include `timeline[]` e i campi scadenze/invii Art. 23).
|
||||
Confine: contenitore `#view-detail` (riga ~336); contenuto interno generato via JS senza id propri (bottone back con classe `.detail-back`, timeline con classi `.nis2-timeline` / `.event-timeline`).
|
||||
|
||||
• U-INCIDENTS.5 — Modale "Aggiorna Incidente" (generata via JS)
|
||||
Mostra: select Stato (Rilevato → Post Mortem), Causa Radice, Azioni di Rimedio, Lezioni Apprese; titolo modale con il codice incidente.
|
||||
Azioni: "Salva Aggiornamento" → aggiorna l'incidente e ricarica lista/dettaglio; "Annulla" → chiude.
|
||||
Dati da: precompilazione: `GET /api/incidents/{id}`; salvataggio: `PUT /api/incidents/{id}` (body `{status, root_cause, remediation_actions, lessons_learned}`).
|
||||
Confine: modale in `#modal-overlay`; campi JS: `#upd-status`, `#upd-root-cause`, `#upd-remediation`, `#upd-lessons` (script righe ~653-674).
|
||||
|
||||
• U-INCIDENTS.6 — Modale "Aggiungi Evento alla Timeline" (generata via JS)
|
||||
Mostra: select Tipo Evento (Rilevamento, Analisi, Contenimento, Eradicazione, Ripristino, Notifica, Azione, Aggiornamento, Altro) e Descrizione*.
|
||||
Azioni: "Aggiungi Evento" → inserisce l'evento e ricarica il dettaglio; "Annulla" → chiude.
|
||||
Dati da: `POST /api/incidents/{id}/timeline` (body `{event_type, description}`).
|
||||
Confine: modale in `#modal-overlay`; campi JS: `#event-type`, `#event-description` (script righe ~1140-1158).
|
||||
|
||||
• U-INCIDENTS.7 — Modali di conferma notifiche NIS2 Art. 23 (generate via JS)
|
||||
Mostra: 3 modali di conferma: "Conferma Early Warning" (registra l'invio dell'allerta iniziale 24h al CSIRT nazionale/ACN, con avviso di trasmettere la comunicazione anche sui canali ufficiali), "Conferma Notifica CSIRT" (notifica 72h con valutazione iniziale, gravità, impatto e indicatori di compromissione), "Conferma Report Finale" (report a 1 mese con descrizione dettagliata, causa radice, misure di mitigazione, impatto transfrontaliero).
|
||||
Azioni: "Conferma Invio" → registra a sistema l'invio della notifica e ricarica il dettaglio; "Annulla" → chiude.
|
||||
Dati da: `POST /api/incidents/{id}/early-warning`; `POST /api/incidents/{id}/notification`; `POST /api/incidents/{id}/final-report`.
|
||||
Confine: modali in `#modal-overlay`; trigger generati via JS nel dettaglio (funzioni `doSendEarlyWarning`/`doSendNotification`/`doSendFinalReport`, script righe ~1045-1136), senza id sui bottoni (vedi ID mancanti).
|
||||
|
||||
⟦ FINE · U-INCIDENTS ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Bottone "+ Nuovo Incidente" (header) | ~271 | `nis2-incidents-btn-nuovo` |
|
||||
| Bottone "Torna alla lista" nel dettaglio (classe `.detail-back`, generato via JS) | script ~765 | `nis2-incidents-btn-back` |
|
||||
| Bottoni "Invia Early Warning / Notifica / Report Finale" (Azioni Rapide e timeline, generati via JS) | script ~919-921 | `nis2-incidents-btn-early-warning`, `nis2-incidents-btn-notifica-72h`, `nis2-incidents-btn-report-finale` |
|
||||
@@ -0,0 +1,65 @@
|
||||
# MAPPA-LOGICA · Gestione Policy
|
||||
|
||||
⟦ INIZIO · U-POLICIES · Videata "Gestione Policy" ⟧
|
||||
File: public/policies.html · URL: /policies.html · Scopo: gestione del ciclo di vita delle policy di sicurezza NIS2 (creazione, modifica, approvazione, generazione AI, template) richieste dall'Art. 21 NIS2 · Profili: tutti gli utenti autenticati dell'organizzazione (voce sidebar "Policy" visibile a tutti i ruoli); le azioni di scrittura/approvazione sono soggette ai permessi backend (org_admin, compliance_manager, consultant)
|
||||
|
||||
• U-POLICIES.1 — Intestazione pagina e azioni globali
|
||||
Mostra: titolo "Gestione Policy"; due pulsanti in alto a destra: "Genera con AI" (icona scintille) e "+ Nuova Policy"
|
||||
Azioni: "Genera con AI" → apre la modale di generazione AI (U-POLICIES.7); "+ Nuova Policy" → apre la modale di creazione (U-POLICIES.5)
|
||||
Dati da: nessun endpoint (elementi statici)
|
||||
Confine: `header.content-header` dentro `main.main-content` (riga ~248-257); i due pulsanti NON hanno id stabile (vedi sezione finale)
|
||||
|
||||
• U-POLICIES.2 — Tab di navigazione (Elenco Policy / Template)
|
||||
Mostra: due tab: "Elenco Policy" (attivo di default) e "Template"
|
||||
Azioni: click su tab → `switchTab('list')` mostra `#tab-list`; `switchTab('templates')` mostra `#tab-templates` e carica i template; il cambio tab nasconde la vista dettaglio
|
||||
Dati da: nessun endpoint diretto (il tab Template innesca GET /api/policies/templates ad ogni click sul tab — `loadTemplates()` non usa cache)
|
||||
Confine: `div.tabs` dentro `#page-content` (riga ~261-264); i singoli bottoni tab NON hanno id stabile
|
||||
|
||||
• U-POLICIES.3 — Tab "Elenco Policy": filtri e tabella
|
||||
Mostra: barra filtri con 2 select: "Tutte le Categorie" (`#filter-category`: Sicurezza Informazioni, Controllo Accessi, Risposta Incidenti, Continuita' Operativa, Supply Chain, Crittografia, Sicurezza HR, Gestione Asset, Sicurezza Rete, Gestione Vulnerabilita') e "Tutti gli Stati" (`#filter-status`: Bozza, In Revisione, Approvata, Pubblicata, Archiviata). Tabella con colonne: Titolo (link), Categoria, Art. NIS2, Versione, Stato (badge colorato), Prossima Revisione, Azioni. Stato vuoto: "Nessuna policy trovata"
|
||||
Azioni: cambio filtro → ricarica lista; click sul titolo o icona occhio → vista dettaglio (U-POLICIES.4); icona matita → modale modifica; icona spunta verde (solo per stato Bozza/In Revisione) → modale conferma approvazione; icona cestino → modale conferma eliminazione
|
||||
Dati da: GET /api/policies/list?category=&status= (`api.listPolicies(params)`)
|
||||
Confine: `#tab-list` (riga ~267); filtri `#filter-category` (riga ~269) e `#filter-status` (riga ~282); tabella renderizzata in `#policies-table` (riga ~293)
|
||||
|
||||
• U-POLICIES.4 — Vista dettaglio policy
|
||||
Mostra: link "← Torna all'elenco"; titolo policy; badge stato + eventuale badge "AI Generata"; se policy AI in stato bozza/revisione: banner arancione "Bozza AI — Revisione obbligatoria prima dell'approvazione" (chiudibile, id dinamico `ai-draft-warning-{id}`); pulsanti "Approva" (solo bozza/revisione) e "Modifica"; card "Contenuto Policy" (testo completo); card laterale "Informazioni" con righe: Categoria, Art. NIS2, Versione, Stato, Creata il, Aggiornata il, Prossima Revisione, e se approvata: Approvata da / Approvata il
|
||||
Azioni: "Torna all'elenco" → `backToList()`; "Approva" → modale conferma → POST approve; "Modifica" → modale modifica
|
||||
Dati da: GET /api/policies/{id} (`api.getPolicy(id)`)
|
||||
Confine: `#policy-detail-view` (riga ~318, contenuto renderizzato via JS `renderPolicyDetail`, righe ~517-618)
|
||||
|
||||
• U-POLICIES.5 — Modale "Nuova Policy" / "Modifica Policy"
|
||||
Mostra: form `#policy-form` con campi: Titolo* (`#form-title`), Categoria* (`#form-category`, select 10 categorie), Articolo NIS2 (`#form-nis2-article`, es. "21.2.a"), Versione (`#form-version`, default 1.0), Prossima Revisione (`#form-review-date`, date), Contenuto (`#form-content`, textarea 12 righe con suggerimento struttura: Scopo, Ambito, Responsabilita', Procedure, Revisione)
|
||||
Azioni: "Annulla" → chiude; "Crea Policy"/"Salva Modifiche" → `savePolicy(id)` con validazione titolo+categoria obbligatori
|
||||
Dati da: POST /api/policies/create (`api.createPolicy`) per creazione; PUT /api/policies/{id} (`api.updatePolicy`) per modifica; in modifica precaricamento via GET /api/policies/{id}
|
||||
Confine: modale generata da `showModal()` in `#modal-overlay` (id stabile creato da common.js); form `#policy-form` (riga ~654)
|
||||
|
||||
• U-POLICIES.6 — Modali di conferma (Approvazione / Eliminazione)
|
||||
Mostra: "Conferma Approvazione": testo "Sei sicuro di voler approvare questa policy?" + avviso che lo stato diventa "Approvata" e l'operazione non e' annullabile. "Conferma Eliminazione": testo con titolo policy + avviso "Questa azione e' irreversibile"
|
||||
Azioni: Approva → POST /api/policies/{id}/approve (`api.approvePolicy`); Elimina → DELETE /api/policies/{id} (`api.del`)
|
||||
Dati da: POST /api/policies/{id}/approve · DELETE /api/policies/{id}
|
||||
Confine: `#modal-overlay` (modale dinamica, funzioni `approvePolicy()` riga ~748 e `confirmDeletePolicy()` riga ~780); i pulsanti interni NON hanno id stabile
|
||||
|
||||
• U-POLICIES.7 — Modale "Genera Policy con AI"
|
||||
Mostra: testo esplicativo; select "Categoria Policy" (`#ai-category`, 10 categorie); pulsante "Genera" (`#ai-generate-btn`); dopo generazione: anteprima con header "Policy Generata: {titolo}" e contenuto in `#ai-preview-container`; il footer cambia in "Salva come Bozza"
|
||||
Azioni: "Genera" → `doAIGenerate()` (spinner durante la chiamata); "Salva come Bozza" → `saveAIGeneratedPolicy()` crea la policy con flag `ai_generated: 1`
|
||||
Dati da: POST /api/policies/ai-generate (`api.aiGeneratePolicy(category)`); salvataggio via POST /api/policies/create
|
||||
Confine: `#modal-overlay`; select `#ai-category` (riga ~824), contenitore anteprima `#ai-preview-container` (riga ~828), pulsante `#ai-generate-btn` (riga ~832)
|
||||
|
||||
• U-POLICIES.8 — Tab "Template": griglia template NIS2
|
||||
Mostra: card "Template Policy NIS2" con griglia di card cliccabili; ogni card: titolo template, tag categoria, eventuale riferimento "Art. {nis2_article}". Stato vuoto: "Nessun template disponibile"
|
||||
Azioni: click su una card → `createFromTemplate()` apre la modale Nuova Policy precompilata con titolo, categoria e articolo NIS2 del template (contenuto vuoto)
|
||||
Dati da: GET /api/policies/templates (`api.getPolicyTemplates()`)
|
||||
Confine: `#tab-templates` (riga ~303); griglia renderizzata in `#templates-grid` (riga ~308); le singole card template NON hanno id stabile
|
||||
|
||||
⟦ FINE · U-POLICIES ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Pulsante "Genera con AI" (header) | 251 | `nis2-policies-btn-ai-generate` |
|
||||
| Pulsante "+ Nuova Policy" (header) | 255 | `nis2-policies-btn-new` |
|
||||
| Contenitore tab bar `div.tabs` | 261 | `nis2-policies-tabs` |
|
||||
| Bottone tab "Elenco Policy" | 262 | `nis2-policies-tab-btn-list` |
|
||||
| Bottone tab "Template" | 263 | `nis2-policies-tab-btn-templates` |
|
||||
| Pulsante "Approva" nella vista dettaglio (HTML dinamico) | 551 | `nis2-policies-detail-btn-approve` |
|
||||
| Pulsante "Modifica" nella vista dettaglio (HTML dinamico) | 555 | `nis2-policies-detail-btn-edit` |
|
||||
@@ -0,0 +1,82 @@
|
||||
# MAPPA-LOGICA · Sicurezza Supply Chain
|
||||
|
||||
⟦ INIZIO · U-SUPPLYCHAIN · Videata "Sicurezza Supply Chain" ⟧
|
||||
File: public/supply-chain.html · URL: /supply-chain.html · Scopo: anagrafica e valutazione di sicurezza dei fornitori (Art. 21.2.d NIS2 — sicurezza della catena di approvvigionamento): KPI di rischio, valutazione interna a punteggio, invio questionario self-assessment al fornitore, import CSV, gestione categorie e template questionari · Profili: tutti gli utenti autenticati dell'organizzazione (voce sidebar "Supply Chain"); azioni di scrittura soggette ai permessi backend (org_admin, compliance_manager, consultant)
|
||||
|
||||
• U-SUPPLYCHAIN.1 — Intestazione pagina e azioni globali
|
||||
Mostra: titolo "Sicurezza Supply Chain"; 4 pulsanti: "Categorie", "Template", "Importa", "+ Nuovo Fornitore"
|
||||
Azioni: "Categorie" → modale gestione categorie (U-SUPPLYCHAIN.9); "Template" → modale template questionari read-only (U-SUPPLYCHAIN.10); "Importa" → modale import CSV (U-SUPPLYCHAIN.8); "+ Nuovo Fornitore" → modale creazione (U-SUPPLYCHAIN.5)
|
||||
Dati da: nessun endpoint (statici); "Categorie"/"+ Nuovo Fornitore" precaricano GET /api/supply-chain/categories
|
||||
Confine: `header.content-header` (righe ~374-382); i 4 pulsanti NON hanno id stabile
|
||||
|
||||
• U-SUPPLYCHAIN.2 — KPI Risk Overview (4 card)
|
||||
Mostra: 4 card numeriche: "Totale Fornitori" (`#stat-total`), "Critici Non Conformi" (`#stat-critical`, rosso: fornitori con criticita' critical/high e requisiti sicurezza non soddisfatti), "Contratti in Scadenza" (`#stat-expiring`, giallo: contratti attivi che scadono entro 90 giorni), "Score Rischio Medio" (`#stat-avg-score`, verde, formato N/100)
|
||||
Azioni: nessuna (sola lettura, calcolo client-side in `updateRiskOverview()`)
|
||||
Dati da: GET /api/supply-chain/list (`api.listSuppliers()`) — i KPI sono calcolati lato client sull'elenco completo
|
||||
Confine: `#risk-overview` (riga ~386); valori `#stat-total` (~388), `#stat-critical` (~392), `#stat-expiring` (~396), `#stat-avg-score` (~400)
|
||||
|
||||
• U-SUPPLYCHAIN.3 — Grafico "Distribuzione Criticita'"
|
||||
Mostra: card con istogramma a 4 barre: Critico (rosso), Alto (arancione), Medio (giallo), Basso (verde), con conteggio sopra ogni barra
|
||||
Azioni: nessuna (sola lettura, `updateCriticalityChart()`)
|
||||
Dati da: GET /api/supply-chain/list (stesso payload della lista, aggregato client-side)
|
||||
Confine: `#criticality-chart` (riga ~411); barre `#chart-bar-critical|high|medium|low` e valori `#chart-val-critical|high|medium|low` (righe ~413-426)
|
||||
|
||||
• U-SUPPLYCHAIN.4 — Filtri ed elenco fornitori
|
||||
Mostra: 2 select filtro: "Tutte le Criticita'" (`#filter-criticality`: Critico, Alto, Medio, Basso) e "Tutti gli Stati" (`#filter-status`: Attivo, In Revisione, Sospeso, Terminato). Tabella con colonne: Nome (link), Tipo Servizio, Criticita' (badge), Score Rischio (barra + valore colorato 0-100), Stato (badge), Ultima Valutazione, Azioni (occhio=visualizza, matita=modifica, checklist blu=valutazione interna, busta=invia questionario al fornitore). Stato vuoto: "Nessun fornitore trovato"
|
||||
Azioni: filtri → `applyFilters()` (filtro client-side, nessuna nuova chiamata); click nome/occhio → dettaglio (U-SUPPLYCHAIN.6); matita → modale modifica; checklist → modale valutazione (U-SUPPLYCHAIN.7); busta → invio questionario (U-SUPPLYCHAIN.11)
|
||||
Dati da: GET /api/supply-chain/list (`api.listSuppliers()`)
|
||||
Confine: `#suppliers-list-section` (riga ~433); filtri `#filter-criticality` (~435) e `#filter-status` (~442); tabella renderizzata in `#suppliers-table` (~452)
|
||||
|
||||
• U-SUPPLYCHAIN.5 — Modale "Nuovo Fornitore" / "Modifica Fornitore"
|
||||
Mostra: form `#supplier-form` con campi: Nome Fornitore* (`#form-name`), Partita IVA (`#form-vat`), Referente (`#form-contact-name`), Email Contatto (`#form-contact-email`), Tipo Servizio* (`#form-service-type`), Criticita' (`#form-criticality`: Basso/Medio/Alto/Critico), Categoria fornitore (`#form-category`, select con categorie preset + personalizzate), Descrizione Servizio (`#form-service-desc`), Inizio Contratto (`#form-contract-start`), Scadenza Contratto (`#form-contract-expiry`), Note (`#form-notes`)
|
||||
Azioni: "Annulla" → chiude; "Aggiungi Fornitore"/"Salva Modifiche" → `saveSupplier(id)` (validazione: nome e tipo servizio obbligatori)
|
||||
Dati da: POST /api/supply-chain/create (`api.createSupplier`) · PUT /api/supply-chain/{id} (`api.updateSupplier`) · categorie da GET /api/supply-chain/categories (`api.getSupplierCategories`) · in modifica precarico via GET /api/supply-chain/{id}
|
||||
Confine: `#modal-overlay` (modale common.js); form `#supplier-form` (riga ~934)
|
||||
|
||||
• U-SUPPLYCHAIN.6 — Vista dettaglio fornitore
|
||||
Mostra: link "← Torna all'elenco"; nome fornitore; badge criticita', stato e Conforme/Non Conforme; pulsanti "Valuta Fornitore", "Invia questionario", "Modifica"; card "Informazioni Fornitore" (Nome, Partita IVA, Referente, Email mailto, Tipo Servizio, Criticita', Inizio/Scadenza Contratto); card opzionali "Descrizione Servizio" e "Note"; gauge circolare "Score Rischio" su 100 con testo "Requisiti di sicurezza soddisfatti" (score ≥70) / "non soddisfatti" / "Nessuna valutazione effettuata"; card "Valutazione" (Ultima Valutazione, Prossima Valutazione, Requisiti Sicurezza Soddisfatti/Non Soddisfatti, Creato il)
|
||||
Azioni: "Valuta Fornitore" → U-SUPPLYCHAIN.7; "Invia questionario" → U-SUPPLYCHAIN.11; "Modifica" → U-SUPPLYCHAIN.5; "Torna all'elenco" → `backToList()`
|
||||
Dati da: GET /api/supply-chain/{id} (`api.getSupplier(id)`)
|
||||
Confine: `#supplier-detail-view` (riga ~462, contenuto renderizzato via `renderSupplierDetail()`, righe ~720-880)
|
||||
|
||||
• U-SUPPLYCHAIN.7 — Modale "Valutazione Fornitore" (assessment interno a 10 domande)
|
||||
Mostra: 10 domande pesate con opzioni Si'/Parziale/No (pill cliccabili): certificazioni ISO 27001/SOC2 (peso 2), SLA sicurezza (1.5), piano incident response (2), crittografia dati in transito e a riposo (2), audit periodici (1.5), controlli di accesso (1), backup e disaster recovery (1.5), conformita' GDPR (1), formazione sicurezza del personale (1), gestione vulnerabilita' (1.5); box "Score Rischio Calcolato" aggiornato live (`#assessment-live-score`, Si'=100, Parziale=50, No=0, media pesata)
|
||||
Azioni: click opzione → `selectAnswer()` + ricalcolo live; "Salva Valutazione" → `submitAssessment(supplierId)` (richiede almeno una risposta); aggiorna score, last_assessment_date e conformita' del fornitore
|
||||
Dati da: POST /api/supply-chain/{id}/assess (`api.assessSupplier(id, {assessment_responses})`)
|
||||
Confine: `#modal-overlay`; domande in `#assessment-questions` (riga ~1079), preview score `#assessment-score-preview` (~1082) e valore `#assessment-live-score` (~1084)
|
||||
|
||||
• U-SUPPLYCHAIN.8 — Modale "Importa fornitori" (CSV)
|
||||
Mostra: istruzioni colonne CSV (name obbligatoria; vat_number, contact_email, contact_name, service_type, criticality, category_slug, external_ref — upsert per external_ref); input file `#importFile`; textarea incolla CSV `#importCsv`; area risultato `#importResult` (creati/aggiornati/saltati + dettagli righe scartate); pulsante `#importRunBtn` "Importa"
|
||||
Azioni: scelta file → contenuto copiato nella textarea; "Importa" → `runSupplierImport()` (max 1000 righe, separatori virgola o punto e virgola); a fine import ricarica la lista
|
||||
Dati da: POST /api/supply-chain/import (`api.importSuppliers(rows)`)
|
||||
Confine: overlay dedicato `#importModalDyn` (creato dinamicamente da `openImportModal()`, righe ~1206-1243); elementi `#importFile` (~1225), `#importCsv` (~1226), `#importResult` (~1228), `#importRunBtn` (~1232)
|
||||
|
||||
• U-SUPPLYCHAIN.9 — Modale "Categorie fornitore"
|
||||
Mostra: elenco categorie in `#categories-list-body` con badge "Preset" (di sistema, non modificabili) o "Personalizzata" (con pulsanti Modifica/Elimina); pulsante "+ Nuova categoria"; sotto-form con Nome categoria* (`#cat-name`) e Descrizione (`#cat-desc`)
|
||||
Azioni: "+ Nuova categoria"/"Modifica" → form categoria → `saveCategory(id)`; "Elimina" → conferma browser → `removeCategory(id)` (fallisce se categoria in uso)
|
||||
Dati da: GET /api/supply-chain/categories · POST /api/supply-chain/categories (`api.createSupplierCategory`) · PUT /api/supply-chain/categories/{id} (`api.updateSupplierCategory`) · DELETE /api/supply-chain/categories/{id} (`api.deleteSupplierCategory`)
|
||||
Confine: `#modal-overlay`; lista `#categories-list-body` (riga ~1343); form `#cat-name` (~1359), `#cat-desc` (~1363)
|
||||
|
||||
• U-SUPPLYCHAIN.10 — Modale "Template questionari" (sola lettura)
|
||||
Mostra: elenco template questionari dell'organizzazione: nome, badge Default/Attivo, categoria, numero domande, versione; dettaglio template con elenco domande numerate e badge: riferimento normativo (nis2_ref), tipo domanda (Si/Parziale/No, Scelta singola/multipla, Scala 1-5, Testo, Numero, Allegato), Peso, Obbligatoria, "Solo alta criticita"; avviso "Sola lettura. L'editor delle domande sara' disponibile in una prossima versione"
|
||||
Azioni: "Vedi domande" → dettaglio template; "← Torna ai template" → elenco; "Chiudi" → chiude
|
||||
Dati da: GET /api/supply-chain/templates (`api.getQuestionnaireTemplates()`) · GET /api/supply-chain/templates/{id} (`api.getQuestionnaireTemplate(id)`)
|
||||
Confine: `#modal-overlay` (contenuto renderizzato in `#modal-overlay .modal-body`, funzioni `openTemplatesModal`/`renderTemplatesModal`/`renderTemplateDetail`, righe ~1414-1485); nessun id proprio sugli elementi interni
|
||||
|
||||
• U-SUPPLYCHAIN.11 — Invio questionario self-assessment al fornitore
|
||||
Mostra: prompt browser nativo "Invia il questionario di sicurezza a {fornitore}. Email del fornitore (lascia vuoto per usare il contatto in anagrafica)"; dopo l'invio, notifica di successo e secondo prompt con il link del questionario (valido 30 giorni, inoltrabile manualmente)
|
||||
Azioni: il pulsante invoca `sendSupplierQuestionnaire(id, nome)` che apre il prompt email; conferma → chiamata API e secondo prompt con il link; annulla → nessuna azione
|
||||
Dati da: POST /api/supply-chain/{id}/send-questionnaire (`api.sendSupplierQuestionnaire(id, email)`)
|
||||
Confine: nessun elemento DOM proprio (usa `window.prompt`; funzione righe ~1183-1203); attivabile dal pulsante busta in tabella (~684) e dal pulsante "Invia questionario" nel dettaglio (~757)
|
||||
|
||||
⟦ FINE · U-SUPPLYCHAIN ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Pulsante "Categorie" (header) | 377 | `nis2-supply-chain-btn-categories` |
|
||||
| Pulsante "Template" (header) | 378 | `nis2-supply-chain-btn-templates` |
|
||||
| Pulsante "Importa" (header) | 379 | `nis2-supply-chain-btn-import` |
|
||||
| Pulsante "+ Nuovo Fornitore" (header) | 380 | `nis2-supply-chain-btn-new` |
|
||||
| Card grafico "Distribuzione Criticita'" (`div.card.mb-24`, usata anche da viewSupplier/backToList via selettore di classe) | 406 | `nis2-supply-chain-chart-card` |
|
||||
| Pulsanti dettaglio "Valuta Fornitore" / "Invia questionario" / "Modifica" (HTML dinamico) | 753-764 | `nis2-supply-chain-detail-btn-assess` / `-send-questionnaire` / `-edit` |
|
||||
@@ -0,0 +1,63 @@
|
||||
# MAPPA-LOGICA · Inventario Asset
|
||||
|
||||
⟦ INIZIO · U-ASSETS · Videata "Inventario Asset" ⟧
|
||||
File: public/assets.html · URL: /assets.html · Scopo: inventario degli asset aziendali (Art. 21.2.i NIS2) con scoring di rilevanza NIS2 a 6 criteri (requisito GV.OC-04 del Framework Nazionale) e import da CSV/CMDB · Profili: tutti gli utenti autenticati dell'organizzazione (voce sidebar "Asset"); azioni di scrittura soggette ai permessi backend (org_admin, compliance_manager, consultant)
|
||||
|
||||
• U-ASSETS.1 — Intestazione pagina e azioni globali
|
||||
Mostra: titolo "Inventario Asset"; etichetta "Art. 21.2.i NIS2"; pulsanti "Importa" (import da CSV/CMDB) e "+ Nuovo Asset"
|
||||
Azioni: "Importa" → modale import CSV (U-ASSETS.7); "+ Nuovo Asset" → modale creazione (U-ASSETS.5)
|
||||
Dati da: nessun endpoint (elementi statici)
|
||||
Confine: `header.content-header` (righe ~267-274); i pulsanti NON hanno id stabile
|
||||
|
||||
• U-ASSETS.2 — Card statistiche (4 KPI)
|
||||
Mostra: "Totale Asset" (`#stat-total`); "Tipologie" (`#stat-types`, numero di tipi distinti) con chip per tipo in `#stat-type-chips` (es. "3 Hardware"); "Asset Critici" (`#stat-critical`, criticita' = critical); "Dismessi" (`#stat-decommissioned`, stato = decommissioned). Nota: i conteggi riflettono il risultato filtrato corrente
|
||||
Azioni: nessuna (sola lettura, calcolo client-side in `updateStats()`)
|
||||
Dati da: GET /api/assets/list?asset_type=&criticality=&status= (`api.listAssets(params)`)
|
||||
Confine: `#asset-stats` (riga ~278); valori `#stat-total` (~284), `#stat-types` (~293), `#stat-type-chips` (~295), `#stat-critical` (~303), `#stat-decommissioned` (~312)
|
||||
|
||||
• U-ASSETS.3 — Barra filtri
|
||||
Mostra: 3 select: "Tutti i tipi" (`#filter-type`: Hardware, Software, Rete, Dati, Servizio, Personale, Struttura), "Tutte le criticita'" (`#filter-criticality`: Critica, Alta, Media, Bassa), "Tutti gli stati" (`#filter-status`: Attivo, Manutenzione, Dismesso)
|
||||
Azioni: cambio filtro → `applyFilters()` → ricarica dal server con i parametri selezionati
|
||||
Dati da: GET /api/assets/list (i filtri sono passati come query string: asset_type, criticality, status)
|
||||
Confine: `div.filters-bar` (righe ~319-343); select `#filter-type` (~320), `#filter-criticality` (~330), `#filter-status` (~337)
|
||||
|
||||
• U-ASSETS.4 — Tabella asset
|
||||
Mostra: colonne: Nome, Tipo, Categoria, Criticita' (badge colorato), Rilevanza NIS2 (punteggio 0-100 + classe Critico/Alto/Medio/Basso/Trascurabile + spunta ✓ se rilevante; "Da valutare" se mai valutato), Owner, Stato (badge), Azioni (grafico=valuta rilevanza, matita=modifica). Stato vuoto: "Nessun asset trovato"
|
||||
Azioni: click sulla riga → modale dettaglio (U-ASSETS.6); icona grafico → modale scoring rilevanza (U-ASSETS.8); icona matita → modale modifica
|
||||
Dati da: GET /api/assets/list (`api.listAssets(params)`)
|
||||
Confine: `#assets-container` (riga ~346, tabella renderizzata via `renderAssets()`)
|
||||
|
||||
• U-ASSETS.5 — Modale "Nuovo Asset" / "Modifica Asset"
|
||||
Mostra: campi: Nome* (`#asset-name`), Tipo* (`#asset-type`), Categoria (`#asset-category`, testo libero es. "Server, Database..."), Descrizione (`#asset-description`), Criticita' (`#asset-criticality`), Stato (`#asset-status`), Owner ID utente (`#asset-owner`), Posizione (`#asset-location`, es. "Data Center Roma"), Indirizzo IP (`#asset-ip`), Fornitore (`#asset-vendor`), Versione (`#asset-version`), Numero Seriale (`#asset-serial`), Data Acquisto (`#asset-purchase-date`), Scadenza Garanzia (`#asset-warranty`)
|
||||
Azioni: "Annulla" → chiude; "Salva" → `saveAsset()` (validazione: nome obbligatorio) → callback create o update
|
||||
Dati da: POST /api/assets/create (`api.createAsset`) · PUT /api/assets/{id} (`api.updateAsset`) · in modifica precarico via GET /api/assets/{id} (`api.getAsset`)
|
||||
Confine: `#modal-overlay` (modale common.js); campi `#asset-*` (righe ~781-845 in `showAssetModal()`)
|
||||
|
||||
• U-ASSETS.6 — Modale dettaglio asset
|
||||
Mostra: griglia campi in sola lettura: Tipo, Categoria, Criticita' (badge), Stato (badge), Owner, Posizione, Indirizzo IP, Fornitore, Versione, Numero Seriale, Data Acquisto, Scadenza Garanzia; sezione "Descrizione" (se presente); sezione "Dipendenze" con tag "ID: n" o "Nessuna dipendenza"
|
||||
Azioni: "Chiudi"; "Valuta Rilevanza NIS2" → chiude e apre modale scoring (U-ASSETS.8); "Modifica" → chiude e apre modale modifica (U-ASSETS.5)
|
||||
Dati da: GET /api/assets/{id} (`api.getAsset(id)`)
|
||||
Confine: `#modal-overlay` (contenuto generato da `showAssetDetail()`, righe ~620-711); i campi interni NON hanno id stabile
|
||||
|
||||
• U-ASSETS.7 — Modale "Importa Asset" (CSV/CMDB)
|
||||
Mostra: istruzioni colonne riconosciute: name, asset_type, criticality, data_classification, internet_facing, dependencies_count, regulated, external_ref, vendor, location; nota "Lo scoring di rilevanza NIS2 (GV.OC-04) viene calcolato automaticamente"; input file `#imp-file`; textarea CSV `#imp-csv` (prima riga = intestazioni, con esempio precompilato come placeholder); area anteprima `#imp-preview`
|
||||
Azioni: scelta file → contenuto copiato nella textarea (`impFile()`); "Importa" → `doImport()` → notifica con esito "N nuovi, N aggiornati, N rilevanti NIS2, N scartati" e ricarica della lista
|
||||
Dati da: POST /api/assets/import (`api.importAssets({source:'csv', assets})`)
|
||||
Confine: `#modal-overlay`; elementi `#imp-file` (riga ~894), `#imp-csv` (~896), `#imp-preview` (~899)
|
||||
|
||||
• U-ASSETS.8 — Modale "Valuta Rilevanza NIS2" (scoring GV.OC-04)
|
||||
Mostra: intestazione con metodologia e soglia di rilevanza (≥ punti soglia restituita dal server); 6 criteri come select (`select.score-criterion`, una per criterio, con etichetta, help e punteggio per opzione, griglia caricata dal server); box riepilogo `#score-preview` con "Totale: N/100" (`#score-total`) e classe calcolata (`#score-class`: Critico ≥80, Alto ≥60, Medio ≥40, Basso ≥20, Trascurabile <20; "Rilevante NIS2 ✓" da 40 in su); nota: il punteggio aggiorna automaticamente anche la criticita' dell'asset
|
||||
Azioni: cambio select → `updateScorePreview()` ricalcola live; "Calcola e Salva" → `submitScoring(id)` (richiede tutti i 6 criteri compilati) → notifica con score e classe, ricarica lista
|
||||
Dati da: GET /api/assets/scoringGrid (`api.getScoringGrid()`, griglia criteri/punteggi/soglia) · POST /api/assets/{id}/score (`api.scoreAsset(id, criteria)`) · precarico asset via GET /api/assets/{id}
|
||||
Confine: `#modal-overlay`; select con classe `score-criterion` e attributo stabile `data-key="<criterio>"` (riga ~566); riepilogo `#score-preview` (~569), `#score-total` e `#score-class` (~570)
|
||||
|
||||
⟦ FINE · U-ASSETS ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Pulsante "Importa" (header) | 271 | `nis2-assets-btn-import` |
|
||||
| Pulsante "+ Nuovo Asset" (header) | 272 | `nis2-assets-btn-new` |
|
||||
| Barra filtri `div.filters-bar` | 319 | `nis2-assets-filters` |
|
||||
| Pulsanti azione riga tabella (valuta/modifica, HTML dinamico `.btn-icon`) | 505-509 | `nis2-assets-row-btn-score-{id}` / `nis2-assets-row-btn-edit-{id}` |
|
||||
| Pulsanti footer modale dettaglio (Chiudi/Valuta/Modifica) | 703-705 | `nis2-assets-detail-btn-close` / `-score` / `-edit` |
|
||||
@@ -0,0 +1,52 @@
|
||||
# MAPPA-LOGICA · Formazione e Awareness
|
||||
|
||||
⟦ INIZIO · U-TRAINING · Videata "Formazione e Awareness" ⟧
|
||||
File: public/training.html · URL: /training.html · Scopo: gestione della formazione in cybersicurezza richiesta dall'Art. 20 NIS2 (obbligo formativo per organi di gestione e dipendenti): catalogo corsi, assegnazioni personali, monitoraggio della compliance formativa per membro · Profili: tutti gli utenti autenticati dell'organizzazione (voce sidebar "Formazione"); il tab "Le Mie Assegnazioni" mostra i corsi dell'utente corrente; creazione corsi e assegnazioni soggette ai permessi backend (org_admin, compliance_manager, consultant)
|
||||
|
||||
• U-TRAINING.1 — Intestazione pagina e azioni globali
|
||||
Mostra: titolo "Formazione e Awareness"; etichetta "Art. 20 NIS2"; pulsante "+ Nuovo Corso"
|
||||
Azioni: "+ Nuovo Corso" → modale creazione corso (U-TRAINING.3)
|
||||
Dati da: nessun endpoint (elementi statici)
|
||||
Confine: `header.content-header` (righe ~230-236); il pulsante NON ha id stabile
|
||||
|
||||
• U-TRAINING.2 — Tab di navigazione (3 tab)
|
||||
Mostra: tab "Corsi" (attivo di default), "Le Mie Assegnazioni", "Compliance Formativa"
|
||||
Azioni: click → `switchTab(tabId, btn)` attiva il pannello corrispondente (`#tab-courses`, `#tab-assignments`, `#tab-compliance`) e carica i dati del tab
|
||||
Dati da: nessun endpoint diretto (ogni tab innesca il proprio caricamento)
|
||||
Confine: `div.tab-nav` (righe ~240-244); i bottoni tab NON hanno id stabile
|
||||
|
||||
• U-TRAINING.3 — Tab "Corsi": catalogo corsi + modale "Nuovo Corso di Formazione"
|
||||
Mostra: griglia di card corso: titolo, badge "Obbligatorio" (se is_mandatory), descrizione, durata in minuti, ruolo destinatario (Tutti, Organi di Gestione, Compliance Manager, Dipendente, Tecnico), riferimento "Art. {nis2_article}", "Soglia: N%" (punteggio minimo quiz). Stato vuoto: "Nessun corso disponibile". Modale creazione con campi: Titolo* (`#course-title`), Descrizione (`#course-description`), Ruolo Destinatario (`#course-target-role`), Durata minuti (`#course-duration`), Articolo NIS2 (`#course-nis2-article`, es. "Art. 20"), Punteggio Minimo % (`#course-passing-score`, default 70), checkbox "Corso obbligatorio" (`#course-mandatory`)
|
||||
Azioni: le card corso sono informative (nessun click); "Crea Corso" nella modale → `createCourse()` (titolo obbligatorio) → POST e ricarica catalogo
|
||||
Dati da: GET /api/training/courses (`api.listCourses()`) · POST /api/training/courses (`api.post('/training/courses', data)`)
|
||||
Confine: pannello `#tab-courses` (riga ~247), griglia `#courses-grid` (~248); campi modale `#course-*` (righe ~415-443) dentro `#modal-overlay`
|
||||
|
||||
• U-TRAINING.4 — Tab "Le Mie Assegnazioni"
|
||||
Mostra: tabella delle assegnazioni dell'utente corrente: Corso (titolo + etichetta rossa "Obbligatorio" se applicabile), Stato (badge: Assegnato, In Corso, Completato, Scaduto — "Scaduto" calcolato client-side se due_date passata e non completato), Scadenza, Punteggio Quiz (%), Azioni. Stato vuoto: "Nessuna assegnazione"
|
||||
Azioni: "Inizia" (stato Assegnato/Scaduto) → `updateAssignment(id, 'in_progress')`; "Completa" (stato In Corso) → `updateAssignment(id, 'completed')`; corsi completati mostrano l'etichetta "Completato"
|
||||
Dati da: GET /api/training/assignments (`api.getMyTraining()`) · PUT /api/training/assignments/{id} (`api.put`, body `{status}`)
|
||||
Confine: pannello `#tab-assignments` (riga ~257), contenuto in `#assignments-container` (~258)
|
||||
|
||||
• U-TRAINING.5 — Tab "Compliance Formativa"
|
||||
Mostra: pulsante "Assegna Corso" in alto a destra; tabella dei membri dell'organizzazione: Nome, Email, Ruolo, Corsi Completati (completati/totali), "% Compliance Obbligatoria" con barra colorata (verde ≥80%, giallo ≥50%, rosso <50%). Stato vuoto: "Nessun membro trovato"
|
||||
Azioni: "Assegna Corso" → modale assegnazione (U-TRAINING.6)
|
||||
Dati da: GET /api/training/compliance-status (`api.getTrainingCompliance()`)
|
||||
Confine: pannello `#tab-compliance` (riga ~267), contenuto in `#compliance-container` (~271); il pulsante "Assegna Corso" NON ha id stabile
|
||||
|
||||
• U-TRAINING.6 — Modale "Assegna Corso"
|
||||
Mostra: select "Corso" (`#assign-course-id`, popolata dal catalogo); campo "Scadenza" (`#assign-due-date`, date); elenco "Seleziona Utenti" con checkbox per membro (`input.assign-user-cb`, nome + ruolo), popolato dai dati del tab Compliance
|
||||
Azioni: "Assegna" → `doAssignCourse()` (richiede almeno un utente selezionato) → POST e ricarica compliance; se non esistono corsi, avviso "Nessun corso disponibile. Crea prima un corso."
|
||||
Dati da: POST /api/training/assign (`api.post('/training/assign', {course_id, user_ids, due_date})`) · catalogo corsi da GET /api/training/courses se non gia' caricato
|
||||
Confine: `#modal-overlay`; select `#assign-course-id` (riga ~687), data `#assign-due-date` (~691), checkbox con classe stabile `assign-user-cb` (~677)
|
||||
|
||||
⟦ FINE · U-TRAINING ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Pulsante "+ Nuovo Corso" (header) | 234 | `nis2-training-btn-new-course` |
|
||||
| Contenitore tab bar `div.tab-nav` | 240 | `nis2-training-tabs` |
|
||||
| Bottone tab "Corsi" | 241 | `nis2-training-tab-btn-courses` |
|
||||
| Bottone tab "Le Mie Assegnazioni" | 242 | `nis2-training-tab-btn-assignments` |
|
||||
| Bottone tab "Compliance Formativa" | 243 | `nis2-training-tab-btn-compliance` |
|
||||
| Pulsante "Assegna Corso" (tab compliance) | 269 | `nis2-training-btn-assign-course` |
|
||||
@@ -0,0 +1,62 @@
|
||||
# MAPPA-LOGICA · Audit & Report
|
||||
|
||||
⟦ INIZIO · U-REPORTS · Videata "Audit & Report" ⟧
|
||||
File: public/reports.html · URL: /reports.html · Scopo: reportistica di compliance NIS2: report esecutivo stampabile, gestione dei controlli di compliance (framework NIS2/ISO 27001), audit log immutabile, mapping NIS2↔ISO 27001:2022, monitoraggio continuo dei controlli (evidence automation) e requisiti operativi ACN (Determina 164179/2025) · Profili: tutti gli utenti autenticati dell'organizzazione (voce sidebar "Audit & Report"); aggiornamento controlli/requisiti soggetto ai permessi backend (org_admin, compliance_manager, auditor in lettura)
|
||||
|
||||
• U-REPORTS.1 — Intestazione pagina e tab di navigazione (6 tab)
|
||||
Mostra: titolo "Audit & Report"; pulsante "Genera Report"; 6 tab: "Report Compliance" (attivo di default), "Controlli", "Audit Log", "ISO 27001", "Monitoraggio Continuo", "Requisiti ACN"
|
||||
Azioni: "Genera Report" → `generateReport()` (attiva il tab Report e genera); click tab → `switchTab()` attiva il pannello e carica i dati corrispondenti
|
||||
Dati da: nessun endpoint diretto (ogni tab innesca il proprio caricamento)
|
||||
Confine: `header.content-header` (righe ~352-357) e `div.tab-nav` (righe ~361-368); pulsante e bottoni tab NON hanno id stabile
|
||||
|
||||
• U-REPORTS.2 — Tab "Report Compliance" (report esecutivo)
|
||||
Mostra: stato iniziale: "Nessun report generato — Clicca 'Genera Report'". Dopo la generazione: intestazione "Report di Compliance NIS2" con nome organizzazione e data/ora; sezione "Informazioni Organizzazione" (Nome, Settore, Tipo Entita', Paese); sezione "Riepilogo Compliance" con barra percentuale colorata (verde ≥80%, giallo ≥50%, rosso <50%) e 5 KPI: Controlli Totali, Implementati, Rischi Aperti, Incidenti, Policy Approvate; sezione "Stato Controlli" (tabella Codice, Titolo, Stato, Implementazione — barra colorata con %); pulsante "Stampa Report"
|
||||
Azioni: "Genera Report" (header) → GET report e render; "Stampa Report" → `window.print()` (CSS @media print nasconde sidebar/header/tab)
|
||||
Dati da: GET /api/audit/report (`api.generateComplianceReport()`)
|
||||
Confine: pannello `#tab-report` (riga ~371), contenuto in `#report-container` (~372)
|
||||
|
||||
• U-REPORTS.3 — Tab "Controlli" (compliance controls)
|
||||
Mostra: tabella controlli: Codice (monospace), Framework (NIS2/ISO27001), Titolo, Stato (badge: Non Iniziato, In Corso, Implementato, Verificato), % Implementazione (barra colorata), Responsabile, Prossima Verifica. Righe cliccabili. Stato vuoto: "Nessun controllo configurato — appariranno dopo il primo assessment"
|
||||
Azioni: click riga → modale "Modifica Controllo: {codice}" con: Titolo (sola lettura), Stato (`#ctrl-status`), % Implementazione (slider `#ctrl-impl-pct` con valore live in `#ctrl-impl-pct-val`), Descrizione Evidenza (`#ctrl-evidence`), Responsabile ID utente (`#ctrl-responsible`), Prossima Verifica (`#ctrl-next-review`); "Salva" → `saveControl(id)` e ricarica
|
||||
Dati da: GET /api/audit/controls (`api.listControls()`) · PUT /api/audit/controls/{id} (`api.updateControl(id, data)`)
|
||||
Confine: pannello `#tab-controls` (riga ~382), contenuto in `#controls-container` (~383); campi modale `#ctrl-*` (righe ~827-846) dentro `#modal-overlay`
|
||||
|
||||
• U-REPORTS.4 — Tab "Audit Log" (registro attivita')
|
||||
Mostra: tabella paginata (25 per pagina): Data/Ora, Utente, Azione (etichette italiane: "Accesso effettuato", "Rischio creato", "Policy approvata", "Pre-allarme inviato", "Evidenza caricata", ecc.), Entita' (tipo + #id), Dettagli (JSON appiattito in "chiave: valore", troncato con tooltip); paginazione "Precedente / Pagina N di M / Successiva". Stato vuoto: "Nessun log disponibile"
|
||||
Azioni: "Precedente"/"Successiva" → `goAuditPage(n)` ricarica la pagina richiesta
|
||||
Dati da: GET /api/audit/logs?page=N&per_page=25 (`api.getAuditLogs(params)`)
|
||||
Confine: pannello `#tab-audit` (riga ~392), contenuto in `#audit-container` (~393); i pulsanti di paginazione (HTML dinamico) NON hanno id stabile
|
||||
|
||||
• U-REPORTS.5 — Tab "ISO 27001" (mapping normativo)
|
||||
Mostra: card "Mapping NIS2 - ISO 27001:2022" con righe di corrispondenza: badge "Art. {nis2}" → freccia → badge dei controlli ISO 27001 corrispondenti → titolo descrittivo della misura. Stato vuoto: "Nessun mapping disponibile"
|
||||
Azioni: nessuna (sola lettura)
|
||||
Dati da: GET /api/audit/iso27001-mapping (`api.getIsoMapping()`)
|
||||
Confine: pannello `#tab-iso` (riga ~402), contenuto in `#iso-container` (~403)
|
||||
|
||||
• U-REPORTS.6 — Tab "Monitoraggio Continuo" (continuous control monitoring)
|
||||
Mostra: testo introduttivo: stato di freschezza dei controlli alimentato dalle evidenze automatiche dei connettori (Evidence Automation), con copertura % (monitorati/totali); 5 card di sintesi: Sano (verde), Attenzione (giallo), Evidenza scaduta (arancione), Non conforme (rosso), Non monitorato (grigio); tabella: Stato (pallino colorato), Controllo (codice), Titolo, Ultima evidenza (o "mai"), Freschezza (giorni). Stato vuoto in tabella: "Nessun controllo. Le evidenze arrivano via POST /api/services/evidence-ingest."
|
||||
Azioni: nessuna (sola lettura; le evidenze sono ingerite da sistemi esterni via Services API)
|
||||
Dati da: GET /api/audit/controlsMonitoring (`api.getControlsMonitoring()`)
|
||||
Confine: pannello `#tab-monitoring` (riga ~412), contenuto in `#monitoring-container` (~413)
|
||||
|
||||
• U-REPORTS.7 — Tab "Requisiti ACN" (specifiche di base, Determina ACN 164179/2025)
|
||||
Mostra: testo introduttivo: requisiti operativi "specifiche di base ACN" (Determina 164179/2025, Framework Nazionale 2025) per il tipo di soggetto dell'organizzazione (essenziale/importante), totale requisiti e "Compliance: N%" con citazione della fonte; 4 card di sintesi: Implementato (verde), In corso (giallo), Da iniziare (grigio), Non applicabile (grigio scuro); requisiti raggruppati per funzione del Framework, in tabelle con colonne: Sottocat. (codice sottocategoria con tooltip testo integrale), Requisito, Stato (pallino + select inline: Da iniziare, In corso, Implementato, Non applicabile)
|
||||
Azioni: cambio select stato → `updateAcn(id, status)` salva subito e ricarica il tab
|
||||
Dati da: GET /api/audit/acnRequirements (`api.getAcnRequirements()`) · PUT /api/audit/acnRequirements/{id} (`api.updateAcnRequirement(id, status, note)`)
|
||||
Confine: pannello `#tab-acn` (riga ~421), contenuto in `#acn-container` (~422); le select di stato (HTML dinamico) NON hanno id stabile
|
||||
|
||||
⟦ FINE · U-REPORTS ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Pulsante "Genera Report" (header) | 355 | `nis2-reports-btn-generate` |
|
||||
| Contenitore tab bar `div.tab-nav` | 361 | `nis2-reports-tabs` |
|
||||
| Bottone tab "Report Compliance" | 362 | `nis2-reports-tab-btn-report` |
|
||||
| Bottone tab "Controlli" | 363 | `nis2-reports-tab-btn-controls` |
|
||||
| Bottone tab "Audit Log" | 364 | `nis2-reports-tab-btn-audit` |
|
||||
| Bottone tab "ISO 27001" | 365 | `nis2-reports-tab-btn-iso` |
|
||||
| Bottone tab "Monitoraggio Continuo" | 366 | `nis2-reports-tab-btn-monitoring` |
|
||||
| Bottone tab "Requisiti ACN" | 367 | `nis2-reports-tab-btn-acn` |
|
||||
| Pulsante "Stampa Report" (HTML dinamico nel report) | 722 | `nis2-reports-btn-print` |
|
||||
| Select stato requisito ACN (HTML dinamico per riga) | 543 | `nis2-reports-acn-status-{id}` |
|
||||
@@ -0,0 +1,74 @@
|
||||
# MAPPA-LOGICA · Modello Organizzativo SGSI (ISO 27001)
|
||||
|
||||
⟦ INIZIO · U-ISMS · Videata "Modello Organizzativo SGSI (ISO 27001)" ⟧
|
||||
File: public/isms.html · URL: /isms.html · Scopo: costruzione guidata del Sistema di Gestione della Sicurezza delle Informazioni secondo ISO/IEC 27001:2022 (clausole 4-10) con Statement of Applicability pre-popolato dalla Gap Analysis NIS2 ed estensioni cloud ISO 27017/27018 · Profili: lettura (modello, SoA, ruoli, documenti, readiness, export) per tutti i membri dell'organizzazione; scrittura (salvataggio step, ri-derivazione SoA, aggiunta/cancellazione ruoli, creazione/generazione AI documenti) riservata a org_admin e compliance_manager (super_admin bypassa); l'aggiornamento del singolo controllo SoA (stato/applicabilità/motivazione) è consentito anche ad auditor — gate backend `requireOrgRole` in IsmsModelController. Disclaimer in pagina: strumento di supporto e pre-audit, non costituisce certificazione ISO 27001.
|
||||
|
||||
• U-ISMS.1 — Header pagina + Esporta SGSI
|
||||
Mostra: titolo "Modello Organizzativo SGSI (ISO 27001)"; indicatore di salvataggio live ("Salvato"/"Salvataggio…"/"Salvataggio in sospeso"); bottone "Esporta SGSI".
|
||||
Azioni: click "Esporta SGSI" → `ismsExportView()` apre una finestra stampabile con: nome organizzazione, data generazione, disclaimer, Ambito, Metodologia di risk assessment, tabella Statement of Applicability (Controllo / Titolo / Applicabile / Stato / %).
|
||||
Dati da: GET /api/isms/export (via api.ismsExport()).
|
||||
Confine: `#isms-savehint` (riga 58); bottone export senza id, dentro `.content-header-actions` (riga 59).
|
||||
|
||||
• U-ISMS.2 — Intro + disclaimer normativo
|
||||
Mostra: box introduttivo "Costruisci il tuo Sistema di Gestione della Sicurezza delle Informazioni" (procedura guidata ISO/IEC 27001:2022, SoA pre-popolato dalla Gap Analysis NIS2, estensioni cloud 27017/27018); disclaimer ambra: gli obblighi normativi derivano da NIS2 / D.Lgs. 138/2024 / Determinazioni ACN, ISO 27001/27017/27018 sono best practice.
|
||||
Azioni: nessuna (solo informativo).
|
||||
Dati da: statico (HTML).
|
||||
Confine: `.isms-intro` (riga 67) e `.isms-disclaimer` (riga 71) — classi, nessun id.
|
||||
|
||||
• U-ISMS.3 — Barra step del wizard (6 step)
|
||||
Mostra: 6 card-step cliccabili numerate: 1 Contesto, 2 Leadership, 3 Risk, 4 SoA, 5 Documenti, 6 Monitoraggio. Step attivo evidenziato (classe `active`), step completati con bordo verde (classe `done`, calcolata da `markDone()` in base allo stato del modello).
|
||||
Azioni: click su uno step → `goStep(i)` mostra il pannello corrispondente e carica i dati lazy (step 2 ruoli, step 4 SoA, step 5 documenti, step 6 readiness).
|
||||
Dati da: GET /api/isms/model (via api.ismsGetModel(), al caricamento pagina) per pre-compilare e marcare gli step done.
|
||||
Confine: `#isms-steps` (riga 73); singoli step generati via JS con id `#step-0` … `#step-5` (isms.js riga 39).
|
||||
|
||||
• U-ISMS.4 — Step 1: Contesto e Ambito (cl. 4)
|
||||
Mostra: textarea "Ambito del SGSI (scope statement)", "Contesto interno", "Contesto esterno", "Parti interessate (una per riga)", "Confini del SGSI", "Esclusioni motivate"; 3 checkbox estensioni cloud: "Usiamo servizi cloud pubblici → ISO 27017", "Siamo fornitori di servizi cloud → ISO 27017 (lato provider)", "Trattiamo dati personali (PII) in cloud pubblico → ISO 27018". I flag cloud attivano i controlli condizionali nel SoA.
|
||||
Azioni: bottone "Salva e continua" → `saveStep1()` → salva e passa allo step 2; invalida la cache SoA (i flag cloud cambiano il perimetro dei controlli applicabili).
|
||||
Dati da: POST /api/isms/model (campi: scope_statement, context_internal, context_external, interested_parties[], boundaries, exclusions, uses_public_cloud, is_cloud_provider, processes_pii_in_cloud).
|
||||
Confine: `#panel-0` (riga 76); campi `#f-scope` (79), `#f-ctx-int` (80), `#f-ctx-ext` (81), `#f-parties` (82), `#f-boundaries` (83), `#f-exclusions` (84), `#f-uses-cloud` (87), `#f-cloud-provider` (88), `#f-pii-cloud` (89).
|
||||
|
||||
• U-ISMS.5 — Step 2: Leadership, ruoli e responsabilità (cl. 5)
|
||||
Mostra: lista dei ruoli SGSI definiti con matrice RACI (badge RACI + nome ruolo + responsabilità); form di inserimento: campo "Ruolo (es. CISO)", campo "Responsabilità", select RACI (R/A/C/I).
|
||||
Azioni: "Aggiungi ruolo" → `addRole()` → POST; "×" su un ruolo → `delRole(id)` → DELETE; "Continua" → step 3.
|
||||
Dati da: GET /api/isms/roles (lista); POST /api/isms/roles (role_name, responsibility, raci); DELETE /api/isms/roles/{id}.
|
||||
Confine: `#panel-1` (riga 96); `#roles-list` (100), `#r-name` (102), `#r-resp` (103), `#r-raci` (104).
|
||||
|
||||
• U-ISMS.6 — Step 3: Risk, metodologia e obiettivi (cl. 6)
|
||||
Mostra: textarea "Metodologia di risk assessment" (es. ISO 27005 / NIST SP 800-30, scala 5×5 del modulo Rischi) e "Obiettivi del SGSI (uno per riga)"; nota: il registro dei rischi vive nel modulo Rischi (link a risks.html), questo step ne dichiara la metodologia.
|
||||
Azioni: "Salva e continua" → `saveStep3()` → salva e passa allo step 4 (SoA).
|
||||
Dati da: POST /api/isms/model (campi: risk_methodology, isms_objectives[]).
|
||||
Confine: `#panel-2` (riga 112); `#f-method` (115), `#f-objectives` (116).
|
||||
|
||||
• U-ISMS.7 — Step 4: Statement of Applicability (SoA)
|
||||
Mostra: controlli ISO raggruppati per standard (gruppi collassabili 27001/27017/27018) e per tema (Organizzativi, Persone, Fisici, Tecnologici, Privacy PII); per ogni controllo: codice (es. badge `soa-code`), titolo IT/EN, badge verde "da NIS2" se pre-popolato dalla Gap Analysis (con tooltip della risposta sorgente), checkbox "Applicabile", 4 stati di attuazione (Da iniziare / In corso / Attuato / Verificato), textarea "Motivazione (inclusione/esclusione)". Riga statistiche: "Applicabili: N · impl. media: X%".
|
||||
Azioni: bottone "Ri-deriva dal NIS2" → `deriveSoa()` ricalcola il pre-popolamento; click su uno stato → autosave con debounce 600ms (% implementazione: not_started=0, in_progress=50, implemented/verified=100); toggle Applicabile → autosave + ricarica dell'intera SoA dopo 400ms (`setSoaApplicable` invalida la cache e richiama `loadSoa()`, i gruppi tornano collassati tranne il primo); modifica motivazione → autosave.
|
||||
Dati da: GET /api/isms/soa (gruppi+controlli+stats); POST /api/isms/soa/derive (ri-derivazione da NIS2); PUT /api/isms/soa (payload per controllo: control_code, applicable | implementation_status+implementation_pct | justification_inclusion/justification_exclusion).
|
||||
Confine: `#panel-3` (riga 123); `#soa-stats` (129), `#soa-groups` (131); singoli controlli renderizzati via JS come `.soa-ctrl[data-code="<control_code>"]` (isms.js riga 187).
|
||||
|
||||
• U-ISMS.8 — Step 5: Documented Information (cl. 7-8) + generazione AI
|
||||
Mostra: select "Tipo di documento" con 6 tipi: Policy SGSI, Dichiarazione di Applicabilità, Politica controllo accessi, Procedura gestione incidenti, Procedura continuità operativa, Politica sicurezza fornitori; hint di generazione ("Generazione bozza in corso…" / "Bozza creata (revisione obbligatoria)."); lista documenti esistenti con titolo, badge "AI" se generato dall'AI, tipo documento, badge stato (approved=verde, altrimenti warning).
|
||||
Azioni: "Genera bozza con AI" → `aiGenDoc()` → POST con doc_type; "Continua" → step 6.
|
||||
Dati da: GET /api/isms/documents (lista); POST /api/isms/documents/ai-generate ({doc_type}).
|
||||
Confine: `#panel-4` (riga 137); `#d-type` (142), `#btn-aigen` (150), `#aigen-hint` (152), `#docs-list` (153).
|
||||
|
||||
• U-ISMS.9 — Step 6: Monitoraggio e Miglioramento (cl. 9-10) + readiness
|
||||
Mostra: nota che audit interni e non conformità si gestiscono nei moduli esistenti (Audit & Report, NCR/CAPA); percentuale grande di "Completamento del SGSI" (es. "62%"); checklist per clausola (badge clausola + etichetta + ✓ verde se completata, — grigio se no).
|
||||
Azioni: nessuna azione diretta (lettura); la checklist si aggiorna al variare del modello.
|
||||
Dati da: GET /api/isms/readiness (overall_pct + checklist[{clause, label, done}]).
|
||||
Confine: `#panel-5` (riga 159); `#readiness-pct` (165), `#readiness-checklist` (167).
|
||||
|
||||
⟦ FINE · U-ISMS ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Bottone "Esporta SGSI" nell'header | 59 | `nis2-isms-btn-export` |
|
||||
| Bottone "Salva e continua" Step 1 | 91 | `nis2-isms-btn-save-step1` |
|
||||
| Bottone "Aggiungi ruolo" Step 2 | 105 | `nis2-isms-btn-add-role` |
|
||||
| Bottone "Continua" Step 2 | 107 | `nis2-isms-btn-next-step2` |
|
||||
| Bottone "Salva e continua" Step 3 | 118 | `nis2-isms-btn-save-step3` |
|
||||
| Bottone "Ri-deriva dal NIS2" Step 4 | 128 | `nis2-isms-btn-derive-soa` |
|
||||
| Bottone "Continua" Step 4 | 132 | `nis2-isms-btn-next-step4` |
|
||||
| Bottone "Continua" Step 5 | 154 | `nis2-isms-btn-next-step5` |
|
||||
| Box intro | 67 | `nis2-isms-intro` |
|
||||
| Box disclaimer | 71 | `nis2-isms-disclaimer` |
|
||||
@@ -0,0 +1,49 @@
|
||||
# MAPPA-LOGICA · Aggiornamenti Normativi
|
||||
|
||||
⟦ INIZIO · U-NORMATIVE · Videata "Aggiornamenti Normativi" ⟧
|
||||
File: public/normative.html · URL: /normative.html · Scopo: feed degli aggiornamenti normativi NIS2 / ACN / DORA / ENISA / ISO 27001 con presa visione (ACK) tracciata e documentata ai fini dell'audit di compliance NIS2 Art.21 · Profili: lettura (lista, pendenti, statistiche) per tutti i membri dell'organizzazione; la presa visione (POST ack) è riservata a org_admin e compliance_manager (super_admin bypassa) — gate backend `requireOrgRole` in NormativeController::acknowledge; la UI mostra comunque il bottone "Prendi in visione" a tutti, ma per gli altri ruoli il backend risponde 403 INSUFFICIENT_ROLE. La presa visione è registrata con nome utente.
|
||||
|
||||
• U-NORMATIVE.1 — Header pagina + "Solo Pendenti"
|
||||
Mostra: titolo "Aggiornamenti Normativi", sottotitolo "Feed NIS2 / ACN / DORA — Presa visione obbligatoria per audit compliance".
|
||||
Azioni: bottone "Solo Pendenti" → `loadPending()` → mostra solo gli aggiornamenti non ancora presi in visione.
|
||||
Dati da: GET /api/normative/pending (risposta: data.pending[]).
|
||||
Confine: `.page-header` (riga 35); bottone senza id, dentro `.page-header-actions` (riga 41).
|
||||
|
||||
• U-NORMATIVE.2 — Statistiche (4 card)
|
||||
Mostra: "Aggiornamenti Totali" (total_updates), "Prese Visione" (acknowledged, verde), "Pendenti" (pending, ambra), "Compliance ACK" (ack_rate %, colore primario).
|
||||
Azioni: nessuna (lettura).
|
||||
Dati da: GET /api/normative/stats (renderizzata da `renderStats()`).
|
||||
Confine: `#stats-grid` (riga 49).
|
||||
|
||||
• U-NORMATIVE.3 — Barra "Avanzamento presa visione"
|
||||
Mostra: percentuale ACK (es. "75%") e progress bar proporzionale; nota: "Documentare la presa visione degli aggiornamenti normativi è richiesto per la compliance NIS2 Art.21".
|
||||
Azioni: nessuna (lettura).
|
||||
Dati da: GET /api/normative/stats (campo ack_rate).
|
||||
Confine: `#ack-pct` (riga 58) e `#ack-bar` (riga 61).
|
||||
|
||||
• U-NORMATIVE.4 — Filtri lista
|
||||
Mostra: select "Tutte le fonti" (D.Lgs. 138/2024, Direttiva NIS2, ACN Guideline, DORA, ENISA, ISO 27001); select "Tutti i livelli" di impatto (Critico, Alto, Medio, Basso, Informativo); checkbox "Solo azione richiesta".
|
||||
Azioni: ogni cambio filtro → `loadUpdates()` ricarica la lista con i parametri query source / impact / action_required=1.
|
||||
Dati da: GET /api/normative/list?source=&impact=&action_required= (risposta: data.updates[]).
|
||||
Confine: `#filter-source` (riga 72), `#filter-impact` (riga 82), `#filter-action` (riga 91).
|
||||
|
||||
• U-NORMATIVE.5 — Lista card aggiornamenti
|
||||
Mostra: per ogni aggiornamento una card con: chip fonte (es. "D.Lgs. 138/2024"), badge impatto colorato (Critico/Alto/Medio/Basso/Informativo), badge "Azione richiesta" (se action_required, con bordo sinistro ambra), badge presa visione ("Preso in visione da <nome>" verde, oppure "Da prendere in visione" ambra — card già ACK in opacità ridotta), titolo, riferimento normativo (code), sommario, chip dei domini impattati (affected_domains), data "In vigore: <data>", link "Fonte" (apre l'URL ufficiale in nuova scheda).
|
||||
Azioni: bottone "Prendi in visione" (solo se non ancora ACK) → apre la modale di presa visione (U-NORMATIVE.6); link "Fonte" → URL esterno.
|
||||
Dati da: GET /api/normative/list (o /api/normative/pending in modalità "Solo Pendenti").
|
||||
Confine: `#updates-container` (riga 98); singole card generate via JS con id `#update-<id>` (riga 207 dello script inline).
|
||||
|
||||
• U-NORMATIVE.6 — Modale "Presa Visione"
|
||||
Mostra: testo esplicativo (documentare la presa visione, note opzionali sull'impatto per l'organizzazione); textarea "Note (opzionale)".
|
||||
Azioni: "Conferma presa visione" → `confirmAck(id)` → POST con le note, poi notifica "Presa visione registrata e documentata.", ricarica lista e statistiche; "Annulla" → chiude la modale.
|
||||
Dati da: POST /api/normative/{id}/ack (body: {notes}) — richiede ruolo org_admin o compliance_manager (super_admin bypassa); altri ruoli ricevono 403 INSUFFICIENT_ROLE.
|
||||
Confine: modale generata da `showModal()` di common.js; campo note `#ack-notes` (riga 249 dello script inline, esiste solo a modale aperta).
|
||||
|
||||
⟦ FINE · U-NORMATIVE ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Bottone "Solo Pendenti" nell'header | 41 | `nis2-normative-btn-pending` |
|
||||
| Bottone "Prendi in visione" su card (dinamico) | 230 (template JS) | `nis2-normative-btn-ack-<id>` (o data-attribute `data-ack-id`) |
|
||||
| Card barra avanzamento ACK | 54 | `nis2-normative-ack-card` |
|
||||
@@ -0,0 +1,58 @@
|
||||
# MAPPA-LOGICA · Segnalazioni Sicurezza (Whistleblowing)
|
||||
|
||||
⟦ INIZIO · U-WB · Videata "Segnalazioni Sicurezza" ⟧
|
||||
File: public/whistleblowing.html · URL: /whistleblowing.html · Scopo: canale interno di segnalazione violazioni e anomalie di sicurezza ai sensi dell'Art. 32 D.Lgs. 138/2024, con segnalazioni anonime protette, tracking via token e gestione del ciclo di vita (ricevuta → revisione → indagine → risolta/chiusa) · Profili: l'invio (POST submit) non richiede autenticazione lato API (supporta segnalazioni anonime; la pagina però è dietro checkAuth client-side) e il tracking anonimo via token è anch'esso senza auth; lista, statistiche, dettaglio e gestione (cambio stato, assegnazione, chiusura, note di risoluzione) sono riservati a org_admin e compliance_manager (super_admin bypassa) — gate backend `requireOrgRole` su list/get/update/assign/close/stats in WhistleblowingController; gli altri ruoli ricevono 403 INSUFFICIENT_ROLE su lista e statistiche.
|
||||
|
||||
• U-WB.1 — Header pagina + switch viste
|
||||
Mostra: titolo "Segnalazioni Sicurezza", sottotitolo "Canale interno Art.32 NIS2 — Segnala violazioni e anomalie di sicurezza".
|
||||
Azioni: bottone "Traccia Segnalazione Anonima" → `switchView('track')` (vista U-WB.6); bottone "Nuova Segnalazione" → `switchView('submit')` (vista U-WB.5). Le 3 viste (list/submit/track) sono mutuamente esclusive.
|
||||
Dati da: nessuno (navigazione client-side).
|
||||
Confine: `.page-header` (riga 38); bottoni senza id, dentro `.page-header-actions` (righe 44 e 48).
|
||||
|
||||
• U-WB.2 — Banner Art. 32
|
||||
Mostra: "Art. 32 D.Lgs. 138/2024 — Canale Segnalazioni Interno": le entità NIS2 devono predisporre canali interni; le segnalazioni anonime sono protette e il segnalante non può essere identificato; ogni segnalazione gestita con priorità e tracciabilità.
|
||||
Azioni: nessuna (informativo).
|
||||
Dati da: statico (HTML).
|
||||
Confine: `.art32-banner` (riga 56) — classe, nessun id.
|
||||
|
||||
• U-WB.3 — Statistiche (4 card)
|
||||
Mostra: "Totale Segnalazioni" (total), "Da Gestire" (received + under_review, ambra), "In Indagine" (investigating), "Critiche/Alte" (critical + high, rosso).
|
||||
Azioni: nessuna (lettura); ricaricate dopo ogni update.
|
||||
Dati da: GET /api/whistleblowing/stats (risposta: data.stats) — riservato a org_admin/compliance_manager (403 INSUFFICIENT_ROLE per gli altri ruoli).
|
||||
Confine: `#stats-grid` (riga 62).
|
||||
|
||||
• U-WB.4 — Vista Lista: filtri + tabella segnalazioni
|
||||
Mostra: filtri: stato (Ricevute / In revisione / In indagine / Risolte / Chiuse), priorità (Critica/Alta/Media/Bassa), categoria (Incidente sicurezza, Data breach, Accesso non autorizzato, Violazione policy, Rischio supply chain, Non conformità NIS2, Altro). Tabella con colonne: Codice (report_code), Categoria (badge), Titolo, Priorità (badge colorato), Stato (badge colorato), Anonima (scudo verde "Anonima" con lucchetto, oppure "Firmata"), Assegnata (nome o —), Data, bottone "Gestisci".
|
||||
Azioni: cambio filtro → `loadReports()` con query status/priority/category; "Gestisci" → `viewReport(id)` apre la modale di gestione (U-WB.7).
|
||||
Dati da: GET /api/whistleblowing/list?status=&priority=&category= (risposta: data.reports[]) — riservato a org_admin/compliance_manager (403 INSUFFICIENT_ROLE per gli altri ruoli).
|
||||
Confine: `#view-list` (riga 67); `#filter-status` (73), `#filter-priority` (82), `#filter-category` (90), `#reports-container` (103).
|
||||
|
||||
• U-WB.5 — Vista "Nuova Segnalazione" (form invio)
|
||||
Mostra: checkbox "Segnalazione anonima — La tua identità non verrà registrata" (spuntata di default); form: Categoria* (8 opzioni incl. Corruzione/Frode), Titolo*, Descrizione dettagliata*, Priorità stimata (Media default, Alta, Critica — Azione immediata richiesta, Bassa), Articolo NIS2 violato (opzionale, es. Art.21/Art.23), Email per follow-up (opzionale — lasciare vuoto per anonimato completo).
|
||||
Azioni: "Invia Segnalazione" → `submitReport()` → POST; in caso di successo mostra modale con il codice segnalazione (report_code) e, se anonima, il token di tracking da conservare (anonymous_token); "Annulla" → torna alla lista.
|
||||
Dati da: POST /api/whistleblowing/submit (body: category, title, description, priority, nis2_article, is_anonymous, contact_email, organization_id da localStorage nis2_org_id).
|
||||
Confine: `#view-submit` (riga 107); `#is-anonymous` (117), `#submit-form` (122), `#rep-category` (125), `#rep-title` (139), `#rep-description` (143), `#rep-priority` (147), `#rep-article` (156), `#contact-email-group` (158), `#rep-email` (160).
|
||||
|
||||
• U-WB.6 — Vista "Traccia Segnalazione Anonima"
|
||||
Mostra: campo "Token Segnalazione"; risultato: codice segnalazione, badge stato, categoria, timeline degli eventi (descrizione + data); messaggio "Token non valido o segnalazione non trovata" se il token non corrisponde.
|
||||
Azioni: "Verifica Stato" → `trackReport()` → GET con il token; "Annulla" → torna alla lista.
|
||||
Dati da: GET /api/whistleblowing/track-anonymous?token=<token>.
|
||||
Confine: `#view-track` (riga 173); `#track-token` (182), `#track-result` (188).
|
||||
|
||||
• U-WB.7 — Modale dettaglio/gestione segnalazione
|
||||
Mostra: titolo "<report_code> — <titolo>"; badge priorità, stato, eventuale scudo "Anonima"; descrizione completa; griglia: Categoria, Art. NIS2, Assegnata a, Data; Timeline degli eventi (descrizione, data/ora, autore); select "Cambia stato..." (In revisione / In indagine / Risolta / Chiusa / Respinta); textarea "Note di risoluzione...".
|
||||
Azioni: "Salva" → `updateReport(id)` → PUT con status e/o resolution_notes, poi notifica "Segnalazione aggiornata." e ricarica lista+stats; "Chiudi" → chiude la modale.
|
||||
Dati da: GET /api/whistleblowing/{id} (dettaglio + timeline); PUT /api/whistleblowing/{id} (body: {status?, resolution_notes?}).
|
||||
Confine: modale generata da `showModal()` di common.js; campi `#modal-status` (riga 353 script inline) e `#modal-notes` (riga 360 script inline), esistono solo a modale aperta.
|
||||
|
||||
⟦ FINE · U-WB ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Bottone "Traccia Segnalazione Anonima" header | 44 | `nis2-wb-btn-track` |
|
||||
| Bottone "Nuova Segnalazione" header | 48 | `nis2-wb-btn-new` |
|
||||
| Banner Art.32 | 56 | `nis2-wb-art32-banner` |
|
||||
| Bottone "Gestisci" per riga (dinamico) | 312 (template JS) | data-attribute `data-wb-view-id` |
|
||||
| Bottone "Verifica Stato" vista track | 185 | `nis2-wb-btn-verify` |
|
||||
| Bottone submit "Invia Segnalazione" | 164 | `nis2-wb-btn-submit` |
|
||||
@@ -0,0 +1,44 @@
|
||||
# MAPPA-LOGICA · Knowledge Base
|
||||
|
||||
⟦ INIZIO · U-KB · Videata "Knowledge Base" ⟧
|
||||
File: public/kb.html · URL: /kb.html · Scopo: caricamento e gestione dei documenti (procedure, policy, normative, training material) che l'AI usa per rispondere con citazioni precise (pipeline RAG su Qdrant), con visibilità a 3 livelli: SYSTEM (vendor), FIRM (studio + condivisioni esplicite), ORG (singola organizzazione cliente) · Profili: lettura/ricerca per tutti gli utenti autenticati (la visibilità applica il filtro authz a 3 livelli); l'upload (ingest) è riservato ai ruoli super_admin, org_admin, compliance_manager e consultant (employee/auditor read-only, 403 KB_FORBIDDEN). Per scope: SYSTEM solo super_admin; FIRM solo utenti con consulting_firm_id (consulenti di studio); ORG richiede ruolo org_admin/compliance_manager sull'organizzazione destinataria (super_admin bypassa) e `organization_id` valorizzato lato backend. La UI mostra/nasconde le radio di scope client-side (`setupScopeForUser`), ma l'enforcement è nel backend (KnowledgeBaseController::ingest).
|
||||
|
||||
• U-KB.1 — Header pagina + "Carica documento"
|
||||
Mostra: titolo "Knowledge Base"; paragrafo introduttivo sul modello di visibilità a 3 livelli (SYSTEM/FIRM/ORG).
|
||||
Azioni: bottone "Carica documento" → toggle del form di upload (U-KB.2); all'apertura chiama `setupScopeForUser()` che mostra/nasconde le opzioni di scope in base a ruolo e firm.
|
||||
Dati da: GET /api/auth/me (per role e consulting_firm_id, determina gli scope disponibili).
|
||||
Confine: `#btn-kb-upload` (riga 34).
|
||||
|
||||
• U-KB.2 — Form di upload/indicizzazione documento (nascosto di default)
|
||||
Mostra: campo "Titolo"; select "Tipo" (Procedura interna / Linea guida / Normativa / Training); textarea "Contenuto (testo libero, 50–50.000 caratteri)"; radio "Visibilità": "Sistema (super_admin)" (visibile solo a super_admin), "Studio + condivisioni" (visibile solo a utenti firm), "Solo organizzazione corrente" (default, sempre visibile); status di indicizzazione ("Indicizzazione in corso..." / "Documento indicizzato (SCOPE, N chunk)" / messaggi di errore con validazione: titolo obbligatorio, testo minimo 50 caratteri).
|
||||
Azioni: "Indicizza documento" → POST ingest (embed Voyage + upsert Qdrant + tracking MySQL), poi svuota i campi e ricarica la lista; "Annulla" → nasconde il form; selezione radio "FIRM" → mostra il blocco condivisione (U-KB.3).
|
||||
Dati da: POST /api/knowledgebase/ingest (body: title, text, entity_type, scope, shared_with_orgs[]).
|
||||
Confine: `#kb-form-card` (riga 50); `#kb-title` (55), `#kb-entity-type` (59), `#kb-text` (70), radio `input[name="kb-scope"]` con label `[data-scope-opt="SYSTEM|FIRM|ORG"]` (righe 77-84), `#btn-kb-submit` (102), `#btn-kb-cancel` (103), `#kb-status` (104).
|
||||
|
||||
• U-KB.3 — Blocco condivisione FIRM (visibile solo con scope=FIRM)
|
||||
Mostra: multi-select "Organizzazioni clienti destinatarie (Ctrl/Cmd per selezione multipla, opzionale)" popolata con le organizzazioni dello studio (nome + P.IVA); nota: "Lascia vuoto per condividere solo con i collaboratori dello studio".
|
||||
Azioni: selezione multipla delle org destinatarie → inviate come shared_with_orgs nell'ingest.
|
||||
Dati da: GET /api/knowledgebase/firmOrgs (risposta: data.organizations[]).
|
||||
Confine: `#kb-share-block` (riga 89), `#kb-shared-with` (riga 93).
|
||||
|
||||
• U-KB.4 — Lista "Documenti caricati visibili"
|
||||
Mostra: per ogni documento visibile all'utente: titolo, badge scope colorato (SYSTEM blu / FIRM ambra / ORG verde), tipo entità, numero chunk, data di creazione; "Nessun documento visibile" se vuota. La visibilità applica il filtro authz a 3 livelli lato backend.
|
||||
Azioni: bottone "Elimina" per documento → conferma → DELETE (rimuove documento + chunk da Qdrant) e ricarica la lista.
|
||||
Dati da: GET /api/knowledgebase/list (risposta: data.documents[]); DELETE /api/knowledgebase/{id}.
|
||||
Confine: card `.kb-doc-list` (riga 110); contenitore lista `#kb-doc-list` (riga 115); bottoni elimina dinamici con attributo `[data-del-id="<id>"]` (kb.js riga 110).
|
||||
|
||||
• U-KB.5 — "Test search semantica"
|
||||
Mostra: campo query (placeholder "Es: come gestire un incidente NIS2?"); risultati: per ogni hit [N] titolo, badge scope, score di similarità, estratto del contenuto (primi 300 caratteri); "Nessun risultato" se vuoto.
|
||||
Azioni: bottone "Cerca" → POST search semantica (top 5 risultati) nel perimetro di visibilità dell'utente.
|
||||
Dati da: POST /api/knowledgebase/search (body: {query, top_k: 5}; risposta: data.results[]).
|
||||
Confine: `#kb-search-query` (riga 127), `#btn-kb-search` (riga 128), `#kb-search-results` (riga 133).
|
||||
|
||||
⟦ FINE · U-KB ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Card lista documenti (wrapper) | 110 | `nis2-kb-doc-list-card` |
|
||||
| Card test search (wrapper) | 122 | `nis2-kb-search-card` |
|
||||
| Paragrafo intro visibilità | 42 | `nis2-kb-intro` |
|
||||
| Bottone "Elimina" documento (dinamico) | kb.js 110 | già presente `data-del-id` (selettore stabile, ok) |
|
||||
@@ -0,0 +1,58 @@
|
||||
# MAPPA-LOGICA · AI Cross-Analysis
|
||||
|
||||
⟦ INIZIO · U-XA · Videata "AI Cross-Analysis" ⟧
|
||||
File: public/cross-analysis.html · URL: /cross-analysis.html · Scopo: analisi AI conversazionale sui dati aggregati e anonimizzati del portfolio clienti di un consulente (gap comuni, rischio medio, categorie NIS2 deboli, benchmark), con storico delle analisi e vista dati portfolio · Profili: SOLO consultant e super_admin — il backend risponde error_code INSUFFICIENT_ROLE agli altri ruoli e la pagina mostra "Funzione riservata a Consulenti e Super Admin".
|
||||
|
||||
• U-XA.1 — Header pagina + badge privacy/ruolo
|
||||
Mostra: titolo "AI Cross-Analysis" con badge verde "Dati aggregati — privacy garantita" e badge viola "Solo Consulenti & Admin".
|
||||
Azioni: nessuna (informativo).
|
||||
Dati da: statico (HTML).
|
||||
Confine: `header.content-header` (riga 280) — nessun id sugli elementi badge.
|
||||
|
||||
• U-XA.2 — Header portfolio (banner viola)
|
||||
Mostra: "Il tuo portfolio — N organizzazioni monitorate" + 4 statistiche: Compliance medio (%), Rischi aperti, Formazione media (%), Organizzazioni. Se ruolo insufficiente: lucchetto + "Funzione riservata a Consulenti e Super Admin". Se errore: "Errore caricamento portfolio".
|
||||
Azioni: nessuna (lettura, caricata al boot da `loadPortfolio()`).
|
||||
Dati da: GET /api/cross-analysis/portfolio (risposta: data.org_count, data.aggregated.{avg_compliance_score, risks.total_open, training.avg_completion_rate, by_sector, score_distribution, assessments.avg_by_category}).
|
||||
Confine: `#portfolio-header` (riga 298).
|
||||
|
||||
• U-XA.3 — Barra tab (Chat AI / Storico / Portfolio dati)
|
||||
Mostra: 3 tab con icone: "Chat AI", "Storico", "Portfolio dati"; tab attiva sottolineata viola.
|
||||
Azioni: click tab → `switchTab()` mostra il pannello corrispondente; la tab Storico carica lazy lo storico (U-XA.6).
|
||||
Dati da: nessuno (navigazione client-side).
|
||||
Confine: `.tab-bar[role="tablist"]` (riga 307); bottoni `.tab-btn` senza id ma con `aria-controls="tab-chat|tab-history|tab-portfolio"` (righe 308-315).
|
||||
|
||||
• U-XA.4 — Tab Chat AI: domande rapide + input
|
||||
Mostra: empty state iniziale "Analisi AI del tuo portfolio clienti — Fai una domanda sui dati aggregati delle tue organizzazioni"; 6 chip di domande rapide: "Gap più frequenti", "Livello di rischio medio", "Categorie NIS2 deboli", "Intervento urgente", "Stato formazione", "Benchmark NIS2" (ognuna pre-compila una domanda in italiano); textarea domanda con invio via Enter (Shift+Enter per newline); bottone invio; nota privacy: "Dati anonimizzati e aggregati — nessun nome organizzazione inviato all'AI".
|
||||
Azioni: chip → `setQuestion()` pre-compila l'input; invio → `sendMessage()` aggiunge la bolla utente, mostra l'indicatore "thinking" animato, poi POST all'AI.
|
||||
Dati da: POST /api/cross-analysis/analyze (body: {question}; risposta: data.result + data.org_count).
|
||||
Confine: `#tab-chat` (riga 320); `#chat-messages` (322), `#chat-empty` (323), `#quick-qs` (330), `#chat-input` (340), `#btn-send` (342).
|
||||
|
||||
• U-XA.5 — Risposta AI strutturata (bolla chat)
|
||||
Mostra: risposta testuale (answer); sezioni opzionali: "Risultati chiave" (key_findings, elenco), "Raccomandazioni" (recommendations, elenco), "Aree di attenzione" (risk_areas, elenco), box viola benchmark (benchmark_note), box ambra nota privacy (privacy_note); footer "Basato su N organizzazioni anonimizzate" + orario. In caso di errore: bolla rossa con il messaggio.
|
||||
Azioni: nessuna (output).
|
||||
Dati da: risposta di POST /api/cross-analysis/analyze (result.{answer, key_findings[], recommendations[], risk_areas[], benchmark_note, privacy_note}).
|
||||
Confine: bolle generate via JS dentro `#chat-messages`; indicatore thinking con id dinamico `#think-<timestamp>`.
|
||||
|
||||
• U-XA.6 — Tab Storico
|
||||
Mostra: lista delle ultime 20 analisi: data/ora (it-IT), domanda (prompt_summary, ripulita dal prefisso "CROSS_ORG [...]"), sintesi risposta (response_summary); "Nessuna analisi precedente." se vuoto.
|
||||
Azioni: caricata al click sulla tab (lazy via `loadHistory()`).
|
||||
Dati da: GET /api/cross-analysis/history?limit=20 (risposta: data.history[]).
|
||||
Confine: `#tab-history` (riga 355), `#history-content` (riga 356).
|
||||
|
||||
• U-XA.7 — Tab Portfolio dati
|
||||
Mostra: card "Distribuzione Settoriale" (settore, conteggio, % con barra viola); card "Distribuzione Score Compliance" (fasce 0-20% … 81-100% colorate dal rosso al verde, conteggio org per fascia); card "Score Medio per Categoria NIS2 (dal più basso)" — fino a 5 categorie con % colorata (rosso <30, ambra <60, verde altrimenti) e mini progress bar.
|
||||
Azioni: nessuna (lettura, renderizzata da `renderPortfolioTab()` con i dati già caricati al boot).
|
||||
Dati da: GET /api/cross-analysis/portfolio (stessa chiamata di U-XA.2: aggregated.by_sector, aggregated.score_distribution, aggregated.assessments.avg_by_category).
|
||||
Confine: `#tab-portfolio` (riga 362), `#portfolio-content` (riga 363).
|
||||
|
||||
⟦ FINE · U-XA ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Tab "Chat AI" | 308 | `nis2-xa-tab-btn-chat` |
|
||||
| Tab "Storico" | 311 | `nis2-xa-tab-btn-history` |
|
||||
| Tab "Portfolio dati" | 314 | `nis2-xa-tab-btn-portfolio` |
|
||||
| Badge privacy header | 284 | `nis2-xa-privacy-badge` |
|
||||
| Badge "Solo Consulenti & Admin" | 289 | `nis2-xa-role-badge` |
|
||||
| Chip domande rapide (6) | 331-336 | `nis2-xa-quickq-1` … `nis2-xa-quickq-6` (o `data-quickq`) |
|
||||
@@ -0,0 +1,95 @@
|
||||
# MAPPA-LOGICA · Impostazioni
|
||||
|
||||
⟦ INIZIO · U-SETTINGS · Videata "Impostazioni" ⟧
|
||||
File: public/settings.html · URL: /settings.html · Scopo: amministrazione completa di organizzazione (dati + classificazione NIS2 + piano), profilo utente, preferenze, membri, sicurezza (sessioni + audit), API Keys, Webhook e branding white-label · Profili: tutti gli utenti autenticati; gestione membri/org tipicamente org_admin; tab "Branding" visibile SOLO a super_admin e consultant (mostrata via /api/auth/me).
|
||||
|
||||
• U-SETTINGS.1 — Header + barra tab
|
||||
Mostra: titolo "Impostazioni" e nome organizzazione corrente nell'header; 8 tab: Organizzazione (default), Profilo, Preferenze, Membri, Sicurezza, API Keys, Webhook, Branding (nascosta di default).
|
||||
Azioni: click tab → `switchTab()` mostra il pannello e carica lazy i dati (members/security/apikeys/webhooks/preferences/branding).
|
||||
Dati da: GET /api/auth/me (per decidere la visibilità della tab Branding: role super_admin o consultant).
|
||||
Confine: `#header-org-name` (riga 208); `.settings-tabs` (riga 214); unico tab con id: `#tab-btn-branding` (riga 222).
|
||||
|
||||
• U-SETTINGS.2 — Tab Organizzazione: Classificazione NIS2
|
||||
Mostra: badge entità calcolato automaticamente da settore/dipendenti/fatturato: "Essenziale" (rosso — supervisione proattiva, sanzioni fino a EUR 10M o 2% fatturato globale), "Importante" (ambra — supervisione reattiva, sanzioni fino a EUR 7M o 1,4%), "Non Applicabile" (grigio) o "Adesione Volontaria" (blu); descrizione del regime; per le entità Non Applicabile: checkbox "Adesione Volontaria alla NIS2".
|
||||
Azioni: toggle adesione volontaria → `toggleVoluntaryCompliance()` → PUT immediato con voluntary_compliance 0/1 e ri-render del badge.
|
||||
Dati da: GET organizzazione corrente via api.getCurrentOrg() (GET /api/organizations/current); PUT via api.updateOrganization(id, …) (PUT /api/organizations/{id}).
|
||||
Confine: `#tab-org` (riga 226); `#entity-classification` (riga 232); checkbox dinamica `#org-voluntary` (template JS riga 954).
|
||||
|
||||
• U-SETTINGS.3 — Tab Organizzazione: Piano di Abbonamento
|
||||
Mostra: badge del piano attivo: Free / Professional / Enterprise.
|
||||
Azioni: nessuna (lettura).
|
||||
Dati da: GET /api/organizations/current (campo subscription_plan).
|
||||
Confine: `#subscription-plan` (riga 240).
|
||||
|
||||
• U-SETTINGS.4 — Tab Organizzazione: form Dati Organizzazione
|
||||
Mostra: Nome Organizzazione*, Settore NIS2* (17 opzioni: Energia, Trasporti, Banche, Sanità, Acqua, Infrastrutture Digitali, Pubblica Amministrazione, Manifatturiero, Servizi Postali, Chimico, Alimentare, Rifiuti, Servizi ICT, Provider Digitali, Spazio, Ricerca, Altro), Partita IVA, Codice Fiscale, Numero Dipendenti, Fatturato Annuo (EUR), Paese, Città, Indirizzo, Sito Web, Email di Contatto, Telefono di Contatto.
|
||||
Azioni: "Salva Modifiche" → `saveOrganization()` → PUT, poi ricarica i dati per aggiornare la classificazione NIS2 (dipendenti/fatturato/settore la determinano).
|
||||
Dati da: GET /api/organizations/current (pre-compilazione); PUT /api/organizations/{id} (campi: name, sector, vat_number, fiscal_code, employee_count, annual_turnover_eur, country, city, address, website, contact_email, contact_phone).
|
||||
Confine: `#org-form` (riga 249); campi `#org-name` (253), `#org-sector` (257), `#org-vat` (283), `#org-fiscal` (287), `#org-employees` (294), `#org-turnover` (298), `#org-country` (305), `#org-city` (309), `#org-address` (315), `#org-website` (321), `#org-email` (325), `#org-phone` (331); bottone `#btn-save-org` (334).
|
||||
|
||||
• U-SETTINGS.5 — Tab Profilo: Informazioni Personali
|
||||
Mostra: Email (disabilitata — "L'email non può essere modificata"), Nome Completo*, Telefono, Lingua Preferita (Italiano/English).
|
||||
Azioni: "Aggiorna Profilo" → `saveProfile()` → PUT.
|
||||
Dati da: GET /api/auth/me (pre-compilazione); PUT /api/auth/profile (full_name, phone, preferred_language).
|
||||
Confine: `#tab-profile` (riga 345); `#profile-form` (354), `#profile-email` (357), `#profile-name` (364), `#profile-phone` (368), `#profile-language` (374); bottone `#btn-save-profile` (380).
|
||||
|
||||
• U-SETTINGS.6 — Tab Profilo: Cambia Password
|
||||
Mostra: Password Attuale*, Nuova Password* con indicatore di forza a 4 segmenti (Debole/Sufficiente/Buona/Forte, calcolato client-side su lunghezza, maiuscole/minuscole, numeri, simboli), Conferma Nuova Password*; avviso: dopo il cambio si viene disconnessi da tutte le sessioni.
|
||||
Azioni: "Cambia Password" → `changePassword()` (validazioni: coincidenza e min 8 caratteri) → POST; al successo: logout e redirect a /login.html dopo 2s.
|
||||
Dati da: POST /api/auth/change-password (current_password, new_password).
|
||||
Confine: `#password-form` (riga 396); `#pw-current` (399), `#pw-new` (404), `#pw-confirm` (416), barra forza `#pw-strength-bar` + `#pw-seg-1..4` (405-409), `#pw-strength-text` (411); bottone `#btn-change-pw` (419).
|
||||
|
||||
• U-SETTINGS.7 — Tab Preferenze (utente)
|
||||
Mostra: Lingua (Italiano/English/Français/Deutsch), Tema (Auto/Chiaro/Scuro), Timezone (8 opzioni, default Europe/Rome), checkbox "Ricevi notifiche via email (incidenti, deadline, training)", checkbox "Mostra notifiche in-app (badge sidebar)"; messaggio "✓ Salvato" temporaneo.
|
||||
Azioni: "Salva preferenze" → PUT.
|
||||
Dati da: GET /api/auth/preferences (pre-compilazione); PUT /api/auth/preferences (preferred_language, theme, timezone, notif_email, notif_inapp).
|
||||
Confine: `#tab-preferences` (riga 430); `#preferences-form` (437), `#pref-lang` (440), `#pref-theme` (450), `#pref-tz` (459), `#pref-notif-email` (473), `#pref-notif-inapp` (480), `#pref-save-btn` (486), `#pref-saved-msg` (487).
|
||||
|
||||
• U-SETTINGS.8 — Tab Membri
|
||||
Mostra: tabella membri dell'organizzazione: Nome, Email, Ruolo (badge: Amministratore, Compliance Manager, Membro CDA, Auditor, Dipendente), Data Ingresso, azione rimozione (icona cestino).
|
||||
Azioni: "Invita Membro" → modale con Email* e Ruolo (l'utente deve essere già registrato sulla piattaforma) → POST invite; cestino → modale conferma "l'utente perderà l'accesso a tutti i dati" → DELETE.
|
||||
Dati da: GET /api/organizations/{orgId}/members; POST /api/organizations/{orgId}/invite ({email, role}); DELETE /api/organizations/{orgId}/members/{userId}.
|
||||
Confine: `#tab-members` (riga 494); `#members-container` (504); campi modale dinamici `#invite-email` e `#invite-role` (template JS righe 1252-1256).
|
||||
|
||||
• U-SETTINGS.9 — Tab Sicurezza: info account + Sessioni Attive + Registro Attività
|
||||
Mostra: (a) card informative: "Autenticazione a Due Fattori (2FA)" con badge "Prossimamente", "Accesso API" con badge JWT; (b) "Sessioni Attive": per ogni dispositivo loggato: etichetta device, badge "Questo dispositivo" sulla sessione corrente, IP, ultimo accesso relativo, data login; (c) "Registro Attività Recenti": tabella Azione (etichette italiane: Accesso effettuato, Password modificata, Assessment completato, Policy approvata, ecc.), Tipo entità, Data — ultimi 20 eventi.
|
||||
Azioni: "Disconnetti" su una sessione → DELETE singola; "Disconnetti gli altri" (visibile se >1 sessione) → DELETE di tutte le altre sessioni.
|
||||
Dati da: GET /api/auth/sessions; DELETE /api/auth/sessions/{id}; DELETE /api/auth/sessions (tutte tranne la corrente); GET audit log via api.getAuditLogs({limit:20}) (GET /api/audit/logs).
|
||||
Confine: `#tab-security` (riga 512); `#card-sessions` (536), `#sessions-container` (545), `#revoke-all-btn` (542), `#audit-log-container` (556).
|
||||
|
||||
• U-SETTINGS.10 — Tab API Keys
|
||||
Mostra: tabella chiavi: Nome (+ "Creata da"), Prefisso (key_prefix...), Scopes (badge), Ultimo Uso, Scadenza, Stato (Attiva/Revocata), azione revoca; card "Scope Disponibili" con descrizione di ogni scope.
|
||||
Azioni: "Nuova API Key" → modale con Nome*, checkbox scopes (read:all, read:compliance, read:risks, read:incidents, read:assets, read:supply_chain, read:policies, admin:licenses, admin:org, sso:login), Scadenza opzionale → POST; al successo modale one-time con la chiave in chiaro ("Salva questa chiave ora. Non sarà più visibile", uso: header X-API-Key); icona cestino → conferma → DELETE (revoca irreversibile).
|
||||
Dati da: GET /api/webhooks/api-keys (api_keys[] + available_scopes); POST /api/webhooks/api-keys ({name, scopes[], expires_at}); DELETE /api/webhooks/api-keys/{id}.
|
||||
Confine: `#tab-apikeys` (riga 564); `#apikeys-container` (579), `#available-scopes-container` (585); campi modale dinamici `#apikey-name` (1386), `#apikey-scopes-checkboxes` (1390), `#apikey-expires` (1401).
|
||||
|
||||
• U-SETTINGS.11 — Tab Webhook: subscriptions + Delivery Log
|
||||
Mostra: tabella webhook: Nome (con warning "⚠ N errori" se failure_count ≥ 5), URL endpoint, Eventi sottoscritti (badge), conteggio Delivery (N✓ N✗), Stato (Attivo/Pausa), 3 azioni (Test Ping, abilita/disabilita, elimina); card "Delivery Log": tabella Evento, Webhook, Stato (delivered/retrying/failed), HTTP status, Tentativo (n/3), Data.
|
||||
Azioni: "Nuovo Webhook" → modale con Nome*, URL Endpoint* (https), checkbox eventi (incident.created/updated/significant/deadline_warning, risk.high_created/updated, compliance.score_changed, policy.approved/created, supplier.risk_flagged, assessment.completed, whistleblowing.received, normative.update, webhook.test, * wildcard) → POST; al successo modale one-time con il secret HMAC (verifica header X-NIS2-Signature, firma sha256=HMAC_SHA256(body, secret)); Test Ping → POST test; toggle → PUT is_active; elimina → DELETE; "Aggiorna" → ricarica i delivery.
|
||||
Dati da: GET /api/webhooks/subscriptions; POST /api/webhooks/subscriptions ({name, url, events[]}); POST /api/webhooks/subscriptions/{id}/test; PUT /api/webhooks/subscriptions/{id} ({is_active}); DELETE /api/webhooks/subscriptions/{id}; GET /api/webhooks/deliveries (opz. ?subscription_id=).
|
||||
Confine: `#tab-webhooks` (riga 591); `#webhooks-container` (606), `#deliveries-container` (615); campi modale dinamici `#wh-name` (1503), `#wh-url` (1507).
|
||||
|
||||
• U-SETTINGS.12 — Tab Branding white-label (solo super_admin/consultant)
|
||||
Mostra: "Nome prodotto custom (opzionale)" (es. Studio Rossi NIS2 Suite), "URL Logo (opzionale)", color picker "Colore primario" (default #1e40af), color picker "Colore secondario" (default #06b6d4); nota: visibile a tutti i clienti loggati dello studio; messaggio "✓ Salvato — ricarica per vedere".
|
||||
Azioni: "Salva branding" → PUT.
|
||||
Dati da: GET /api/branding/current (pre-compilazione); PUT /api/branding (custom_brand_name, logo_url, primary_color, secondary_color).
|
||||
Confine: `#tab-branding` (riga 621); `#branding-form` (628), `#brand-name` (631), `#brand-logo` (636), `#brand-pri` (641), `#brand-sec` (646), `#brand-save-btn` (650), `#brand-saved-msg` (651).
|
||||
|
||||
⟦ FINE · U-SETTINGS ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Tab "Organizzazione" | 215 | `nis2-settings-tab-btn-org` |
|
||||
| Tab "Profilo" | 216 | `nis2-settings-tab-btn-profile` |
|
||||
| Tab "Preferenze" | 217 | `nis2-settings-tab-btn-preferences` |
|
||||
| Tab "Membri" | 218 | `nis2-settings-tab-btn-members` |
|
||||
| Tab "Sicurezza" | 219 | `nis2-settings-tab-btn-security` |
|
||||
| Tab "API Keys" | 220 | `nis2-settings-tab-btn-apikeys` |
|
||||
| Tab "Webhook" | 221 | `nis2-settings-tab-btn-webhooks` |
|
||||
| Bottone "Invita Membro" | 498 | `nis2-settings-btn-invite-member` |
|
||||
| Bottone "Nuova API Key" | 573 | `nis2-settings-btn-new-apikey` |
|
||||
| Bottone "Nuovo Webhook" | 600 | `nis2-settings-btn-new-webhook` |
|
||||
| Bottone "Aggiorna" delivery log | 612 | `nis2-settings-btn-reload-deliveries` |
|
||||
|
||||
Nota: `switchTab()` (riga 711) seleziona i tab per indice posizionale (`document.querySelectorAll('.settings-tab')[tabMap[tab]]`) — l'aggiunta di id NON deve cambiare ordine/numero dei bottoni tab.
|
||||
@@ -0,0 +1,46 @@
|
||||
# MAPPA-LOGICA · Le Mie Aziende (vista consulente)
|
||||
|
||||
⟦ INIZIO · U-COMPANIES · Videata "Le Mie Aziende" (vista consulente) ⟧
|
||||
File: public/companies.html · URL: /companies.html · Scopo: portafoglio clienti del consulente — elenco aziende seguite con compliance score, rischi/incidenti e accesso rapido alla gestione di ciascuna org · Profili: solo utenti con ruolo `consultant` (la pagina verifica `api.isConsultant()` cioè `localStorage nis2_user_role === 'consultant'`; chi non è consulente viene rediretto a dashboard.html, riga 351-354)
|
||||
|
||||
• U-COMPANIES.1 — Header pagina e azioni
|
||||
Mostra: titolo "Le Mie Aziende" + sottotitolo "Gestisci il portafoglio clienti e monitora la compliance NIS2"; campo di ricerca con placeholder "Cerca azienda..."; bottone primario "Aggiungi Cliente" (link a onboarding.html)
|
||||
Azioni: digitare nel campo di ricerca filtra le card per nome in tempo reale (`oninput="filterCompanies(this.value)"`, filtro client-side su attributo `data-name`); click "Aggiungi Cliente" → naviga a /onboarding.html
|
||||
Dati da: nessuna chiamata API (filtro locale)
|
||||
Confine: `#search-input` (input ricerca, riga 290); contenitore header `.companies-header` (riga 282, senza id)
|
||||
|
||||
• U-COMPANIES.2 — Griglia card aziende
|
||||
Mostra: una card per ogni organizzazione del consulente con: avatar a iniziali, ragione sociale, Partita IVA (prefisso "IT"), badge classificazione NIS2 ("Essenziale" rosso / "Importante" giallo / "Volontaria" / "Non NIS2"), barra "Compliance" con percentuale colorata (caricata in asincrono), due contatori "Rischi aperti" e "Incidenti attivi" (asincroni), etichetta settore in italiano (mappa `getSectorLabel`, 30 settori NIS2 Allegato I/II), bottoni "Connettori" e "Gestisci". All'avvio mostra 2 skeleton card di caricamento.
|
||||
Azioni: click "Gestisci" → `manageCompany(orgId)`: imposta l'organizzazione attiva (`api.setOrganization`) e naviga a dashboard.html; click "Connettori" → apre la modale connettori (U-COMPANIES.4)
|
||||
Dati da: GET /api/organizations/list (lista org); per OGNI org GET /api/dashboard/overview con header `X-Organization-Id` commutato temporaneamente (campi usati: `compliance_score`, `open_risks`, `active_incidents`)
|
||||
Confine: `#companies-grid` (riga 300); ogni card `.company-card[data-org-id]`; elementi asincroni con id dinamici `#score-row-{orgId}`, `#score-fill-{orgId}`, `#score-val-{orgId}`, `#stats-row-{orgId}`, `#stat-risks-{orgId}`, `#stat-incidents-{orgId}` (template righe 422-440)
|
||||
|
||||
• U-COMPANIES.3 — Stato vuoto
|
||||
Mostra: icona edificio, titolo "Nessuna azienda ancora", testo "Aggiungi il tuo primo cliente per iniziare a monitorare la compliance NIS2.", bottone "Aggiungi Primo Cliente". Compare se la lista è vuota, se l'API fallisce, oppure se il filtro di ricerca non trova nulla.
|
||||
Azioni: click "Aggiungi Primo Cliente" → /onboarding.html
|
||||
Dati da: stesso GET /api/organizations/list (mostrato quando `data` è vuoto)
|
||||
Confine: `#companies-empty` (riga 323, inizialmente `display:none`)
|
||||
|
||||
• U-COMPANIES.4 — Modale "Connettori — {azienda}" (Evidence Automation)
|
||||
Mostra: per ogni tipo di connettore disponibile (etichette: Microsoft 365 / Entra ID, Google Workspace, Amazon Web Services, Microsoft Azure, Identity Provider, EDR / XDR, SIEM / SOC, Ticketing (Jira/ServiceNow)) una riga con: checkbox "Attivo", input `tenant_id / account_id`, input `client_id / app_id`, badge stato segreto ("Segreto non impostato" grigio / "Segreto in attesa" giallo / "Segreto configurato" verde), bottone "Salva". Nota in testa: qui si salvano solo parametri NON segreti; il client secret va nel vault dell'amministratore.
|
||||
Azioni: "Salva" per riga → PUT con `{type, enabled, config:{tenant_id, client_id}, secret_status:'pending'}`; al successo notifica "Connettore salvato" + alert con `cli_hint` (comando vault per il segreto); "✕" o click sullo sfondo → chiude la modale
|
||||
Dati da: GET /api/organizations/{orgId}/connectors (apertura: `connectors` esistenti + `available_types`); PUT /api/organizations/{orgId}/connectors (salvataggio)
|
||||
Confine: `#conn-modal` (creato dinamicamente da `showConnModal`, riga 504); righe `.conn-row[data-type]` con input `.c-en`, `.c-tenant`, `.c-client`
|
||||
|
||||
• U-COMPANIES.5 — Sidebar di navigazione
|
||||
Mostra: sidebar Bootstrap Italia condivisa dell'app (voci generate da common-bi.js)
|
||||
Azioni: navigazione verso le altre viste
|
||||
Dati da: nessuna (markup iniettato da `loadSidebar()` di js/common-bi.js)
|
||||
Confine: `#sidebar` (riga 275)
|
||||
|
||||
⟦ FINE · U-COMPANIES ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Bottone header "Aggiungi Cliente" (link) | 292 | `nis2-companies-add-btn` |
|
||||
| Bottone empty state "Aggiungi Primo Cliente" | 329 | `nis2-companies-add-first-btn` |
|
||||
| Bottone card "Connettori" (per card) | 444 | `nis2-companies-connectors-btn-{orgId}` |
|
||||
| Bottone card "Gestisci" (per card) | 447 | `nis2-companies-manage-btn-{orgId}` |
|
||||
| Contenitore header pagina `.companies-header` | 282 | `nis2-companies-header` |
|
||||
| Bottone "Salva" riga connettore (modale) | 489 | `nis2-companies-conn-save-{type}` |
|
||||
@@ -0,0 +1,53 @@
|
||||
# MAPPA-LOGICA · Onboarding — Configurazione Iniziale
|
||||
|
||||
⟦ INIZIO · U-ONBOARDING · Videata "Onboarding — Configurazione Iniziale" (wizard) ⟧
|
||||
File: public/onboarding.html · URL: /onboarding.html · Scopo: wizard di configurazione iniziale dell'organizzazione dopo la registrazione — ricerca azienda per Partita IVA, completamento dati aziendali, profilo utente e classificazione NIS2 automatica · Profili: qualsiasi utente autenticato senza organizzazione configurata (richiede solo `checkAuth()`; nessun vincolo di ruolo). NOTA: nella UI V2 Bootstrap Italia il wizard ha 4 step (lo storico "5 step" con scelta metodo/visura è stato compattato: l'upload visura resta solo come funzione legacy `analyzeVisura()` nel JS, righe 587-613, senza UI dedicata).
|
||||
|
||||
• U-ONBOARDING.1 — Header e stepper di avanzamento
|
||||
Mostra: logo scudo + titolo "NIS2 Agile" / sottotitolo "Configurazione Iniziale"; stepper orizzontale a 4 passi con etichette "Partita IVA", "Dati Aziendali", "Il Tuo Profilo", "Classificazione"; il passo corrente è evidenziato in blu, i completati in verde con segno di spunta
|
||||
Azioni: nessuna diretta (lo stepper riflette `goToStep(n)` / `updateStepper`)
|
||||
Dati da: nessuna
|
||||
Confine: `#stepper` (riga 122); singoli passi `.stepper-step[data-step="1..4"]`; connettori `.stepper-connector[data-after]`
|
||||
|
||||
• U-ONBOARDING.2 — Step 1 "Inserisci la Partita IVA dell'azienda"
|
||||
Mostra: card con campo "Partita IVA *" (prefisso fisso "IT", 11 cifre numeriche, hint "11 cifre numeriche senza prefisso IT"), bottone "Cerca Azienda", area risultato (alert verde "✓ {ragione sociale}" con indirizzo, oppure alert giallo "Azienda non trovata. Puoi inserire i dati manualmente."), spinner "Ricerca in corso... / Interrogazione registro imprese", link "Non trovi l'azienda? Inserisci manualmente", bottone "Continua" (appare solo dopo ricerca riuscita o scelta manuale)
|
||||
Azioni: "Cerca Azienda" (anche tasto Invio nel campo) → `step1FetchCompany()`: valida 11 cifre, chiama l'API e precompila lo stato del wizard (name, fiscal_code, address, city, website, email/pec, phone, suggested_sector, employees_range) marcando i campi auto-compilati; "Inserisci manualmente" → `step1ManualEntry()`: salva solo la P.IVA e abilita "Continua"; "Continua" → `goToStep(2)`
|
||||
Dati da: POST /api/onboarding/fetch-company con body `{vat_number}` (sorgente backend: CertiSource); fonte dati mostrata poi come "Dati precompilati da CertiSource"
|
||||
Confine: `#step-1` (riga 150); input `#s1-vat`, risultato `#s1-result`, bottone `#s1-fetch-btn`, spinner `#s1-loading`, bottone continua `#s1-continue-btn`
|
||||
|
||||
• U-ONBOARDING.3 — Step 2 "Verifica e Completa i Dati Aziendali"
|
||||
Mostra: banner verde con la fonte dati (es. "Dati precompilati da CertiSource", visibile solo se auto-fill); form a 2 colonne: Ragione Sociale* (`#company-name`), Partita IVA (`#vat-number`), Codice Fiscale (`#fiscal-code`), Indirizzo (`#address`), Città (`#city`), Sito Web (`#website`), Email Aziendale (`#company-email`), Telefono Aziendale (`#company-phone`), Settore NIS2* (`#sector`, select con optgroup "Settori ad Alta Criticità (Allegato I)" 18 voci e "Altri Settori Critici (Allegato II)" 12 voci + "Altro"), Numero Dipendenti* (`#employee-count`), Fatturato Annuo EUR* (`#annual-turnover`). I campi auto-compilati hanno bordo verde e badge "auto-compilato".
|
||||
Azioni: "Indietro" → `goToStep(1)`; "Continua" → `submitStep3()`: valida ragione sociale, settore, dipendenti > 0, fatturato ≥ 0 e salva nello stato wizard, poi `goToStep(3)`
|
||||
Dati da: nessuna chiamata diretta (usa i dati raccolti allo step 1; validazione client-side)
|
||||
Confine: `#step-2` (riga 199); banner `#data-source-banner` + testo `#data-source-text`
|
||||
|
||||
• U-ONBOARDING.4 — Step 3 "Completa il tuo profilo"
|
||||
Mostra: card con Nome Completo (`#full-name`, precompilato dal profilo se vuoto), Ruolo in Azienda* (`#role`, select: CEO/Amministratore Delegato, CTO/Direttore Tecnico, CISO/Responsabile Sicurezza, DPO/Data Protection Officer, Compliance Manager, IT Manager, Responsabile Legale, Membro CDA, Consulente Esterno, Altro), Telefono (`#user-phone`)
|
||||
Azioni: "Indietro" → `goToStep(2)`; "Continua" → `submitStep4()`: ruolo obbligatorio, salva profilo e `goToStep(4)`
|
||||
Dati da: GET /api/auth/me (all'ingresso nello step, `loadUserProfile()` precompila `full_name`)
|
||||
Confine: `#step-3` (riga 312)
|
||||
|
||||
• U-ONBOARDING.5 — Step 4 "Classificazione NIS2" (risultato + riepilogo)
|
||||
Mostra: riquadro risultato classificazione con icona scudo, etichetta e descrizione. Esiti possibili calcolati da `classifyLocally()` (logica interamente client-side: Allegato I + grande impresa ≥250 dip. o ≥50M€ → "Soggetto Essenziale"; Allegato I/II + media impresa ≥50 dip. o ≥10M€ → "Soggetto Importante"; settore non coperto → "Non Applicabile"; settore coperto sotto soglia → "Sotto le Soglie"). Se non applicabile compare la card "Adesione Volontaria alla NIS2" con checkbox. Sotto, card "Riepilogo Dati Aziendali" con: Ragione Sociale, Partita IVA, Settore, Tipologia Soggetto, Dipendenti, Fatturato Annuo.
|
||||
Azioni: checkbox adesione volontaria → `onVoluntaryChange()`: cambia il riquadro in "Adesione Volontaria" e aggiorna il riepilogo; "Indietro" → `goToStep(3)`; "Completa e Vai alla Dashboard" → `completeOnboarding()` (U-ONBOARDING.6)
|
||||
Dati da: nessuna chiamata per la classificazione (calcolo locale `classifyLocally(sector, employees, turnover)`, righe 731-762)
|
||||
Confine: `#step-4` (riga 362); risultato `#classification-result` con `#classification-icon`, `#classification-label`, `#classification-desc`; sezione volontaria `#voluntary-section`, card `#voluntary-card`, checkbox `#voluntary-checkbox`; riepilogo `#sum-company`, `#sum-vat`, `#sum-sector`, `#sum-entity-type`, `#sum-employees`, `#sum-turnover`
|
||||
|
||||
• U-ONBOARDING.6 — Completamento onboarding
|
||||
Mostra: il bottone diventa "Completamento in corso..."; al successo notifica "Configurazione completata con successo!" e redirect dopo 1s (consulente → companies.html, altrimenti → dashboard.html)
|
||||
Azioni: invio payload `{name, vat_number, fiscal_code, address, city, website, contact_email, contact_phone, sector, employee_count, annual_turnover_eur, voluntary_compliance, full_name, phone, country:'IT'}`; al successo imposta l'org attiva con `api.setOrganization(orgId)`
|
||||
Dati da: POST /api/onboarding/complete; (legacy, senza UI in V2: POST /api/onboarding/upload-visura via `api.uploadVisura()` per la visura camerale PDF)
|
||||
Confine: `#complete-btn` (riga 409)
|
||||
|
||||
⟦ FINE · U-ONBOARDING ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Bottone "Non trovi l'azienda? Inserisci manualmente" (step 1) | 182 | `nis2-onboarding-manual-btn` |
|
||||
| Bottone "Indietro" step 2 | 298 | `nis2-onboarding-back-2` |
|
||||
| Bottone "Continua" step 2 | 303 | `nis2-onboarding-next-2` |
|
||||
| Bottone "Indietro" step 3 | 348 | `nis2-onboarding-back-3` |
|
||||
| Bottone "Continua" step 3 | 353 | `nis2-onboarding-next-3` |
|
||||
| Bottone "Indietro" step 4 | 404 | `nis2-onboarding-back-4` |
|
||||
| Select settore: nessun id mancante (ha `#sector`) | — | — |
|
||||
@@ -0,0 +1,69 @@
|
||||
# MAPPA-LOGICA · Standard Continuità di Servizio
|
||||
|
||||
⟦ INIZIO · U-SERVICE-CONTINUITY · Videata "Standard Continuità di Servizio" (documento standalone) ⟧
|
||||
File: public/service-continuity.html · URL: /service-continuity.html · Scopo: documento informativo statico (stampabile) che descrive la strategia di continuità di servizio della piattaforma NIS2 Agile — architettura, resilienza a 7 livelli, rate limiting, maintenance mode, matrice rischi, SLA e checklist operativa · Profili: pagina pubblica, nessun controllo di autenticazione né ruolo (non carica api.js/common.js; non ha sidebar applicativa). NOTA: pagina interamente statica — nessuna chiamata API, nessun dato dinamico; gli unici script sono il bundle Bootstrap Italia e `bootstrap.loadFonts`.
|
||||
|
||||
• U-SERVICE-CONTINUITY.1 — Intestazione documento
|
||||
Mostra: brand "NIS2 Agile / Cybersecurity Compliance NIS2" con icona lucchetto; meta "Standard Operativo — Continuità di Servizio"; titolo "Strategia di Continuità di Servizio"; sottotitolo "Architettura di resilienza, monitoraggio, auto-recovery e protezione dei dati"; 4 tag: "Aprile 2026", "PHP+MySQL+Qdrant", "Hetzner CPX31", "99.9% SLA Target"
|
||||
Azioni: nessuna
|
||||
Dati da: nessuna (contenuto statico)
|
||||
Confine: `header.doc-header` (riga 62, senza id)
|
||||
|
||||
• U-SERVICE-CONTINUITY.2 — Sezione 1 "Architettura di Servizio"
|
||||
Mostra: tabella Servizio/Stack/Healthcheck: `nis2-app` (PHP+MySQL+Qdrant, /health), MySQL/PostgreSQL (Database condiviso, ping), Qdrant (Vector DB embeddings, HTTP 200), AgileHub NEXUS (Ticket + AI + Notifiche, /health); box informativo "Deploy a caldo" (bind mount Docker / PM2 reload, nessun rebuild)
|
||||
Azioni: nessuna
|
||||
Dati da: nessuna
|
||||
Confine: primo `h2` dentro `main.content` (riga 81, senza id)
|
||||
|
||||
• U-SERVICE-CONTINUITY.3 — Sezione 2 "Strategia di Resilienza a 7 Livelli"
|
||||
Mostra: 7 blocchi numerati L1-L7: L1 Auto-Restart Container/PM2 (recovery < 30s); L2 Healthcheck Nativo (endpoint /health ogni 30s, ricreazione dopo 3 fail); L3 Database Retry con Reconnect (errori MySQL 2006/2013/1213, 2 retry con backoff); L4 Resilienza API Esterne (Claude AI, ElevenLabs TTS, Voyage — 3 retry, degradazione graceful, fallback frontend "AI temporaneamente non disponibile"); L5 Error Alerting in Tempo Reale (notifica AgileHub entro 30s); L6 Monitoraggio Esterno AgileHub (cron ogni 2 minuti); L7 Manutenzione Preventiva (tabella: disk monitor ogni 6 ore, cleanup settimanale, SSL renewal settimanale, refresh token Claude orario)
|
||||
Azioni: nessuna
|
||||
Dati da: nessuna
|
||||
Confine: blocchi `.layer` con `.layer-num`/`.layer-body` (righe 92-149, senza id)
|
||||
|
||||
• U-SERVICE-CONTINUITY.4 — Sezione 3 "Protezione da Abuso" (Rate Limiting)
|
||||
Mostra: tabella limiti: Login 5 tentativi/15 min per IP + lockout; API generiche 100 req/ora per chiave/utente; Password reset 3 req/ora per email; Webhook esterni 50 req/min per IP
|
||||
Azioni: nessuna
|
||||
Dati da: nessuna
|
||||
Confine: `h2` "3. Protezione da Abuso" (riga 151, senza id)
|
||||
|
||||
• U-SERVICE-CONTINUITY.5 — Sezione 4 "Modalità Manutenzione"
|
||||
Mostra: procedura automatica in 5 passi (flag `/tmp/maintenance-NIS2.flag`, pagina di manutenzione Apache, applicazione fix, rimozione flag, redirect automatico); box di avvertenza "Nessun intervento manuale richiesto"
|
||||
Azioni: nessuna
|
||||
Dati da: nessuna
|
||||
Confine: `h2` "4. Modalità Manutenzione" (riga 164, senza id)
|
||||
|
||||
• U-SERVICE-CONTINUITY.6 — Sezione 5 "Matrice Rischi e Mitigazione"
|
||||
Mostra: tabella a 5 colonne (Scenario, Probabilità, Impatto, Mitigazione, Recovery) con 7 scenari: crash singolo servizio, database restart, AI non disponibile, disco pieno, SSL scaduto, attacco brute force, errore deployment; badge colorati Bassa/Media (probabilità) e Basso/Medio/Alto (impatto)
|
||||
Azioni: nessuna
|
||||
Dati da: nessuna
|
||||
Confine: `h2` "5. Matrice Rischi e Mitigazione" (riga 178, senza id)
|
||||
|
||||
• U-SERVICE-CONTINUITY.7 — Sezione 6 "Service Level Agreement"
|
||||
Mostra: tabella Metrica/Target/Misurazione: uptime 99.9% (8.7h downtime/anno), recovery da crash < 30 secondi, recovery da aggiornamento < 5 minuti, rilevamento downtime < 5 minuti, tempo risposta API p95 < 500ms
|
||||
Azioni: nessuna
|
||||
Dati da: nessuna
|
||||
Confine: `h2` "6. Service Level Agreement" (riga 193, senza id)
|
||||
|
||||
• U-SERVICE-CONTINUITY.8 — Sezione 7 "Checklist Operativa" + footer
|
||||
Mostra: checklist "Verifica automatica (quotidiana)" (container healthy, campanella AgileHub, email alert) e "Prima di un aggiornamento manuale" (4 passi con `docker compose ps` / `pm2 list`); footer con copyright, link nis2.agile.software e "Standard Continuità di Servizio v1.0 • Aprile 2026 • Agile Technology SRL"
|
||||
Azioni: click sul link https://nis2.agile.software nel footer
|
||||
Dati da: nessuna
|
||||
Confine: `h2` "7. Checklist Operativa" (riga 206) e `footer.doc-footer` (riga 222, senza id)
|
||||
|
||||
⟦ FINE · U-SERVICE-CONTINUITY ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
La pagina non contiene NESSUN id: tutte le ancore sono solo classi/struttura.
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Header documento | 62 | `nis2-continuity-header` |
|
||||
| Sezione 1 Architettura (h2) | 81 | `nis2-continuity-architettura` |
|
||||
| Sezione 2 Resilienza 7 livelli (h2) | 90 | `nis2-continuity-resilienza` |
|
||||
| Blocchi L1-L7 | 92-149 | `nis2-continuity-layer-1` … `nis2-continuity-layer-7` |
|
||||
| Sezione 3 Rate limiting (h2) | 151 | `nis2-continuity-rate-limiting` |
|
||||
| Sezione 4 Manutenzione (h2) | 164 | `nis2-continuity-manutenzione` |
|
||||
| Sezione 5 Matrice rischi (h2) | 178 | `nis2-continuity-matrice-rischi` |
|
||||
| Sezione 6 SLA (h2) | 193 | `nis2-continuity-sla` |
|
||||
| Sezione 7 Checklist (h2) | 206 | `nis2-continuity-checklist` |
|
||||
| Footer documento | 222 | `nis2-continuity-footer` |
|
||||
@@ -0,0 +1,51 @@
|
||||
# MAPPA-LOGICA · Pannello Amministrazione
|
||||
|
||||
⟦ INIZIO · U-ADMIN-INDEX · Videata "Pannello Amministrazione" ⟧
|
||||
File: public/admin/index.html · URL: /admin/index.html · Scopo: dashboard di amministrazione piattaforma — KPI globali su organizzazioni, utenti, assessment, incidenti, rischi e AI, distribuzione piani di abbonamento, collegamenti rapidi alle gestioni · Profili: solo `super_admin` (check `api.getMe()`: se `role !== 'super_admin'` notifica "Accesso non autorizzato..." e redirect a /dashboard.html dopo 1,5s, righe 327-339)
|
||||
|
||||
• U-ADMIN-INDEX.1 — Header pagina
|
||||
Mostra: titolo "Pannello Amministrazione" + badge rosso "Super Admin"
|
||||
Azioni: nessuna
|
||||
Dati da: nessuna
|
||||
Confine: `header.content-header` (riga 191, senza id)
|
||||
|
||||
• U-ADMIN-INDEX.2 — Riga statistiche 1 (organizzazioni e utenti)
|
||||
Mostra: 4 card KPI: "Totale Organizzazioni", "Organizzazioni Attive", "Totale Utenti", "Utenti Attivi" (valori "--" finché non caricati)
|
||||
Azioni: nessuna (solo lettura)
|
||||
Dati da: GET /api/admin/stats (campi `total_organizations`, `active_organizations`, `total_users`, `active_users`)
|
||||
Confine: `#stats-row-1` (riga 200); valori `#stat-total-orgs`, `#stat-active-orgs`, `#stat-total-users`, `#stat-active-users`; etichette `#lbl-total-orgs`, `#lbl-active-orgs`, `#lbl-total-users`, `#lbl-active-users`
|
||||
|
||||
• U-ADMIN-INDEX.3 — Riga statistiche 2 (attività compliance)
|
||||
Mostra: 4 card KPI: "Assessment Completati", "Incidenti Aperti", "Totale Rischi", "Interazioni AI"
|
||||
Azioni: nessuna
|
||||
Dati da: GET /api/admin/stats (campi `completed_assessments`, `open_incidents`, `total_risks`, `ai_interactions`)
|
||||
Confine: `#stats-row-2` (riga 232); valori `#stat-assessments`, `#stat-incidents`, `#stat-risks`, `#stat-ai`; etichette `#lbl-assessments`, `#lbl-incidents`, `#lbl-risks`, `#lbl-ai`
|
||||
|
||||
• U-ADMIN-INDEX.4 — Card "Distribuzione Piani"
|
||||
Mostra: grafico a barre verticali con conteggio organizzazioni per piano: Free (grigio), Professional (blu), Enterprise (viola); spinner durante il caricamento; `aria-label` descrittivo per accessibilità
|
||||
Azioni: nessuna (grafico statico renderizzato da `renderPlansChart`)
|
||||
Dati da: GET /api/admin/stats (campo `plans_distribution`: array di `{subscription_plan, count}`)
|
||||
Confine: `#plans-chart` (riga 269)
|
||||
|
||||
• U-ADMIN-INDEX.5 — Card "Gestione Piattaforma" (collegamenti rapidi)
|
||||
Mostra: 2 card-link: "Gestisci Organizzazioni" ("Visualizza e gestisci tutte le organizzazioni registrate sulla piattaforma.") e "Gestisci Utenti" ("Visualizza e gestisci tutti gli utenti registrati sulla piattaforma.")
|
||||
Azioni: click → naviga a /admin/organizations.html oppure /admin/users.html
|
||||
Dati da: nessuna
|
||||
Confine: `nav.quick-links-grid[aria-label="Collegamenti rapidi gestione piattaforma"]` (riga 281, senza id); singole card `a.quick-link-card` (righe 282 e 291, senza id)
|
||||
|
||||
• U-ADMIN-INDEX.6 — Sidebar di navigazione
|
||||
Mostra: sidebar Bootstrap Italia condivisa dell'app (iniettata da `loadSidebar()` di /js/common-bi.js)
|
||||
Azioni: navigazione app
|
||||
Dati da: nessuna
|
||||
Confine: `#sidebar` (riga 188)
|
||||
|
||||
⟦ FINE · U-ADMIN-INDEX ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Header pagina con badge Super Admin | 191 | `nis2-admin-header` |
|
||||
| Nav collegamenti rapidi | 281 | `nis2-admin-quick-links` |
|
||||
| Card-link "Gestisci Organizzazioni" | 282 | `nis2-admin-link-organizations` |
|
||||
| Card-link "Gestisci Utenti" | 291 | `nis2-admin-link-users` |
|
||||
| Card "Distribuzione Piani" (contenitore card) | 264 | `nis2-admin-plans-card` |
|
||||
@@ -0,0 +1,39 @@
|
||||
# MAPPA-LOGICA · Gestione Organizzazioni (admin)
|
||||
|
||||
⟦ INIZIO · U-ADMIN-ORGS · Videata "Gestione Organizzazioni" (admin) ⟧
|
||||
File: public/admin/organizations.html · URL: /admin/organizations.html · Scopo: elenco paginato in sola lettura di TUTTE le organizzazioni registrate sulla piattaforma con classificazione NIS2, membri, ultimo score, piano e stato · Profili: solo `super_admin` (check `api.getMe()`: se `role !== 'super_admin'` notifica "Accesso non autorizzato." e redirect a /dashboard.html dopo 1,5s, righe 159-171)
|
||||
|
||||
• U-ADMIN-ORGS.1 — Header pagina e breadcrumb
|
||||
Mostra: titolo "Gestione Organizzazioni" + badge rosso "Super Admin"; breadcrumb "Amministrazione › Organizzazioni"
|
||||
Azioni: click "Amministrazione" → torna a ../admin/index.html
|
||||
Dati da: nessuna
|
||||
Confine: `header.content-header` (riga 110) e `nav.admin-breadcrumb[aria-label="Percorso di navigazione"]` (riga 119), entrambi senza id
|
||||
|
||||
• U-ADMIN-ORGS.2 — Tabella organizzazioni
|
||||
Mostra: tabella con colonne: Nome, Settore (etichette italiane da mappa `sectorLabels`: Energia, Trasporti, Banche, Sanità, Acqua, Infrastrutture Digitali, Pubblica Amministrazione, Manifatturiero, Servizi Postali, Chimico, Alimentare, Rifiuti, Servizi ICT, Provider Digitali, Spazio, Ricerca, Altro), Tipo Entità (badge "Essenziale" rosso / "Importante" giallo / "N/A" grigio), Membri (conteggio), Ultimo Score (pallino colorato + percentuale arrotondata, "-" se assente), Piano (badge Free/Professional/Enterprise), Stato (pallino "Attiva" verde / "Inattiva" grigio), Data Creazione. Spinner durante il caricamento; stato vuoto "Nessuna organizzazione trovata / Le organizzazioni registrate appariranno qui."; in caso di errore "Errore nel caricamento" o "Errore di connessione".
|
||||
Azioni: nessuna azione per riga (vista in sola lettura, nessun bottone modifica/elimina)
|
||||
Dati da: GET /api/admin/organizations?page={n} (campi per riga: `name`, `sector`, `entity_type`, `member_count`, `last_score`, `subscription_plan`, `is_active`, `created_at`; `pagination`: `total`, `per_page` default 20, `page`)
|
||||
Confine: `#orgs-container` (riga 128); tabella e righe generate dinamicamente da `renderOrganizations` senza id
|
||||
|
||||
• U-ADMIN-ORGS.3 — Paginazione
|
||||
Mostra: se più pagine: "Visualizzati {start}-{end} di {total} organizzazioni" + bottoni "« Precedente" / "Successivo »" (disabilitati ai bordi); se una sola pagina: "Totale: {n} organizzazione/i"
|
||||
Azioni: "Precedente"/"Successivo" → `loadOrganizations(page±1)` ricarica la tabella
|
||||
Dati da: GET /api/admin/organizations?page={n} (stesso endpoint, parametro `page`)
|
||||
Confine: `.pagination` dentro `#orgs-container` (generata dinamicamente, righe 286-309 del sorgente; senza id)
|
||||
|
||||
• U-ADMIN-ORGS.4 — Sidebar di navigazione
|
||||
Mostra: sidebar Bootstrap Italia condivisa (iniettata da `loadSidebar()` di ../js/common-bi.js)
|
||||
Azioni: navigazione app
|
||||
Dati da: nessuna
|
||||
Confine: `#sidebar` (riga 107)
|
||||
|
||||
⟦ FINE · U-ADMIN-ORGS ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Header pagina | 110 | `nis2-admin-orgs-header` |
|
||||
| Breadcrumb | 119 | `nis2-admin-orgs-breadcrumb` |
|
||||
| Tabella organizzazioni (generata in JS) | 228-229 | `nis2-admin-orgs-table` |
|
||||
| Bottone paginazione "Precedente" | 293 | `nis2-admin-orgs-prev` |
|
||||
| Bottone paginazione "Successivo" | 296 | `nis2-admin-orgs-next` |
|
||||
@@ -0,0 +1,53 @@
|
||||
# MAPPA-LOGICA · Gestione Utenti (admin)
|
||||
|
||||
⟦ INIZIO · U-ADMIN-USERS · Videata "Gestione Utenti" (admin) ⟧
|
||||
File: public/admin/users.html · URL: /admin/users.html · Scopo: elenco paginato di tutti gli utenti della piattaforma con ruolo, organizzazioni di appartenenza, ultimo login; attivazione/disattivazione account e impersonificazione (login come l'utente per 1 ora) · Profili: solo `super_admin` (check `api.getMe()`: se `role !== 'super_admin'` notifica "Accesso non autorizzato." e redirect a ../dashboard.html dopo 1,5s, righe 181-193)
|
||||
|
||||
• U-ADMIN-USERS.1 — Header pagina e breadcrumb
|
||||
Mostra: titolo "Gestione Utenti" + badge rosso "Super Admin"; breadcrumb "Amministrazione › Utenti"
|
||||
Azioni: click "Amministrazione" → torna a ../admin/index.html
|
||||
Dati da: nessuna
|
||||
Confine: `header.content-header` (riga 132) e `nav.admin-breadcrumb[aria-label="Percorso di navigazione"]` (riga 141), entrambi senza id
|
||||
|
||||
• U-ADMIN-USERS.2 — Tabella utenti
|
||||
Mostra: tabella con colonne: Nome, Email, Ruolo (badge colorato; etichette: Super Admin, Amministratore, Compliance Manager, Membro CDA, Auditor, Dipendente), Organizzazioni (tag multipli, "-" se nessuna), Ultimo Login (data/ora oppure "Mai"), Attivo (toggle switch), Data Creazione, Azioni (bottone "Impersonate"). Spinner durante il caricamento (`aria-live="polite"` sul contenitore); stato vuoto "Nessun utente trovato / Gli utenti registrati appariranno qui."; errori "Errore nel caricamento" / "Errore di connessione".
|
||||
Azioni: vedi U-ADMIN-USERS.3 (toggle) e U-ADMIN-USERS.4 (impersonate)
|
||||
Dati da: GET /api/admin/users?page={n} (campi per riga: `full_name`, `email`, `role`, `organizations` lista CSV, `last_login_at`, `is_active`, `created_at`, `id`; `pagination`: `total`, `per_page` default 20, `page`)
|
||||
Confine: `#users-container` (riga 150); tabella generata dinamicamente da `renderUsers` senza id
|
||||
|
||||
• U-ADMIN-USERS.3 — Toggle "Attivo" per utente
|
||||
Mostra: interruttore on/off per riga (verde = attivo); disabilitato per gli utenti `super_admin`; con etichette ARIA accessibili ("Attiva/Disattiva utente {email}") e focus visibile WCAG
|
||||
Azioni: cambio stato → `toggleUserActive(userId, checked)`: PUT con `{is_active: 1|0}`; al successo notifica "Utente attivato/disattivato con successo."; in caso di errore notifica e ricarica la pagina corrente per resettare lo stato
|
||||
Dati da: PUT /api/admin/users/{userId} (body `{is_active}`)
|
||||
Confine: `label.active-toggle` con `input[type=checkbox]` per riga (generati in JS, righe 286-290 del sorgente; senza id — selezionabili solo per posizione di riga)
|
||||
|
||||
• U-ADMIN-USERS.4 — Azione "Impersonate"
|
||||
Mostra: bottone "Impersonate" con icona scambio e tooltip "Entra come questo utente per 1 ora"; visibile solo per utenti NON super_admin e attivi ("-" negli altri casi)
|
||||
Azioni: click → `confirm('Entrare come {email} per 1 ora?...')`; se confermato POST con `{user_id}`; al successo salva la sessione originale in sessionStorage (`nis2_impersonate_origin_token`, `nis2_impersonate_origin_refresh`, `nis2_impersonate_target_email`), sostituisce il token con quello impersonato (senza refresh token) e naviga a ../dashboard.html; il ritorno alla propria sessione avviene col logout
|
||||
Dati da: POST /api/auth/impersonate (risposta: `data.access_token`)
|
||||
Confine: bottoni `button.btn.btn-secondary.btn-sm` con `onclick="impersonateUser(...)"` generati in JS (riga 295 del sorgente; senza id)
|
||||
|
||||
• U-ADMIN-USERS.5 — Paginazione
|
||||
Mostra: se più pagine: "Visualizzati {start}-{end} di {total} utenti" + bottoni "« Precedente" / "Successivo »" (disabilitati ai bordi); se una sola pagina: "Totale: {n} utente/i"
|
||||
Azioni: "Precedente"/"Successivo" → `loadUsers(page±1)` ricarica la tabella
|
||||
Dati da: GET /api/admin/users?page={n}
|
||||
Confine: `.pagination` dentro `#users-container` (generata dinamicamente, righe 314-336 del sorgente; senza id)
|
||||
|
||||
• U-ADMIN-USERS.6 — Sidebar di navigazione
|
||||
Mostra: sidebar Bootstrap Italia condivisa (iniettata da `loadSidebar()` di ../js/common-bi.js)
|
||||
Azioni: navigazione app
|
||||
Dati da: nessuna
|
||||
Confine: `#sidebar` (riga 129)
|
||||
|
||||
⟦ FINE · U-ADMIN-USERS ⟧
|
||||
|
||||
## ID STABILI MANCANTI (da aggiungere)
|
||||
| Elemento | Riga | Id proposto |
|
||||
|---|---|---|
|
||||
| Header pagina | 132 | `nis2-admin-users-header` |
|
||||
| Breadcrumb | 141 | `nis2-admin-users-breadcrumb` |
|
||||
| Tabella utenti (generata in JS) | 240-242 | `nis2-admin-users-table` |
|
||||
| Toggle attivo per riga (input checkbox) | 288 | `nis2-admin-users-toggle-{userId}` |
|
||||
| Bottone "Impersonate" per riga | 295 | `nis2-admin-users-impersonate-{userId}` |
|
||||
| Bottone paginazione "Precedente" | 321 | `nis2-admin-users-prev` |
|
||||
| Bottone paginazione "Successivo" | 324 | `nis2-admin-users-next` |
|
||||
@@ -0,0 +1,547 @@
|
||||
# SELETTORI_DEMO — Registry canonico NIS2 (campo → selettore CSS)
|
||||
> Fonte di verità per: manifest tour, demo-selectors.js (whitelist SPA), RAG persona.
|
||||
> Regola 3-way: DOM ↔ demo-selectors.js ↔ questo file devono restare allineati.
|
||||
>
|
||||
> Compilato dal gate A3 (2026-06-12) a partire dalle 22 mappe-logiche (sezioni Confine + Azioni).
|
||||
> Tutti i selettori sono stati verificati contro gli HTML/JS reali in `public/` (campionamento avversariale ~38 selettori + 18 endpoint: 0 rotti).
|
||||
> Convenzioni note: `(runtime)` = elemento generato via JS, esiste solo dopo l'apertura di modale/vista; `{id}`/`{tipo}` = porzione dinamica.
|
||||
|
||||
## dashboard (/dashboard.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Data corrente header | `#header-date` | Valorizzata da JS (`toLocaleDateString('it-IT')`) |
|
||||
| Gauge avanzamento misure Art.21 | `#compliance-gauge` | SVG renderizzato via JS |
|
||||
| Griglia 4 KPI | `#stats-grid` | |
|
||||
| KPI Rischi Aperti | `#stat-risks` | |
|
||||
| KPI Incidenti Attivi | `#stat-incidents` | |
|
||||
| KPI Policy Approvate | `#stat-policies` | |
|
||||
| KPI Formazione % | `#stat-training` | |
|
||||
| Lista Prossime Scadenze (max 5) | `#deadlines-list` | Badge Urgente ≤3gg, Prossima ≤7gg |
|
||||
| Lista Attività Recenti (max 8) | `#activity-list` | |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Azioni Rapide (3 bottoni) | `.quick-actions .quick-action-btn` | Naviga ad assessment/incidents o apre modale policy AI |
|
||||
| Select categoria policy AI | `#ai-policy-category` (runtime) | In `#modal-overlay`; "Genera" → POST /api/policies/ai-generate |
|
||||
|
||||
## assessment (/assessment.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Schermata iniziale | `#assessment-start` | |
|
||||
| Tabella assessment esistenti | `#existing-assessments` | |
|
||||
| Wizard | `#assessment-wizard` | |
|
||||
| Indicatore step (10 categorie) | `#steps-indicator` | Step generati via JS con classe `.step` |
|
||||
| Barra avanzamento | `#progress-bar-fill` | |
|
||||
| % avanzamento / contatori | `#progress-pct`, `#progress-answered`, `#progress-total` | |
|
||||
| Titolo categoria / contatore domanda | `#category-title`, `#question-counter` | |
|
||||
| Area domanda corrente | `#question-area` | Campi interni generati via JS |
|
||||
| Contenitore risultati | `#assessment-results` | |
|
||||
| Gauge punteggio complessivo | `#results-gauge` | |
|
||||
| Barre punteggio per categoria | `#category-scores` | Verde ≥60%, giallo ≥40%, rosso <40% |
|
||||
| Card Analisi AI | `#ai-analysis-card`, `#ai-analysis-content` | |
|
||||
| Card generazione NCR | `#ncr-generation-card`, `#ncr-generation-result` | |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Analisi AI (header) | `#btn-ai-analyze` | POST /api/assessments/{id}/ai-analyze (nascosto fuori dai risultati) |
|
||||
| Nuovo Assessment | `#btn-new-assessment` | POST /api/assessments/create + apre wizard |
|
||||
| Precedente / Successiva | `#btn-prev`, `#btn-next` | Su ultima domanda `#btn-next` diventa "Completa Assessment" |
|
||||
| Slider maturità | `#maturity-slider` (runtime), valore `#maturity-value` (runtime) | Dentro `#question-area` |
|
||||
| Note / Evidenza | `#question-notes`, `#question-evidence` (runtime) | |
|
||||
| Genera NCR dai gap | `#btn-generate-ncr` | POST /api/ncr/from-assessment |
|
||||
|
||||
## acn-gap (/acn-gap.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Intro normativa | `#acn-intro` | |
|
||||
| Schermata START | `#acn-start` | |
|
||||
| Badge livello + perimetro | `#acn-level-info` | Importanti 37/87, essenziali 43/116 |
|
||||
| Lista assessment esistenti | `#acn-existing` | |
|
||||
| Catalogo requisiti (card + body) | `#acn-catalog`, `#acn-catalog-body` | Cache `window._acnCatalog` |
|
||||
| Wizard | `#acn-wizard` | |
|
||||
| Titolo / badge livello wizard | `#acn-wizard-title`, `#acn-wizard-level` | |
|
||||
| Progress bar / contatori | `#acn-bar-fill`, `#acn-answered`, `#acn-total` | |
|
||||
| Hint salvataggio | `#acn-savehint` | aria-live="polite" |
|
||||
| Accordion funzioni/requisiti | `#acn-functions` | |
|
||||
| Messaggio wizard | `#acn-wizard-msg` | |
|
||||
| Risultati | `#acn-results` | |
|
||||
| Punteggio complessivo | `#acn-overall` | Verde ≥80, lime ≥60, ambra ≥40, rosso <40 |
|
||||
| Punteggi per funzione GV/ID/PR/DE/RS/RC | `#acn-func-scores` | |
|
||||
| Requisiti non conformi | `#acn-gaps` | |
|
||||
| Card Analisi AI | `#acn-ai-card`, `#acn-ai-body` | |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Analisi AI dei gap (header) | `#btn-ai-analyze` | POST /api/acn-gap/{id}/aiAnalyze — NB: stesso id di assessment.html, pagina diversa |
|
||||
| Nuova Gap Analysis ACN | `#btn-new-acn` | POST /api/acn-gap/create |
|
||||
| Pillole risposta requisito | `.acn-opt[data-key][data-val]` (runtime) | Autosave batch debounce 700ms |
|
||||
| Calcola punteggio e completa | `#btn-acn-complete` | POST /api/acn-gap/{id}/complete |
|
||||
|
||||
## risks (/risks.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Vista Tabella | `#view-table` | |
|
||||
| Corpo tabella rischi | `#risks-table-body` | Badge score: <10 low, 10-14 medium, 15-19 high, ≥20 critical |
|
||||
| Vista Matrice 5x5 | `#view-matrix`, griglia `#risk-matrix-grid` | |
|
||||
| Vista FAIR | `#view-fair` | |
|
||||
| Risultati FAIR | `#fair-result`; `#fair-p10`, `#fair-p50`, `#fair-p90`, `#fair-mean`, `#fair-lef`, `#fair-histogram`, `#fair-histogram-labels` | |
|
||||
| ALE di portafoglio / registro | `#fair-portfolio`, `#fair-register-body` | |
|
||||
| Vista KRI | `#view-kri`; riepilogo `#kri-summary`; tabella `#kri-table-body` | |
|
||||
| Vista Dettaglio rischio | `#view-detail` | Contenuto generato via JS |
|
||||
| Anteprima score modale | `#score-preview-value`, `#likelihood-value`, `#impact-value`, `#likelihood-detail`, `#impact-detail` (runtime) | Scala ISO 27005 |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Toggle 4 viste | `#view-toggle` (bottoni interni senza id) | `switchView()` Tabella/Matrice/FAIR/KRI |
|
||||
| AI Suggerisci | `#btn-ai-suggest` | POST /api/risks/ai-suggest → modale suggerimenti |
|
||||
| Filtri tabella | `#filter-category`, `#filter-status` | Ricarica GET /api/risks/list |
|
||||
| Select rischio FAIR | `#fair-risk-select` | |
|
||||
| Input FAIR | `#fair-tef-min`, `#fair-tef-ml`, `#fair-tef-max`, `#fair-vuln`, `#fair-lm-min`, `#fair-lm-ml`, `#fair-lm-max` | |
|
||||
| Calcola ALE | `#btn-run-fair` | POST /api/risks/{id}/fair |
|
||||
| Torna alla lista (dettaglio) | `.detail-back` (runtime) | |
|
||||
| Campi modale rischio | `#risk-title`, `#risk-description`, `#risk-category`, `#risk-treatment`, `#risk-threat-source`, `#risk-vulnerability`, `#risk-likelihood`, `#risk-impact`, `#risk-owner`, `#risk-review-date`, `#risk-nis2-article` (runtime) | POST create / PUT {id} |
|
||||
| Campi modale KRI | `#kri-name`, `#kri-desc`, `#kri-cat`, `#kri-unit`, `#kri-cur`, `#kri-target`, `#kri-warn`, `#kri-crit`, `#kri-dir` (runtime) | POST/PUT /api/risks/kri |
|
||||
| Campi modale trattamento | `#treatment-description`, `#treatment-responsible`, `#treatment-due-date`, `#treatment-status`, `#treatment-notes` (runtime) | POST /api/risks/{id}/treatments |
|
||||
|
||||
## incidents (/incidents.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Vista Lista | `#view-list` | |
|
||||
| Corpo tabella incidenti | `#incidents-table-body` | 3 dot Art.23 (verde inviato, rosso scaduto, giallo <6h, grigio in attesa) |
|
||||
| Vista Dettaglio | `#view-detail` | Contenuto via JS; timeline `.nis2-timeline` / `.event-timeline` |
|
||||
| Esito significatività | `#significance-result` (runtime) | Box rosso ≥1 criterio / verde 0 criteri |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Filtri lista | `#filter-classification`, `#filter-severity`, `#filter-status` | Ricarica GET /api/incidents/list |
|
||||
| Campi modale registrazione | `#inc-title`, `#inc-description`, `#inc-classification`, `#inc-severity`, `#inc-detected-at`, `#inc-significant`, `#inc-affected-services`, `#inc-affected-users`, `#inc-cross-border`, `#inc-malicious` (runtime) | POST /api/incidents/create |
|
||||
| Checkbox criteri Art.23 | `#crit-users`, `#crit-duration`, `#crit-crossborder`, `#crit-attack`, `#crit-financial` (runtime) | `evalSignificance()` |
|
||||
| Campi modale aggiornamento | `#upd-status`, `#upd-root-cause`, `#upd-remediation`, `#upd-lessons` (runtime) | PUT /api/incidents/{id} |
|
||||
| Campi modale evento timeline | `#event-type`, `#event-description` (runtime) | POST /api/incidents/{id}/timeline |
|
||||
| Torna alla lista (dettaglio) | `.detail-back` (runtime) | |
|
||||
|
||||
## policies (/policies.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Tab Elenco | `#tab-list`; tabella `#policies-table` | |
|
||||
| Vista dettaglio | `#policy-detail-view` | Banner bozza AI: `#ai-draft-warning-{id}` (runtime) |
|
||||
| Tab Template | `#tab-templates`; griglia `#templates-grid` | |
|
||||
| Anteprima AI | `#ai-preview-container` (runtime) | |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Filtri elenco | `#filter-category`, `#filter-status` | GET /api/policies/list |
|
||||
| Form policy | `#policy-form`; `#form-title`, `#form-category`, `#form-nis2-article`, `#form-version`, `#form-review-date`, `#form-content` (runtime) | POST create / PUT {id} |
|
||||
| Generazione AI | `#ai-category`, `#ai-generate-btn` (runtime) | POST /api/policies/ai-generate |
|
||||
|
||||
## supply-chain (/supply-chain.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| KPI overview | `#risk-overview`; `#stat-total`, `#stat-critical`, `#stat-expiring`, `#stat-avg-score` | Scadenza contratti = 90 giorni, calcolo client-side |
|
||||
| Grafico criticità | `#criticality-chart`; barre `#chart-bar-critical|high|medium|low`; valori `#chart-val-critical|high|medium|low` | |
|
||||
| Sezione elenco | `#suppliers-list-section`; tabella `#suppliers-table` | |
|
||||
| Vista dettaglio fornitore | `#supplier-detail-view` | Contenuto via JS |
|
||||
| Score live valutazione | `#assessment-score-preview`, `#assessment-live-score` (runtime) | Sì=100, Parziale=50, No=0, media pesata |
|
||||
| Esito import | `#importResult` (runtime) | |
|
||||
| Lista categorie | `#categories-list-body` (runtime) | |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Filtri elenco | `#filter-criticality`, `#filter-status` | Filtro client-side |
|
||||
| Form fornitore | `#supplier-form`; `#form-name`, `#form-vat`, `#form-contact-name`, `#form-contact-email`, `#form-service-type`, `#form-criticality`, `#form-category`, `#form-service-desc`, `#form-contract-start`, `#form-contract-expiry`, `#form-notes` (runtime) | POST create / PUT {id} |
|
||||
| Domande valutazione (10) | `#assessment-questions` (runtime, pill Sì/Parziale/No) | POST /api/supply-chain/{id}/assess |
|
||||
| Import CSV | overlay `#importModalDyn` (runtime); `#importFile`, `#importCsv`, `#importRunBtn` | POST /api/supply-chain/import (max 1000 righe) |
|
||||
| Form categoria | `#cat-name`, `#cat-desc` (runtime) | POST/PUT/DELETE /api/supply-chain/categories |
|
||||
|
||||
## assets (/assets.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Card statistiche | `#asset-stats`; `#stat-total`, `#stat-types`, `#stat-type-chips`, `#stat-critical`, `#stat-decommissioned` | Riflettono il filtro corrente |
|
||||
| Contenitore tabella | `#assets-container` | Render via JS |
|
||||
| Riepilogo scoring | `#score-preview`, `#score-total`, `#score-class` (runtime) | Critico ≥80, Alto ≥60, Medio ≥40, Basso ≥20; rilevante da 40 |
|
||||
| Anteprima import | `#imp-preview` (runtime) | |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Filtri | `#filter-type`, `#filter-criticality`, `#filter-status` | GET /api/assets/list con query |
|
||||
| Form asset | `#asset-name`, `#asset-type`, `#asset-category`, `#asset-description`, `#asset-criticality`, `#asset-status`, `#asset-owner`, `#asset-location`, `#asset-ip`, `#asset-vendor`, `#asset-version`, `#asset-serial`, `#asset-purchase-date`, `#asset-warranty` (runtime) | POST create / PUT {id} |
|
||||
| Import CSV/CMDB | `#imp-file`, `#imp-csv` (runtime) | POST /api/assets/import |
|
||||
| Select criteri scoring (6) | `select.score-criterion[data-key]` (runtime) | POST /api/assets/{id}/score |
|
||||
|
||||
## training (/training.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Tab Corsi | `#tab-courses`; griglia `#courses-grid` | |
|
||||
| Tab Assegnazioni | `#tab-assignments`; `#assignments-container` | |
|
||||
| Tab Compliance | `#tab-compliance`; `#compliance-container` | Barra verde ≥80%, giallo ≥50%, rosso <50% |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Form nuovo corso | `#course-title`, `#course-description`, `#course-target-role`, `#course-duration`, `#course-nis2-article`, `#course-passing-score`, `#course-mandatory` (runtime) | POST /api/training/courses (soglia default 70) |
|
||||
| Form assegnazione | `#assign-course-id`, `#assign-due-date`, checkbox `input.assign-user-cb` (runtime) | POST /api/training/assign |
|
||||
|
||||
## reports (/reports.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Tab Report | `#tab-report`; `#report-container` | Barra verde ≥80%, giallo ≥50%, rosso <50% |
|
||||
| Tab Controlli | `#tab-controls`; `#controls-container` | |
|
||||
| Tab Audit Log | `#tab-audit`; `#audit-container` | Paginato 25/pagina |
|
||||
| Tab ISO 27001 | `#tab-iso`; `#iso-container` | Mapping NIS2 ↔ ISO 27001:2022 |
|
||||
| Tab Monitoraggio Continuo | `#tab-monitoring`; `#monitoring-container` | Evidence Automation |
|
||||
| Tab Requisiti ACN | `#tab-acn`; `#acn-container` | Determina ACN 164179/2025 |
|
||||
| Valore live slider controllo | `#ctrl-impl-pct-val` (runtime) | |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Campi modale controllo | `#ctrl-status`, `#ctrl-impl-pct`, `#ctrl-evidence`, `#ctrl-responsible`, `#ctrl-next-review` (runtime) | PUT /api/audit/controls/{id} |
|
||||
|
||||
## isms (/isms.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Hint salvataggio | `#isms-savehint` | aria-live="polite" |
|
||||
| Intro / disclaimer | `.isms-intro`, `.isms-disclaimer` | Solo classi (vedi ID da aggiungere) |
|
||||
| Barra step wizard | `#isms-steps`; step `#step-0` … `#step-5` (runtime, isms.js) | Classi `active`/`done` |
|
||||
| Pannelli step | `#panel-0` … `#panel-5` | |
|
||||
| Lista ruoli | `#roles-list` | |
|
||||
| Statistiche / gruppi SoA | `#soa-stats`, `#soa-groups`; controlli `.soa-ctrl[data-code]` (runtime) | 111 controlli 27001/27017/27018 |
|
||||
| Hint generazione AI / lista documenti | `#aigen-hint`, `#docs-list` | |
|
||||
| Readiness | `#readiness-pct`, `#readiness-checklist` | |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Step 1 contesto | `#f-scope`, `#f-ctx-int`, `#f-ctx-ext`, `#f-parties`, `#f-boundaries`, `#f-exclusions`; flag cloud `#f-uses-cloud`, `#f-cloud-provider`, `#f-pii-cloud` | POST /api/isms/model |
|
||||
| Step 2 ruoli | `#r-name`, `#r-resp`, `#r-raci` | POST/DELETE /api/isms/roles |
|
||||
| Step 3 risk | `#f-method`, `#f-objectives` | POST /api/isms/model |
|
||||
| Step 4 SoA | stati/checkbox dentro `.soa-ctrl[data-code]` (runtime) | PUT /api/isms/soa, autosave debounce 600ms; toggle Applicabile ricarica SoA dopo 400ms |
|
||||
| Step 5 documenti | `#d-type`, `#btn-aigen` | POST /api/isms/documents/ai-generate |
|
||||
|
||||
## normative (/normative.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Statistiche | `#stats-grid` | |
|
||||
| Avanzamento ACK | `#ack-pct`, `#ack-bar` | |
|
||||
| Lista aggiornamenti | `#updates-container`; card `#update-{id}` (runtime) | |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Filtri | `#filter-source`, `#filter-impact`, `#filter-action` | GET /api/normative/list |
|
||||
| Note presa visione | `#ack-notes` (runtime) | POST /api/normative/{id}/ack (403 se non org_admin/compliance_manager) |
|
||||
|
||||
## whistleblowing (/whistleblowing.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Banner Art.32 | `.art32-banner` | Art. 32 D.Lgs. 138/2024 — classe, nessun id |
|
||||
| Statistiche | `#stats-grid` | 403 per ruoli non gestori |
|
||||
| Vista Lista | `#view-list`; `#reports-container` | |
|
||||
| Vista Track | `#view-track`; risultato `#track-result` | |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Filtri lista | `#filter-status`, `#filter-priority`, `#filter-category` | GET /api/whistleblowing/list |
|
||||
| Form segnalazione | `#view-submit`; `#is-anonymous`, `#submit-form`, `#rep-category`, `#rep-title`, `#rep-description`, `#rep-priority`, `#rep-article`, `#contact-email-group`, `#rep-email` | POST /api/whistleblowing/submit (no auth API) |
|
||||
| Tracking anonimo | `#track-token` | GET /api/whistleblowing/track-anonymous?token= |
|
||||
| Modale gestione | `#modal-status`, `#modal-notes` (runtime) | PUT /api/whistleblowing/{id} |
|
||||
|
||||
## kb (/kb.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Card form upload | `#kb-form-card` | Nascosta di default |
|
||||
| Status indicizzazione | `#kb-status` | |
|
||||
| Lista documenti | `#kb-doc-list` (dentro card `.kb-doc-list`) | |
|
||||
| Risultati search | `#kb-search-results` | |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Carica documento (toggle form) | `#btn-kb-upload` | `setupScopeForUser()` |
|
||||
| Campi upload | `#kb-title`, `#kb-entity-type`, `#kb-text` | POST /api/knowledgebase/ingest |
|
||||
| Radio scope | `input[name="kb-scope"]`; label `[data-scope-opt="SYSTEM|FIRM|ORG"]` | Visibilità per ruolo (enforcement backend) |
|
||||
| Condivisione FIRM | `#kb-share-block`, multi-select `#kb-shared-with` | GET /api/knowledgebase/firmOrgs |
|
||||
| Indicizza / Annulla | `#btn-kb-submit`, `#btn-kb-cancel` | |
|
||||
| Elimina documento | `[data-del-id="{id}"]` (runtime, kb.js) | DELETE /api/knowledgebase/{id} |
|
||||
| Search semantica | `#kb-search-query`, `#btn-kb-search` | POST /api/knowledgebase/search (top 5) |
|
||||
|
||||
## cross-analysis (/cross-analysis.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Header portfolio | `#portfolio-header` | Solo consultant/super_admin |
|
||||
| Tab Chat | `#tab-chat`; `#chat-messages`, `#chat-empty` | Indicatore thinking `#think-{timestamp}` (runtime) |
|
||||
| Tab Storico | `#tab-history`; `#history-content` | Ultime 20 analisi, lazy |
|
||||
| Tab Portfolio dati | `#tab-portfolio`; `#portfolio-content` | |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Tab bar | `.tab-bar[role="tablist"] .tab-btn[aria-controls="tab-chat|tab-history|tab-portfolio"]` | `switchTab()` |
|
||||
| Domande rapide (6 chip) | `#quick-qs` (chip interne senza id) | Pre-compila `#chat-input` |
|
||||
| Input domanda / invio | `#chat-input`, `#btn-send` | POST /api/cross-analysis/analyze |
|
||||
|
||||
## settings (/settings.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Nome org header | `#header-org-name` | |
|
||||
| Tab Organizzazione | `#tab-org`; classificazione `#entity-classification`; piano `#subscription-plan` | |
|
||||
| Tab Profilo | `#tab-profile` | |
|
||||
| Indicatore forza password | `#pw-strength-bar`, `#pw-seg-1`…`#pw-seg-4`, `#pw-strength-text` | |
|
||||
| Tab Preferenze | `#tab-preferences`; conferma `#pref-saved-msg` | |
|
||||
| Tab Membri | `#tab-members`; `#members-container` | |
|
||||
| Tab Sicurezza | `#tab-security`; `#card-sessions`, `#sessions-container`, `#audit-log-container` | |
|
||||
| Tab API Keys | `#tab-apikeys`; `#apikeys-container`, `#available-scopes-container` | |
|
||||
| Tab Webhook | `#tab-webhooks`; `#webhooks-container`, `#deliveries-container` | |
|
||||
| Tab Branding | `#tab-branding`; conferma `#brand-saved-msg` | Solo super_admin/consultant |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Barra tab | `.settings-tabs .settings-tab` | ⚠ `switchTab()` seleziona per INDICE posizionale — non alterare ordine/numero bottoni |
|
||||
| Tab Branding (unico con id) | `#tab-btn-branding` | Mostrato via /api/auth/me |
|
||||
| Form organizzazione | `#org-form`; `#org-name`, `#org-sector`, `#org-vat`, `#org-fiscal`, `#org-employees`, `#org-turnover`, `#org-country`, `#org-city`, `#org-address`, `#org-website`, `#org-email`, `#org-phone`; `#btn-save-org` | PUT /api/organizations/{id} |
|
||||
| Adesione volontaria | `#org-voluntary` (runtime) | PUT immediato voluntary_compliance |
|
||||
| Form profilo | `#profile-form`; `#profile-email` (disabled), `#profile-name`, `#profile-phone`, `#profile-language`; `#btn-save-profile` | PUT /api/auth/profile |
|
||||
| Cambio password | `#password-form`; `#pw-current`, `#pw-new`, `#pw-confirm`; `#btn-change-pw` | POST /api/auth/change-password (logout dopo successo) |
|
||||
| Preferenze | `#preferences-form`; `#pref-lang`, `#pref-theme`, `#pref-tz`, `#pref-notif-email`, `#pref-notif-inapp`; `#pref-save-btn` | PUT /api/auth/preferences |
|
||||
| Invito membro | `#invite-email`, `#invite-role` (runtime) | POST /api/organizations/{orgId}/invite |
|
||||
| Disconnetti altre sessioni | `#revoke-all-btn` | DELETE /api/auth/sessions |
|
||||
| Nuova API Key | `#apikey-name`, `#apikey-scopes-checkboxes`, `#apikey-expires` (runtime) | POST /api/webhooks/api-keys (chiave one-time) |
|
||||
| Nuovo Webhook | `#wh-name`, `#wh-url` (runtime) | POST /api/webhooks/subscriptions (secret HMAC one-time) |
|
||||
| Branding | `#branding-form`; `#brand-name`, `#brand-logo`, `#brand-pri`, `#brand-sec`; `#brand-save-btn` | PUT /api/branding |
|
||||
|
||||
## companies (/companies.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Griglia card aziende | `#companies-grid`; card `.company-card[data-org-id]` | Solo ruolo consultant |
|
||||
| Elementi asincroni per card | `#score-row-{orgId}`, `#score-fill-{orgId}`, `#score-val-{orgId}`, `#stats-row-{orgId}`, `#stat-risks-{orgId}`, `#stat-incidents-{orgId}` (runtime) | |
|
||||
| Stato vuoto | `#companies-empty` | |
|
||||
| Sidebar | `#sidebar` | Iniettata da common-bi.js |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Ricerca azienda | `#search-input` | Filtro client-side su `data-name` |
|
||||
| Modale connettori | `#conn-modal` (runtime); righe `.conn-row[data-type]`; campi `.c-en`, `.c-tenant`, `.c-client` | GET/PUT /api/organizations/{orgId}/connectors |
|
||||
|
||||
## onboarding (/onboarding.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Stepper 4 passi | `#stepper`; passi `.stepper-step[data-step="1..4"]`; connettori `.stepper-connector[data-after]` | |
|
||||
| Pannelli step | `#step-1` … `#step-4` | |
|
||||
| Risultato ricerca P.IVA / spinner | `#s1-result`, `#s1-loading` | |
|
||||
| Banner fonte dati | `#data-source-banner`, `#data-source-text` | "Dati precompilati da CertiSource" |
|
||||
| Risultato classificazione | `#classification-result`; `#classification-icon`, `#classification-label`, `#classification-desc` | Calcolo client-side `classifyLocally()` |
|
||||
| Sezione volontaria | `#voluntary-section`, `#voluntary-card` | |
|
||||
| Riepilogo dati | `#sum-company`, `#sum-vat`, `#sum-sector`, `#sum-entity-type`, `#sum-employees`, `#sum-turnover` | |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| P.IVA + ricerca | `#s1-vat`, `#s1-fetch-btn`, continua `#s1-continue-btn` | POST /api/onboarding/fetch-company |
|
||||
| Form dati aziendali | `#company-name`, `#vat-number`, `#fiscal-code`, `#address`, `#city`, `#website`, `#company-email`, `#company-phone`, `#sector`, `#employee-count`, `#annual-turnover` | Validazione client-side |
|
||||
| Form profilo | `#full-name`, `#role`, `#user-phone` | |
|
||||
| Adesione volontaria | `#voluntary-checkbox` | `onVoluntaryChange()` |
|
||||
| Completa onboarding | `#complete-btn` | POST /api/onboarding/complete |
|
||||
|
||||
## service-continuity (/service-continuity.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Header documento | `header.doc-header` | ⚠ La pagina NON contiene alcun id: solo ancore strutturali/classi |
|
||||
| Blocchi resilienza L1-L7 | `.layer` (con `.layer-num`, `.layer-body`) | |
|
||||
| Footer documento | `footer.doc-footer` | |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| — (pagina statica, nessuna azione) | — | Unico link esterno nel footer |
|
||||
|
||||
## admin/index (/admin/index.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Riga KPI 1 | `#stats-row-1`; `#stat-total-orgs`, `#stat-active-orgs`, `#stat-total-users`, `#stat-active-users`; etichette `#lbl-total-orgs`, `#lbl-active-orgs`, `#lbl-total-users`, `#lbl-active-users` | Solo super_admin |
|
||||
| Riga KPI 2 | `#stats-row-2`; `#stat-assessments`, `#stat-incidents`, `#stat-risks`, `#stat-ai`; etichette `#lbl-assessments`, `#lbl-incidents`, `#lbl-risks`, `#lbl-ai` | |
|
||||
| Grafico piani | `#plans-chart` | role="img" con aria-label |
|
||||
| Sidebar | `#sidebar` | |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Collegamenti rapidi | `nav.quick-links-grid a.quick-link-card` | Naviga a organizations.html / users.html (senza id) |
|
||||
|
||||
## admin/organizations (/admin/organizations.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Contenitore tabella | `#orgs-container` | Tabella e paginazione generate via JS senza id |
|
||||
| Sidebar | `#sidebar` | |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Paginazione | `.pagination` dentro `#orgs-container` (runtime, bottoni senza id) | `loadOrganizations(page±1)` |
|
||||
|
||||
## admin/users (/admin/users.html)
|
||||
### Visualizzazione
|
||||
| Campo/Elemento | Selettore | Note |
|
||||
|---|---|---|
|
||||
| Contenitore tabella | `#users-container` | aria-live="polite" |
|
||||
| Sidebar | `#sidebar` | |
|
||||
### Azioni
|
||||
| Azione | Selettore | Effetto |
|
||||
|---|---|---|
|
||||
| Toggle attivo per riga | `label.active-toggle input[type=checkbox]` (runtime, senza id — solo per posizione) | PUT /api/admin/users/{id} {is_active} |
|
||||
| Impersonate | `button.btn.btn-secondary.btn-sm[onclick^="impersonateUser"]` (runtime, senza id) | POST /api/auth/impersonate (1h) |
|
||||
| Paginazione | `.pagination` dentro `#users-container` (runtime, senza id) | `loadUsers(page±1)` |
|
||||
|
||||
---
|
||||
|
||||
## ID STABILI DA AGGIUNGERE (consolidato)
|
||||
> Worklist per modifiche chirurgiche SOLO-ATTRIBUTO (aggiunta `id`/`data-*`, zero cambi di markup/logica).
|
||||
> Unione deduplicata delle sezioni "ID STABILI MANCANTI" delle 22 mappe. Nessun id proposto risulta duplicato cross-vista.
|
||||
> Esclusi: kb "Elimina documento" (ha già `data-del-id`, selettore stabile) e onboarding `#sector` (id già presente).
|
||||
|
||||
| Vista | Elemento | Riga | Id proposto |
|
||||
|---|---|---|---|
|
||||
| dashboard | Bottone "Nuovo Assessment" (azioni rapide) | ~91 | `nis2-dashboard-qa-assessment` |
|
||||
| dashboard | Bottone "Registra Incidente" (azioni rapide) | ~95 | `nis2-dashboard-qa-incidente` |
|
||||
| dashboard | Bottone "Genera Policy AI" (azioni rapide) | ~99 | `nis2-dashboard-qa-policy-ai` |
|
||||
| dashboard | Card "Azioni Rapide" | ~85 | `nis2-dashboard-quick-actions` |
|
||||
| dashboard | Card "Prossime Scadenze" (wrapper) | ~110 | `nis2-dashboard-card-scadenze` |
|
||||
| dashboard | Card "Attività Recenti" (wrapper) | ~120 | `nis2-dashboard-card-attivita` |
|
||||
| assessment | Bottone "Salva Progresso" (footer card domanda) | ~80 | `nis2-assessment-btn-salva` |
|
||||
| assessment | Bottone "Analisi AI" header card Risultati | ~97 | `nis2-assessment-btn-ai-risultati` |
|
||||
| acn-gap | Bottone "Consulta il catalogo dei requisiti" | ~75 | `nis2-acn-gap-btn-catalogo` |
|
||||
| acn-gap | Bottone "Torna all'inizio" (risultati) | ~134 | `nis2-acn-gap-btn-restart` |
|
||||
| risks | Bottone toggle "Tabella" | ~311 | `nis2-risks-toggle-tabella` |
|
||||
| risks | Bottone toggle "Matrice" | ~312 | `nis2-risks-toggle-matrice` |
|
||||
| risks | Bottone toggle "Quantitativo (FAIR)" | ~313 | `nis2-risks-toggle-fair` |
|
||||
| risks | Bottone toggle "KRI" | ~314 | `nis2-risks-toggle-kri` |
|
||||
| risks | Bottone "+ Nuovo Rischio" (header) | ~320 | `nis2-risks-btn-nuovo` |
|
||||
| risks | Bottone "+ Nuovo KRI" (vista KRI) | ~467 | `nis2-risks-btn-nuovo-kri` |
|
||||
| risks | Bottone "Torna alla lista" dettaglio (`.detail-back`, JS) | script ~918 | `nis2-risks-btn-back` |
|
||||
| incidents | Bottone "+ Nuovo Incidente" (header) | ~271 | `nis2-incidents-btn-nuovo` |
|
||||
| incidents | Bottone "Torna alla lista" dettaglio (`.detail-back`, JS) | script ~765 | `nis2-incidents-btn-back` |
|
||||
| incidents | Bottoni invio notifiche Art.23 (JS) | script ~919-921 | `nis2-incidents-btn-early-warning`, `nis2-incidents-btn-notifica-72h`, `nis2-incidents-btn-report-finale` |
|
||||
| policies | Pulsante "Genera con AI" (header) | ~251 | `nis2-policies-btn-ai-generate` |
|
||||
| policies | Pulsante "+ Nuova Policy" (header) | ~255 | `nis2-policies-btn-new` |
|
||||
| policies | Contenitore tab bar `div.tabs` | ~261 | `nis2-policies-tabs` |
|
||||
| policies | Bottone tab "Elenco Policy" | ~262 | `nis2-policies-tab-btn-list` |
|
||||
| policies | Bottone tab "Template" | ~263 | `nis2-policies-tab-btn-templates` |
|
||||
| policies | Pulsante "Approva" vista dettaglio (JS) | script ~551 | `nis2-policies-detail-btn-approve` |
|
||||
| policies | Pulsante "Modifica" vista dettaglio (JS) | script ~555 | `nis2-policies-detail-btn-edit` |
|
||||
| supply-chain | Pulsante "Categorie" (header) | ~377 | `nis2-supply-chain-btn-categories` |
|
||||
| supply-chain | Pulsante "Template" (header) | ~378 | `nis2-supply-chain-btn-templates` |
|
||||
| supply-chain | Pulsante "Importa" (header) | ~379 | `nis2-supply-chain-btn-import` |
|
||||
| supply-chain | Pulsante "+ Nuovo Fornitore" (header) | ~380 | `nis2-supply-chain-btn-new` |
|
||||
| supply-chain | Card grafico "Distribuzione Criticità" | ~406 | `nis2-supply-chain-chart-card` |
|
||||
| supply-chain | Pulsanti dettaglio Valuta/Questionario/Modifica (JS) | script ~753-764 | `nis2-supply-chain-detail-btn-assess`, `nis2-supply-chain-detail-btn-send-questionnaire`, `nis2-supply-chain-detail-btn-edit` |
|
||||
| assets | Pulsante "Importa" (header) | ~271 | `nis2-assets-btn-import` |
|
||||
| assets | Pulsante "+ Nuovo Asset" (header) | ~272 | `nis2-assets-btn-new` |
|
||||
| assets | Barra filtri `div.filters-bar` | ~319 | `nis2-assets-filters` |
|
||||
| assets | Pulsanti azione riga tabella (JS) | script ~505-509 | `nis2-assets-row-btn-score-{id}`, `nis2-assets-row-btn-edit-{id}` |
|
||||
| assets | Pulsanti footer modale dettaglio (JS) | script ~703-705 | `nis2-assets-detail-btn-close`, `nis2-assets-detail-btn-score`, `nis2-assets-detail-btn-edit` |
|
||||
| training | Pulsante "+ Nuovo Corso" (header) | ~234 | `nis2-training-btn-new-course` |
|
||||
| training | Contenitore tab bar `div.tab-nav` | ~240 | `nis2-training-tabs` |
|
||||
| training | Bottone tab "Corsi" | ~241 | `nis2-training-tab-btn-courses` |
|
||||
| training | Bottone tab "Le Mie Assegnazioni" | ~242 | `nis2-training-tab-btn-assignments` |
|
||||
| training | Bottone tab "Compliance Formativa" | ~243 | `nis2-training-tab-btn-compliance` |
|
||||
| training | Pulsante "Assegna Corso" (tab compliance) | ~269 | `nis2-training-btn-assign-course` |
|
||||
| reports | Pulsante "Genera Report" (header) | ~355 | `nis2-reports-btn-generate` |
|
||||
| reports | Contenitore tab bar `div.tab-nav` | ~361 | `nis2-reports-tabs` |
|
||||
| reports | Bottone tab "Report Compliance" | ~362 | `nis2-reports-tab-btn-report` |
|
||||
| reports | Bottone tab "Controlli" | ~363 | `nis2-reports-tab-btn-controls` |
|
||||
| reports | Bottone tab "Audit Log" | ~364 | `nis2-reports-tab-btn-audit` |
|
||||
| reports | Bottone tab "ISO 27001" | ~365 | `nis2-reports-tab-btn-iso` |
|
||||
| reports | Bottone tab "Monitoraggio Continuo" | ~366 | `nis2-reports-tab-btn-monitoring` |
|
||||
| reports | Bottone tab "Requisiti ACN" | ~367 | `nis2-reports-tab-btn-acn` |
|
||||
| reports | Pulsante "Stampa Report" (JS) | script ~722 | `nis2-reports-btn-print` |
|
||||
| reports | Select stato requisito ACN (JS, per riga) | script ~543 | `nis2-reports-acn-status-{id}` |
|
||||
| isms | Bottone "Esporta SGSI" (header) | 59 | `nis2-isms-btn-export` |
|
||||
| isms | Bottone "Salva e continua" Step 1 | 91 | `nis2-isms-btn-save-step1` |
|
||||
| isms | Bottone "Aggiungi ruolo" Step 2 | 105 | `nis2-isms-btn-add-role` |
|
||||
| isms | Bottone "Continua" Step 2 | 107 | `nis2-isms-btn-next-step2` |
|
||||
| isms | Bottone "Salva e continua" Step 3 | 118 | `nis2-isms-btn-save-step3` |
|
||||
| isms | Bottone "Ri-deriva dal NIS2" Step 4 | 128 | `nis2-isms-btn-derive-soa` |
|
||||
| isms | Bottone "Continua" Step 4 | 132 | `nis2-isms-btn-next-step4` |
|
||||
| isms | Bottone "Continua" Step 5 | 154 | `nis2-isms-btn-next-step5` |
|
||||
| isms | Box intro | 67 | `nis2-isms-intro` |
|
||||
| isms | Box disclaimer | 71 | `nis2-isms-disclaimer` |
|
||||
| normative | Bottone "Solo Pendenti" (header) | 41 | `nis2-normative-btn-pending` |
|
||||
| normative | Bottone "Prendi in visione" su card (JS) | script ~230 | `nis2-normative-btn-ack-{id}` (o `data-ack-id`) |
|
||||
| normative | Card barra avanzamento ACK | 54 | `nis2-normative-ack-card` |
|
||||
| whistleblowing | Bottone "Traccia Segnalazione Anonima" (header) | 44 | `nis2-wb-btn-track` |
|
||||
| whistleblowing | Bottone "Nuova Segnalazione" (header) | 48 | `nis2-wb-btn-new` |
|
||||
| whistleblowing | Banner Art.32 | 56 | `nis2-wb-art32-banner` |
|
||||
| whistleblowing | Bottone "Gestisci" per riga (JS) | script ~312 | data-attribute `data-wb-view-id` |
|
||||
| whistleblowing | Bottone "Verifica Stato" (vista track) | 185 | `nis2-wb-btn-verify` |
|
||||
| whistleblowing | Bottone "Invia Segnalazione" | 164 | `nis2-wb-btn-submit` |
|
||||
| kb | Card lista documenti (wrapper) | 110 | `nis2-kb-doc-list-card` |
|
||||
| kb | Card test search (wrapper) | 122 | `nis2-kb-search-card` |
|
||||
| kb | Paragrafo intro visibilità | 42 | `nis2-kb-intro` |
|
||||
| cross-analysis | Tab "Chat AI" | 308 | `nis2-xa-tab-btn-chat` |
|
||||
| cross-analysis | Tab "Storico" | 311 | `nis2-xa-tab-btn-history` |
|
||||
| cross-analysis | Tab "Portfolio dati" | 314 | `nis2-xa-tab-btn-portfolio` |
|
||||
| cross-analysis | Badge privacy header | 284 | `nis2-xa-privacy-badge` |
|
||||
| cross-analysis | Badge "Solo Consulenti & Admin" | 289 | `nis2-xa-role-badge` |
|
||||
| cross-analysis | Chip domande rapide (6) | 331-336 | `nis2-xa-quickq-1` … `nis2-xa-quickq-6` (o `data-quickq`) |
|
||||
| settings | Tab "Organizzazione" | 215 | `nis2-settings-tab-btn-org` |
|
||||
| settings | Tab "Profilo" | 216 | `nis2-settings-tab-btn-profile` |
|
||||
| settings | Tab "Preferenze" | 217 | `nis2-settings-tab-btn-preferences` |
|
||||
| settings | Tab "Membri" | 218 | `nis2-settings-tab-btn-members` |
|
||||
| settings | Tab "Sicurezza" | 219 | `nis2-settings-tab-btn-security` |
|
||||
| settings | Tab "API Keys" | 220 | `nis2-settings-tab-btn-apikeys` |
|
||||
| settings | Tab "Webhook" | 221 | `nis2-settings-tab-btn-webhooks` |
|
||||
| settings | Bottone "Invita Membro" | 498 | `nis2-settings-btn-invite-member` |
|
||||
| settings | Bottone "Nuova API Key" | 573 | `nis2-settings-btn-new-apikey` |
|
||||
| settings | Bottone "Nuovo Webhook" | 600 | `nis2-settings-btn-new-webhook` |
|
||||
| settings | Bottone "Aggiorna" delivery log | 612 | `nis2-settings-btn-reload-deliveries` |
|
||||
| companies | Bottone header "Aggiungi Cliente" (link) | 292 | `nis2-companies-add-btn` |
|
||||
| companies | Bottone empty state "Aggiungi Primo Cliente" | 329 | `nis2-companies-add-first-btn` |
|
||||
| companies | Bottone card "Connettori" (per card, JS) | script ~444 | `nis2-companies-connectors-btn-{orgId}` |
|
||||
| companies | Bottone card "Gestisci" (per card, JS) | script ~447 | `nis2-companies-manage-btn-{orgId}` |
|
||||
| companies | Contenitore header pagina `.companies-header` | 282 | `nis2-companies-header` |
|
||||
| companies | Bottone "Salva" riga connettore (modale, JS) | script ~489 | `nis2-companies-conn-save-{type}` |
|
||||
| onboarding | Bottone "Inserisci manualmente" (step 1) | 182 | `nis2-onboarding-manual-btn` |
|
||||
| onboarding | Bottone "Indietro" step 2 | 298 | `nis2-onboarding-back-2` |
|
||||
| onboarding | Bottone "Continua" step 2 | 303 | `nis2-onboarding-next-2` |
|
||||
| onboarding | Bottone "Indietro" step 3 | 348 | `nis2-onboarding-back-3` |
|
||||
| onboarding | Bottone "Continua" step 3 | 353 | `nis2-onboarding-next-3` |
|
||||
| onboarding | Bottone "Indietro" step 4 | 404 | `nis2-onboarding-back-4` |
|
||||
| service-continuity | Header documento | 62 | `nis2-continuity-header` |
|
||||
| service-continuity | Sezione 1 Architettura (h2) | 81 | `nis2-continuity-architettura` |
|
||||
| service-continuity | Sezione 2 Resilienza 7 livelli (h2) | 90 | `nis2-continuity-resilienza` |
|
||||
| service-continuity | Blocchi L1-L7 | 92-149 | `nis2-continuity-layer-1` … `nis2-continuity-layer-7` |
|
||||
| service-continuity | Sezione 3 Rate limiting (h2) | 151 | `nis2-continuity-rate-limiting` |
|
||||
| service-continuity | Sezione 4 Manutenzione (h2) | 164 | `nis2-continuity-manutenzione` |
|
||||
| service-continuity | Sezione 5 Matrice rischi (h2) | 178 | `nis2-continuity-matrice-rischi` |
|
||||
| service-continuity | Sezione 6 SLA (h2) | 193 | `nis2-continuity-sla` |
|
||||
| service-continuity | Sezione 7 Checklist (h2) | 206 | `nis2-continuity-checklist` |
|
||||
| service-continuity | Footer documento | 222 | `nis2-continuity-footer` |
|
||||
| admin/index | Header pagina con badge Super Admin | 191 | `nis2-admin-header` |
|
||||
| admin/index | Nav collegamenti rapidi | 281 | `nis2-admin-quick-links` |
|
||||
| admin/index | Card-link "Gestisci Organizzazioni" | 282 | `nis2-admin-link-organizations` |
|
||||
| admin/index | Card-link "Gestisci Utenti" | 291 | `nis2-admin-link-users` |
|
||||
| admin/index | Card "Distribuzione Piani" | 264 | `nis2-admin-plans-card` |
|
||||
| admin/organizations | Header pagina | 110 | `nis2-admin-orgs-header` |
|
||||
| admin/organizations | Breadcrumb | 119 | `nis2-admin-orgs-breadcrumb` |
|
||||
| admin/organizations | Tabella organizzazioni (JS) | script ~228 | `nis2-admin-orgs-table` |
|
||||
| admin/organizations | Bottone paginazione "Precedente" (JS) | script ~293 | `nis2-admin-orgs-prev` |
|
||||
| admin/organizations | Bottone paginazione "Successivo" (JS) | script ~296 | `nis2-admin-orgs-next` |
|
||||
| admin/users | Header pagina | 132 | `nis2-admin-users-header` |
|
||||
| admin/users | Breadcrumb | 141 | `nis2-admin-users-breadcrumb` |
|
||||
| admin/users | Tabella utenti (JS) | script ~240 | `nis2-admin-users-table` |
|
||||
| admin/users | Toggle attivo per riga (JS) | script ~288 | `nis2-admin-users-toggle-{userId}` |
|
||||
| admin/users | Bottone "Impersonate" per riga (JS) | script ~295 | `nis2-admin-users-impersonate-{userId}` |
|
||||
| admin/users | Bottone paginazione "Precedente" (JS) | script ~321 | `nis2-admin-users-prev` |
|
||||
| admin/users | Bottone paginazione "Successivo" (JS) | script ~324 | `nis2-admin-users-next` |
|
||||
|
||||
⚠ Vincolo settings: `switchTab()` seleziona i tab per indice posizionale (`querySelectorAll('.settings-tab')[tabMap[tab]]`) — l'aggiunta degli id NON deve cambiare ordine/numero dei bottoni tab.
|
||||
@@ -176,6 +176,9 @@
|
||||
entity_type: entityType,
|
||||
scope: scope,
|
||||
shared_with_orgs: sharedWith,
|
||||
// FIX 2026-06-12: il backend richiede organization_id per scope=ORG
|
||||
// (422 KB_ORG_REQUIRED) — prima non veniva inviato e l'upload ORG falliva.
|
||||
organization_id: parseInt(localStorage.getItem('nis2_org_id') || '0', 10) || undefined,
|
||||
}),
|
||||
}).then(function (r) { return r.json().then(function (j) { return { ok: r.ok, body: j }; }); })
|
||||
.then(function (res) {
|
||||
|
||||
Reference in New Issue
Block a user