Work08

Training Room

One app, three roles — member, coach and owner

Year
2026
Role
Sole engineer — app and API
Built with
  • React Native (Expo)
  • TypeScript
  • tRPC + Hono
  • PostgreSQL / Drizzle
Illustration of the set logger, drawn from the app’s own design tokens.

The member and staff app for a functional-fitness gym in Skopje — booking and check-in, a set logger built for sweaty hands, and the back office that runs the timetable, the programming and the money.

Training Room is a functional fitness gym in Skopje, running since 2016. The app is one build with three roles in it. A member sees today’s session, books a class, marks themselves present, logs the workout set by set and watches how much membership is left. A coach gets the front desk, the roster, the timetable and the programming. The owner gets everything a coach has plus the members, the plans and the payment ledger — money is visible to him alone.

The first decision was to take a feature out. The design assumed door hardware: unlock the door, and the unlock is what marks you present. There are no readers and no keypads in that building, so the app lets nobody in. Attendance is what the unlock was really for, and attendance survives without it — marked at the desk, ticked off on the coach’s roster, or tapped on a class you booked. Shipping the door would have meant shipping a screen that lies about the room it is standing in.

The core of it is the set logger, because the hard part of gym software is a phone held with chalk on your hands and ninety seconds of rest. No keyboards, no modals: pre-filled steppers, one tap banks a set, copies the weight forward and starts the clock. It opens at what you lifted last time rather than the number the coach wrote for the class, so most sets need no adjustment at all — and when a barbell set does, you load the bar the way you load it on the floor, tap the plates in their real colours and let the app do the arithmetic.

The conditioning has a name on it and a board. A day’s metcon comes from a list of named workouts — Cindy, Fran, and whatever the gym writes itself — and each is scored the way it is actually scored: rounds for an AMRAP, a clock for a for-time piece. The board ranks the day fastest or furthest first and keeps scaled results in their own section, because Cindy with a band is a different workout and a board that mixes the two is a board nobody believes.

Underneath is a tRPC API over Postgres, and its schema is where the honesty lives. One row per set, not an aggregate, because the logger needs each set’s own weight. A waitlist with a queue position, promoted inside the same transaction that frees the seat and behind the same row lock, so two cancellations cannot hand one place to two people. Memberships are paid to a date in cash or by transfer and the owner records what he saw — there are no cards and no invoices, because that is how the gym is actually paid. And nothing a member has trained can be deleted.