Files
nis2-agile/docs/mappa-logica/16_settings.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

12 KiB

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.