The Leaderboard Was a Window
A few weeks ago I wrote about leaderboards. Podium for the top three, weekly stats, trend indicators, race-scoped chat. It worked. But there was a gap.
You could see that someone training for the same marathon just logged a 30K long run. You could be impressed. You could not tell them. The leaderboard showed training without letting you react to it. Race chat existed, but it was general conversation — "anyone doing the hilly route Saturday?" — disconnected from specific sessions.
The missing piece: seeing a workout and being able to say something about it.
One Tap
Kudos is the simplest feature I've shipped and one of the most satisfying. Tap the thumbs-up. It fills. That's it. Tap again, it unfills. The database does an insert-or-delete based on whether your kudos already exists. Toggle semantics — no state to manage, no "like" vs "unlike" API split.
The button shows a count and a tooltip listing who gave it. Capped at ten names before truncating, because after ten you get the point.
Both runners need to be on the same leaderboard. The workout has to be completed — no kudos for intentions. Display names are cached when the kudos is created so rendering a page with thirty workouts doesn't fire thirty extra queries. Loading kudos for all thirty? One batch query.
Small feature. Turns a training log into something shared.
280 Characters
Comments follow the same rules as kudos. Same leaderboard, completed workouts only. But comments have more surface area, so they have more guardrails.
Max length: 280 characters. Not Twitter nostalgia — workout comments should be "that negative split was clean" or "how'd the knee feel on the downhill?" Short reactions, not reviews.
Rate limit: 10 per day. Soft delete with a timestamp, so you can remove what you said without breaking the thread. No dedicated sanitize layer for XSS — Askama auto-escapes everything on render, which handles it cleanly without the double-encoding headache of sanitize-then-escape.
Who Gets to See What
The social layer is narrow on purpose. Every interaction runs through the same access check: are you on the leaderboard? Is the workout owner? Is the workout completed? Are you both training for the same race?
That last one is a configurable gate. Right now it's on — you only see workouts from people chasing the same finish line. Proposed workouts, the ones you haven't done yet, are never visible to anyone else.
This isn't a social network. It's a training group. Small enough to feel connected. Small enough to not become another feed to check. See a teammate's session. Tap the thumbs-up. Maybe leave a note. Get back to your own training. That's the right amount.