Multi-city sports academy fee collection
Recurring fees across every city, center and batch — online and offline — with reporting the finance team actually trusts.
The problem we were handed.
A multi-city academy needed recurring fee collection across centers, with online and offline payments and flexible monthly-to-yearly plans.
The academy had grown the way academies grow — a coach opens a batch in a new neighborhood, a center gets added in a new city, and the roster follows. What didn't scale was the accounting. Each center ran its own spreadsheet, its own receipt book and its own idea of when a month starts. Cash handed to a coach on the field existed in one system; a bank transfer from a parent existed in another; nothing agreed. Head office could tell you how much money arrived, eventually. It could not tell you who still owed it.
Chasing dues was the visible cost. The invisible one was reconciliation — someone senior spending days a month stitching center-level records into a number the founders could act on. Every question that started with "how much did" ended in a manual export.
Parents felt the same friction from the other side. A reminder over chat, a UPI transfer, a screenshot as proof, and a receipt that may or may not arrive. Nobody had a single place to see what was due, what was paid and what was next.
How we built it.
A Slim + React platform with bulk student/plan uploads, city/center/batch management, custom receipts, a public parent payment portal and filterable income reporting.
City, center and batch management
A hierarchy that mirrors how the academy actually operates, so fees roll up cleanly. A student belongs to a batch, a batch to a center, a center to a city — and every payment inherits that path the moment it's recorded. Reporting stopped being an aggregation exercise and became a filter.
- One hierarchy shared by roster, plans, payments and reports
- Center-scoped access so staff see their own students and nothing else
- New cities and centers added as data, not as a code change
Bulk student and plan onboarding
The academy already had its roster — in spreadsheets, in varying shapes, per center. Rather than ask anyone to retype it, we built import as a first-class feature: upload, validate, review, commit. It ran repeatedly during rollout as each city came online, and it still runs every intake season.
- Dry-run validation that reports bad rows before anything is written
- Students, plans, batches and opening dues in the same pass
- Idempotent imports — re-running a corrected file doesn't duplicate a student
Plans that bend from monthly to yearly
Fees are not one product. A batch may run monthly, a sibling may be on a quarterly plan, a serious athlete pays annually, and discounts get applied by the center head on the spot. We modeled the plan as a schedule generator rather than a price tag, so dues are derived — not hand-typed — and every adjustment leaves a trail.
- Monthly, quarterly and yearly cycles off one plan definition
- Per-student overrides and concessions recorded against the plan, not hidden in a note
- Dues generated ahead of time so the collections view is a forecast, not a surprise
One ledger for cash and online
The hardest part of this build wasn't the payment gateway — it was cash. Money collected at a center had to land in the same ledger as an online payment, with the same receipt series, the same effect on dues and the same visibility to head office. Offline entries are attributed to the staff member who recorded them, so reconciliation has a name attached to it.
- Gateway callbacks and manual entries write through the same posting path
- Part-payments, refunds and adjustments as ledger events, never as edits
- Custom receipts issued identically whether a parent paid by card or by cash
Parent portal and income reporting
Parents get a public portal — no account, no password, no app. They find their student, see what's due, pay, and keep the receipt. Head office gets the other half: income reporting filterable by city, center, batch, plan and period, built on the same ledger the portal writes to, so the two views can never drift.
- A React front end that stays usable on a mid-range phone on mobile data
- Receipts generated in the academy's own format and retrievable later
- Reports that drill from a national total down to a single batch without an export
Architecture & integrations.
What it delivered.
Fee collection is the boring problem in education software, which is exactly why it's usually broken. Get the ledger right and everything downstream — receipts, dues, reporting, a parent portal — is a view over it. Get it wrong and no dashboard saves you. We treat the boring problems as carefully as the new ones, and this one paid back in the first month-end close.
Questions this project raises.
Because cash was the hard part. Dues, receipts and payments are append-only entries, so part-payments, refunds and adjustments are recorded events rather than edits to a row — which is the only way an offline entry and a gateway callback agree at month-end.
As a repeatable import rather than a one-off script: upload, dry-run validation, review, commit. It ran again as each city came online and still runs every intake season, and it's idempotent — re-uploading a corrected file doesn't duplicate a student.
The structure is city, center, batch and student, so a campus, a branch or a course intake maps onto it directly. What changes per organization is the plan rules and the receipt format, and both are configuration rather than a rebuild.
Plan complexity, how many centers exist on day one, and how clean the roster data is. This one ran project-based with milestone billing. If a phase is bigger than you think it is, we say so during scoping rather than at the end of it.
That was the design constraint — center staff are coaches, not operators, and anything needing a training manual goes unused. The console was built for that audience, and handoff is the repo plus runbooks, with the code yours and no lock-in.
Related work.
Have a problem shaped like this one?
Tell us what's in the way. You'll hear back from a senior engineer within one business day.