Commit Graph
420 Commits
Author SHA1 Message Date
DevEnv nis2-agileandClaude Opus 4.8 f1156a81bb [FIX] Rischi #500: ripristino tasti Nuovo/AI LIMITATI ai profili admin (decisione utente)
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>
2026-07-27 15:20:44 +02:00
DevEnv nis2-agileandClaude Opus 4.8 b5f936bba2 [FEAT] Rischi #500 punto 4: rimossi tasti 'Nuovo Rischio' e 'AI Suggerisci' (elenco = requisiti Lex&ISO, sola lettura)
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>
2026-07-27 15:13:48 +02:00
DevEnv nis2-agileandClaude Opus 4.8 4e7e75582a [FEAT] Rischi #500 fase 2 (frontend): elenco rischi = requisiti Lex&ISO
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>
2026-07-27 14:15:03 +02:00
DevEnv nis2-agileandClaude Opus 4.8 571e151305 [FEAT] Rischi #500 fase 2 backend: endpoint /api/risks/derived (rischi dai requisiti LEX&ISO, codifica RSK-<misura>Com.N)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 13:41:11 +02:00
DevEnv nis2-agileandClaude Opus 4.8 7c711b727a [FEAT] Rischi: matrice sempre visibile, rimosse viste FAIR e KRI (ticket #500 fase 1)
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>
2026-07-27 12:15:22 +02:00
DevEnv nis2-agileandClaude Opus 4.8 896663d24c [FEAT] Dashboard: card Documenti istituzionali funzionante + UI (ticket #499)
- 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>
2026-07-24 15:15:26 +02:00
DevEnv nis2-agileandClaude Opus 4.8 1b65321ffb [FEAT] Documenti istituzionali dashboard: backend + mig 065 (ticket #499)
Card 'Documenti istituzionali' resa funzionale (era stato vuoto onesto).
- mig 065: tabella institutional_documents (per-org, descrizione obbligatoria)
- InstitutionalDocsController: list/save/delete (org-scoped, org_admin+compliance_manager)
- 5 voci standard sempre presenti: Codice Etico, Mission, Vision, Statuto, Piano Sanzionatorio
- registrato in index.php controllerMap/actionMap

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 15:13:13 +02:00
DevEnv nis2-agileandClaude Opus 4.8 ecb17e59f0 [DOCS] CONTEXT: mail a Massimo (rientro + installa app) + follow-up silent re-auth
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 14:35:45 +02:00
DevEnv nis2-agileandClaude Opus 4.8 006d06533f [DOCS] CONTEXT: v1.25.0 + fix bug sessione scaduta (segnalazione Massimo)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 10:12:10 +02:00
DevEnv nis2-agileandClaude Opus 4.8 41476c88f2 [FIX] api.js: sessione scaduta → login invece di pagina bloccata "--"
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>
2026-07-14 10:09:50 +02:00
DevEnv nis2-agileandClaude Opus 4.8 64e10b152b [RELEASE] v1.25.0 — UI V3: version.json + shell service worker aggiornati
- 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>
2026-07-07 16:26:36 +02:00
DevEnv nis2-agileandClaude Opus 4.8 e15e1b8645 [DOCS] CONTEXT_LAST_SESSION: V3 test completo + 2 bug fixati + polish + coda ticket vuota
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 23:40:58 +02:00
DevEnv nis2-agileandClaude Opus 4.8 a71d1a096d [FIX] V3 polish: spotlight ARIA su top-nav + CSP font segnala-anonimo
- 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>
2026-06-27 17:57:21 +02:00
DevEnv nis2-agileandClaude Opus 4.8 95e77a668a [FIX] i18n V3: chiavi mr.title/normative.title mancanti (si vedeva la chiave)
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>
2026-06-27 17:36:39 +02:00
DevEnv nis2-agileandClaude Opus 4.8 a223923fd6 [FIX] ARIA data-aware via chat: AiController risolve l'org per org_data_ok
ask() chiamava requireAuth() ma non requireOrgAccess(), quindi getCurrentOrgId()
restava null → org_data_ok sempre falso → ARIA rispondeva "non ho accesso ai dati"
anche con membership valida. Ora l'org si risolve da X-Organization-Id → param
org_id → currentOrgId → org primaria dell'utente; lo spoofing resta neutralizzato
dal controllo membership esistente. Verificato: ARIA ora cita i numeri reali
(rischi/incidenti/asset...) via /api/ai/ask. Bug pre-esistente (Fase B 24/6),
emerso nel test di rilascio V3.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 17:18:47 +02:00
DevEnv nis2-agileandClaude Opus 4.8 9971fbc065 [DOCS] CONTEXT_LAST_SESSION: UI V3 live + allineamento help/i18n/KB/ARIA + mail tester
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 16:48:25 +02:00
DevEnv nis2-agileandClaude Opus 4.8 58b4bdbe5e [FIX] UI V3 — allineamento help/i18n/KB/ARIA al menu top-nav
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>
2026-06-27 16:38:07 +02:00
DevEnv nis2-agileandClaude Opus 4.8 a4150b5389 [FEAT] UI V3 — flotta: chrome top-nav + design system su 32 pagine app
Migrazione UI dal V2 (Bootstrap Italia, sidebar) al V3 (top-nav mega-menu
navy/oro, Inter+Lucide self-host) fedele ai mockup docs/mockup Ui/.
- 32 pagine app convertite (incl. admin/*): head Inter+v3.css, chrome
  topnav-v3, contenuti in card V3, dati REALI preservati (id/data-* intatti),
  i18n/help/FAB reali invariati, nessun CDN esterno.
- v3.css: aggiunti widget condivisi (modal/toast/form/btn-variant/spinner/
  progress/tag/badge) + utility (.btn base, .text-muted, .sr-only) + alias
  variabili V2->token V3, così modali/form/toast di common.js funzionano
  ovunque senza style.css.
- maintenance.html: finestra estesa a ~12:15.
- docs/UI_V3_FLEET_BRIEF.md: ricetta operativa della flotta.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 15:57:35 +02:00
DevEnv nis2-agileandClaude Opus 4.8 b0fc190704 [FEAT] UI V3 — foundation (v3.css + topnav-v3.js + Inter/Lucide self-host) + dashboard pilota fedele al mockup
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>
2026-06-27 10:59:08 +02:00
DevEnv nis2-agileandClaude Opus 4.8 2a5d90f8bb [OPS] Manutenzione flag-gated: .htaccess (503→maintenance.html) + pagina + bypass token
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>
2026-06-27 10:42:29 +02:00
DevEnv nis2-agileandClaude Opus 4.8 b2fa1a163e [DOCS] UI V3 mockup: estratti index/assessment/calendario + zip (fonte visiva flotta)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 10:18:30 +02:00
DevEnv nis2-agileandClaude Opus 4.8 f9baf39599 [DOCS] UI V3 revamp — spec operativa per flotta di agenti (da mockup docs/mockup Ui)
Analisi dei 3 mockup (top-nav mega-menu, tema navy/oro, Inter, Lucide) → spec per
migrare l'UI dal V2 (Bootstrap Italia/sidebar) al V3: design system (token/chrome/
componenti), architettura migrazione (riusa api.js/auth/help/i18n/FAB, sostituisce
solo chrome+css), work-breakdown a fasi (F0 foundation+dashboard pilota; F1 flotta
1 agente/gruppo IA in worktree; F2 verifica), mappa IA, guardrail, acceptance per
pagina, decisioni utente aperte (§7). Mockup = fonte visiva, dati reali non mock.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 10:18:09 +02:00
DevEnv nis2-agileandClaude Opus 4.8 eb69a4f22e [FEAT] Discovery agent AWS (EC2/RDS/S3/SG → assets-ingest)
Connettore di discovery cloud AWS parallelo all'agente di rete: elenca
EC2/RDS/S3 via AWS CLI (zero dipendenze npm) + flussi SG ingress aperti
verso 0.0.0.0/0, mappa in asset NIS2 e POSTa a /api/services/assets-ingest
(source=aws). Config via env (RESOURCES/AWS_REGION/MAX_ITEMS/DRY_RUN),
gestione errori robusta (aws assente o comando fallito → messaggio chiaro).
README aggiornato con sezione AWS + permessi IAM read-only minimi.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 10:15:55 +02:00
DevEnv nis2-agileandClaude Opus 4.8 b787c327c1 [FEAT] Canale anonimo Vocea: pagina pubblica pre-login (scheletro) + risposta a Vocea
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>
2026-06-27 08:29:03 +02:00
DevEnv nis2-agileandClaude Opus 4.8 1fe5b7ae61 [DOCS] StarGateWB/Vocea: direttive anonimato segnalante per embed widget + gap NIS2
Ricevute da Vocea (27/6) le 6 regole per preservare l'anonimato del segnalante
nell'embed del widget. Gap analysis NIS2: la pagina app «Segnalazioni»
(whistleblowing.html) è dietro login → NON usabile come canale anonimo; serve una
pagina PUBBLICA pre-login. Più: no-log apertura, no id nell'URL iframe, check
event.origin, Referrer-Policy no-referrer, CSP frame-src app.vocea.cloud.
Origin da dare a Vocea per frame-ancestors: https://nis2.agile.software.
Da applicare all'attivazione Vocea (oggi scaffold dormiente).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 08:22:23 +02:00
DevEnv nis2-agileandClaude Opus 4.8 01b016da50 [FEAT] Connettori Discovery — UI gestione per org (Fase 4)
Pagina connettori-discovery.html + connettori-discovery.js (DiscoveryUI): lista
connettori, crea (mostra la chiave API una sola volta + comando agente), dettaglio
con storico run, rigenera chiave, elimina. Solo org_admin.
- Voce sidebar V2 "Connettori Discovery" in Operativo (common-bi.js, data-nav auto).
- api.js: metodi list/create/get/update/delete/rotateDiscoveryKey.
- ARIA navigationMapBlock: aggiunta la voce (coerenza assistente↔menu).
- help.js: _pageMap + guida contestuale "Connettori Discovery" (multi-connettore,
  come funziona, sicurezza scope ingest:assets).
Smoke: pagina 200, /api/discovery-connectors/list 401 (auth). Cache-buster
common-bi/help/api -> 20260625d.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 12:03:31 +02:00
DevEnv nis2-agileandClaude Opus 4.8 3d0bec1f7f [FEAT] Discovery agent di riferimento (scan rete → auto-popola NIS2) — Fase 3
scripts/discovery-agent.mjs (Node 18+, zero dipendenze): scansiona CIDR/IP via
TCP-connect (no root), reverse-DNS, deduce tipo asset + criticità dalle porte aperte,
costruisce asset (external_ref=net:<ip>) + flussi di rete e li POSTa a
/api/services/assets-ingest col X-API-Key del connettore. Concorrenza, MAX_HOSTS,
DRY_RUN, isPrivate (RFC1918+loopback+link-local). + README_discovery_agent.md (uso,
variabili, cron, multi-connettore, estensione cloud, sicurezza).
Validato: node --check + DRY_RUN reale (listener temporaneo) → rileva porta aperta,
costruisce asset+flusso corretti.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 11:45:13 +02:00
DevEnv nis2-agileandClaude Opus 4.8 b8ac793c8f [FEAT] Connettori discovery rete/cloud per-org → auto-popola Inventario (backend, mig 064)
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>
2026-06-26 11:38:55 +02:00
DevEnv nis2-agileandClaude Opus 4.8 cc7c6e4cf2 [FIX] ARIA: regola anti-invenzione record — stop confabulazione su reclami/ticket
Bug (segnalato "risponde mele per pere"): chiedendo ad ARIA "analizza la segnalazione
di Massimo Tagliavini e com'è stata gestita", ARIA FABBRICAVA un record falso (segnalante
"CISO", data "25 gennaio 2025", citazione inventata, gravità/stato/processo) — i ticket
dei singoli utenti vivono in AgileHub, non nei dati di ARIA → confabulava.
Fix: regola ANTI-INVENZIONE vincolante (priorità massima) nel system prompt di askWithRag:
non inventare MAI record specifici (segnalazioni/reclami/ticket/incidenti/persone/date/
citazioni/esiti) non presenti nei DATI ORG o nel contesto; i reclami/ticket dei singoli
utenti sono un sistema separato non accessibile → dichiararlo e indicare dove consultarli,
senza inventare. Smoke: ora ARIA NEGA correttamente l'accesso, nessun dettaglio fabbricato.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 16:05:37 +02:00
DevEnv nis2-agileandClaude Opus 4.8 ab3e88299e [FEAT] Inventario: ordinamento lista per colonna (#442)
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>
2026-06-25 10:41:34 +02:00
DevEnv nis2-agileandClaude Opus 4.8 87fc5bf959 [FEAT] Inventario: esportazione CSV in formato import-compatibile (#441)
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>
2026-06-25 09:13:22 +02:00
DevEnv nis2-agileandClaude Opus 4.8 b33e0d051e [FIX] ARIA polish post #439/#440: help Inventario allineato + regola anti-invenzione
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>
2026-06-25 08:56:25 +02:00
DevEnv nis2-agileandClaude Opus 4.8 9c36604b2b [FEAT] Inventario: Mappa Dipendenze + eliminazione beni (#440, #439)
- 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>
2026-06-25 08:43:54 +02:00
DevEnv nis2-agileandClaude Opus 4.8 3bd2f09a45 [DOCS] CONTEXT_LAST_SESSION 2026-06-24: Vocea scaffold + segnalazioni Massimo + Agile=studio + upgrade ARIA (A→D) + avviso tester
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 09:40:06 +02:00
DevEnv nis2-agileandClaude Opus 4.8 a982797fa2 [FEAT] ARIA voce naturale (proxy TTS nexus-voice-ms) + toggle voce — Fase C
Porting voce TRPG/AllTax (ElevenLabs "Sarah") sull'ARIA chat NIS2:
- AiController::tts() + route POST /api/ai/tts: proxy same-origin a nexus-voice-ms
  (config VOICE_MS_URL=172.21.0.1:4215, voce TTS_VOICE_ID=EXAVITQu4vr4xnSDxMaL,
  eleven_turbo_v2_5). requireAuth, cache MP3 sha256 (sys_get_temp_dir/nis2-tts-cache),
  validazioni (text<=800, voice_id allowlist), stream audio/mpeg, 502 se upstream non-audio.
- common.js: speak(answer) dopo ogni risposta ARIA (voce discreta vol .55, markdown
  strip), toggle 🔊/🔇 nell'header (muto persistito localStorage nis2_aria_voice),
  autoplay best-effort.
Smoke: voice-ms da nis2-app HTTP 200 audio/mpeg 19KB; /api/ai/tts 401 senza auth.
Reachability OK (no allowlist VOX necessaria). Cache-buster common.js -> 20260624g.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 08:58:05 +02:00
DevEnv nis2-agileandClaude Opus 4.8 fe7d0555c6 [FEAT] ARIA data-aware: snapshot dati org dell'utente nel prompt (Fase B)
Richiesta: "AI deve sapere i contenuti dei dati a cui ha accesso l'utente".
- AIService::orgDataSnapshotBlock($orgId): aggregati LIVE dell'org (compliance score,
  rischi aperti per livello + top 5, incidenti aperti, asset attivi/rilevanti NIS2,
  fornitori critici scoperti, NC aperte, formazione, policy per stato). Query con
  colonne reali (riuso DashboardController), ognuna in try/catch (degrada, non rompe).
- Iniettato in askWithRag SOLO se org_data_ok.
- SICUREZZA multi-tenant: AiController verifica membership in user_organizations
  (super_admin bypassa) → org_data_ok; scope rigoroso organization_id → niente leak
  cross-org da X-Organization-Id falsificato. PRIVACY: niente nome/fatturato (anonimizz.).
Smoke: con membership ARIA cita score 80% + 14 rischi (org 996003); senza membership
nega l'accesso ai dati. php-fpm reload.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 08:44:16 +02:00
DevEnv nis2-agileandClaude Opus 4.8 42529043d3 [FEAT] ARIA puntatore guida "Mostrami dov'è" — spotlight verso il menu (Fase D)
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>
2026-06-24 08:39:47 +02:00
DevEnv nis2-agileandClaude Opus 4.8 bafc305503 [FEAT] ARIA allineata all'Help contestuale della pagina + pageId canonico (Fase A)
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>
2026-06-24 08:30:10 +02:00
DevEnv nis2-agileandClaude Opus 4.8 3b9f30a890 [FEAT] Agile Technology = studio di consulenza che gestisce sé stessa (consolidamento)
Opzione A (decisione utente 24/6): nessun duplicato, nessuna rinomina. Seeder
idempotente+transazionale build_agile_consulente.php:
- consulting_firm 1: anagrafica REALE (P.IVA 07776161213, sede legale Roma Piazza
  di Campitelli 2 00186 RM, PEC agile.software@pec.it) — erano dati placeholder.
- org 996003 (Nuova Agile Technology srl, P.IVA 07776161213): consulting_firm_id=1
  → prima azienda auto-gestita dallo studio.
- firm_org_assignments: studio 1 ↔ org 996003 ↔ 4 admin.
- users.consulting_firm_id=1 per Benassati(4, consulente), Silvia Garretto(103,
  legale rappr = presidenza@), Tagliavini(326), Fattori(330).
Manuale/procedure/policy (12 doc published) già su 996003, non toccati. Rollback nel file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 08:09:07 +02:00
DevEnv nis2-agileandClaude Opus 4.8 e5f7a7d3a6 [FIX] Widget Segnalazioni: cap descrizione 1900 char + contatore, evita errore 'Data too long operative_summary' (ticket #430)
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>
2026-06-24 03:11:19 +02:00
DevEnv nis2-agileandClaude Opus 4.8 08d4ac0cc4 [FIX] ARIA: inietta griglia esatta combo Rilevanza NIS2 nel prompt (ticket #429)
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>
2026-06-24 00:09:24 +02:00
DevEnv nis2-agileandClaude Opus 4.8 cf23be9c77 [FEAT] Inventario Rilevanza NIS2: significato opzioni combo + dettaglio punteggio per criterio (ticket #431, #432)
- 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>
2026-06-23 22:43:43 +02:00
DevEnv nis2-agileandClaude Opus 4.8 ea5966eaee [FIX] ARIA: mappa navigazione reale + contesto pagina (ticket #424)
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>
2026-06-23 21:12:36 +02:00
DevEnv nis2-agileandClaude Opus 4.8 d45bd472cd [FIX] Vocea scaffold: rotta tenantInfo non versionata + portalUrl reale + namespace vault
Correzioni dallo smoke live su api.vocea.cloud (23/6, VIGILE/Vocea):
- tenantInfo(): /tenants/{slug}/info è sotto /api/wb (NON /api/wb/v1) → request() ora
  accetta baseOverride; aggiunto $apiBase (base senza /vN). I 3 /integrations/* restano /v1.
- portalUrl(): path reale /{locale}/segnala/{slug} (era /wb/{slug}); aggiunto
  portalStatusUrl() /{locale}/stato/{slug}; channelStatus espone portal_status_url.
- Vault namespace corretto: tier1__nis2-app__vocea (l'app reale è nis2-app, non nis2-agile).

Scaffold resta DORMIENTE (VOCEA_ENABLED=false). NB: VIGILE segnala che le route
/api/wb/v1/integrations sono ancora 404 (deploy MS incompleto) → non attivare finché
Vocea non completa il deploy e l'API key non è nel vault.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 19:50:50 +02:00
DevEnv nis2-agileandClaude Opus 4.8 637e1ec510 [FEAT] Inventario: rinomina/rimuovi sottoclassi org dalla modifica bene (ticket #426)
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>
2026-06-23 19:42:02 +02:00
DevEnv nis2-agileandClaude Opus 4.8 7529c59a75 [FIX] Inventario: combo Rilevanza NIS2 ripopolate alla riapertura (ticket #427)
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>
2026-06-23 18:36:33 +02:00
DevEnv nis2-agileandClaude Opus 4.8 bd1e95542c [FIX] ARIA chat: indicatore 'sta scrivendo' + input multi-riga (Shift+Invio)
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>
2026-06-23 18:13:38 +02:00
DevEnv nis2-agileandClaude Opus 4.8 4e2e56ec0b [FEAT] Vocea whistleblowing — scaffold integrazione (dormiente) + handoff AgileHub
Scaffold per sostituire il modulo whistleblowing interno (plaintext) con Vocea
(nexus-whistleblowing-ms), prodotto zero-knowledge della suite. Modalita C
(integrazione verticale, nessuna crypto re-implementata). DORMIENTE: VOCEA_ENABLED
=false di default -> zero impatto sul modulo legacy.

- docs/sql/063_vocea_channel.sql + application/cli/migrate_063_vocea_channel.php
  (idempotente): organizations += vocea_tenant_slug/channel_status/enrolled_at.
  NON ancora applicata al DB.
- application/services/VoceaService.php (nuovo): client API integratori (X-API-Key
  su api.vocea.cloud) per submit/status/reports/keyholders + portalUrl (embed
  wb-link.js). Guard enabled()/isEnabledForOrg(): se OFF/non provisioned ritorna
  DISABLED/NOT_PROVISIONED senza chiamate di rete.
- config.php: costanti VOCEA_ENABLED/BASE_URL/API_KEY/PORTAL_URL (default off).
- WhistleblowingController: branch dormiente in list() (delega a Vocea se attivo) +
  endpoint GET channelStatus + helper voceaOrg/listViaVocea. Modulo legacy invariato.
- public/index.php: route GET:channelStatus.
- docs handoff: richiesta a VIGILE (OUTGOING) + risposta VIGILE (INCOMING).

Attivazione a MS live: applicare migrate_063 + VOCEA_ENABLED=true + VOCEA_API_KEY
(vault tier1__nis2-agile__vocea__*) + slug canale su organizations.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 09:07:49 +02:00
DevEnv nis2-agileandClaude Opus 4.8 ef9a7282c5 [DOCS] Contesto: sedi Nuova Agile (anagrafica completa) + mail a Simon con richieste ACN aperte (92 vs 87 + date Determinazioni)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 12:26:29 +02:00
DevEnv nis2-agileandClaude Opus 4.8 be44e33b81 [CLIENT] Nuova Agile: sedi (legale Roma + operativa Modena) + scope SGSI allineato
Anagrafica: sede legale Piazza di Campitelli 2, 00186 Roma (address/city); sede operativa Strada Scaglia Est 15, 41121 Modena (mission). Scope/contesto SGSI resi precisi: sedi registrate ma modello work-from-anywhere. Anagrafica Nuova Agile ora completa (P.IVA + sedi + classificazione + DPO).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 12:20:05 +02:00