What it is
AVG Vidyalaya is a matriculation school in Chennai with more than 700 students. Their ERP is something I built alone: management portal, teacher portal and super-admin portal served from one Next.js app by host-based routing, a Flutter app for parents, and one NestJS API behind all of it. It covers admissions, attendance, marks, fees, payroll, homework, messaging and certificates. It is multi-tenant by design, so the next school is added without a second deployment.
Permissions are not role strings. There is a catalog of 130 capabilities, each tri-state, with dependency rules and pairing keys that force the person who initiates a sensitive action and the person who approves it to be different people. Schools compose roles from the catalog; they never invent capabilities.
Fees is a full finance module: cashier collection, concessions, waivers, installments, late fees, cheque clearance, Razorpay payment from the parent's phone, then settlement and bank reconciliation with discrepancy reporting. Every receipt PDF carries a signed QR code that anyone can verify at a public URL.
Architecture
Decisions that mattered
A sync layer instead of WebSockets
Parent-facing reads never touch the school's source tables. Modules emit domain events onto a queue; a sync service builds what parents see, filtered for DPDPA compliance and cached per parent. Idempotency is enforced at three levels, and a storm-collapse window stops one bulk marks entry from firing 700 notifications.
Everything degrades when Redis is absent
Redis is optional by configuration. Queues fall back to inline fan-out, caches to direct queries, scheduled jobs carry catch-up sweeps for anything missed at boot. A school's ERP should limp, not die, when a box goes down.
Receipts that prove themselves
Every fee receipt is a PDF with a cryptographically signed QR code. Scan it and a public verification page confirms the receipt is genuine, no login needed. Parents trust paper; this makes the paper trustworthy.
A parent app built like a bank app
The Flutter app keeps an encrypted offline cache under SQLCipher with the key in secure storage, stacks sessions for parents with several children, and offers biometric lock. Feature gates are server-driven so unfinished tabs ship dark. Fonts include Noto Sans Tamil, because the audience reads Tamil.
Spec first, at a strange ratio
45 functional spec documents, about 47,600 lines of markdown, drive the build through a gated rollout chain. That is roughly one line of specification for every four lines of code. It is why 184k lines in ten weeks did not collapse into a mess.