Preschool Platform
Smarter Preschool Management, Happier Parents
A complete preschool management platform that connects admins, teachers, and parents under one roof. The admin dashboard handles enrollment, attendance, fee collection, and daily reports β while dedicated mobile apps keep teachers and parents in sync with real-time updates, photos, and notifications. Built for schools that want to spend less time on paperwork and more time with kids.
Key Features
Built With
Feature-complete across the domains below and runnable end to end, but not yet running in production. What is deliberately unfinished is listed under Decisions we took.
The problem
A preschool runs on six systems that do not know about each other
A small preschool is an unusually broad operation for its size. It runs an admissions pipeline, a daily attendance register, a fee book with GST on it, a curriculum and assessment record, a transport roster, a safety and pickup protocol, and a constant parent-communication load β usually across a WhatsApp group, a spreadsheet, a paper register and an accounting package that were never introduced to each other.
The consequences are specific rather than abstract. A child is marked present on paper and absent in the app. A fee receipt is issued outside the numbering sequence and the GST return does not reconcile. A parent is not on the group and misses the pickup change. Nobody can say with confidence who is authorised to collect a particular child today.
The software that exists for this segment is mostly built for K-12 schools and scaled down, which means it carries an exam-and-marks model that early-years education explicitly rejects, and misses the things a preschool actually does daily: nap and meal logs, developmental observation, and proof of who handed a child to whom.
Why it exists
A rebuild, taken as a chance to fix the data model
The platform is a greenfield rebuild of an older system rather than an extension of it. That decision was taken specifically to change things that cannot be changed incrementally: how tenants are isolated, how money is represented, and which records are allowed to be edited after the fact.
The architecture is a modular monolith β one Go binary hosting every feature module behind strict internal layering, plus a separate worker for background jobs. For a system with this many domains and one team, that keeps the seams explicit and refactorable inside a single transaction boundary, without paying the operational cost of microservices before anything demands it.
The single most consequential decision is that tenant isolation lives in the database, not in application code. Every tenant-scoped table has Row-Level Security with an identical fail-closed policy, and the application connects as a non-superuser role for which that policy is enforced. A bug in a query cannot leak another school's children.
How it works
How a request stays inside one school
- 01
Authenticate, and resolve the audience
Login is school code plus email plus password, verified with argon2id. An audience gate separates the two populations completely: the web console is staff-only and parents are mobile-only. Access tokens are short-lived RS256 JWTs.
- 02
Open a transaction with tenant context
Every tenant-scoped query runs inside a helper that sets transaction-local Postgres settings for tenant, branch and user. Transaction-local matters: the values cannot bleed across a pooled connection to the next request.
- 03
Let the database enforce isolation
Row-Level Security policies compare the row's tenant against that setting. The policy is written so that an unset value reads as NULL and excludes every row β a request arriving with no tenant context sees nothing rather than everything.
- 04
Apply the authorisation the database cannot
RLS is tenant-only by design. Finer rules β a teacher owning a class, a student belonging to a branch β are enforced in the service layer, because they are business logic rather than data partitioning.
Who it is for
Who actually uses this
- School administrators
- The daily operators of the web console: admissions pipeline, roster, fees and collections, staff records, and the master lists everything else selects from.
- Teachers
- Attendance, daily reports, observations against curriculum outcomes, and progress cards β on the web console or the mobile app, whichever is at hand during a class.
- Parents
- Mobile only, and read-only for records: published daily reports, attendance history, chat with the school, and notifications. Deliberately not given a web login.
- Front-desk and transport staff
- Daycare check-in and check-out, pickup verification, transport trips, and incident reporting β a narrower role gate than full administration.
What it does
Capabilities, in detail
Admissions and student records
Admissions CRM
A lead pipeline with a kanban board, a status state machine, follow-ups, document checklists and source analytics β ending in an atomic enrol that creates the student and the opening invoice together.
Public online apply
An unauthenticated application path, IP rate-limited, that reaches the same pipeline without exposing anything else.
Student 360
Profile, guardians as a many-to-many relationship so siblings work properly, enrolment history, allergies, health records, documents, authorised pickups, and bulk Excel import.
Daily operations
Attendance
A daily register over a monthly-partitioned ledger, with a school calendar for holidays and working-day overrides, and a scheduled job that seeds the day at 05:00 IST.
Daily reports
A per-child, per-day feed with typed timeline entries, moving draft to published β and publishing is the single point where the parent notification fires and the media-consent gate is checked.
Daycare check-in and check-out
Check-in reconciles the attendance record to present; check-out validates the collecting adult against the authorised-pickup list rather than trusting the counter.
Transport
Vehicles, drivers, routes with ordered stops, per-student assignment, and daily trips with append-only board and alight events.
Curriculum and assessment
NCF-2022 framework
Developmental goals to competencies to coded learning outcomes, seedable per tenant, with no marks anywhere in the model.
Observation-based assessment
Anecdotal observations tagged to outcomes with a qualitative indicator and an optional work sample. The portfolio is a projection over observations rather than a separate store.
Holistic Progress Cards
Termly cards generated from observations, curated by a teacher, then finalised and shared β draft, final, shared, as distinct states.
Fees, safety and privacy
GST-aware fees
Fee heads and plans, gap-free legal invoice numbering, idempotent payments with FIFO allocation, an append-only ledger, on-demand invoice PDFs, and defaulter reporting.
Child safety
Severity-graded incident reports with a workflow and acknowledgement, an emergency-contact overlay, and a break-glass safety profile.
Pickup verification
Proof of handoff for collecting a child, storing only a hash of the one-time code, one open request per child at a time, with any override audited.
DPDP-2023 compliance
An immutable consent ledger, data-principal rights requests for access, export, erasure and correction, and an immutable audit of every state transition.
Communication
Chat
Persist-then-publish: a message is written with a gap-free per-conversation sequence number and idempotency on a client-supplied id, then published to subscribers.
Notifications and outbox
Per-recipient notifications backed by a transactional outbox, so WhatsApp and push delivery is at-least-once rather than fire-and-forget.
Announcements
Broadcasts with audience, category and priority, separate from direct conversations.
Engineering
Decisions we took, and what they cost
- Tenant isolation is a database control, not a code convention
- Every tenant table carries an identical Row-Level Security policy, and the runtime connects as a non-superuser role so the policy actually applies. The policy is written to fail closed: an unset tenant setting resolves to NULL and matches no rows. A forgotten WHERE clause returns nothing instead of everything, and there is an integration test in CI that proves an app-role connection cannot see another tenant's rows.
- Money is integer paise, and derived totals are generated by the database
- Floating point has no place in a fee ledger. Amounts are exact integers, and derived balances are GENERATED ... STORED columns with CHECK constraints enforcing the money identities, so an invoice's outstanding amount cannot drift from its lines through an application bug. GST splits are computed, not typed in.
- Operational records are append-only, enforced by triggers
- Attendance, the fee ledger, consent, lead history and trip events reject UPDATE and DELETE at the database level. A correction is a new row, not an edited one. That is what makes the audit trail worth having when a parent disputes a fee or a regulator asks who consented to what.
- Two populations, two applications, one audience gate
- Staff use the web console; parents use the mobile app; neither can log into the other. Enforcing that at authentication rather than by hiding navigation removes an entire category of authorisation mistake.
- Time is handled as three different things
- Instants are timestamptz. Business dates are DATE, derived in the branch's own timezone rather than the server's. Weekends are computed rather than stored. For a system whose core record is 'was this child here on this day', getting that wrong is not a rounding error.
- What is deliberately not finished
- The web console currently polls for unread counts rather than holding a live realtime connection; only the mobile chat thread subscribes. The mobile app has no media capture yet. Push token registration works but the sender behind the outbox is still a stub. These are tracked as deferred rather than described as done.
Technology
What it is built on
- Backend
- Go 1.25chiModular monolithSeparate worker binary
- Data
- PostgreSQL 16Row-Level Securitypgx/v5sqlcgolang-migrate
- Jobs & realtime
- asynqRedis 7CentrifugoTransactional outbox
- Web
- React 19ViteTypeScriptTanStack QueryZustandTailwind
- Mobile
- Flutterflutter_blocget_itdioFirebase Messaging
- Platform
- Docker ComposeCaddyAzure BlobOpenTelemetryPrometheus
What is next
Stated on the product itself
- Live realtime in the web console, replacing the current polling
- End-to-end push delivery behind the notification outbox
- Media capture and upload in the mobile app
- httpOnly-cookie auth hardening
What it taught us
What transfers to client work
- Multi-tenant SaaS where a leak is unacceptable
- Row-Level Security with a fail-closed policy, a non-superuser application role, and transaction-local tenant context is the pattern we reach for whenever one database serves many customers and the cost of cross-tenant exposure is not recoverable. It is materially harder to retrofit than to start with.
- Regulated money in Indian products
- GST-aware invoicing with gap-free legal numbering, exact integer money, FIFO payment allocation and an append-only ledger. These are the parts auditors examine, and they are decided by the schema long before anyone writes a report.
- DPDP-2023 as an architecture, not a policy page
- A consent ledger that cannot be edited, rights requests with an immutable transition audit, and a consent gate enforced at the moment media is published. Consent recorded as data with a timestamp and version is the difference between claiming compliance and being able to demonstrate it.
- Modular monolith as a deliberate choice
- Twenty-two feature modules in one deployable binary, with strict internal layering and one transaction boundary. For a single team building broad domain coverage, this is faster to change than a distributed system and can be decomposed later if load ever justifies it.
Related work
Building multi-tenant software where a leak is unacceptable?
Row-level tenant isolation, append-only audit trails, GST-aware money and DPDP consent as data β this platform is where we worked those out. Tell us what you are building and who has to be able to audit it.
Services this draws on
- SaaS development
Multi-tenancy, billing and role models β the plumbing under the features.
- Mobile app development
Flutter apps for two different audiences against one backend.
- Software modernization
Greenfield rebuild of a legacy system, taken as a chance to fix the data model.