Files
nis2-agile/docs/mappa-logica/07_supply-chain.md
T
DevEnv nis2-agileandClaude Opus 4.8 4dfab2a391 [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>
2026-06-12 18:50:19 +02:00

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