# MAPPA-LOGICA · AI Cross-Analysis ⟦ INIZIO · U-XA · Videata "AI Cross-Analysis" ⟧ File: public/cross-analysis.html · URL: /cross-analysis.html · Scopo: analisi AI conversazionale sui dati aggregati e anonimizzati del portfolio clienti di un consulente (gap comuni, rischio medio, categorie NIS2 deboli, benchmark), con storico delle analisi e vista dati portfolio · Profili: SOLO consultant e super_admin — il backend risponde error_code INSUFFICIENT_ROLE agli altri ruoli e la pagina mostra "Funzione riservata a Consulenti e Super Admin". • U-XA.1 — Header pagina + badge privacy/ruolo Mostra: titolo "AI Cross-Analysis" con badge verde "Dati aggregati — privacy garantita" e badge viola "Solo Consulenti & Admin". Azioni: nessuna (informativo). Dati da: statico (HTML). Confine: `header.content-header` (riga 280) — nessun id sugli elementi badge. • U-XA.2 — Header portfolio (banner viola) Mostra: "Il tuo portfolio — N organizzazioni monitorate" + 4 statistiche: Compliance medio (%), Rischi aperti, Formazione media (%), Organizzazioni. Se ruolo insufficiente: lucchetto + "Funzione riservata a Consulenti e Super Admin". Se errore: "Errore caricamento portfolio". Azioni: nessuna (lettura, caricata al boot da `loadPortfolio()`). Dati da: GET /api/cross-analysis/portfolio (risposta: data.org_count, data.aggregated.{avg_compliance_score, risks.total_open, training.avg_completion_rate, by_sector, score_distribution, assessments.avg_by_category}). Confine: `#portfolio-header` (riga 298). • U-XA.3 — Barra tab (Chat AI / Storico / Portfolio dati) Mostra: 3 tab con icone: "Chat AI", "Storico", "Portfolio dati"; tab attiva sottolineata viola. Azioni: click tab → `switchTab()` mostra il pannello corrispondente; la tab Storico carica lazy lo storico (U-XA.6). Dati da: nessuno (navigazione client-side). Confine: `.tab-bar[role="tablist"]` (riga 307); bottoni `.tab-btn` senza id ma con `aria-controls="tab-chat|tab-history|tab-portfolio"` (righe 308-315). • U-XA.4 — Tab Chat AI: domande rapide + input Mostra: empty state iniziale "Analisi AI del tuo portfolio clienti — Fai una domanda sui dati aggregati delle tue organizzazioni"; 6 chip di domande rapide: "Gap più frequenti", "Livello di rischio medio", "Categorie NIS2 deboli", "Intervento urgente", "Stato formazione", "Benchmark NIS2" (ognuna pre-compila una domanda in italiano); textarea domanda con invio via Enter (Shift+Enter per newline); bottone invio; nota privacy: "Dati anonimizzati e aggregati — nessun nome organizzazione inviato all'AI". Azioni: chip → `setQuestion()` pre-compila l'input; invio → `sendMessage()` aggiunge la bolla utente, mostra l'indicatore "thinking" animato, poi POST all'AI. Dati da: POST /api/cross-analysis/analyze (body: {question}; risposta: data.result + data.org_count). Confine: `#tab-chat` (riga 320); `#chat-messages` (322), `#chat-empty` (323), `#quick-qs` (330), `#chat-input` (340), `#btn-send` (342). • U-XA.5 — Risposta AI strutturata (bolla chat) Mostra: risposta testuale (answer); sezioni opzionali: "Risultati chiave" (key_findings, elenco), "Raccomandazioni" (recommendations, elenco), "Aree di attenzione" (risk_areas, elenco), box viola benchmark (benchmark_note), box ambra nota privacy (privacy_note); footer "Basato su N organizzazioni anonimizzate" + orario. In caso di errore: bolla rossa con il messaggio. Azioni: nessuna (output). Dati da: risposta di POST /api/cross-analysis/analyze (result.{answer, key_findings[], recommendations[], risk_areas[], benchmark_note, privacy_note}). Confine: bolle generate via JS dentro `#chat-messages`; indicatore thinking con id dinamico `#think-`. • U-XA.6 — Tab Storico Mostra: lista delle ultime 20 analisi: data/ora (it-IT), domanda (prompt_summary, ripulita dal prefisso "CROSS_ORG [...]"), sintesi risposta (response_summary); "Nessuna analisi precedente." se vuoto. Azioni: caricata al click sulla tab (lazy via `loadHistory()`). Dati da: GET /api/cross-analysis/history?limit=20 (risposta: data.history[]). Confine: `#tab-history` (riga 355), `#history-content` (riga 356). • U-XA.7 — Tab Portfolio dati Mostra: card "Distribuzione Settoriale" (settore, conteggio, % con barra viola); card "Distribuzione Score Compliance" (fasce 0-20% … 81-100% colorate dal rosso al verde, conteggio org per fascia); card "Score Medio per Categoria NIS2 (dal più basso)" — fino a 5 categorie con % colorata (rosso <30, ambra <60, verde altrimenti) e mini progress bar. Azioni: nessuna (lettura, renderizzata da `renderPortfolioTab()` con i dati già caricati al boot). Dati da: GET /api/cross-analysis/portfolio (stessa chiamata di U-XA.2: aggregated.by_sector, aggregated.score_distribution, aggregated.assessments.avg_by_category). Confine: `#tab-portfolio` (riga 362), `#portfolio-content` (riga 363). ⟦ FINE · U-XA ⟧ ## ID STABILI MANCANTI (da aggiungere) | Elemento | Riga | Id proposto | |---|---|---| | Tab "Chat AI" | 308 | `nis2-xa-tab-btn-chat` | | Tab "Storico" | 311 | `nis2-xa-tab-btn-history` | | Tab "Portfolio dati" | 314 | `nis2-xa-tab-btn-portfolio` | | Badge privacy header | 284 | `nis2-xa-privacy-badge` | | Badge "Solo Consulenti & Admin" | 289 | `nis2-xa-role-badge` | | Chip domande rapide (6) | 331-336 | `nis2-xa-quickq-1` … `nis2-xa-quickq-6` (o `data-quickq`) |