- Garmin sync: read sleepScores from dailySleepDTO (Garmin nests it there),
so sleep score is actually stored instead of always null
- Dashboard: pass YYYY-MM-DD to the intraday endpoint (was a full ISO
timestamp), so the body-battery tile populates
- Segment matching: follow the segment in its created direction with a
path-length sanity check, so out-and-back routes no longer match an early
start pass to a late finish (the >1h bogus segment times)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Lap bests: compare against OTHER activities on the route (exclude self),
so single-activity routes no longer show every lap as "best"
- Segment create: POST to trailing-slash URL (was a 307 that dropped the body);
surface errors in the UI
- PR splits: scale GPS distance stream to the activity's official distance so
over-measured GPS no longer yields bogus split PRs
- Speed route colours: red->orange->green->blue->purple (slow->fast) with smooth
interpolation + a Slow/Fast gradient key under the map
- Health body battery: snap activity highlight to the categorical axis;
white tooltip text + % suffix
- Health weight: y-min = lowest weight - 20kg; st/lb hover shows total lbs too
- Health sleep: move 8h/avg reference labels into the right margin
- Dashboard: Health-today pulls latest non-null values (sleep score, VO2 max);
body battery tile renders a condensed colour-graded intraday graph
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fixes:
- Dashboard: featured most-recent activity card with map + stats
- Maps default to Street; preferCanvas + larger tile buffer for smoother pan/zoom
- Running cadence as colour-banded dots + 165 spm guide line
- Routes: inline row expansion, rename (PATCH /routes/{id}), podium + deltas, tiled map
- Records: remove reversed pace Y-axis
- Profile: remove resting HR; add goal weight
- Health: snapshot weight carry-forward; VO2 trend axis 30-70;
weight goal line + kg/st-lb toggle + axis max; sleep 8h/avg lines
- Garmin sync progress moved to global store with persistent floating bar
Features:
- Speed-coloured activity route (default) with Speed/Solid toggle
- GPS-geometry segments: draw on map, match across all activities,
1st/2nd/3rd leaderboard + podium badges (replaces old distance segments)
- Lap bests: best time per lap across a route + delta column
- Body Battery: highlight activity time windows
Schema: users.goal_weight_kg ALTER; new segments/segment_efforts tables.
Removes RouteSegment, the Segments page, and segment-bests endpoints.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Pace: FIT 0xFFFF sentinel (65.535 m/s) was stored as avg_speed_ms on every
activity and lap; add _sanitize_speed() to parser falling back to dist/dur,
plus a startup SQL migration that fixed 120 activities and 688 laps in-place
- Records: remove swimming from Distance PRs; Route Records rows are clickable
(navigate to activity), View button removed, small SVG route map per row;
Segment Records uses same tiled route-card layout as Segments page
- Segments: replace route dropdown with responsive tile grid showing SVG map
thumbnails; selecting a tile reveals the segment management panel below
- RouteMiniMap: new pure-SVG component (no Leaflet) for route thumbnails,
decodes polyline and normalises coords into a fixed viewBox
- Health: rename "Avg Heart Rate (day)" → "Heart Rate"; weight chart now
filters to non-null rows and enables connectNulls + dots for sparse data
- Dashboard: 4-col layout at lg breakpoint so Body Battery sits between weekly
chart and Health Today; Body Battery card gains a 24-hr sparkline from the
values[] already present in the health summary response
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Body battery: replace circular ring with compact full-height colored bar chart,
level as line overlay, legend shows only types present in data
- Dashboard: add mini body battery summary card above health today panel
- Profile: remove editable resting HR and manual weight log; show 7-day avg
resting HR and latest Garmin weight as read-only
- Backend: add GET /routes/{id}/segment-bests bulk endpoint (fetches all matched
activity data points in one query, computes best segment time per segment)
- Backend: add GET /records/routes for fastest activity per named route
- Routes page: add Segments panel to route detail (grouped as 1km splits vs
hills/turns, best times, delete, theoretical best)
- Activity detail page: show segment times computed client-side from data points,
🏆 badge if new best
- Records page: add Route Records and Segment Records tabs alongside Distance PRs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Segments page: new /segments route with auto-generate (1km splits, turn
detection, hill detection), manual segment creation, per-segment performance
times across matched activities; fixed auth on existing segment endpoints
- YTD distance: new /activities/stats/ytd endpoint; Dashboard replaces
'Total distance' with 'Running this year' + 'Cycling this year'; Activities
page shows YTD stats row
- Weekly chart click: clicking a Dashboard bar navigates to Activities filtered
to that week; Activities reads from/to query params with dismissable chip
- Route matching: add ±2.5% distance gate + 3% relative DTW threshold
(was flat 80m); tighten candidate pre-filter from 80/120% to 95/105%
- Body battery layout: HR chart and body battery now side-by-side at same
height on large screens instead of stacked full-width
- Pace display fix: MetricTimeline clamps GPS speed outliers before computing
Y-axis domain; tick formatter guards against v<=0 or v>25 m/s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>