Smart Stadiums & Tournament Operations · one Next.js app · three role surfaces (Fan · Ops · Volunteer) · deterministic simulated telemetry (seed 2026) · a mock-first GenAI layer that boots with zero configuration
Demo context: the FIFA World Cup 2026 Final at MetLife Stadium (capacity 82,500), July 19 2026. Every number on screen is a clearly-labeled deterministic simulation — "Simulated telemetry · seed 2026." StadiumIQ never claims live FIFA or stadium data.
- Live URL: add after deploying — the app is deploy-ready (one Next.js app, no external services).
- Fan surface needs no login. Open
/and everything a spectator uses works immediately. Staff/volunteer surfaces use the one-click demo logins below. - Light & dark theme — a "broadcast night" dark theme (defaults to your OS preference) with a one-click toggle in every header; both themes are WCAG-AA contrast-checked in CI.
npm install
npm run verify # lint → typecheck → 383 tests + coverage gates → prod build → client-secret scan
npm run dev # → http://localhost:3000No environment variables are required. With none set, the app boots into offline Mock-AI mode (a dismissible banner says so) and every test runs without secrets. .env.example documents the two optional variables (GEMINI_API_KEY, AUTH_SECRET).
Open /?demo=finale (or press Play demo scenario on any page). The whole match day plays out unattended in ~90 seconds:
gates open → kickoff surge → 52′ Gate C hits 92% → threshold alert + AI mitigation + a multilingual PA broadcast landing on fan surfaces → halftime concession spike → full-time egress wave.
Every surface reacts live. Verified end-to-end with zero console errors (e2e/finale-walkthrough.spec.ts). A minute-by-minute narration is in docs/DEMO_SCRIPT.md.
Shown on /login on purpose — the evaluator path is one click. They exercise the real auth stack (bcrypt compare → HS256 JWT → RBAC); see SECURITY.md.
| Role | Password | What it unlocks | |
|---|---|---|---|
| Ops lead (staff) | ops@stadiumiq.demo |
WorldCup2026! |
/ops dashboard, incidents, PA studio, copilot |
| Gate C coordinator (volunteer) | volunteer@stadiumiq.demo |
GateC2026! |
/volunteer hub + incident reporting |
The Fan Companion (
/assistant,/navigate,/match,/food) requires no login at all.
Each criterion below links to living evidence in the repo. Self-audit scorecard (adversarial, ≥98 on every criterion) with full reasoning: docs/QA_REPORT.md.
| Criterion | How it's enforced | Evidence → file paths |
|---|---|---|
| Code Quality | tsc strict + noUncheckedIndexedAccess; ESLint strict-type-checked at --max-warnings 0 with an enforced complexity budget (cyclomatic ≤ 12, nesting ≤ 4, ≤ 5 params); Prettier formatting gated in verify; zero any; process.env walled into one module |
tsconfig.json, eslint.config.mjs, framework-free core in src/lib/, one-line JSDoc on every export, 10 ADRs in docs/adr/ |
| Security | RBAC in edge proxy and every route from one truth table; zod strictObject bodies; two-dimension login throttle; layered prompt-injection defense; client-bundle secret scan |
SECURITY.md, src/lib/auth/, src/proxy.ts, src/lib/ai/guards.ts, scripts/check-no-secrets.mjs, e2e/auth-rbac.spec.ts |
| Efficiency | First-load JS budget gated in CI on all 11 routes (≤250 KB, measured 241–250 KB); Lighthouse desktop 100 Perf | PERFORMANCE.md, e2e/perf-measure.spec.ts, one shared SSE connection, per-zone memoized selectors, lazy demo engine, zod-free type split |
| Testing | Coverage gates fail CI (80% global; 95% lines on simulation/nav/guards); 383 unit/component + 62 e2e against the prod build | TESTING.md, vitest.config.ts, e2e/ (incl. axe on every route) |
| Accessibility | @axe-core/playwright on every route + keyboard/RTL/reduced-motion/reflow checks fail CI; Lighthouse A11y 100 |
ACCESSIBILITY.md (full WCAG 2.2 AA table), e2e/a11y.spec.ts, src/lib/theme-contrast.test.ts |
| Problem Statement Alignment | The brief mapping below + the unattended /?demo=finale tour that fires the full operational story |
/?demo=finale, docs/DEMO_SCRIPT.md, the mapping table below |
GenAI is load-bearing across all four tracks — concierge, triage, copilot, PA translation, match commentary and mitigation are the product, not a bolted-on chatbot.
| Brief track | Feature | GenAI component |
|---|---|---|
| Dynamic crowd management | Live 16-zone SVG density heatmap, gate queue board (EWMA + Little's-Law waits), >80% threshold alerts with acknowledgement — src/features/ops/crowd/, src/lib/simulation/ |
Per-alert AI mitigation suggestions rendered in all six languages — src/lib/ai/mitigation.ts |
| Smart indoor navigation | Congestion-aware A* over live occupancy, find-my-seat, nearest restroom/food/first-aid/prayer, step-free toggle, localized turn-by-turn + route on map — src/lib/nav/, src/features/nav-ui/ |
Route weights consume the same live telemetry the AI tools read; directions localize through the i18n layer |
| Real-time decision support | Incident reporting (ops + volunteer) with AI triage (P1–P4, category confirm, actions, dedup), Ops Copilot NL Q&A with inline charts, one-click shift handover — src/features/incidents/, src/features/askops/, src/features/ops/HandoverCard.tsx |
Triage + copilot + handover on the provider layer behind a code-enforced 4-tool allowlist — src/lib/ai/triage.ts, askOps.ts, handover.ts, tools.ts |
| Multi-language assistance | Streaming concierge on an authored KB; full UI in en/es/fr/ar/pt/de with real Arabic RTL; PA Studio: English draft → 6 locales + tone check → broadcast to fan surfaces — src/features/concierge/, src/features/announcements/, src/lib/i18n/ |
Concierge + PA translation on the provider layer; injection guards + refusals — src/lib/ai/guards.ts, src/lib/ai/knowledge/ |
Fan Companion — Arabic RTL (/assistant) |
Volunteer Hub (/volunteer) |
|---|---|
![]() |
![]() |
PA Announcement Studio — 6-locale broadcast (/ops/announcements) |
Congestion-aware navigation (/navigate) |
|---|---|
![]() |
![]() |
Dark "broadcast night" landing with all three role surfaces: docs/screenshots/01-landing.png · the same landing in light theme: docs/screenshots/08-landing-light.png · Match center with AI commentary: docs/screenshots/06-match.png.
flowchart LR
subgraph Engine["Deterministic core (pure TS, framework-free) · src/lib"]
SIM["simulation/\nseeded engine · timeline\nqueue math (EWMA + Little's Law)"]
NAV["nav/\nA* over weighted zone graph\naccessible routing"]
I18N["i18n/\n6 locale dictionaries\nparity-tested"]
KB["ai/knowledge/\nauthored stadium KB ×6 locales"]
end
subgraph Server["Next.js route handlers (server)"]
HUB["telemetry hub\n1 sim instance · 3s ticks"]
SSE["/api/telemetry/stream (SSE)\n+ polling fallback"]
AI["/api/ai/* — chat · triage ·\nask-ops · announce · handover"]
AUTH["/api/auth/* + proxy.ts RBAC\n(jose HS256 httpOnly cookie)"]
end
subgraph Providers["LLM provider layer · src/lib/ai"]
IFACE["LLMProvider\nchat · generateStructured · stream"]
MOCK["MockProvider\ndeterministic · network-free\n(default, all tests)"]
GEM["GeminiProvider\nserver-only · flash-lite"]
GUARD["guards · LRU cache ·\nrate limits · tool allowlist"]
end
subgraph Client["Client (one shared SSE connection)"]
STORE["Zustand store\nalerts · acks · demo mode"]
FAN["Fan: assistant · navigate ·\nmatch · food"]
OPS["Ops: heatmap · queues ·\nincidents · copilot · PA studio"]
VOL["Volunteer hub"]
end
SIM --> HUB --> SSE --> STORE
STORE --> FAN & OPS & VOL
NAV --> FAN
KB --> IFACE
AI --> IFACE --> MOCK & GEM
GUARD --- IFACE
AUTH --- OPS & VOL
Strict, acyclic layering — app → features → components → lib (no feature imports a sibling feature). Deeper detail: docs/ARCHITECTURE.md and the 10 ADRs in docs/adr/.
| Script | Purpose |
|---|---|
npm run dev / build / start |
Develop / production build / serve |
npm run lint · typecheck |
ESLint strict-type-checked (zero warnings) · tsc --noEmit |
npm run test · test:coverage |
Vitest unit + component (coverage thresholds enforced) |
npm run test:e2e |
Playwright e2e + axe scans + security-header + JS-budget tests |
npm run check:secrets |
Greps the built client bundle for secrets (fails CI on a leak) |
npm run verify |
The full gate: lint → typecheck → coverage → build → secret scan |
Next.js 16 (App Router) + TypeScript strict · Tailwind CSS v4 · Zustand (slices + memoized selectors) · zod v4 (every API body, env, LLM output, SSE frame) · jose + bcryptjs (hand-rolled minimal sessions) · lucide-react · @google/genai (server-only) · Vitest + Testing Library · Playwright + @axe-core/playwright. No heavy UI kit, no chart library (the bar chart and the entire stadium plan are hand-rolled SVG — zero image assets). Every stack deviation is recorded as an ADR.
All telemetry is a deterministic simulation, labeled on every surface. The concession checkout is a demo order — no real payment and never renders a payment form. Mock-AI mode is announced by a banner. Fictional teams ("Blue" vs "Gold") — no real match data claimed.
MIT — see LICENSE.




