The story
A full ERP for a sports and social club, written on a PHP framework I built from scratch, with its own router, template engine, query builder and event bus. It covers memberships with spouses and children, subscriptions and fines, academies and bookings, the cashier and treasury, double-entry accounting, HR and payroll, procurement and stock.
It went from the first commit to staff signing in on production in five and a half months. The club website, the member portal and the members’ app all run on the same code and the same database.
Hard parts cleared
- Accounting that posts itself: 33 business events (payments, sales, payroll, fines, installments, purchases, transfers) each write a balanced journal entry, and a coverage check finds any document left without one.
- A tamper-evident audit trail: every change is stored before and after, and each row carries an HMAC of the one before it, so editing or deleting history breaks the chain in plain sight.
- Membership numbers with a memory: the club renumbered in 2026, so one number can belong to a member today and to someone else yesterday. Every lookup answers both.
- Moved the club’s Excel history, payments back to 2006, into production through an extract, match, verify and report pipeline, with a full backup before every step.
- Treasury discipline: every payment goes through a cashier session, refunds and transfers wait for a second approval, and cheques have a lifecycle of their own.
- Tested at 50 signed-in users at once with zero errors. Backups are encrypted, and changing a single byte makes the restore refuse.















