Michael Surtees
case-studies/strava-dashboard-v3 --view=terminal
Strava Dashboard
2026 · Building with Claude Code
— the data is always there. the understanding isn't.
Strava Dashboard — Today tab, synthesis above the PMC chart

A cycling dashboard, in daily personal use for three months, as a way to understand what my Strava data was showing me.

role
Design · build, solo
stack
React · Strava APIs · LLM
year
2026
status
In daily use · 3 months
// thesis
The data told me what happened. It didn't help me understand how, or why, or what to do next.
01

Ritual

I ride every morning on my Zwift trainer. Monday recovery, Tuesday hard, Wednesday light but long, Thursday hard, Friday steady, long rides on the weekend. FTP test every six to eight weeks. Last year I rode 8,495 miles; since 2020 I've logged 4,905 rides across 42,680.7 miles.

The post-ride loop was the same every time. Open Strava, check the Fitness & Freshness graph — did the line go up or down? I liked seeing three months of context but I never really knew what the line meant. Shouldn't it always be going up? Then into the ride itself: summary tiles top-right, then the analysis stack — Speed, Power, Heart Rate, Cadence, Relative Effort, Power Curve, Zone Distribution.

The charts were clean. They just lacked context.

02

Diagnosis

Strava's mobile AI tried to fill the gap and mostly didn't. The observations repeated across rides, the tone stayed generic — broad commentary rather than anything that knew me or my week.

The deeper problem was that a single ride raises questions its own data can't answer. How did this ride fit the fitness I've built? How does today compare to the same day last week — Tuesday against Tuesday, not Tuesday against Saturday? Am I tracking to the week's shape? On pace for the month? The ride is where the questions start, but the answers live at different time horizons.

// diagnosis
No single screen can carry all of them, and cross-referencing charts to assemble even a guess wasn't a read — it was work.
03

Structure

The ride is the anchor. The tabs are zoom levels out from it.

One tab per horizon, no overlap. Open the tab that maps to your question, read the answer, close the tab.

Today tab — post-ride view
fig.01Today · the anchor tab
04

Craft

Four decisions made the structure work rather than just exist.

Decision 01Synthesis as first-class content.

Charts answer what. Written synthesis answers so what. The syntheses are specific, reasoned, and written to be read once — they assume the reader can handle nuance and show the reasoning alongside the read.

// synthesis sample
"Tuesday's sweet spot session cost you 63 fewer RE points despite nearly identical power and duration, suggesting either improved fitness adaptation or incomplete recovery masking the true cost" — rather than "you're adapting well."

The rule I was designing against was Strava's AI failure mode: if the synthesis could be cut and pasted onto any rider's week, it wasn't doing its job. I wrote the first two weeks of syntheses by hand to lock the voice — coach-in-your-ear rather than analyst-in-a-deck — then handed off to an LLM with those examples as style anchors.

Decision 02Reading order as the real design surface.

Each page resolves to a decision through an ordered read. Today opens with a takeaway paragraph, then the PMC, then red flags, then paired diagnostic cards (Execution, Power↔HR, Ride Cost, Week Shape) tagged Watch or On Target, then context modules for the week, month, and recovery HR, then a recommendation. The synthesis doesn't sit on top of the charts — the page is ordered so the charts become evidence for the sentences above them.

The reading order shifts with time. The top synthesis block adapts its framing to where in the window you are: Current Week on a Wednesday reads COURSE CORRECTION because there's still runway to change the back half of the week; Current Month on day 28 reads NEXT MONTH SETUP because the verdict is already written and the real question has moved on. Same tab, different question depending on when you open it.

Current Week tab — COURSE CORRECTION
fig.02Week · COURSE CORRECTION
Current Month tab — NEXT MONTH SETUP
fig.03Month · NEXT MONTH SETUP

Decision 03Relative Effort as the common unit.

Every other comparable metric had gaps — power meters die, Zwift calibration drifts, hardtail weekend rides have no W/kg at all. I standardized on Relative Effort (RE), a normalized score from heart rate and duration, and made every chart load on RE first. Power and W/bpm became optional secondary layers.

// trade-off accepted
RE compresses intensity — a 200W sweet-spot hour and a 170W tempo hour can score similarly. That nuance moved into the synthesis layer, which is the right place for it.

Decision 04Analysis as the long-memory tab.

Twelve weeks is long enough to see a block, short enough to still be actionable. Four sub-views: Fitness trend, Zones, Workout type, Comparison. Workout type is the one that earns its keep most consistently — it surfaces what's missing, not just what's there.

A recent read: 70% Endurance, 15% Tempo, under 1% Threshold. That gap is invisible in any single week's data and obvious across twelve.

Analysis / Fitness trend
fig.04Fitness trend · 12-week shape
Analysis / Zones
fig.05Zones · philosophy alignment
Analysis / Workout type
fig.06Workout type · what's missing, not just what's there
05

Build

The build was solo, end-to-end, with Claude Code. Design decisions and implementation decisions stayed in the same head. The synthesis rule survived contact with the codebase because there was no handoff to lose it across — when a chart didn't earn its sentence, I could cut it the same afternoon I noticed.

// method
Humans set the taste, models scale it. The handwritten two-week corpus was the taste layer; the LLM implemented and iterated against it.

A personal project was the right vehicle because the question — what does a data product look like when synthesis is the object? — needed someone acting as designer, user, and coach at once, running the loop daily without a brief.

06

What it feels like now

It's the first thing I open in the morning after a ride, and the first thing I check before one. The old ritual — Fitness & Freshness, then the chart stack, then guessing — has been replaced by a new one: the Takeaway paragraph, then the charts if I want the evidence.

The Comparison view is the clearest version of this. Five synthesis blocks — Overview, Progression, Effort Distribution, Volume & Consistency, Coaching Synthesis — sit between the comparison bars and the activity list. I read the paragraphs first. The bars become reference material, not the read.

Analysis / Comparison
fig.07Comparison · paragraphs first, bars second

Beneath every synthesis view the raw activity log is always there — day by day, ride by ride, with effort sparklines and RE scores. Synthesis frames the data without hiding it.

Activities list — ride-by-ride log with effort sparklines
fig.08Activities · the log beneath the synthesis

The Fitness & Freshness line I didn't understand for a decade didn't move. It's still on the Today tab, still the PMC. What changed is what surrounds it — a takeaway paragraph above, red flags below, paired cards explaining execution and ride cost and where the week is shaped.

// the closer
The line was never the problem. The silence around it was.

What's next