Skip to content

Design Spec: Resilient Player Sessions & ScanView Refactor

1. Problem Statement

Players currently lose their scavenger hunt progress if their mobile browser clears localStorage or if they accidentally close an "In-App" browser (common in QR scanners). This creates friction and frustration in a museum/venue setting. Additionally, the ScanView.vue component has become too large and complex to maintain easily.

2. Goals

  • Recovery: Allow players to recover sessions using their Nickname and PIN.
  • Resilience: Decouple "Collection" views from transient local storage.
  • Maintainability: Decompose ScanView.vue into smaller, reusable components.

3. Proposed Changes

3.1 Player Recovery UI (PlayerView.vue)

  • Empty State Update: If no participantId is found in localStorage, display a "Resume Adventure" card instead of "No Active Hunt".
  • Recovery Form: A simple form (Nickname + PIN) that calls /api/scan/progress.
  • Session Restoration: Upon successful API response, restore the participantId to localStorage and refresh the view.

3.2 Unified Join/Resume (ScanView.vue)

  • UI Update: Change form title to "Join or Resume".
  • Subtext: Add: "Already playing? Enter your details to continue where you left off."
  • Logic: The existing /api/scan/join endpoint is already deterministic (Name+PIN+Date). If a user "Joins" with existing credentials, it will return their current progress seamlessly.

3.3 Component Decomposition (ScanView.vue)

Split ScanView.vue into:

  • ScanInfoCard.vue: Displays hunt name, organization logo, and stop details.
  • ScanStatus.vue: Handles loading, error, and success states (Found It / Victory).
  • ScanJoinForm.vue: The Name/PIN/Email form logic.

3.4 Backend Consistency

  • Ensure the Participant record in Firestore tracks device_uuids as an array (Already implemented).
  • Verify that the participant_id generation logic in scans.py remains stable for the duration of a visit (Same-day expiry).

4. Testing & Validation

  • Manual Test:
    1. Scan Stop A, join as "Hunter1" / "0000".
    2. Verify Stop A appears in "My Collection".
    3. Manually clear browser data.
    4. Return to "My Collection", use the "Resume" form with "Hunter1" / "0000".
    5. Verify Stop A is recovered.
  • Edge Case: Entering the wrong PIN should show a "Name/PIN combination not found" or "Incorrect PIN" error.