What We Shipped
-
9-step onboarding tour — The biggest thing to land today. New users now get a guided walkthrough of every major part of the app: the calendar, workout builder, training load dashboard, AI coach, and settings. Each step highlights the actual UI element you're supposed to interact with, not just a tooltip floating in space. Completion is tracked per user, and there's a "Take the Tour" option in the user dropdown so you can replay it any time.
-
Garmin recent-refresh cron — Garmin has a known quirk: their activity history API caps at 86,400 seconds (24 hours) per request. We added a background cron job that runs on a rolling 23-hour window to stay safely within limits and keep recent activities up to date without manual sync. The UI now shows an animated syncing indicator while it's running. Also squashed a gnarly bug where HIIT workouts were syncing twice and dropping cadence and power metrics along the way.
-
Mission Control agent cards — Reworked the Mission Control dashboard to lead with visual agent cards instead of the dense table view. Much easier to see at a glance who's active, what they're working on, and their current status. Also added an
updateAPI action so you can change an agent's name, role, or model without tearing it down and recreating it. -
Mobile settings expanded — Refer & Earn and the Agent API are now accessible from the mobile settings sheet. Cleaned up the dev-only actions that were showing up in production (Browse Plans, Import AI Plan, Training Dashboard — not ready for users). Also fixed a ghost scroll bug caused by using
100vhon the mobile shell wrapper —100dvhis the right answer on mobile. -
Waitlist flow hardening — Patched a few gaps in the referral and conversion pipeline: OAuth callbacks now properly fire the waitlist conversion endpoint, conversion tracking fires regardless of the
early_accessflag, and invite sends now respect Resend's 2 req/sec rate limit to avoid silent drops. Also refreshed the invite email template while we were in there. -
Sleep score fixes — Found two bugs in the weighted average calculation: it was using the wrong weight field (
totalWeightinstead ofscoreWeight), and nights with no score data were being counted in the denominator, dragging averages down. Both fixed. -
Theme and polish — The training status card was using a hardcoded dark background instead of theme tokens, which looked broken in light mode. Fixed. Recovery intervals missing zone references now get properly backfilled. Calendar workouts no longer disappear during concurrent refresh calls.
What We Learned
- Onboarding is only as good as the UI elements it points to. Abstract tooltips teach nothing. Highlighting the actual button the user needs to click is the whole game.
- Garmin's API docs bury the 86400-second cap. You find out the hard way when your sync window starts silently truncating. A rolling 23h window is the pragmatic workaround.
What's Next
- Onboarding tour user testing and feedback loop
- Garmin sleep data enrichment timing improvements
- Polar data sync pipeline (OAuth is live — now we need to actually pull the data)
- Weekly coach recap polish