← Blog

A Gym OS in Seven Weeks

On the fifth of July I made the first commit to Ragnarok, a gym operating system built with and for Ragtag Training, Aidan's CrossFit gym in Singapore. On the eighteenth of August the whole gym was on it: 441 members, 1,284 workouts of history, and the incumbent software switched off. Seven weeks.

Danielle built it with me (339 of the 979 commits are hers; 612 are mine), which is worth saying up front because "I built a SaaS in seven weeks" stories usually hide a second pair of hands.

The pitch was simple. Gyms like Ragtag run on WodUp: coaches program workouts in it, members log results in it, and everyone tolerates it. We wanted the parts coaches actually use, plus the member context WodUp never had, in one app: a member PWA, a staff console, and a platform admin surface.

Some numbers from the repo, because the shape of the build matters more than the deadline. 979 commits across 32 active days. About 97,000 lines of source. 123 append-only SQL migrations. 62 decision records and 23 per-feature PRDs, written as we went, not reconstructed after.

Two architecture calls did most of the work.

First, raw SQL over pg, no ORM. Every query is visible, every migration is a file, and an AI coding agent can read the whole data layer without inferring what an ORM is doing behind its back. I've written before about how an app framework's job is to make agents produce working code on the first try; raw SQL turned out to be the same idea applied to a codebase I own end to end.

Second, multi-tenancy through Postgres row-level security from day one. Every table carries a gym_id, the app connects as a role with NOSUPERUSER NOBYPASSRLS, and tenant isolation is enforced by the database rather than by remembering to add a WHERE clause. Watching the Volty team make this work at platform scale convinced me it's the only version of multi-tenancy I trust; Ragnarok is my own small-scale proof.

The migration was the unglamorous half. WodUp doesn't want you to leave, so leaving meant importing the entire back-catalogue: 1,284 workouts across six programs, member history going back to June 2025, and per-member CSVs (one member had 128 results imported set by set). The benchmark library grew from 37 to 130 workouts along the way, every CrossFit Open since 2011 included, because a leaderboard is only interesting if the history is on it.

The gym-specific product work is the part I'd defend hardest. A live MindBody integration for schedules, rosters, and no-shows. Telegram briefs so coaches get tonight's class list and a 6am digest without opening anything. An at-risk list that flags a member against their own attendance rhythm, not a global threshold, because the member who drops from five sessions a week to two is the story, and a fixed cutoff misses them.

We ran a beta with 11 members on the fourteenth of August and went gym-wide on the eighteenth. Four days. That was only possible because a bug bot had been filing beta reports into Notion and answering them all week, which meant go-live day was boring.

The honest caveat: it's multi-tenant software with one tenant. The RLS work, the white-labelling, the platform admin, all of it is unproven until gym number two signs up and the isolation claims get tested by a stranger's data. That's the next thing to find out.