[DEMO] Frontend demo-mode (punto 4): demo-mode.js + demo-selectors.js + demo.css + hook ?demo=

Avatar di prodotto, product-demo-protocol v1.0.1 (NIS2 multi-page):
- public/js/demo-mode.js: runtime canale postMessage (inbound navigate/highlight/scroll_to/
  trigger_action/open_tab/...; outbound ready/spa_state_changed/step_animation_done/...),
  verifica origin+HMAC (chiave SHA-256(jwt:seed:demo-control-channel))+idempotency, banner read-only.
- public/js/demo-selectors.js: whitelist 17 viste (view->url) + azioni read-only sicure.
- public/css/demo.css: highlight pulse-blue/halo + banner.
- common-bi.js: hook che inietta gli asset SOLO con ?demo= (no-op per utenti normali).

NOTE: (a) HMAC canonical del MESSAGGIO da riconciliare con AgileHub al collaudo (canonicalize()).
(b) manca il manifest (steps+selettori) — dipende dagli id stabili in corso.
node --check OK su tutti.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile
2026-06-13 08:56:36 +02:00
co-authored by Claude Opus 4.8
parent be29895446
commit d16fdd2c02
4 changed files with 278 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
/*
* NIS2 Agile — Avatar di prodotto: WHITELIST selettori/azioni demo (product-demo-protocol v1.0.1).
*
* Fonte di verità (regola 3-way): DOM ↔ questo file ↔ docs/mappa-logica/SELETTORI_DEMO.md
* devono restare allineati. Se cambi un selettore qui o nel DOM → avvisa AgileHub per il re-ingest RAG.
*
* - VIEWS: nomi-vista del manifest → URL pagina reale (NIS2 è multi-page: navigate = cambio pagina,
* con ?demo=<id> preservato da demo-mode.js).
* - ACTIONS: SOLO azioni read-only sicure lanciabili dal tour (trigger_action). Ogni azione mappa a un
* anchor data-demo-action="<nome>" nel DOM. In demo:read-only le scritture sono già bloccate server-side
* (guard DEMO_READ_ONLY); qui restano solo azioni di consultazione (apri tab/dettaglio/pannello).
*/
(function (w) {
'use strict';
// vista (manifest view_target) → pagina reale
var VIEWS = {
'dashboard': '/dashboard.html',
'assessment': '/assessment.html',
'acn-gap': '/acn-gap.html',
'risks': '/risks.html',
'incidents': '/incidents.html',
'policies': '/policies.html',
'supply-chain': '/supply-chain.html',
'assets': '/assets.html',
'training': '/training.html',
'reports': '/reports.html',
'isms': '/isms.html',
'normative': '/normative.html',
'whistleblowing': '/whistleblowing.html',
'kb': '/kb.html',
'cross-analysis': '/cross-analysis.html',
'settings': '/settings.html',
'companies': '/companies.html'
};
// azioni read-only sicure (whitelist). value = come eseguirle in pagina.
// { type:'click', selector } | { type:'tab', selector } | { type:'anchor', action }
// NB: anchor = clicca l'elemento [data-demo-action="<action>"] (da cablare nel DOM).
var ACTIONS = {
// navigazione interna sicura (apertura tab di una vista)
'open-tab-matrix': { type: 'anchor', action: 'open-tab-matrix' }, // risks: vista Matrice 5x5
'open-tab-fair': { type: 'anchor', action: 'open-tab-fair' }, // risks: vista FAIR
'open-tab-controls': { type: 'anchor', action: 'open-tab-controls' }, // reports: tab Controlli
'open-tab-iso': { type: 'anchor', action: 'open-tab-iso' }, // reports: tab ISO 27001
'open-tab-audit': { type: 'anchor', action: 'open-tab-audit' }, // reports: tab Audit Log
'open-tab-acn': { type: 'anchor', action: 'open-tab-acn' }, // reports: tab Requisiti ACN
// pannelli/consultazione (read-only)
'open-ai-panel': { type: 'anchor', action: 'open-ai-panel' }, // cross-analysis: chat ARIA
'open-first-detail': { type: 'anchor', action: 'open-first-detail' } // apre il primo dettaglio di una lista
};
w.NIS2_DEMO_SELECTORS = {
version: '1.0',
// protocollo: queste sono le UNICHE viste/azioni eseguibili dal canale demo
views: VIEWS,
actions: ACTIONS,
viewUrl: function (view) { return VIEWS[view] || null; },
isAllowedAction: function (name) { return Object.prototype.hasOwnProperty.call(ACTIONS, name); },
action: function (name) { return ACTIONS[name] || null; }
};
})(window);