Appearance
UC-029.1: Route Library & Ride-to-Route Extraction Engine β
π 1. Context & Problem Statement β
Historical Strava activities contain valuable GPS data (summary_polyline). Users need a way to extract these past rides and save them as permanent, reusable "Routes" in a personal Library for future navigation. Additionally, when extracting multiple times or duplicating routes, the system must prevent naming collisions using a smart string-suffix algorithm.
π 2. Database Schema (Drizzle ORM) β
Create the routes table:
id(uuid, primary key)userId(uuid, foreign key referencingusers.id, non-null)sourceActivityId(uuid, foreign key referencingactivities.id, nullable)name(varchar, non-null)distance(double precision, non-null)polyline(text, non-null) β The encoded GPS path for MapLibre rendering.isEbike(boolean, default false) β Auto-tagged if extracted from an EBikeRide.createdAt(timestamp, default now)
βοΈ 3. Backend Logic & API (apps/api) β
Endpoint: POST /api/routes/extract/:activityId
- Fetch the target activity. Ensure
summary_polylineexists (Return 400 if it was an indoor ride with no GPS). - Smart Naming Algorithm (The "Copy" Logic):
- Query existing routes owned by the user.
- If original name is "Morning Ride", check for exact matches.
- If match found, append suffix ->
"Morning Ride (Copy)". - If
(Copy)exists, extract the number and increment ->"Morning Ride (Copy 2)", then(Copy 3), etc.
- Save the new route to the
routestable. Auto-setisEbike = trueif the source activity wasEBikeRide.
Endpoint: GET /api/routes
- Return the user's saved routes, sorted by newest first.
π¨ 4. User Interface (apps/web) β
- Activity History Action: In
HistoryLog.tsx, wire up the[ πΊοΈ Generate Route ]button to call the/extractAPI. Show a loading spinner during execution. On success, show a toast:β Route Saved: {Route Name}. - Route Library View: Create a new page/view
/library(or a tab in the Garage) that displays a list of the user's saved Routes. - Library Cards: Each card displays the Route Name, Distance, an
E-Bikebadge (if applicable), and a[ πΊοΈ Open on Map ]button (which will route to the MapLibre engine in the next phase).
π§ͺ 5. Testing Requirements β
- Backend: Pure unit tests for the Smart Naming Algorithm ensuring it correctly increments
(Copy)to(Copy 2)and(Copy 3). Integration test verifyingisEbikeis parsed correctly. - Frontend: Verify the button loading states and toast notifications.## π 5. Implementation Log
Status: β Completed (May 2026)
- Database:
routestable created via Migration0020with cascade deletes. - Backend:
POST /api/routes/extractimplemented with Smart Naming Algorithm (safe transaction-based regex for(Copy)suffixes) andisEbikeauto-tagging. Rejected indoor rides missing GPS data. - Frontend: Built filterable Library View with Layout Switcher, E-Bike badges, and native polyline-to-GeoJSON decoding that dispatches the geometry directly into the MapLibre interactive map store.
- Testing: 100% green across 872 tests. Pure math and regex thoroughly covered.