Files
nis2-agile/docs/DEMO_AVATAR_NIS2.md
T
DevEnv nis2-agileandClaude Opus 4.8 e1ab0b3ea0 [DEMO] Avatar di prodotto Fase 1 — fondazione backend (5 endpoint /api/demo/*)
product-demo-protocol v1.0.1, Modalita A. Additivo (zero impatto endpoint esistenti).

- DemoController: session-start, manifest, event, credentials, reset-dataset
  * demo_jwt scope=demo:read-only, org_id 996001 (range demo 996000-996999), TTL 30m
  * hmac_key_seed base64 44ch, rate-limit 5/min+50/h per IP, eventi idempotenti
- Migration 040: tabelle demo_sessions + demo_events
- Rotte 'demo' in index.php (chiavi camelCase: router camelCasa il segmento URL)
- docs/DEMO_AVATAR_NIS2.md: piano Fase1/Fase2, decisioni, punti integrazione AgileHub, gap protocollo

Smoke prod OK: session-start 201, manifest 200, credentials 200, event 204, reset 401(no key).
TODO Fase 1: read-only guard in requireAuth, dataset demo 996001, frontend demo-mode, manifest+mappe.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 18:15:37 +02:00

69 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Avatar di prodotto NIS2 — Demo + Formazione (standard product-demo-complete)
> Stato: **Fase 1 (DEMO) in costruzione**. Owner prodotto: NIS2. Owner persona/voce/collaudo: AgileHub.
> Persona già LIVE: `ARIA_SUPPORT_NIS2` (id=4). Voce ARIA riusata (niente consenso voce).
> Modalità **A** (prodotto live: l'avatar pilota la SPA reale).
## Decisioni prese (2026-06-12)
1. **Scopo**: ENTRAMBI, in 2 fasi → Fase 1 DEMO (vetrina prospect ~10 step) poi Fase 2 FORMAZIONE (riusa i mattoni + curriculum/quiz/attestato).
2. **Completamento formazione**: **esame con soglia** (quiz valutato da LLM-giudice, attestato solo se ≥ soglia, es. 80%). Coerente col gate G7.
3. **Dominio same-origin**: **dimostrazione.agile.software** (come ALLTAX/TRPG): landing serve la SPA NIS2 in iframe same-origin con proxy `/api/*` → backend NIS2.
## Range riservato demo (NIS2)
`organization_id` **996000–996999** (per standard §7.1). Org demo isolata: **996001** (ente fittizio). Separata dalle org reali e dalle 2 golden-demo (#151/#152).
## Deliverable lato prodotto — DEMO (punti 1–5 del brief)
- [x] **Migration** `docs/sql/040_demo_sessions.sql` — tabelle `demo_sessions` + `demo_events`.
- [x] **DemoController** (`application/controllers/DemoController.php`) — 5 endpoint (vedi sotto).
- [x] **Rotte** `demo` registrate in `public/index.php`.
- [ ] **Guardia read-only + demo-JWT in `requireAuth`** (BaseController) — *step isolato, delicato: tocca l'auth di ogni endpoint*. Design sotto §Read-only.
- [ ] **Dataset demo isolato** (org 996001 + dati finti) + reset.
- [ ] **Frontend**: `public/js/demo-mode.js`, `public/js/demo-selectors.js`, `public/css/demo.css`, hook `?demo=` nell'entry-point.
- [ ] **Manifest** `public/demo/nis2-tour-2026.json` (~10 step IT; EN dopo).
- [ ] **Mappe** `docs/mappa-logica/*.md` (1 per vista) + `SELETTORI_DEMO.md` + anchor `data-demo-action` + id stabili nel DOM.
## Deliverable IN PIÙ — FORMAZIONE (punti 6–7, dopo la demo)
- [ ] Mappa-logica **COMPLETA** (tutte le viste, non solo le 10 della demo).
- [ ] **Tassonomia corso** (moduli → lezioni → argomenti, prerequisiti, durata). *Formato JSON da definire (lo standard non lo fissa).*
- [ ] (opz.) banca esercizi/domande per modulo + sandbox scrivibile isolata.
## Endpoint (route shape scelta)
Per non combattere il router NIS2 (path-param numerici), il `session_id` (stringa `demo-<uuid>`) viaggia in **query/body**, non in path. Le URL esatte che userà il widget sono quelle che ritorno io in `session-start` (`manifest_url`, `credentials_url`), quindi è conforme.
| Endpoint | Metodo | Auth | Note |
|---|---|---|---|
| `/api/demo/session-start` | POST | pubblico (rate-limit 5/min, 50/h per IP) | ritorna session_id, demo_jwt (scope=demo:read-only, org_id 996001, TTL 30m), hmac_key_seed (base64 44ch), spa_iframe_url, manifest_url, credentials_url, expires_at, presentation_mode |
| `/api/demo/manifest?session_id=` | GET | Bearer demo_jwt o session_id | ritorna il manifest tour |
| `/api/demo/event` | POST | Bearer demo_jwt | telemetria step (idempotente) |
| `/api/demo/credentials?session_id=` | GET | session valida (same-origin/bearer) | ritorna demo_jwt+org+expires (per bootstrap SPA in iframe) |
| `/api/demo/reset-dataset` | POST | `X-Internal-Key` | reset dataset demo (cron 0 3 * * *) |
## Read-only enforcement (design — da implementare con cura)
Il demo_jwt è messo dalla SPA in `localStorage.jwt` e usato sulle API reali (dashboard, risks, ...). Quindi `BaseController::requireAuth()` deve **riconoscere** il demo_jwt:
- se `payload.scope === 'demo:read-only'`: **bypassa** il check `jti`/`active_sessions`, imposta org corrente = `payload.org_id` (forzato nel range 996000–996999), e **blocca ogni verbo di scrittura** (POST/PUT/PATCH/DELETE) sulle API app → `403 DEMO_READ_ONLY` (eccetto gli endpoint `/api/demo/*`);
- range guard: demo_jwt fuori range → `403 DEMO_JWT_CANNOT_ACCESS_PRODUCTION`; JWT di produzione su org in range demo → `403 PRODUCTION_JWT_CANNOT_ACCESS_DEMO`.
- `getCurrentOrgId()` in demo ignora `X-Organization-Id` e usa l'org del JWT.
## Punti di integrazione DA CONFERMARE con AgileHub (gap dello standard)
1. **Canonical HMAC del canale postMessage**: lo standard ha **2 versioni divergenti** di `signDemoMessage`/`verifyDemoMessage` (ordine canonical `{message_id,...}` vs `{message_id,session_id,...}`, channelKey CryptoKey vs raw). Il `demo-mode.js` di NIS2 deve combaciare **byte-per-byte** col widget AgileHub deployato → **confermare quale canonical usa il widget live** prima dello smoke.
2. **Nome storage seed**: `bootstrapDemoAuth` legge `sessionStorage['demo_hmac_seed']` ma il campo API è `hmac_key_seed` → allineare chi scrive il seed in sessionStorage (widget) e chi lo legge (SPA).
3. **Same-origin / proxy** su `dimostrazione.agile.software` → `/api/*` verso backend NIS2 (config gateway lato AgileHub) + CSP che permetta l'iframe.
4. **Catalog/binding tour**: lato AgileHub servono `provider_resources_catalog (demo_tour)` + `agent_resource_bindings (demo_tour)` o il bootstrap meet-page aborta "no matching tour".
5. **Allineamento 3-way** DOM ↔ `demo-selectors.js` ↔ `SELETTORI_DEMO.md`: ogni cambio selettore → avvisare AgileHub per re-ingest RAG (dedup per content_hash → erasure-prima).
## Collaudo (definizione di "fatto")
DEMO: G1 selezione ≥95% PASS · **G2 parlato ≥8/10 e 0 leak** · G3 vista ≤5% falsi positivi · G4 sicurezza/GDPR verde.
FORMAZIONE (+): G5 copertura (nessun buco) · G6 accuratezza didattica · G7 validità assessment.
> "Fatto" solo quando passa il collaudo (mostra la cosa giusta, dice cose vere) — non quando l'avatar parla.
## Tour proposto (~10 step, sulla V2 reale)
1 Dashboard (score+scadenze) · 2 Assessment (gap Art.21) · 3 Rischi (matrice+trattamenti) · 4 Incidenti Art.23 (24h/72h) · 5 Policy · 6 Supply chain · 7 Asset (relevance GV.OC-04) · 8 Report · 9 Normative/ACN · 10 ARIA (assistente AI).
## Riferimenti
- Standard protocollo: `agile-services/docs/STANDARD_PRODUCT_DEMO_PROTOCOL.md` (v1.0.1)
- Standard metodo+collaudo: `agile-services/docs/STANDARD_PRODUCT_DEMO_COMPLETE.md`
- Requisiti NIS2: `agile-services/docs/OUTGOING_TO_NIS2_2026_05_29_demo_avatar_requirements.md`
- How-to mappe: `agile-services/docs/PLAYBOOK_DEMO_AVATAR_MAPPE.md`
- Esempio dev: `agile-services/docs/SPEC_ALLTAX_DEMO_AVATAR_PER_DEV.md`
- Formazione: `agile-services/docs/DESIGN_AVATAR_FORMAZIONE.md`