[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>
This commit is contained in:
DevEnv nis2-agile
2026-06-12 18:15:37 +02:00
co-authored by Claude Opus 4.8
parent 2b197440f6
commit e1ab0b3ea0
4 changed files with 355 additions and 0 deletions
+12
View File
@@ -113,6 +113,7 @@ $controllerMap = [
'ai' => 'AiController', // Assistente AI ARIA (askWithRag + fonti certe)
'branding' => 'BrandingController', // White-label firm (Fase 5 / G16)
'supplier-portal' => 'SupplierPortalController', // Portale fornitore Fase 3 (auth OTP/magic-link separata)
'demo' => 'DemoController', // Avatar di prodotto — demo guidata (product-demo-protocol v1.0.1)
];
if (!isset($controllerMap[$controllerName])) {
@@ -541,6 +542,17 @@ $actionMap = [
'GET:current' => 'getCurrent',
'PUT:index' => 'update',
],
// ── DemoController — Avatar di prodotto (product-demo-protocol v1.0.1) ──
// NB: il router camelCasa il segmento URL (session-start → sessionStart), quindi le chiavi
// dei multi-parola vanno in camelCase. URL esterni: /api/demo/session-start, /reset-dataset.
'demo' => [
'POST:sessionStart' => 'sessionStart',
'GET:manifest' => 'manifest',
'POST:event' => 'event',
'GET:credentials' => 'credentials',
'POST:resetDataset' => 'resetDataset',
],
];
// ═══════════════════════════════════════════════════════════════════════════