All work
GymTeam
Club management: one platform, many clubs
The staff side of the Fitofan ecosystem: sports clubs run members, classes, check-in, progression and payments, each club in its own private space.
- Role
- Senior Full-Stack Engineer
- Period
- 2025 – 2026


Context
GymTeam is where club owners, managers and coaches work; athletes and parents use Fitofan, which also signs them in. I split it out of the Fitofan codebase into its own product and shipped most of it.
The challenge
Serve many independent clubs from one application with strict data isolation, take payments in every market the clubs operate in, and keep club data consistent with the athlete platform in real time.
Built across the stack
- Next.js 16 admin on Feature-Sliced Design: 80+ pages, 11 locales
- NestJS backend: a module per entity with use cases, repositories and validated DTOs; 95 migrations
- Tenant isolation: a guard resolves each club by id or slug and checks membership before any handler runs
- Members, invitations and trials, weekly schedules with waitlists, live check-in, attendance, curriculum and belt levels, waivers, homework, assessments
- Payments: Finix, Stripe, PayPal, Square, Monopay, LiqPay, GCash and Mercado Pago plus cash and debts, a daily billing scheduler, AES-256-GCM credential storage
- RabbitMQ contract shared with Fitofan: 29 routing keys, a typed envelope with correlation ids, documented topology
- QR login over WebSockets, a Socket.IO session gateway, S3-compatible media storage
- Revenue, attendance and coach analytics with CSV and PDF export
- Same delivery pipeline as Fitofan: type-check and Jest gate, Docker image, SSH deploy
Engineering highlights
- Tenant scope enforced on the server, never trusted from the client
- Webhooks idempotent by provider and event id; payment intents carry idempotency keys
- A custom ESLint rule with its own tests keeps the Feature-Sliced layers honest
- Registration and club-creation flows come from packages shared by both products
What it enables
Each club gets a product that feels built for them, while engineering stays one codebase and one deployment.