[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>
This commit is contained in:
DevEnv nis2-agile
2026-06-23 21:12:36 +02:00
co-authored by Claude Opus 4.8
parent d45bd472cd
commit ea5966eaee
43 changed files with 112 additions and 59 deletions
+4
View File
@@ -39,10 +39,14 @@ class AiController extends BaseController
}
$user = $this->getCurrentUser() ?? [];
// Pagina corrente (facoltativa) inviata dal frontend, per dare ad ARIA
// contesto sulla schermata da cui l'utente sta scrivendo (ticket #424).
$page = mb_substr(trim((string) $this->getParam('page', '')), 0, 120);
$userContext = [
'user_id' => $userId,
'organization_id' => $this->getCurrentOrgId(), // può essere null
'consulting_firm_id' => $user['consulting_firm_id'] ?? null,
'page' => $page,
];
try {
+37 -2
View File
@@ -56,6 +56,30 @@ class AIService
. "5. ENISA, NIST e ISO sono best practice di settore, NON fonti normative vincolanti: gli obblighi italiani derivano da Direttiva (UE) 2022/2555, D.Lgs. 138/2024 e Determinazioni ACN.\n";
}
/**
* Mappa REALE della barra laterale dell'applicazione, da iniettare nel
* system prompt dell'assistente ARIA cosi' che le indicazioni di navigazione
* usino i nomi ESATTI del menu e non vengano inventati moduli/fasi inesistenti.
*
* ⚠️ TENERE SINCRONIZZATA con la fonte di verita' della sidebar:
* public/js/common-bi.js (array navItems). Se aggiungi/rinomini una voce
* di menu li', aggiorna anche questo elenco.
* (Ticket #424, 2026-06-23: ARIA citava voci di menu inesistenti.)
*/
private function navigationMapBlock(): string
{
return "\n## MAPPA DELLA NAVIGAZIONE (barra laterale REALE dell'app)\n"
. "Sezione \"Principale\": Dashboard · Calendario · Compliance Journey · Gap Analysis · Misure e Requisiti · Modello SGSI (ISO 27001).\n"
. "Sezione \"Gestione\": Organigramma · Competenze · Rischi · Incidenti · Policy · Supply Chain · Stakeholder · Attivita' stakeholder · Segnalazioni · Normative · AI Cross-Analysis · Knowledge Base.\n"
. "Sezione \"Operativo\": Formazione · Inventario · Audit interni · Controlli periodici · Riesame di Direzione · Audit & Report.\n"
. "Sezione \"Sistema\": Guida all'uso · Impostazioni · Architettura · Simulazione Demo · Integrazioni Esterne.\n"
. "\nREGOLE DI NAVIGAZIONE (vincolanti):\n"
. "1. Quando indichi DOVE cliccare o COME raggiungere una funzione, usa ESCLUSIVAMENTE i nomi delle voci qui sopra, esattamente come scritti, indicando la sezione (es. \"nella sezione Operativo, voce Inventario\").\n"
. "2. NON inventare nomi di menu, \"fasi\", codici (es. \"A4\", \"Fase 4.1\") o moduli che NON compaiono in questo elenco.\n"
. "3. L'inventario degli asset si trova in: sezione Operativo > Inventario. La valutazione del rischio in: sezione Gestione > Rischi. Misure e requisiti in: sezione Principale > Misure e Requisiti.\n"
. "4. Se l'utente cerca una funzione che non corrisponde ad alcuna voce, dillo chiaramente e suggerisci la voce piu' vicina, senza inventarne una.\n";
}
/**
* Analizza risultati gap analysis e genera raccomandazioni
*/
@@ -702,9 +726,20 @@ PROMPT;
error_log('[AIService::askWithRag] RAG failed, fallback diretto: ' . $e->getMessage());
}
$systemPrompt = "Sei un esperto consulente di cybersecurity NIS2 (EU 2022/2555) e D.Lgs. 138/2024.\n"
$systemPrompt = "Sei ARIA, l'assistente dell'applicazione NIS2 Agile, esperta di cybersecurity NIS2 (EU 2022/2555) e D.Lgs. 138/2024.\n"
. "Rispondi in modo preciso e cita le fonti del contesto quando rilevanti.\n"
. $this->authoritativeSourcesBlock();
. $this->authoritativeSourcesBlock()
. $this->navigationMapBlock();
// Pagina corrente dell'utente (se inviata dal frontend): aiuta ARIA a
// dare indicazioni contestuali invece di rimandare a moduli a caso.
$page = trim((string) ($userContext['page'] ?? ''));
if ($page !== '') {
$systemPrompt .= "\n## CONTESTO UTENTE\n"
. "L'utente si trova attualmente nella pagina: \"" . $page . "\". "
. "Tieni conto di dove si trova quando dai indicazioni di navigazione.\n";
}
if (!empty($contextBlock)) {
$systemPrompt .= "\n## Contesto documentale (knowledge base)\n" . $contextBlock
. "\n\nQuando rispondi, cita esplicitamente i numeri tra parentesi quadre [1], [2], ... che corrispondono ai documenti del contesto.";