# Fan Passport: The World Cup Journey — Demo Release Package Milestone #5 connects the interactive frontend prototype to the backend MVP and turns the project into a runnable end-to-end demo. The app lets a fan create a passport, collect teams/matches/stadiums/stickers, answer trivia, submit predictions, unlock badges, complete challenges, add memories, and see their leaderboard rank move. The 2026 draw is not complete at the time of this milestone, so the content model uses deterministic demo fixtures and representative teams/stadiums. The code is structured so the seed data can be replaced with official draw data later without rewriting the user flows. ## Stack - **Monorepo:** npm workspaces - **Shared model package:** TypeScript content seeds and API contracts - **API:** Node 20+, Express 4, Zod validation, in-memory demo store, gamification engine - **Web:** React 18, Vite, TypeScript - **Tests:** Vitest + Supertest integration tests, React Testing Library, Playwright E2E, Axe accessibility scan through Playwright No lockfile is hand-written in this release. Generate one on a clean machine with `npm install`. ## Quickstart ```bash npm install npm run dev ``` Open: ```text http://localhost:5173 ``` The API runs at: ```text http://localhost:4000/api ``` Health check: ```bash curl http://localhost:4000/api/health ``` Expected response shape: ```json { "ok": true, "version": "2026-demo-v1", "uptime": 1.23 } ``` ## Environment configuration Local defaults work without extra configuration. To customise ports/origins: ```bash cp apps/api/.env.example apps/api/.env cp apps/web/.env.example apps/web/.env.local ``` API variables: | Variable | Default | Purpose | | --- | --- | --- | | `PORT` | `4000` | API port | | `HOST` | `0.0.0.0` | API listen host | | `CORS_ORIGIN` | `http://localhost:5173,http://127.0.0.1:5173` | Comma-separated allowed web origins | Web variables: | Variable | Default | Purpose | | --- | --- | --- | | `VITE_API_BASE_URL` | `http://localhost:4000/api` | Browser API base URL | ## Demo journey 1. Create a passport as “Backer Demo Fan”. 2. Collect the Group B teams: England, USA, Iran, Wales. 3. Answer the first trivia question correctly. 4. Predict USA to beat England as the giant-killing pick. 5. Add a tournament memory. 6. Watch the challenge panel, badge shelf, achievement timeline, and leaderboard update. A presenter-ready walkthrough is in [`docs/demo-script.md`](docs/demo-script.md). ## Important scripts ```bash npm run dev # Build shared contracts, then run API + web together npm run build # Build shared package, API, and web npm run test # Shared build, API integration tests, web component tests npm run test:integration # API integration tests only npm run test:e2e # Playwright E2E and accessibility smoke test npm run qa # Unit/integration + Playwright E2E npm run release:check # Build + non-browser automated tests ``` For Playwright on a fresh machine, install browsers once: ```bash npx playwright install --with-deps chromium ``` If your environment does not support `--with-deps`, use: ```bash npx playwright install chromium ``` ## API endpoints All endpoints are under `/api`. | Method | Endpoint | Purpose | | --- | --- | --- | | `GET` | `/health` | Service health | | `GET` | `/content` | Teams, stadiums, matches, trivia, badges, challenges, collection items | | `POST` | `/users` | Create a demo passport user | | `GET` | `/passport/:userId` | Get current passport state | | `GET` | `/leaderboard` | Get global demo leaderboard | | `POST` | `/collect` | Collect team/match/stadium/sticker | | `POST` | `/trivia/:questionId/answer` | Answer a trivia question | | `POST` | `/predictions` | Submit or update a match prediction | | `POST` | `/memories` | Add a tournament memory | | `POST` | `/demo/reset` | Clear in-memory demo users | Example create-user request: ```bash curl -X POST http://localhost:4000/api/users \ -H "Content-Type: application/json" \ -d '{"displayName":"Backer Demo Fan","country":"England"}' ``` Example collection request: ```bash curl -X POST http://localhost:4000/api/collect \ -H "Content-Type: application/json" \ -d '{"userId":"USER_ID_FROM_CREATE","itemType":"team","contentId":"england"}' ``` ## Data and persistence This milestone intentionally uses an in-memory store for a safe public demo. The store includes: - Duplicate collection protection - Input validation and useful error responses - Idempotent trivia-answer handling - Prediction update handling before kick-off - Challenge completion rewards applied once - Leaderboard ranking rebuilt after each action For a production launch, replace `DemoStore` with a database-backed implementation behind the same shared API contracts. ## QA and release documentation - [`docs/qa-plan.md`](docs/qa-plan.md): automated/manual QA coverage, accessibility checks, edge cases, responsive notes - [`docs/deployment.md`](docs/deployment.md): deploy options and environment guidance - [`docs/release-checklist.md`](docs/release-checklist.md): public release checklist - [`docs/crowdfunding-update.md`](docs/crowdfunding-update.md): short update text for backers ## Build hygiene notes - Dependencies are declared in the workspace/package manifest that imports them. - The shared package must be built before API/web dev commands; root scripts do this automatically. - Node is constrained to `>=20` rather than an exact or stale toolchain pin. - No generated lockfile is included. Run `npm install` once to create `package-lock.json` for reproducible installs. - The API and web share TypeScript contracts from `@fan-passport/shared`, preventing route/request/response drift. ## Maintainer verification checklist Because this package was authored without running a compiler in this environment, verify these SDK calls after dependency resolution: 1. Express 4 middleware wiring: `express.json`, `cors`, `helmet`, `morgan`. 2. Zod 3 parsing and `ZodError#flatten`. 3. Vite 5 React plugin config through `@vitejs/plugin-react`. 4. Vitest config loading for ESM TypeScript workspaces. 5. Playwright `defineConfig`, `webServer`, and `@axe-core/playwright` `AxeBuilder`. 6. React Testing Library render/query APIs with React 18. Run `npm run release:check` and then `npm run test:e2e` before publishing the demo.