Run every gym on one platform.
GYMGUARD is a multi-tenant gym management system: a NestJS API, a Flutter app for the front desk, and this console for the gyms themselves. Create a tenant, hand its owner a login, and the whole stack is live.
| Gym | Owner | Members | Staff |
|---|---|---|---|
| Iron Vault Kemang | owner@ironvault.gym | 412 | 9 |
| Pulse Fitness BSD | halo@pulsefit.id | 1,284 | 23 |
| Demo Gym | owner@demo.gym | 38 | 3 |
Built for the parts that are hard to undo.
Tenant data, money and access control get the careful treatment. Everything else follows from those three.
Isolation by construction
A request-scoped Prisma extension forces gymId onto every read and write. One gym can't reach another's data, even if a query forgets to ask.
Money that reconciles
Row locks serialize stock allocation, refunds and day-close. Transaction numbers are issued per gym as YYYY-MMDD-NNNN, with no gaps and no collisions.
The front desk, in hand
Staff check members in, register and renew memberships, sell products, loan equipment and run classes from the Flutter app on the gym floor.
Reports that answer questions
Revenue by week, month or year. Retention windows, at-risk members, renewals due, traffic by weekday, product sales — and CSV export for the rest.
Roles, then permissions
An OWNER role plus six granular permissions — check-in, registration, payments, equipment, day-close, reports — enforced route by route.
Photos, handled
Member, staff and product images upload straight to S3-compatible storage with public URLs, namespaced per gym and replaced cleanly on change.
Two layers, two apps.
Gym staff never see another gym. You never touch the gym floor. Separate logins, separate surfaces, separate scopes.
The mobile app
Owners, front desk and trainers work inside a single gym. Check-ins, memberships, POS, equipment loans, classes, freezes, shifts and the day's till close — all scoped to their tenant by the token they sign in with.
- Roles: OWNER, FRONT_DESK, TRAINER
- Business dates computed in the gym's timezone
- Member status derived, never stale
This console
A global account that sits above every tenant. Create gyms and their first owner, edit details, watch member and staff counts, and remove a tenant completely when it's time.
- Separate admin JWT, 12-hour sessions
- Cross-tenant reads for counts and rollups
- Deletes cascade in one transaction
A gym’s whole life, from this screen.
Onboarding a tenant is one form. Removing one is one confirmation. Neither leaves anything half-written.
Create the tenant
One form creates the gym and its OWNER login in a single transaction. Duplicate owner emails are rejected, not half-written.
Hand over the keys
The owner signs in on the mobile app and starts adding staff, plans and members. Their data is isolated from that moment on.
Watch, or wind down
Member and staff counts roll up here. Deleting a gym cascades the whole tenant away transactionally — nothing orphaned.
Sign in to the console.
Platform admin accounts only. Gym staff sign in from the mobile app with the credentials their owner issues.
Admin sign in