Sprint 8 — Ride Recap Video Module (Additive Only) Scope Implement a Ride Recap Video feature on the existing ride view: https://freebikers.dk/mep/rides/{id} Important constraints (do NOT break previous sprints) - Sprint 4, 5, 6, and 7 are locked. - You must NOT overwrite or delete any existing methods or files. - Changes must be additive only (new files, new methods, or clearly named modifications that I explicitly approve). - If you need to change or understand any existing file, ask me to upload the latest version first. Do NOT rely on memory. High-level requirement After a ride is approved, the rider should be able to: - Preview a generated ride video on the ride page. - Download the video. - Share the video to Facebook with a proper video preview. Video specification (V1) 1. Duration - Total video length should be configurable via .env: VIDEO_DURATION_MODE=fast|normal|slow - Exact durations to be defined by you, but they must be derived from this mode. 2. Technical format - 30 FPS - MP4 (H.264) — Facebook compatible format. 3. Video sequence (V1) Scene 1 — Branding (4 seconds total) - First 2 seconds: show COMPANY LOGO centered on screen. - Next 2 seconds: show CHALLENGE LOGO centered on screen. Scene 2 — Map background - Show the full ride map (OpenStreetMap + Leaflet style). - At this stage, DO NOT draw the route yet (blank map with path area visible). Scene 3 — Start - Mark the START point on the map. - Show the start photos (start_photo + odometer_start_photo) for 1 second total. Scene 4 — Route animation - Animate the route drawing as a polyline from start to finish. - V1 simplification: only use START and FINISH photos (no intermediate photos in V1). - The line should be drawn smoothly over time, proportionate to video duration. Scene 5 — Finish - When the route reaches the end point: - Show finish photos (finish_photo + odometer_end_photo) for 1 second. - Then display: - Winner cup icon - Rider name - Challenge name - Challenge logo 4. Data sources (must use existing data) - Route: ride_trackpoints table - Photos: ride_media table (start, finish, odometer start, odometer end) - Logos: company logo + challenge logo from Sprint 7 storage 5. Storage & performance - Generated videos should be stored in: /mep_backend/storage/videos/{ride_id}/{uuid}.mp4 - Re-generation should reuse an existing video if already created (idempotent). 6. UI changes (ride view only) On /mep/rides/{id} page: - Add a “Create / View Video” section after the certificate section. - Buttons: - “Preview Video” - “Download Video” - “Share to Facebook” 7. Backend endpoints (new) POST /api/v1/rides/{id}/video → generate video (if not exists) GET /api/v1/rides/{id}/video → return video URL GET /api/v1/rides/{id}/video/stream → stream for preview 8. Deliverables (when you implement) - New VideoService.php - New VideoController.php - Required routes in api.php (append only) - Minimal JS for preview on ride page - No changes to certificates, payments, shipping, or validation logic. Please acknowledge this scope before proceeding.