- Activity detail: show "Imported from wahoo" badge when activity was
imported from an external provider
- Activity detail: add delete button with confirmation, cleans up
sync_imports so the workout can be reimported
- Import page: show "No GPS" badge with tooltip on workouts that have
no file URL from the provider
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Route/activity list pages: map thumbnails with route drawn on OSM tiles
- Route/activity detail pages: interactive Leaflet map with zoom controls
- Server: expose GeoJSON from PostGIS via ST_AsGeoJSON (simplified for lists)
- RouteMapThumbnail component: shared, supports thumbnail and interactive modes
- Placeholder shown for routes/activities without geometry
- Archive journal-route-previews change, sync specs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Distance was only stored in the elevation profile array, which was
empty when track points had no <ele> elements. Now computed via
haversine independently and exposed as gpxData.distance.
Tested: berlin-dresden-radweg-2021.gpx (5660 points, no elevation)
now correctly reports 248.8 km.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The initial approach (#150) didn't work because:
1. routes.server.ts used parseGpx (sync, needs browser DOMParser)
instead of parseGpxAsync (uses linkedom on Node.js) — GPX parsing
silently failed, so stats AND geom were never populated
2. Drizzle's customType doesn't pass SQL expressions through toDriver
Fixes:
- Switch to parseGpxAsync for all server-side GPX parsing
- Use db.execute() with raw ST_GeomFromGeoJSON SQL after insert
- Remove unused lineStringFromCoords helper from schema
- Share setGeomFromGpx between routes and activities
- Add unit tests for GPX→GeoJSON coordinate extraction
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract coordinates from parsed GPX tracks and store as PostGIS
LineString geometry via ST_GeomFromGeoJSON. Applied to:
- createRoute / updateRoute (routes.server.ts)
- createActivity / createRouteFromActivity (activities.server.ts)
Adds lineStringFromCoords() helper to the journal schema that
builds the SQL expression from [lon, lat] coordinate pairs.
Unblocks spatial queries (e.g. route discovery via ST_Intersects).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Node's --experimental-strip-types requires explicit .ts extensions on
relative imports. Add allowImportingTsExtensions to both app tsconfigs
and update server-side imports in planner and journal for consistency.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Activity CRUD:
- Activity list page (/activities) with date, distance, elevation
- Create activity with GPX upload, description, optional route link
- Activity detail with stats and date
- "Link to Route" action (select from existing routes)
- "Create Route from Activity" action (creates route from GPX)
Server logic in activities.server.ts with async GPX parsing.
Uses ClientDate component for SSR-safe date rendering.
All 6 Group 10 tasks complete.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>