Wodmark
A training log for functional fitness. Every block is a triple: what's held constant, what's measured, how it scores.

Why I built it
Functional fitness doesn't log the way a normal lifting app expects it to. An EMOM and an AMRAP can use the exact same movements and still be completely different things to record — one holds time constant and measures work done, the other holds work constant and measures time. Most training-log apps flatten that into a generic “workout” and lose the distinction.
Wodmark is built around a different unit: a block is a triple — what's held constant, what's measured, how it scores. An EMOM and an AMRAP built from identical movements come out as genuinely different objects, because they are.

The bet on privacy
Gym staff can see aggregates, never a named athlete's log, and aggregates only render once five or more athletes are logging — below that, the dashboard shows “suppressed” instead of a number. That's enforced in the API layer, not a setting someone could toggle off, because a privacy policy I could turn off isn't one I trust either.
Who pays
The category's usual model charges the gym and gives the athlete a login. I inverted it: the athlete pays, and gyms get the authoring tools for free as a distribution channel. It's a bet that athletes who actually want their history to survive a gym switch will pay for it themselves, and that gyms will hand out a free tool more readily than they'll buy one.

Where it actually is
Three consoles are running against seeded, in-memory data — app-admin, gym-admin, and the athlete view — with 140 tests covering the domain logic. There's no real backend yet; the API layer is deliberately built as the seam a real one plugs into later, not a shortcut I'm hoping to forget about.
What I'd tell someone building this
Model the domain before the schema. The block-as-triple idea only showed up after I'd tried and rejected two flatter data models — the extra week spent arguing with myself about it was cheaper than the migration would have been.