Skip to content

πŸ“ Feature 04: Turn-by-Turn Cue Sheets & Prompts ​

NOTE

🧭 Navigation: 🧩 Features Index | 🚲 Wiki Home

The Turn-by-Turn Cue Sheets module allows riders to embed custom navigation cues, turn alerts, and environmental hazard prompts directly along a designed cycling route. These prompts are serialized within the track coordinates, helping riders export perfect navigation files.


πŸ” How it Works (Product perspective) ​

  1. Inline Marker Placement:
    • When a route is calculated on the map canvas, users can right-click anywhere along the active path line. This opens the Cue Sheet Creation popup.
  2. Turn & Prompt Categories:
    • The creation dialog allows cyclists to classify their markers:
      • ⬅️ Left Turn (ΠŸΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π½Π°Π»Π΅Π²ΠΎ)
      • ➑️ Right Turn (ΠŸΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π½Π°ΠΏΡ€Π°Π²ΠΎ)
      • ⚠️ Danger / Hazard (ΠžΠΏΠ°ΡΠ½ΠΎΡΡ‚ΡŒ / ΠŸΡ€Π΅Π΄ΡƒΠΏΡ€Π΅ΠΆΠ΄Π΅Π½ΠΈΠ΅) (e.g., sharp curves, bad gravel, loose rocks)
      • ℹ️ Information (Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΎΠ½Π½Π°Ρ ΠΌΠ΅Ρ‚ΠΊΠ°) (e.g., campsites, water sources, restaurants)
  3. Maneuver Description:
    • Planning users can write explicit textual alerts (e.g., "Turn left past the red barn" or "Caution: Sand section begins").
  4. Chronological Bottom Panel:
    • All placed cues are dynamically sorted chronologically by distance offset along the track coordinates and rendered in the bottom navigation tray. Clicking any row in the panel pans the map viewport directly to that waypoint cue.
  5. XML GPX Metadata Sync:
    • During GPX exports, cue data is automatically formatted into Garmin/Wahoo compatible waypoint extensions (<wpt>), overlaying indicators on GPS device screens during active rides.

πŸ—οΈ Technical Architecture & Key Files ​

πŸ–₯️ Frontend State & UI Components ​

  • UI Widgets:
    • apps/web/src/features/cue-sheets/ (turn panel, direction icons, auto-generation utilities).
    • apps/web/src/features/cue-sheets/ui/CuePopup.tsx (popups, inline coordinate forms).
    • apps/web/src/features/cue-sheets/ui/CueRescuePopup.tsx (handles emergency recovery dialogs).
  • Zustand State Store: useCueStore in apps/web/src/features/cue-sheets/model/cueStore.ts.
    • Slice Fields:
      • cuePoints: CuePoint[] (ordered array of turn markers). Strict technical constraint: capped at a maximum of 50 cues per track to prevent file bloating and memory leaks during XML serialization.
      • isLoading: boolean (network transition tracking).

πŸ”Œ API Integration & Core Services ​

  • Backend API Routes:
    • Important Architectural Detail: Cue sheets do not utilize an independent API router or join table. Instead, they are embedded directly inside the main tracks database table within the cues JSONB column (cues: jsonb('cues')).
    • During track saves (POST /api/tracks), the client serializes the active cuePoints array into the request payload.

πŸ’Ύ Database Schema (Drizzle & PostgreSQL) ​

  • Table: tracks column cues: jsonb in apps/api/src/db/schema.ts.
  • CuePoint Type Contract:
    typescript
    export interface CuePoint {
      id: string;
      coordinates: [number, number]; // [longitude, latitude] tuple
      category: 'LEFT' | 'RIGHT' | 'HAZARD' | 'INFO';
      distanceOffsetMeters: number; // accumulated distance from route start
      notes: string; // custom instructions
    }

πŸ§ͺ Test Suite Coverage & Regressions ​

πŸ”¬ Vitest Unit Tests ​

  • apps/web/src/features/cue-sheets/model/__tests__/cueStore.test.ts:
    • Enforces the max 50 items limit constraint.
    • Verifies chronological distance-offset sorting algorithms.
    • Validates waypoint inserts, updates, and delete state cascades.

🎭 Playwright E2E Tests ​

  • CRITICAL E2E TEST GAP: The Turn-by-Turn Cue Sheets feature currently has no Playwright E2E automated layout verification. There are no automated tests asserting that intermediate turn indicators render on the canvas, or that right-clicking maps opens the creation dialog. This is a high-priority testing gap.

🐞 Known Issues & Resolved Bugs ​

  • Accidental Cue Deletions (Resolved): Direct clicks on the delete icon removed complex cues immediately.
    • The Fix: Implemented a Double-Confirmation deletion flow inside CuePopup.tsx. Clicking delete transitions the button to an active danger state reading "Confirm Deletion". A second click executes, and a 3-second self-resetting timeout returns the button to default styling if unclicked.
  • Double Submission / Ghost Cues (Resolved): Rapid double clicks created identical cue markers on the map canvas.
    • The Fix: Enabled a loading/saving state tracker that visually disables the "Add Cue" action button during API writes.

πŸ‘£ Step-by-Step Manual Verification ​

  1. Load http://localhost:3000 and build a basic route.
  2. Right-click directly on the calculated route line.
  3. Observe the Cue Creation dialog opening at that exact coordinate.
  4. Select the ⚠️ Danger icon, type "Watch out for deep mud!", and hit Save.
  5. Confirm the warning triangle icon overlays the route.
  6. Click the warning triangle marker. The cue view details open.
  7. Click the Delete button once. Observe it changing color to red and displaying "Confirm Deletion".
  8. Wait 3 seconds without clicking. Verify the button safely resets back to default styling automatically.
  9. Click Delete once, and click it a second time within 3 seconds. Verify the cue is deleted and removed from the map.

πŸ“Έ Interface Artifacts ​

  • Cue Sheets UI should be verified in the current app, because the old screenshot artifact was retired with the editor cleanup.