Brookstone Schools Portal
Invoicing & receivables
BuildingBackend / full-stack · team of two · Apr 2026 – now
Fee billing, payments and a per-student subledger for a group of Nigerian schools. Every rule that touches money is enforced inside MySQL, so a buggy action, seeder or tinker session can't corrupt the ledger. I own notifications, audit logging, the guardian portal and the approval path into finance.
Receivables by account
1 / 6
Decisions worth explaining
Amounts are integer minor units plus an ISO-4217 code, wrapped in an immutable value object that refuses cross-currency maths. The currency CHECK runs under
utf8mb4_bin, because the default collation happily accepts'ngn'.A
CHECK (submitted_by <> decided_by)on every approval table, a route gate built from the permission catalog, and a carve-out that keeps*.approveaway fromsuper_admin. Platform staff can raise a credit note but never sign one off.no_updateandno_deletetriggers make the subledger append-only, so voiding a charge writes a reversal. Balances are a projection updated with an atomicbalance = balance + :deltaupsert, underlockForUpdateon the invoice.reconcile-accountsrebuilds balances from the ledger.audit-ledger-coherencehas no--fixflag on purpose: a void with no reversal has two consistent explanations, and picking one would write money on a guess.school_idis the only tenant boundary.super_adminskips authorization, never isolation. Jobs enter a school only throughrunFor($schoolId), and CI fails any code that reads the actor's ownschool_id.
- Laravel 13
- PHP 8.3
- MySQL 8
- React 19
- Inertia
- TypeScript
- AWS SES + SNS


