What We Shipped
- Oura / Whoop / Polar integrations — All three wired in end-to-end (#517). Health data from these platforms now flows into recovery metrics and training load.
- Mobile coach layout — Chat messages were rendering below the input bar on mobile. Fixed by switching from
min-height: 100dvhtoheight: 100dvhso the messages flex container stays above the input (#524). - Mobile nav double-shell — Bottom nav was scrolling with content on the workouts page instead of staying fixed. Removed the nested shell (#522).
- Mobile metrics weeks dropdown — The dropdown for switching time ranges in the metrics view wasn't responding. Now functional (#523).
- Pace zone percentages — Laps with no speed data were breaking zone percentage calculations. Fixed by guarding against null lap speed (#521).
- Mobile recent workouts recap metrics — Missing metrics in the recap view on mobile (#512).
- Mobile workout detail button — Tap target fix on mobile workout cards (#511).
- Garmin pull token expiry surfaced — Instead of silently returning 0 records when the CPT token expired, we now surface the error clearly so users know to reconnect (#518).
What We Learned
Oura/Whoop/Polar were "registered" but not actually wired — the sync routes existed but batchUpsert calls were never hooked up. Classic "it's built but not connected" issue.
What's Next
More mobile polish. The coach layout fix exposed that the mobile experience needs a full audit — each screen should be tested on a real device, not just desktop responsive mode.