# Edge Cases and Failure Modes This document captures the integration behaviours that should remain stable as the Fan Passport demo evolves from World Cup 2026 into future football passports. ## Principle Every user action should be: - validated before mutation; - idempotent where repeated clicks are plausible; - clear about reward outcomes; - recoverable after network failure; - reflected consistently in challenges, badges, XP, and leaderboard data. ## Collection edge cases ### Duplicate collection Expected behaviour: - The item remains collected. - XP is not awarded a second time. - Duplicate entries are not added to the collection list. - Challenge progress does not exceed its configured maximum. - UI shows “collected”, disabled, or equivalent state. Reviewer check: 1. Collect a team. 2. Trigger the same collect action again using the UI or browser replay. 3. Confirm XP and progress remain stable after the first award. ### Unknown item ID Expected behaviour: - API returns a structured validation/not-found error. - Frontend shows a friendly error. - No partial mutation occurs. - User can continue using the app. Reviewer check: - Use integration tests for invalid IDs. - If manually testing, alter a request in devtools or use an HTTP client against the local API. ### Fast double click Expected behaviour: - UI disables or de-dupes the pending action. - Backend idempotency still protects XP and badge awards. - Final state is the same as one click. Reviewer check: 1. Slow the network in devtools. 2. Double-click a collect button. 3. Confirm only one reward event is counted. ## Trivia edge cases ### Re-answering a question Expected behaviour: - First answer records correctness and rewards according to rules. - Later attempts do not create duplicate reward events. - UI communicates that the question has already been answered. ### Invalid option Expected behaviour: - API rejects the request. - Frontend highlights the problem. - No answer record or XP mutation is created. ### No trivia available Expected behaviour: - Trivia panel shows an empty state. - Empty copy points users toward other passport activities. - No uncaught runtime error occurs. ### Correctness feedback Expected behaviour: - Correct/incorrect result is written as visible text. - Color is supplementary. - Challenge progress updates only when the action qualifies. ## Prediction edge cases ### Incomplete prediction Expected behaviour: - Submit is blocked client-side when possible. - API still validates server-side. - Error copy identifies the missing field. ### Impossible score or invalid team Expected behaviour: - API rejects invalid payload. - Frontend keeps the user’s input so it can be corrected. - No XP, badge, or challenge progress is awarded. ### Duplicate prediction Expected behaviour depends on the selected product rule: - If predictions are editable: update the existing prediction in place and do not award first-submit XP again. - If predictions are locked: reject the duplicate with clear copy. - In both cases, leaderboard and challenge progress must not double-count. ### Locked prediction window Expected behaviour for future production hardening: - Prediction submission is rejected after kickoff/lock time. - The UI explains why the action is unavailable. - Previously submitted predictions remain visible. The demo can simulate this rule through seeded content or validation tests even if real kickoff automation is not included yet. ## Challenge and badge edge cases ### Multiple unlocks from one action Expected behaviour: - All unlocked badges/challenges are recorded. - UI remains readable and does not hide later unlocks. - XP total equals the sum of eligible first-time rewards. - Refresh shows all unlocked achievements. ### Progress beyond maximum Expected behaviour: - Stored progress may track raw action counts internally if useful. - Displayed progress should cap at 100% or `required / required`. - Completion should not be awarded more than once. ### Challenge with missing content Expected behaviour: - Challenge catalogue should not crash if seeded content is incomplete. - UI should show unavailable/in-progress state rather than broken references. - Release QA should treat missing content for demo-critical challenges as a blocker. ## Leaderboard edge cases ### Tie scores Expected behaviour: - Users with the same XP appear in deterministic order. - Rank display is consistent after refresh. - Demo user’s row is easy to find. ### Empty leaderboard Expected behaviour: - UI shows an empty state with an invitation to earn XP. - API returns an empty list rather than an error. - First XP action creates a leaderboard entry. ### XP consistency Expected behaviour: - User profile/passport XP and leaderboard XP agree. - Badge/challenge reward XP is added once. - Recomputing leaderboard from store data yields the same order. ## Loading and concurrency edge cases ### Slow first load Expected behaviour: - Loading text/skeleton appears. - Layout does not jump excessively when data arrives. - User is not shown stale error copy before the first request resolves. ### Mutation pending Expected behaviour: - The control being submitted enters a pending or disabled state. - Other unrelated controls remain usable where safe. - If the mutation succeeds, state updates without full page reload. - If it fails, the control recovers. ### Refresh during mutation Expected behaviour: - Backend remains source of truth. - On reload, UI reflects either the completed mutation or the previous stable state. - Partial client-only optimistic state is not permanently trusted. ## API and deployment failure modes ### API unavailable Expected behaviour: - Frontend shows a clear error state. - Previously loaded static shell still renders. - Retry after API restart works. ### CORS or wrong API base URL Expected behaviour: - Deployment documentation identifies the required frontend API environment variable. - Browser console error is expected during diagnosis, but UI should still show user-friendly copy. - Smoke check should be run against deployed URLs before public sharing. ### Port conflict locally Expected behaviour: - README or runbook explains default ports and how to override them. - API and web app should not silently point at different environments. ### Malformed JSON Expected behaviour: - API returns a structured 400-style error. - Server does not crash. - Logs contain enough context for the maintainer to diagnose. ## Data reset and demo repeatability The demo should be repeatable for rehearsals and public recordings. Acceptable reset approaches: - restart in-memory API store; - reseed demo data on server start; - use a unique demo user ID for each rehearsal; - expose a documented development-only reset route if implemented. Reset must not be available as an unauthenticated destructive action in a production-like public deployment unless the deployment is explicitly disposable. ## Public demo blocker list Do not publish the demo if any of these remain: - duplicate collection or trivia answers can farm unlimited XP; - leaderboard XP disagrees with passport XP; - a failed API request leaves primary buttons permanently disabled; - unknown IDs crash the server; - empty seeded data causes a blank page; - mobile users cannot complete trivia or predictions; - the demo cannot be reset or repeated for reviewers.