Root cause: InstitutionalDocsController::list() usava requireAuth()+getCurrentOrgId(),
ma currentOrgId e' popolato solo da requireOrgAccess() → getCurrentOrgId() = null →
l'endpoint rispondeva sempre NO_ORG (400) → loadDocs riceveva standards=[] → la card
mostrava solo "Aggiungi voce" (screenshot Simon). L'endpoint NON aveva mai funzionato a runtime.
- Backend: list() usa resolveOrgId() (risolve X-Organization-Id senza lanciare) e restituisce
SEMPRE le 5 voci standard; i documenti salvati solo se un'org e' selezionata.
- Frontend (dashboard.js): render condiviso + STD_FALLBACK → le 5 voci si mostrano sempre,
anche se l'API fallisce. Buster dashboard.js 20260825.
- Backend attivato via reload php-fpm host.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Prevenzione proattiva dello stesso freeze latente trovato in organigramma: le pagine
raci.html e competenze.html richiamavano createIcons() su ogni mutazione DOM. Debounce+disconnect.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Secondo possibile innesco del freeze: lo script inline richiamava lucide.createIcons()
su OGNI mutazione DOM (MutationObserver subtree). Poiche' createIcons muta il DOM
(<i>->svg), poteva auto-ritriggerarsi. Ora: debounce 120ms + disconnect durante il
render + flag applying per ignorare le mutazioni auto-prodotte. HTML network-first -> live al reload.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Segnalazione Simon: in Struttura interna/Organigramma il clic su "Nuovo Ruolo"
blocca l'intero sito. Causa: né il tree builder server (OrgRoleController::buildTree,
$attach) né il render client (organigramma.js orgNodeHtml) avevano una guardia
anti-ciclo su parent_role_id → con una gerarchia ciclica la ricorsione va in loop
infinito (hang del backend / freeze del render).
- organigramma.js orgNodeHtml(node, seen): salta gli id già visti (rompe il ciclo);
orgRender passa un Set condiviso. Live via bind-mount (buster 20260806).
- OrgRoleController::buildTree: $attach porta la catena antenati e non ridiscende su
un id già visto. ⚠️ Richiede reload php-fpm host (opcache) per andare live.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Richieste Simon sulla finestra Rischi:
1) Matrice 5×5: eliminata la fascia 10-14; fasce = 1-2 basso (verde), 3-8 medio
(arancione), 9-12 alto (rosso tenue), 15-25 critico (rosso). Unificate con le
bande Alert. (matrixBand + CSS band-low/med/high/crit; rimosse level-1..10).
2) La matrice riepiloga i giudizi INERENTI o RESIDUI con un tasto di selezione
(setMatrixView; matrixPoints legge likelihood/impact o residual_*).
3) Rischi trasversali:
3.1 sezione spostata in FONDO (matrice dai requisiti risalita subito dopo la
tabella derivata);
3.2 tabella trasversali convertita alle STESSE 12 colonne (inerente+residuo+
alert+esito), editing inline P/I via api.updateRisk (onTransversalScoreChange);
3.3 tasti "AI Suggerisci" e "Nuovo Rischio" spostati in testa alla tabella;
3.4 seconda matrice 5×5 dei trasversali con lo stesso toggle inerente/residuo;
3.5 tasto Elimina per ogni rischio trasversale (confirmDeleteRisk).
- Solo frontend/statico. version 1.27.0 + SW cache bump.
- Verificato puppeteer (996002): 4 bande, 2 toggle funzionanti, 12 col, 6 delete, 0 errori.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Compromesso approvato (Simon/Cristiano) al posto della cancellazione richiesta al
punto 3 del #501 — validato nis2-expert (all-hazards = obbligo art.21.2 Direttiva
-> art.24 D.Lgs.138/2024; rimuoverla = lacuna di conformità).
- risks.html: la sezione diventa un <details> comprimibile. Header sempre visibile
con titolo "Rischi trasversali (approccio multirischio / all-hazards) - art. 24
D.Lgs. 138/2024" + contatore. Apri-se-vuota (updateAllhazardHeader): vuota -> aperta
(presidiata in audit), con voci -> chiusa (meno ingombro). Nota riformulata che la
distingue dai "rischi di non conformità".
- i18n.js custom_heading/custom_help (IT+EN) + help.js allineati.
- Manuale + KB RISCHI_MODELLO.md aggiornati. Cache-buster help/i18n 20260731.
- Solo frontend/statico.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Riscontro Simon sulla tabella Gestione Rischi:
- Titoli di gruppo sui tripletti Probabilità/Impatto/Valutazione: da
"VALUTAZIONE RISCHIO INERENTE/RESIDUO" a "Rischio Inerente"/"Rischio Residuo"
(risks.html thead + i18n.js grp_inherent/grp_residual IT+EN).
- Ritirata eccezione #3: banda Alert riportata a spec Simon 15-25/9-12/3-8/1-2.
Simon ha ragione: con P,I in 1-5 i prodotti 7/11/13/14 non esistono → nessun
buco. alertBand resta >=9 (=9-12 in pratica); aggiornati commento, help.js,
manuale, KB (9-14 -> 9-12).
- Cache-buster help.js/i18n.js -> 20260730b (i18n va bustato o riscrive il titolo).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Evita la "sessione scaduta" e i deploy che restano invisibili all'utente.
- api.js: refresh PROATTIVO dell'access token ~2 min prima della scadenza
(scheduleTokenRefresh su exp del JWT, riprogrammato ad ogni setTokens) +
ensureFreshToken() per rinnovo immediato al ritorno sulla scheda. Con refresh
a 7gg l'utente resta loggato senza mai vedere il login.
- common.js: watch versione (poll version.json ogni 5 min + su visibilitychange)
→ banner "È disponibile una nuova versione — Aggiorna" (reload) quando cambia;
nudge service worker (registration.update); su visibilitychange chiama anche
api.ensureFreshToken(). Nessun hard-refresh manuale.
- Cache-buster api/common ?v=20260729b. version 1.25.12. Solo frontend.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Un utente con role='consultant' e consulting_firm_id vede solo i CLIENTI del
proprio studio (organizations.consulting_firm_id = suo firm) UNION le proprie
membership dirette — non tutte le org (quello resta super_admin), non solo le
membership. Applicato in OrganizationController::list (selettore azienda) e
ConsultantController::portfolio (cruscotto). Additivo: super_admin e altri ruoli
invariati. Verificato: utente-test consultant/firm1 vede 2 aziende (cliente studio
996003 + membership 996001), non tutte. version 1.25.11.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Punto 1: la tabella 'Rischi dai requisiti del framework di sicurezza' e ora
un riquadro a scorrimento verticale (max-height 60vh, header sticky) invece di
allungare la pagina.
- Punto 2: elenca SOLO i requisiti applicabili alla classe del soggetto
(importante -> Allegato 1, essenziale -> Allegato 2, Det. ACN 164179/2025);
le righe non pertinenti non sono piu mostrate (prima solo attenuate).
- help.js allineato + cache-buster help.js?v=20260729b su 35 pagine; version.json 1.25.10.
- Punto 3 (rimozione sezione all-hazard) NON applicato: contraddice la decisione
documentata nel #500 (copertura multirischio art.24 D.Lgs.138/2024) -> escalato.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
companies.html diventa il cruscotto dello studio consulente: barra KPI (aziende,
compliance media, scadenze in ritardo/in arrivo), griglia aziende (compliance/
rischi/incidenti + badge ritardo, clic = entra nell'azienda) e sezione "Scadenze
generali" aggregata su TUTTE le aziende ordinata per data. Una sola chiamata
api.consultantPortfolio(). Voce menu V3 "Le mie aziende" (icona briefcase) gata a
consultant/super_admin. help.js + i18n (nav.studio + companies.*) aggiornati.
Cache-buster api/topnav-v3/i18n/help ?v=20260729. version 1.25.9.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GET /api/consultant/portfolio — vista d'insieme per consulente/studio: per ogni
azienda visibile all'utente (super_admin=tutte, altri=proprie membership) ritorna
compliance score, rischi/incidenti aperti, scadenze in ritardo/in arrivo; +
elenco SCADENZE AGGREGATE su tutte le aziende (incidenti CSIRT, policy, trattamenti
rischio, formazione) ordinate per data; + KPI d'insieme. Read-only, additivo.
Rotta registrata in index.php. Verificato: 5 aziende, 20 scadenze, compliance media 74%.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Nella modale "Valuta" di un rischio-requisito non ancora valutato, Probabilità e
Impatto vengono pre-compilati in base allo stato (conforme→basso 1/2, parziale→
medio 3/3, non conforme→alto 4/4) con nota esplicita "Valori suggeriti … è solo
un suggerimento, modificabili". Se già valutato, usa i valori salvati. Idea
pre-avallata dal nis2-expert (precompilare l'asse dallo stato = rischio residuo).
Solo frontend (risks.html); nessun valore imposto (art.24 non prescrive metodo).
version 1.25.8.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Il supervisore autonomo (b5f936b) aveva RIMOSSO del tutto i tasti 'Nuovo Rischio'
e 'AI Suggerisci' applicando il ticket alla lettera. Decisione utente (Cristiano):
NON rimuoverli ma limitarli ai profili super_admin/org_admin — l'inserimento libero
serve a coprire i rischi all-hazard non legati a un singolo requisito (art.24
D.Lgs.138/2024, confermato nis2-expert). Ripristinato il gating (gateAdminActions):
i tasti compaiono solo agli admin, nascosti agli altri. version 1.25.6.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
I rischi in Gestione Rischi corrispondono ai requisiti del framework (Determinazione ACN 164179/2025);
niente inserimento manuale/AI. Reverte l'admin-gating: la spec del richiedente e il piano originale
prevedevano la rimozione dei tasti. La sezione 'Rischi aggiuntivi' resta come elenco in sola lettura.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
La pagina Gestione Rischi mostra come tabella primaria (read-only) i requisiti
del framework Lex&ISO come rischi, codice RSK-<misura>Com.N via /api/risks/derived,
filtrati per classe (importante All.1 / essenziale All.2). Framing normativo
(validato nis2-expert): ogni voce = "rischio derivante dal mancato/parziale
soddisfacimento del requisito", mai "requisito = rischio"; RSK e "92" NON come
codici/numeri ufficiali ACN; matrice = strumento di rappresentazione (art.24).
- Rischi CUSTOM mantenuti in sezione "Rischi aggiuntivi (all-hazard)".
- Tasti "Nuovo Rischio"/"AI Suggerisci" limitati a super_admin/org_admin (non
rimossi): l'inserimento libero serve al multirischio (art.24 D.Lgs.138/2024).
- api.js derivedRisks(); help.js + i18n aggiornati; version 1.25.4; SW v1.25.4.
- Cache-buster api/help/i18n ?v=20260727r. Backend/DB non toccati.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ticket #500 (Simon Fattori) - semplificazione pagina Gestione Rischi:
- matrice 5x5 ora sempre visibile sotto la tabella (rimosso bottone 'Matrice' e il view-toggle)
- rimosse le viste 'Quantitativo (FAIR)' e 'KRI' con relativi bottoni, blocchi HTML e JS
- help.js allineato (rimosse sezioni FAIR/KRI), cache-buster help.js -> 20260727a
- version.json -> 1.25.2
Rimandato a fase 2 (richiede modello dati): rischi derivati dai requisiti LEX&ISO
+ codifica RSK-<misura>Com.N + rimozione bottoni 'Nuovo Rischio'/'AI Suggerisci'.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- loadDocs: 5 voci standard sempre presenti + voci custom + 'Aggiungi voce'
- modale add/edit con descrizione OBBLIGATORIA (richiesta punto 1), link doc opzionale
- delete voci custom; controlli visibili a org_admin/compliance_manager/super_admin
- CSS .doc-* in v3.css; cache-buster dashboard.js/v3.css su dashboard.html; version 1.25.1
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bug segnalato da un tester "sono tornato su nis2 e non funziona più" (utente/
aziende "--", inventario bloccato su Caricamento, niente FAB segnalazioni).
Causa: un 401 su /auth/refresh (refresh token scaduto/invalido) rientrava nel
handler di refresh (la condizione non escludeva l'endpoint auth) → ricorsione:
doRefreshToken() non ritornava mai, quindi logout()/redirect a login non
scattava e la pagina restava rotta. Riprodotto con puppeteer (access scaduto +
refresh invalido → dashboard "--" identica allo screenshot).
Fix: escludi /auth/refresh e /auth/login dall'auto-refresh; inoltre un 401 senza
refresh token disponibile fa logout() → login. Ora un utente che torna dopo la
scadenza del token viene mandato a login (ri-accede) invece di vedere "--".
Bug PRE-ESISTENTE in api.js (non introdotto dal V3), critico ora col push tester.
Cache-buster api.js ?v=20260627u su tutte le pagine.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- version.json 1.24.15 → 1.25.0 (MINOR: nuova interfaccia V3) con changelog
utente; allinea footer/changelog e la versione nel bug-reporter alla UI reale.
- sw.js: cache 'nis2-shell-v1.23.0' → 'v1.25.0' + PRECACHE portato allo shell V3
(v3.css/topnav-v3.js/inter/lucide al posto di style.css/common-bi/bootstrap-italia).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- aria-guide "Mostrami dov'è": ora aggancia le voci del menu IN ALTO V3
(data-nav aggiunto in topnav-v3.js su voci dirette + mega-link). Se la voce è
in un mega-menu, lo apre (.aria-guide-open) e ci punta lo spotlight; coach
"menu in alto". Fallback navigazione invariato. (Prima cercava .sidebar-nav V2.)
- segnala-anonimo.html: CSP font-src 'self' → 'self' data: (sbloccato il font
data: embeddato, niente più violazione CSP).
- Cache-buster: topnav-v3.js/common.js ?v=20260627t, aria-guide.js ?v=20260627t.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
La flotta V3 aveva messo data-i18n="mr.title"/"normative.title" sugli <h1> di
misure-requisiti e normative, ma le chiavi non erano in i18n.js → I18n.t()
ritorna la chiave → il titolo mostrava "mr.title"/"normative.title". Aggiunte
le 2 chiavi (it+en). Cache-buster i18n.js ?v=20260627p su tutte le pagine.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dopo il revamp V3, allineati i layer che descrivevano ancora la sidebar V2:
- topnav-v3.js: aggiunte le pagine orfane in nav (Matrice RACI → Struttura
interna, Scadenziario → Monitoraggio, Compliance Journey → Guida) + cablato
data-i18n su gruppi e voci del mega-menu (traduzione IT/EN come in V2).
- i18n.js: nuove chiavi nav V3 (gruppi mega-menu + connettori/whistleblowing/
normative/cross-analysis/kb/architettura/simulazione/integrazioni/workflow/
audit ACN/registra incidente).
- AIService.php navigationMapBlock: riscritta sul menu IN ALTO V3 (9 gruppi +
pulsante "Registra incidente"), sync con topnav-v3.js NAV_GROUPS; ARIA non
parla più di "barra laterale".
- help.js: corrette le 3 menzioni "sidebar" → barra/menu in alto.
- KB nis2_kb: nuovo docs/kb/V3_UI_NAVIGAZIONE.md + scripts/ingest-v3-ui-doc.php
(ingerito host-side: 3 chunk SYSTEM, rimossi i chunk V2; ARIA RAG ora guida
sul top-nav).
- Cache-buster ?v=20260627n sui 3 JS modificati su tutte le pagine.
Deploy: JS/HTML statici live via bind-mount; php-fpm reload (host + nis2-app)
per AIService.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fase 0 della migrazione UI V3 (sidebar V2 → top-nav navy/oro, font Inter, icone Lucide).
- public/css/v3.css: design system portato fedelmente dal mockup index.html
(token :root, chrome appbar+mega-menu, card/stat/calendario/anag/doc/fab, @media ≤900/≤560),
+ aggiunte minime V3+ per stati loading/empty/error, mobile nav toggle e touch≥44px (AGID/WCAG).
- public/vendor/inter/: Inter self-host (variable woff2 latin+latin-ext) + inter.css + README (NO Google CDN).
- public/vendor/lucide/lucide.min.js: Lucide UMD self-host (NO unpkg CDN).
- public/js/topnav-v3.js: appbar + mega-menu data-driven dalla mappa IA (§6, 9 gruppi),
aria-current sulla voce attiva, riusa gli helper di common.js (utente/logout/versione/org-switcher,
branding, impersonate) e i 3 FAB reali (ARIA + bug-reporter + notifiche). window.loadSidebar=loadTopnavV3.
- public/dashboard.html: convertita al V3 fedele al mockup, cablata sui DATI REALI via api.js
(overview/compliance-score/upcoming-deadlines/recent-activity/organizations-current);
monitor giornaliero/settimanale alimentati dagli eventi reali; documenti istituzionali = stato vuoto onesto.
- public/js/dashboard.js (nuovo): wiring dati reali + render calendario/scadenze/attività/anagrafica;
stati loading/empty/error; zero dati finti del mockup.
node --check OK su topnav-v3.js e dashboard.js. Solo UI: nessun PHP/DB/api.js toccato.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Meccanismo riusabile: presenza di ../.maintenance (gitignored) → ogni richiesta 503 +
maintenance.html (mostra la finestra). Bypass ?mnt=<token>/cookie. Accendi: touch
.maintenance · Spegni: rm .maintenance. Attivato ora per il revamp UI V3 (~1h).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
segnala-anonimo.html: pagina PUBBLICA (no checkAuth, no sidebar, no common.js/api.js/
pwa.js, no analytics) che ospiterà l'iframe del canale Vocea, conforme alle 6 regole
anonimato StarGateWB: Referrer-Policy no-referrer (meta + iframe), CSP frame-src
app.vocea.cloud, slug del canale da ?canale=<slug> (nessun id del segnalante nell'URL),
postMessage con check event.origin + envelope {source:'vocea'} e NESSUNA persistenza
del recovery code (solo autosize). Dormiente finché non c'è lo slug/MS live.
+ docs/OUTGOING_TO_VOCEA_...: conferma origin frame-ancestors https://nis2.agile.software.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Più connettori per azienda; ogni connettore ha una api_key dedicata (scope ingest:assets)
che l'agente esterno usa per mappare e auto-popolare NIS2.
- mig 064: discovery_connectors (per-org, multi) + discovery_runs (storico) + network_flows (ID.AM-03).
- DiscoveryConnectorController (org_admin): CRUD connettori + emissione/rotazione api_key
(mostrata 1 volta) + dettaglio con ultimi run.
- ServicesController::ingestAssets esteso: accetta anche "flows" (upsert network_flows,
dedup external_ref) e, se la chiave appartiene a un connettore, registra discovery_run
+ aggiorna last_run del connettore. Auto-scoring rilevanza NIS2 già in bulkUpsert.
- AssetController::bulkUpsert: ora salva anche "dependencies" → popola la Mappa Dipendenze.
- Router: /api/discovery-connectors (list/create/{id}/update/delete/rotateKey).
Smoke E2E (HTTP 201): 2 asset scorati + 1 flusso + run tracciato + dipendenze persistite.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Click su un'intestazione (Nome/Tipo/Categoria/Criticita/Rilevanza NIS2/Owner/Stato)
ordina l'inventario; secondo click inverte (freccia ▲/▼, aria-sort).
Criticita e Rilevanza ordinano per valore reale, non alfabetico.
Client-side sull'inventario gia' caricato (no paginazione su assets), si combina
coi filtri, accessibile da tastiera. Help aggiornato + cache-buster help.js.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Nuovo pulsante "Esporta" in assets.html: scarica l'intero inventario
(tutte le pagine) in CSV con le stesse colonne riconosciute
dall'import (name, asset_type, criticality, data_classification,
internet_facing, dependencies_count, regulated, external_ref, vendor,
location). I criteri data_classification/internet_facing/
dependencies_count/regulated sono ricostruiti da relevance_criteria con
mappatura reversibile (round-trip stabile, verificato 100/100 casi).
Parser import reso quote-aware (RFC-style) per round-trip lossless di
nomi con virgola; retro-compatibile con CSV non quotato.
help.js + cache-buster (?v=20260625b) su tutte le pagine. version 1.24.14.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Completa i 2 punti rimandati dal supervisore:
- help.js sezione Inventario: documentate le nuove funzioni che il supervisore ha
aggiunto (commit 9c36604) → "Mappa Dipendenze" con il campo Dipendenze per popolarla;
"Elimina bene" (cestino, org_admin) distinto dallo stato "dismesso".
- AIService::navigationMapBlock: 2 regole nuove → (5) NON citare nomi file .html/URL
interni; (6) NON inventare pulsanti/funzioni/passi inesistenti, usare solo le funzioni
della guida/contesto della pagina. Elimina l'allucinazione "rischi.html" e simili.
Smoke: ARIA cita Elimina + Mappa Dipendenze, zero nomi-file, "Gestione > Rischi".
Cache-buster help.js -> 20260625a. php-fpm reload.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Nuovo pulsante "Mappa Dipendenze" in toolbar: vista delle relazioni
tra i beni (costruita client-side da allAssets, endpoint backend gia'
esistente dependencyMap).
- Campo "Dipendenze" (multi-select) nel form bene: consente di compilare
la mappa che ARIA indicava ma che non aveva UI. create/update salvano
gia' il campo dependencies.
- Pulsante "Elimina" bene nella lista e nel dettaglio (DELETE /assets/{id}
gia' esistente, richiede org_admin).
- Dettaglio bene: dipendenze mostrate per nome anziche' per ID grezzo.
- version.json -> 1.24.13.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Porting del pattern TRPG (CHANGE_aria_voice_pointer.md) sulla sidebar V2:
- public/js/aria-guide.js (nuovo): DESTINATIONS (26 voci menu → keyword IT),
matchDestination(question), pointTo(nav,label) = overlay + spotlight pulsante +
puntatore animato + coach-mark "Vai →"; Esc/click per chiudere; fallback navigate
se la voce non è visibile; rispetta prefers-reduced-motion; self-contained, no inline-CSS.
- common-bi.js: data-nav="<href senza .html>" sulle voci sidebar (aggancio puntatore).
- common.js: inietta aria-guide.js dopo login; dopo ogni risposta ARIA, se la domanda
combacia con una destinazione mostra il bottone "📍 Mostrami dov'è: <voce>".
Frontend-only, additivo. Cache-buster common.js/common-bi.js -> 20260624f.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lamentela: "AI non allineata con help online e contesto". Causa: ARIA e Help
erano due fonti separate (Help=help.js, ARIA=KB) → divergevano.
Fix (fonte unica = help.js, zero duplicazione):
- help.js: getContextText(pageId) (testo piano dell'help della pagina) + detectPageId().
- common.js: invia page_id (canonico) + page_help (stesso testo del pannello "?") a /api/ai/ask.
- AiController: passa page_id/page_help in userContext.
- AIService::askWithRag: inietta "GUIDA CONTESTUALE DELLA PAGINA" nel system prompt
(ARIA si allinea all'help mostrato all'utente, non lo contraddice) + usa page_id
per il trigger relevanceGrid (più robusto del title).
Smoke: ARIA cita "registro dei rischi" dall'help + "Gestione > Rischi". Cache-buster
common.js/help.js -> 20260624e (39 pagine).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
La colonna operative_summary lato ticket-ms e' VARCHAR(2000): descrizioni
lunghe causavano l'errore SQL grezzo a video. Aggiunto maxlength + contatore
live + guard al submit nel widget locale public/js/bug-reporter.js.
Cache-buster: bug-reporter.js?v=20260624 in common.js + common.js?v=20260624
su tutte le pagine. Causa radice (dimensione colonna) inoltrata ad AgileHub.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ARIA (askWithRag) conosceva solo il nome pagina + KB/fonti, non la griglia
reale delle tendine della finestra «Valuta Rilevanza NIS2» (AssetScoringService::GRID):
dava risposte generiche non corrispondenti alla finestra. Aggiunto
relevanceGridBlock() (6 criteri, opzioni, punteggi, desc dalla fonte di verita')
iniettato nel system prompt quando l'utente e nell'Inventario o chiede della
rilevanza. Additivo, nessun impatto su altri flussi.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- AssetScoringService::GRID: aggiunto campo 'desc' a tutte le 35 opzioni dei 6 criteri (significato operativo, additivo)
- assets.html: ogni combo mostra il significato dell'opzione selezionata + nuovo box 'Dettaglio punteggio per criterio' (live, anche alla riapertura di una valutazione salvata)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ARIA citava voci di menu inesistenti (es. 'A4 - Analisi e Valutazione
del Rischio' / 'Fase 4.1 - Inventario') non corrispondenti alla barra
laterale, e non sapeva da quale pagina scrivesse l'utente.
- AIService::askWithRag: iniettata la mappa REALE della sidebar
(navigationMapBlock, sincronizzata con common-bi.js) con regole che
vietano di inventare menu/fasi/codici; aggiunto contesto pagina utente.
- AiController::ask: accetta e passa il campo 'page' dal frontend.
- common.js (ARIA FAB): invia la pagina corrente in /api/ai/ask.
- Cache-buster common.js 20260623->20260623h su tutte le pagine.
NB: questo commit include anche il fix#419 gia' applicato e live in
common.js (email bug-reporter recuperata via api.getMe quando assente
nelle claims JWT), finora non committato — incluso come backup.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Aggiunti endpoint PUT/DELETE /api/assets/subclasses/{id} (org-scoped, le
sottoclassi di sistema restano protette; FK ON DELETE SET NULL scollega i
beni senza cancellarli) + link UI «rinomina»/«rimuovi» accanto a «aggiungi».
Cache-buster api.js + bump version 1.24.8.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
La valutazione rilevanza salva relevance_criteria come mappa piatta
{criterio: optionValue} (AssetController::score), ma showScoringModal
leggeva prev[key].value (forma a oggetto) -> sempre undefined -> nessuna
combo pre-selezionata alla riapertura. Letto ora il valore-stringa diretto,
con fallback retro-compatibile alla forma a oggetto {value:...}.
Fix solo frontend (JS inline in assets.html), nessuna migrazione.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Risolve #418/#420 (ARIA sembrava non rispondere / serviva riaprire il pannello):
l'attesa della risposta /api/ai/ask (RAG+Claude, alcuni secondi) non mostrava
alcun indicatore -> ora compare 'ARIA sta scrivendo...' con input disabilitato
(anti doppio-invio). Indicatore rispetta prefers-reduced-motion (AGID/WCAG).
Risolve #425: il campo di scrittura era <input> a riga singola -> ora <textarea>
con Invio=invia, Shift+Invio=a capo, auto-crescita e aria-label.
common.js e' statico (no PHP/USR2): bump cache-buster ?v=20260623 su 39 pagine
(public + admin) + version.json 1.24.6.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>