Skip to content
Health & Fitness

Gym Management System

Memberships, check-in, dues, receipts and trainer pay in one system — built so that nothing is ever deleted, every price is versioned, and the counter reconciles at the end of the shift.

Scroll to zoom · drag to pan · F to resize

The owner's dashboard. Collection is charted net of reversals rather than gross, members are split by the service they actually train on, and the two lists that drive the day — who is about to expire, and what just happened at the counter — sit side by side.

Who it's for

Built for a specific kind of business

Single-location gyms, fitness studios and training academies selling duration-based memberships over a counter. The point where this stops being an Excel problem is usually around 200 members and the first month nobody can say how much is outstanding without adding it up by hand.

Business type
Gym, fitness studio, CrossFit box or martial-arts academy
Size
150 to 3,000 members on file
Locations
One gym per deployment — multi-branch is a customisation, not a setting
Runs today on
A register at the desk, an Excel sheet, and WhatsApp for renewals
Decision maker
Owner, or the manager who runs the floor

The problem

What this actually costs you today

In the words operators use, not the words software vendors use.

  • Nobody can answer "who owes us money?" without an afternoon of work

    Part payments are normal in a gym — a member pays four thousand of a twelve-thousand plan and promises the rest next week. Once that is spread across a register, a receipt book and someone's memory, the total outstanding is not a number anyone can produce on demand, and the oldest debts are the ones that go unnoticed longest.

  • Renewal is the entire business model and it depends on someone remembering

    Members lapse quietly. Without a list of who expires this week and who has stopped turning up, the first signal is a revenue dip a month after the member had already decided to stop coming.

  • The drawer and the books disagree, and nobody finds out until month end

    Cash, card, bank transfer and wallet payments are taken across shifts by different staff, and expenses are paid out of the same drawer. Without a figure for what should be in it right now, a variance is discovered weeks later, when nobody can explain it.

  • Putting prices up quietly rewrites history

    Editing the price on a plan is the obvious implementation, and it silently changes what last year's reports say the gym charged. Old receipts stop agreeing with the plan they point at, and the one question an owner cannot afford to fumble — why was I charged this? — becomes unanswerable.

  • Trainer pay is recalculated from scratch, and argued about, every month

    A trainer on a salary plus a percentage of what their own members pay needs someone to work out which collections were attributable to them. Done by hand, it is slow, it is disputed, and it is usually done late.

  • Delete is the most dangerous button in gym software

    A receptionist deleting a payment entered in error is indistinguishable from a receptionist deleting a payment they pocketed. Any system where a cash record can simply disappear cannot be used to settle a dispute, which is most of what an owner needs it for.

What it does

Grouped by who uses it

Feature lists organised by technical module tell you nothing about whether the software fits your team. These are grouped by the person who lives in them.

Members and the register

Receptionist

One searchable register for everyone who has ever joined. Nobody is deleted — a cancelled member and their whole history stay on file and stay searchable.

  • Sequential member IDs on a configurable prefix and padding — GL-00001
  • Name, phone, CNIC, gender, date of birth, address and join date
  • Emergency contact, and free-text notes for anything staff should know
  • A card number per member, so an RFID card works at the desk
  • Duplicate phone numbers caught on entry, including against cancelled records
  • Every column searchable on its own, not just one global search box
  • Active plans, expiry, outstanding balance and last visit on every row
  • Deactivate and reactivate, so leaving and coming back is one record
  • Excel and CSV export of any filtered view

Memberships, renewals and freezes

Manager

A membership is a dated cycle holding one or more plans, and every plan on it shares a single expiry date. That one decision is what keeps renewal reminders from firing four times for one member.

  • Numbered cycles per member, so cycle 1, 2 and 3 are all visible as history
  • Several services on one membership — a Workout plan and a Personal Training plan under one expiry
  • Freeze, with the frozen days recorded and added to the end date
  • Cancel, and edit the dates, both restricted away from the front desk
  • Discounts as an explicit permission, with negative discounts off by default
  • Filters for running now, expiring in 7 or 30 days, lapsed, with dues, and frozen

Check-in and attendance

Receptionist

The highest-frequency action in the building, with the door policy decided in settings rather than by whoever is on the desk.

  • Find by phone, name, member ID or card, then admit in one action
  • Status, expiry and outstanding balance shown before the member is admitted
  • Configurable grace period after expiry, during which check-in is normal
  • Warn or block, separately, for expired members and for members who owe money
  • A warning must be acknowledged with a reason, which is kept on the record
  • Check-out optional — anything left open is auto-closed at end of day and flagged as such
  • Inactive-member report by how long since the last visit

Payments, receipts and dues

Receptionist

Every receipt sits in an unbroken sequence per financial year. Mistakes are corrected by a linked reversal, never by a delete, and both entries stay visible.

  • Receipt numbering as PREFIX/2026-2027/00001, fixed for the financial year
  • Cash, card, bank transfer and wallet, with a reference field
  • Part payments against a membership, with the balance carried
  • Advance payments held against the member and drawn down later
  • Reversals as linked entries, permitted to managers and owners only
  • Outstanding dues aged into bands the owner configures — 0-7, 8-15, 16-30, 31-60, 60+

Collection and the daily reconciliation

Manager

What actually came through the counter, net of reversals, and what should therefore be in the drawer right now.

  • Net collected, gross receipts and reversals as three separate figures
  • Cash taken and cash paid out, resolving to cash in hand
  • Filter by day, week, month or a custom range, and by the staff member who took it
  • A receptionist sees only their own collection, for shift reconciliation
  • Advances taken and members who paid, counted separately
  • Day-by-day and by-method breakdowns

Services, plans and pricing

Owner

A service is what the gym offers; a plan is that service with a duration and a price. Changing a price creates a new plan and retires the old one rather than editing in place.

  • Services — Workout, Cardio, Personal Training — each with their own plans
  • Durations priced independently, so 12 months is not forced to be 12x the monthly rate
  • Price changes versioned, so old receipts and reports never move
  • Retire rather than delete, keeping historical reporting intact
  • Members currently on each plan, and total ever sold, on the same row

Trainers, assignments and payouts

Owner

Trainer compensation computed from the collections actually attributable to the members assigned to them, rather than reconstructed by hand each month.

  • Salary, a percentage of collections from their own members, or both
  • Dated member-to-trainer assignments, so history survives a reassignment
  • Monthly payout runs prepared as drafts, then approved
  • Salary, attributable collections, commission and payable shown as four separate figures
  • Draft, approved and paid as distinct states

Expenses and profit

Owner

Collection is not profit, and the system refuses to let the two be confused.

  • Expense vouchers numbered per financial year, voided rather than deleted
  • Categories — rent, salaries, utilities, maintenance, marketing, equipment
  • Trainer payouts recorded against the salaries category
  • Profit as collections for a period minus expenses for that period, with the margin
  • Month-by-month money-in against money-out over 6, 12, 18 or 24 months

Reminders over SMS and WhatsApp

Manager

The reminder rules are configured on the screen, not in code. Expiry, lapse and dues chasing are rules with schedules, caps and templates.

  • Rules for expiring soon, expiry day, lapsed follow-up and outstanding dues
  • Repeat intervals and a maximum send count, counted within the current membership
  • A minimum outstanding amount before a dues chase fires
  • Templates with merge fields, previewed as the member will read them
  • SMS over a generic HTTP gateway, WhatsApp over the Meta Cloud API
  • Provider credentials encrypted at rest and shown back masked, with a test send
  • A message log, so "we never got it" is checkable

Roles, permissions and the audit trail

Owner

Roles are a label. The system enforces individual permissions, which is what lets one capability be granted or revoked for one person without inventing a new role.

  • Fifty-six permissions across members, memberships, money, trainers, messaging and setup
  • Owner, Manager, Receptionist and Trainer as shipped bundles, all reshapeable
  • Custom roles, and per-person overrides on top of a role
  • Before-and-after audit on payments, memberships, plans, staff accounts, permission changes and messaging setup
  • Every record stamped with who created it and who last changed it
  • Login history with time, IP address and device

Screenshots

The actual interface

Every screenshot uses generated demo data. No real customer, student or member record appears anywhere on this site.

  • Check-in. Two characters is enough to find a member, and the admit button itself carries the policy — green to let them straight in, amber where money is outstanding, so the decision is made before the member is through the door rather than discovered afterwards.

  • The member register. Active plans, expiry, what they owe and when they were last in, on one row — with the outstanding total for the filtered page footed at the bottom.

  • One member's timeline. Renewals, plans, payments and visits in a single feed — the screen to open when somebody disputes what they paid, because the answer is on it rather than across four screens.

  • Every membership sold, by cycle. All the plans on one membership share a single expiry date, which is what keeps a member with two services from being chased twice.

  • The price list. Changing a price creates a new plan and retires the old one instead of editing in place, so it stays clear which price was in force when — and an old receipt never changes years later.

  • Attendance history. Check-out is optional, so visits left open are closed at end of day and labelled as automatic rather than given an invented time — the distinction that keeps the stay-duration figures honest.

  • Outstanding dues, aged. The bands are set by the owner in settings, and the table carries how long each balance has been outstanding — so the oldest money is visible instead of buried under the newest.

  • Every receipt, in an unbroken sequence per financial year, with the staff member who took it on the row. A mistake is corrected by a linked reversal — payments are never deleted, because a gap in the numbering reads as theft.

  • The counter reconciliation. Cash taken minus cash paid out gives what should be in the drawer right now, and net collection is shown separately from gross so a reversal cannot flatter the day.

  • Profit, stated as collections minus expenses for the same period, with the margin. Collection alone is not profit — so money in and money out are charted as paired bars month by month, with the same period's spending broken out by category beside them.

  • The monthly trainer payout run. Salary, the collections attributable to that trainer's own members, and the commission computed from them are separate figures on the row — so the payable amount can be explained rather than asserted.

  • Reminder rules, configured on the screen rather than in code. Each rule carries its offset, repeat interval and send cap — and the cap counts within the member's current membership, so renewing starts the conversation again.

  • The four shipped roles. Nothing in the system checks a role name — it checks the individual permissions underneath, which is why a role can be reshaped, or one capability revoked for one person, without touching code.

  • The door policy, as configuration. Every gym runs an informal grace period; making it explicit — and forcing an override to carry a reason — is what stops staff waving people through until the block means nothing.

  • The audit trail. Before-and-after history is kept deliberately for payments, memberships, plans, staff accounts, permission changes and messaging setup — not for every table, because an audit log nobody can read is not evidence.

Scroll to zoom · drag to pan · ←/→ to browse · F to resize

Roles & permissions

Who can do what

Publishing this table is unusual. It is also the fastest way to show that the system was designed for a real deployment rather than for a demo.

Four roles ship with the system, but no screen checks a role name. Every endpoint checks an individual permission — fifty-six of them, plus one that scopes a trainer to their own assigned members — so the Owner can grant or revoke a single capability for a single person without inventing a new role. This table is the shipped default, and all of it is editable.

Capabilities by role. Each row is a capability; each column is a role.
Capability Owner All 56 Manager 50 of 56 Receptionist 26 of 56 Trainer Read-only, 7
Owner: Full Manager: Full Receptionist: Edit Trainer: Own
Owner: Full Manager: Full Receptionist: — Trainer: —
Owner: View Manager: View Receptionist: View Trainer: Own
Owner: Full Manager: Full Receptionist: Edit Trainer: View
Owner: Full Manager: Full Receptionist: Edit Trainer: —
Owner: Full Manager: Full Receptionist: — Trainer: —
Owner: Full Manager: Full Receptionist: Edit Trainer: —
Owner: Full Manager: Full Receptionist: — Trainer: —
Owner: View Manager: View Receptionist: View Trainer: —
Owner: Full Manager: Full Receptionist: Own Trainer: —
Owner: Full Manager: Full Receptionist: Full Trainer: View
Owner: Full Manager: Full Receptionist: — Trainer: —
Owner: Full Manager: Full Receptionist: View Trainer: View
Owner: Full Manager: Full Receptionist: — Trainer: —
Owner: Full Manager: Full Receptionist: — Trainer: —
Owner: View Manager: View Receptionist: — Trainer: —
Owner: View Manager: View Receptionist: View Trainer: —
Owner: Full Manager: Full Receptionist: Edit Trainer: —
Owner: Full Manager: Full Receptionist: — Trainer: —
Owner: Full Manager: — Receptionist: — Trainer: —
Owner: Full Manager: View Receptionist: — Trainer: —
Owner: Full Manager: View Receptionist: — Trainer: —
Owner: View Manager: — Receptionist: — Trainer: —
  • Full: Create, edit and remove
  • Edit: Create and update, with the limits noted on each row
  • View: Read only
  • Own: Only their own records — their own shift, or their own assigned members
  • No access

Demo access and customisation

See it running

A demo environment with seeded data is available on request during a call. Every member name, phone number, payment and visit in it — and in every screenshot above — is generated. No real member data appears anywhere on this page.

Deploy as-is, or fit it to your process

As-is
1 to 2 weeks
Customised
4 to 8 weeks

Plans, pricing, the grace period, door policy, dues ageing bands, reminder rules and every role are configuration and need no development. The two things that usually do need work are hardware — turnstiles and biometric readers vary enormously and are confirmed during discovery, not after — and multi-branch, if you run more than one gym.

FAQ

Gym Management — questions we get asked

  • Can we run more than one branch on it?

    Not as it stands, and we would rather say so than imply otherwise. It is built as one gym per deployment: one identity, one price list, one drawer. Running a second branch today means a second deployment. Proper multi-branch — staff scoped to a location, consolidated reporting for the owner — is a customisation we scope explicitly, because branch scoping has to be enforced somewhere a developer cannot forget it rather than added as a column.

  • What happens when a member whose membership has run out turns up at the door?

    Whatever you configure. There is a grace period in days during which check-in is completely normal. Past it, expired members and members who owe money are handled by two separate rules, each set to either warn the receptionist or block the check-in outright. A warning has to be acknowledged with a reason, and that reason is kept on the visit record — which is what stops the override quietly becoming the default.

  • What happens to old receipts when we put our prices up?

    Nothing, which is the point. Changing a price retires the existing plan and creates a new one at the new price. Memberships already sold keep pointing at the plan they were sold on, so last year's receipts and last year's reports still say what they said. You can always answer why a member was charged what they were charged.

  • Can a payment entered by mistake be deleted?

    No, deliberately. It is corrected with a reversal, which is a linked entry; both the original and the reversal stay visible, and the receipt sequence stays unbroken. A gap in receipt numbering reads as theft to a gym owner, and a system that allows one cannot be used to settle the disputes it exists to settle. Reversal is a manager-and-above permission.

  • Can the receptionist see how much the gym makes?

    No. She sees her own collection, which is what she needs to reconcile her drawer at the end of a shift, and she can take payments and issue receipts all day. Gym-wide revenue, profit, expenses and trainer payouts are separate permissions she does not hold by default — and because authorisation is per permission, you can hand her one of them without handing her the rest.

  • Do members need an app?

    No, and there is deliberately no member login. Reminders reach them over SMS or WhatsApp — expiry warnings, expiry-day notices, lapsed follow-ups and dues chasing — on rules you set. For a gym this size, a member portal is a feature that gets built, launched and then not used.

  • Who owns the data?

    Your data is yours, without qualification — exportable to Excel or CSV from every list in the system at any time, with no exit fee and nothing held back.

    The deployment is yours to place. Run it on your own server, or on ours, whichever your policy requires.

Under the hood — for your IT team

Technical architecture

How it is built

An ASP.NET Core API over SQL Server with a React single-page front desk, run on IIS. The two decisions that shape everything else are that records are corrected rather than deleted, and that authorisation is checked per permission rather than per role — so the audit trail is complete by construction, and access can be tuned per person without a code change.

  1. Clients

    • Front deskReact SPA, route-split
    • Owner & manager viewsSame app, gated per permission
    • MembersNo app — reached by SMS / WhatsApp
  2. Application

    • ASP.NET Core APIREST, hosted on IIS
    • Permission gate56 keys, checked per endpoint
    • Ledger rulesReverse, void, retire — never delete
  3. Scheduled work

    • Hourly state processIdempotent; leaves Frozen and Cancelled alone
    • Reminder rulesExpiry, lapse and dues, with send caps
    • Messaging adaptersSMS gateway / WhatsApp Cloud API
  4. Data

    • SQL ServerMembers, memberships, payments, visits
    • Numbering sequencesReceipts and vouchers, unbroken per year
    • Audit entriesBefore and after, on money and on access
Authorisation is a per-permission check on every endpoint rather than a role-name check, and corrections are entries rather than deletions — so numbering stays unbroken and the audit trail is complete by construction.
Stack, layer by layer
  • API ASP.NET Core (C#), REST

    The team's deepest language, and a runtime whose authorisation primitives map directly onto per-permission checks.

  • Database SQL Server, EF Core

    Money, dates and memberships are a relational problem. Transactional integrity matters more than schema flexibility.

  • Front desk React + TypeScript, Vite, TanStack Query

    Dense tables with per-column search and fast filtering, which is most of what a receptionist does all day.

  • Auth JWT access token carrying the permission set, with a refresh token

    The UI can hide what a user cannot do without a round trip, while the API still checks every call independently.

  • Scheduled work A single idempotent hourly process

    Expiry, lapse and open-visit closing are all date arithmetic. One job that can safely run twice beats several that cannot.

  • Messaging Adapter-based — generic HTTP for SMS, Meta Cloud API for WhatsApp

    Local SMS gateways vary by country and by year. Swapping one is configuration, not a rewrite.

  • Hosting IIS on Windows Server, with HSTS and a strict header policy

    Most gyms of this size already have a Windows host, or want one they can point at.

Data model highlights
  • Member with a sequential, immutable member code — Cancelled is a status, never a deletion
  • Membership as a numbered, dated cycle whose plans all share one expiry date
  • Service → Plan, where a price change retires the plan and creates a new one rather than editing it
  • Payment carrying a receipt number unbroken per financial year, with Reversal as a linked entry
  • Advance held against the member and drawn down, kept separate from settled payments
  • Visit with check-in, optional check-out, an auto-closed flag, and the override reason if one was given
  • TrainerAssignment as a dated link from member to trainer, so payout history survives a reassignment
  • Role, Permission, and per-person overrides on top of a role
  • AuditEntry with before-and-after values on payments, memberships, plans, accounts, permissions and messaging setup
Integrations
  • SMS through a generic HTTP gateway adapter, so a local aggregator can be pointed at it
  • WhatsApp through the Meta Cloud API
  • Excel and CSV export on every list and every report
Deployment topology

Single-tenant — one database per gym, on IIS over SQL Server, on a small VM or an existing Windows host. Provider credentials are encrypted at rest. Multi-branch is a customisation rather than a setting, because branch scoping touches every query and is not worth carrying for the single-site gyms this was built for.

Notable engineering decisions

The trade-offs we made, and why

This is the section that separates a system somebody built from a system somebody screenshotted.

One membership, one expiry date

The obvious model gives every plan its own start and end date. A member buys a twelve-month Workout plan in January and adds three months of Personal Training in March, and the two run on independent clocks.

It is more flexible, and it is wrong for this business. Every downstream feature immediately has to answer “expiring when?” for a member with two answers. The renewal list shows the member twice. The reminder rules fire twice. The receptionist looks at the screen and cannot tell you, in the two seconds she has while the member is standing there, whether this person is current.

So a membership is a dated cycle that holds plans, and the cycle owns the expiry. Each plan is charged at its own list price, and the cycle runs to the furthest of their end dates — a member on a twelve-month Workout plan who adds three months of Personal Training has one expiry, not two. The member has one date, the desk has one answer, and the reminder rules have one thing to count against.

The cost is real and worth naming: a three-month add-on inside a twelve-month cycle gets no renewal prompt of its own three months in. Gyms at this size generally treat that as the right trade — the renewal conversation happens once a year rather than four times — but if you sell short add-ons you intend to re-sell on their own clock, that is the first thing to change.

A price change is a new plan, not an edit

Editing the price on a plan is one UPDATE. It is also the quietest way to corrupt a year of reporting.

Once the price has moved, every historical row pointing at that plan now implies the wrong figure. Last March’s revenue report disagrees with last March’s receipts. Nobody notices until a member produces a receipt that no longer matches what the system says the plan costs, and by then there is no way to reconstruct which price was in force when.

So a price change retires the existing plan and creates a new one. Existing memberships keep pointing at the plan they were sold on. New sales get the new plan. The plan list shows both, one marked current and one retired, with the number of members still on each.

The same reasoning runs through the rest of the system, and it is the single idea the product is organised around:

  • Members are deactivated, never deleted — a cancelled member keeps their history and stays searchable.
  • Payments are reversed, never deleted, with the reversal linked to what it reverses and both visible.
  • Expenses are voided, never deleted, so voucher numbering stays unbroken.
  • Services and plans are retired, never deleted.

Receipt numbers run in an unbroken sequence per financial year, and the format cannot be changed part-way through a year once receipts exist. That constraint is not fussiness. A gym owner reading their own receipt book treats a gap as theft, and they are usually right to.

Permissions are enforced; roles are only a label

The system ships with Owner, Manager, Receptionist and Trainer. Nothing in the code checks any of those names.

Every endpoint checks a single permission key — payments.reverse, collection.view.all, memberships.dates.edit — and a role is just a named bundle of them. Fifty-six keys, with a fifty-seventh that scopes a trainer to their own assigned members.

This matters because of how the request always arrives. A gym does not ask for a new role. It asks whether one specific receptionist can start applying discounts, because she has been there four years and the manager is tired of being called over. With role-name checks, that is either a code change or a third role called “Receptionist Plus” — and a year later there are five of those and nobody knows what distinguishes them. With permission checks it is a checkbox, and the audit trail records who ticked it.

Two boundaries in the shipped defaults are worth pointing at:

  • The front desk can take money all day and never see what the gym makes. collection.view.own covers reconciling a shift. collection.view.all, revenue and profit are separate permissions the Receptionist does not hold.
  • Nobody can reverse their own mistake. payments.create is a front-desk permission; payments.reverse is not. The correction is always made by somebody other than the person who made the error.

The door policy is configuration, and the override is evidence

Every gym already runs a grace period. It is just undocumented, inconsistent between staff, and impossible to audit.

So it is a setting, in days, during which an expired member checks in completely normally. Past it, two separate rules decide what happens — one for members whose membership has run out, one for members who owe money — each set to warn or to block outright.

The part that does the real work is what a warning costs. It has to be acknowledged with a reason, that reason is stored on the visit record, and the check-in screen counts the result as admitted with an override. A policy that can be waved through at no cost stops being a policy within a fortnight. One that leaves a countable trail stays one — and the count itself becomes the useful number. If three hundred people were admitted on an override last month, the grace period is set wrong, and that is worth knowing.

One hourly job, safe to run twice

Membership state is date arithmetic — active until an end date, expired after it, lapsed some days later. The tempting implementation computes it at read time, and it works until two screens disagree because they rounded a timezone differently.

Instead a single process runs every hour and settles it: Active and Expired are recalculated from the dates, member status follows their memberships, and visits left open are closed and flagged as automatic rather than given an invented check-out time.

Two properties make it safe to leave running unattended.

It is idempotent — running it twice changes nothing the second time, so a retry after a failure is free, and the button in the settings screen that runs it on demand cannot hurt anything.

And it never overwrites a human decision. Frozen and Cancelled are states a person chose, and the job does not touch them. This sounds obvious and is the bug most often found in systems like this one: a nightly job that helpfully reactivates a membership somebody cancelled that afternoon.

Book a walkthrough of Gym Management.

We will show you the working system, tell you honestly what would need changing for your operation, and give you a range before you commit to anything.

30 minutes · We reply within one business day.

WhatsApp Book a call