Replacing spreadsheets with one API
Short answer: A studio group tracked appointments, stock and staff commissions in spreadsheets, one file per branch. The same client could hold two records and monthly commissions were rebuilt by hand. The replacement was one API with a single record per client and per appointment, and the branches reading from it. Handover included the schema, the migration of existing rows, and a check that the commission figure now comes out of the data.
Checked on 2026-10-20
A studio group with several branches tracked appointments, stock and staff commissions in spreadsheets. Every branch kept its own file, the same client could hold two appointment records, and monthly commission numbers were reconstructed by hand at the end of each month.
What shaped the work?
Four constraints shaped the build: branches that had been keeping their own files, appointments and stock that had to share one record, commissions computed by hand, and staff who would not use anything slower than a spreadsheet.
- Staff were not going to learn a new desktop tool — the admin had to work in a browser and be usable on a tablet at the counter.
- Customers already lived inside a chat app, so the customer-facing surface had to be a Mini Program rather than a web login.
- Money-adjacent numbers (stock movements, commissions) had to be auditable: who changed what, when.
- Existing historical records needed to survive the move, including the inconsistencies.
What does it run on?
React (admin) · Django REST API · MySQL · WeChat Mini Program
What did we actually build?
The build replaced four spreadsheets with one API. What follows is the shape of it: the tables, the endpoints the branches call, and the two reports that used to be assembled by hand at month end.
- One API behind both surfaces: booking, stock, staff, reporting. No business rule lives in the client apps, so the admin and the Mini Program can never disagree.
- Booking carries explicit conflict rules (staff, room, service duration) instead of the soft warnings a spreadsheet gives.
- Stock movements are recorded as events tied to the service that consumed them, so a reconciliation can be reconstructed retrospectively.
- Commission is a function of stored events, not a typed number — recalculating an old month gives the same answer.
- The accountant exports one file per month from the admin rather than extracting anything from the database.
The choices that mattered
Single API, thin clients
Two front ends over one rulebook beats two implementations that drift apart in month two.
Events, not balances
A stored balance cannot answer "why is this number different from last month".
Import the mess, then clean
We imported the historical rows verbatim and flagged the duplicates, rather than silently merging records and losing the trail.
Boring stack
Django and MySQL: a future maintainer can read it without a framework tour.
What we would do next
- Branch-level performance views — the manager currently reads branch comparisons off raw exports.
- Reminder sequence for no-shows, driven from the booking records rather than a separate tool.
What is not on this page
No client name, no screenshots of their data and no metrics: those are theirs. What is here is the engineering, which is the part a buyer can evaluate. On a call we will walk through the code.