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>
11 KiB
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 |