AI Workflow Platform

Teachers speak. AI writes. Admins approve. 70+ letters reach parents.

A multi-tenant school operations platform that turns a teacher's voice notes into branded, parent-ready progress letters — with approval gates, delivery tracking and permanent history.

Client
Little Lumos Preschool, Kakinada
Little Lumos report review screen showing a generated progress letter beside its branded PDF preview and approval controls

What was the problem?

Each report meant recalling a month of observations, writing warm parent-facing prose, formatting it on letterhead and emailing it to two parents. Roughly 3–4 working days of staff time every month, with tone that varied by teacher and no record of what was actually sent.

What made it hard

Commercially

  • The output goes to parents under the school's name, so quality could not be left to a model unsupervised
  • A letter already in a parent's inbox cannot be recalled

Technically

  • Serverless functions have a hard 60-second ceiling, and a class-sized run does not fit inside it
  • AI vendors retire model IDs without notice, and rate limits at batch scale are the common path rather than the edge case
  • Teacher answers are untrusted free text being fed to a language model
  • A PDF and the image of that PDF in an email must never disagree

Operationally

  • A report going to both parents is two independent deliveries, and a retry must not re-mail a parent who already received it
  • Teachers must be able to answer by speaking, on a phone, between classes

At scale

  • 25 AI letters is roughly 13 seconds of model time plus database writes; 25 sends rasterise a page each and push megabytes through SMTP

Security

  • Every document must be scoped to one school so a query cannot span two tenants
  • Teachers must not be able to see parent contact details
  • An administrator tuning the school's voice must not be able to delete the rule that stops the model inventing a child's achievements

What we built

Teachers answer per child by speaking; browser speech recognition transcribes and the teacher confirms before anything is saved. The AI engine drafts each letter using the school's configured perspective, age stage, tone and length bands. An administrator reviews side by side, edits, regenerates if needed, previews both the PDF and the actual email, and approves. Bulk send then delivers only approved reports as a tracked campaign, one delivery record per parent address, with retry of just the failures.

What it does

  • Voice-first answer capture

    Teachers speak their observations per child; the transcript is edited and confirmed before saving.

  • AI letter generation

    Configurable perspective, age stage, tone and length bands across three AI providers.

  • Approval gate

    Only approved reports can be sent, with side-by-side editing and full revision history.

  • Branded PDF rendering

    Versioned templates rendered as real PDFs with a defined safe content area.

  • Bulk send with delivery tracking

    A tracked campaign per cycle, with one delivery record per parent address and retry of failures only.

  • Cycle snapshotting

    Questions, template version and AI configuration frozen into the cycle at creation.

  • CSV roster import

    Column mapping, dry-run plan with per-row outcomes, then apply.

  • Roster sync mid-cycle

    Children who joined after a cycle was created can be pulled in on demand, idempotently.

  • Length correction

    A letter outside the configured word band by more than a paragraph triggers an automatic corrected call.

  • Ad-hoc branded messaging

    Emails to staff, parents or external addresses with honorific-aware greetings.

  • Permission matrix

    22 capabilities, editable per school.

  • Installable PWA

    Runs on staff phones and tablets with update-on-confirm and an offline fallback.

  • Deployment self-diagnosis

    A public health endpoint reports which environment variables are missing by name only, never value.

Engineering decisions

Choices that could have gone another way, and what each one bought.

  1. A resumable job runner built without a queue service

    Serverless functions have a hard 60-second ceiling and a class-sized run does not fit. The runner claims a lease, processes items until its time budget runs out, saves every item's state, and POSTs to itself to start the next chunk on a fresh invocation with a fresh clock.

    Why it matters. A naive implementation gets killed part-way, leaves its job stuck on 'running' forever, and can only recover by starting from zero — rewriting letters that were already written and charging for them twice.

  2. Ownership is a lease, not a flag

    A run is owned by a lease deadline claimed by compare-and-set inside a Firestore transaction. A killed invocation frees the run by failing to renew, and a continuation racing the UI's nudge resolves to exactly one winner.

    Why it matters. There is no cleanup step that itself has to survive the crash, and no path where two workers duplicate every item in a batch.

  3. Every AI failure is classified before it is retried

    Model-scoped failures try the next approved model from the same provider. Retry-scoped failures back off exponentially with jitter, honouring the vendor's Retry-After. Provider-scoped failures skip the provider entirely. Only when all three are exhausted does it move on, and finally to a local writer.

    Why it matters. Vendors retire model IDs without notice and rate limits at batch scale are the common path, not the edge case. Jitter matters specifically because a batch that trips the quota gets its 429s milliseconds apart — retrying them all on a fixed delay just recreates the burst.

  4. The no-fabrication rules cannot be edited away

    The prompt is built in four strictly separated layers, with untrusted teacher observations confined to the user role inside explicit delimiters. The rules against inventing achievements, grades, behaviours, medical or family information are appended by the builder and are not exposed in the admin UI.

    Why it matters. An administrator tuning the school's voice cannot accidentally delete the rule that stops the model inventing a child's achievements — and a teacher typing into a free-text box cannot instruct the model either.

  5. Snapshots make the past immutable

    Cycle creation freezes the question set, the template version and the AI writing configuration in one atomic step. The acceptance test is the proof: move a child from Class 1 to Class 2 mid-year, and September's report still says Class 1, October's says Class 2, and the child was never deleted or recreated.

    Why it matters. A letter already in a parent's inbox cannot be recalled. If later configuration edits could reach backwards, the system of record would disagree with what families actually read.

  6. The cache is never the source of truth

    Redis mirrors job counters so the progress UI polls one command instead of re-reading the job document, but Redis is never consulted for what has actually been done.

    Why it matters. A cache failure becomes a cache miss rather than a wrong answer — the system can never report a letter as sent because a counter drifted.

Technical detail

Collapsed by default. Open whichever part you are evaluating.

Frontend
  • Next.js 16
  • React 19
  • Installable PWA
Backend
  • TypeScript service layer
  • Serverless functions with a 60-second ceiling
Database
  • Firestore
  • In-memory JSON backend for local development
Storage
  • Firebase Storage
Authorization
  • Per-school permission matrix over 22 capabilities, enforced in the service layer
Background processing
  • Lease-based resumable chunked job runner with HMAC-authenticated self-continuation
Caching
  • Upstash Redis mirroring job counters for cheap progress polling
Messaging
  • Email with per-recipient delivery accounting
Deployment
  • Serverless
Monitoring
  • Public health endpoint naming missing environment variables
  • Append-only audit log
  • Per-cycle activity timeline

Frontend
  • Next.js 16
  • React 19
  • TypeScript
  • PWA
Backend
  • TypeScript
Database
  • Firestore
Cloud
  • Firebase Storage
  • Upstash Redis
Integrations
  • Google Gemini
  • OpenAI
  • Anthropic Claude
  • Puppeteer
  • PDFKit
  • SMTP email
Tools
  • Browser speech recognition

Authorization
  • 22 granular capabilities with an editable per-school permission matrix
  • Every gate checked in the service layer; hiding a field in the UI is treated as cosmetic
  • Rewriting an already-sent report requires a distinct capability
Data protection
  • Every document carries a tenant ID, enforced at the data layer so a query cannot span two schools
  • The service worker never caches student, parent or report data — only hashed static assets and public brand files are cache-first
Abuse prevention
  • Prompt-injection hardening: the prompt is built in four strictly separated layers, with system instructions, style config and report context in the system role and teacher observations in the user role inside explicit delimiters
  • No-fabrication rules (never invent achievements, grades, behaviours, medical or family information) are appended by the builder and are not editable from the admin UI
  • Self-continuation requests are authenticated with an HMAC signed over the job ID and bound to a 5-minute window
Auditability
  • Append-only audit log across every mutation
  • Readable per-cycle activity timeline
  • Revision history on every report
Privacy
  • Data minimisation — teachers deliberately cannot see parent contact details

Mechanisms

  • Lease-based resumable chunked job runner
  • Per-item durable state on the job document
  • Compare-and-set lease claiming inside a Firestore transaction
  • HMAC-authenticated self-continuation bound to a 5-minute window
  • Stall detection and automatic restart
  • Three-scope AI failure classification with multi-provider fallback
  • Exponential backoff with jitter honouring Retry-After
  • Per-recipient delivery rows written at provider acceptance
  • Tuned concurrency — 3 lanes for generation, 2 for sending
  • Redis used only as a progress cache, never as a source of truth

Failure scenarios handled

  • A serverless invocation is killed part-way through a class-sized run
  • An AI vendor retires a model ID without notice
  • A batch trips the provider's rate limit and returns 429s milliseconds apart
  • A provider auth failure or sustained outage
  • A continuation request never lands because of a deploy mid-run or a cold start
  • Two workers race for the same run
  • A send succeeds but the status write fails
  • A cache (Redis) failure during progress polling
  • A multi-page report that would otherwise silently lose page 2 when rasterised

Idempotency. Work is never repeated. A run that died at student 21 generates 22–25 and leaves 1–20 alone; retry targets only the failed items. A retry never re-mails a parent who already received the letter, because the delivery row is written per address at the moment the provider accepts.

Recovery. Ownership is a lease deadline rather than a flag, so a killed invocation frees its run by failing to renew — no cleanup step that itself has to survive the crash. If a continuation never arrives, anything that later reads the job's progress notices it is stalled and restarts it. No human has to spot it.

Before and after

Before

  • 70+ reports written by hand each month
  • Roughly 3–4 working days of staff time per cycle
  • Tone and quality varying by teacher
  • No record of what was sent, to whom, or whether it arrived
  • Reports formatted manually onto letterhead and emailed individually

After

  • Teachers answer by speaking; AI drafts the letter
  • An administrator reviews, edits and approves before anything is sent
  • Branded PDFs generated from versioned templates
  • One tracked delivery record per parent address, with retry of failures only
  • Permanent, immutable report history with revisions preserved

The build, by the numbers

What was built, at what scale. These describe the system's size, not its business results.

automated tests
411automated testsAcross 44 files, all passing in under 5 seconds
reports per cycle
70+reports per cyclePreviously written by hand over 3–4 working days each month
lines of TypeScript
~33,500lines of TypeScriptAcross 218 files in strict mode
collections
19collectionsFully typed domain layer
external integrations
5external integrationsEach behind a swappable interface with a zero-credential local fallback
granular capabilities
22granular capabilitiesEditable per-school permission matrix

What changed as a result?

A multi-day manual writing cycle became an afternoon of review and approval, with 70+ branded letters reaching parents per cycle and a permanent record of exactly what each family received. The platform carries 411 automated tests across 44 files, covering tenant isolation, email idempotency, bulk resumability, AI fallback and snapshot integrity — and runs end to end with no credentials at all, which is what makes those tests possible.

  • Replaced a 3–4 day monthly manual reporting cycle with a review-and-approve workflow
  • 70+ branded letters delivered per cycle with per-parent delivery tracking
  • Bulk generation and sending resume exactly where they stopped after a serverless timeout
  • Three AI providers behind a three-layer failure model, with a local writer as final fallback
  • 411 automated tests covering tenant isolation, email idempotency and bulk resumability

Why does this matter in schools & preschools?

School software is the combination of two things: the website that wins an admission enquiry, and the system that handles everything after it. Most of our delivered work is here. A school site is judged by parents in under a minute, and a school office runs on processes that spreadsheets stop supporting the moment you add a second campus.

  • Admission enquiries leak before anyone calls back

    Long forms and delayed follow-up lose parents who were ready to enquire. The Little Lumos admission form was cut to ten questions and completes in under 30 seconds, which dropped drop-off and shortened time-to-first-call.

  • Fee collection eats an administrator's week

    Manually generating fee entries per student per term, then reconciling receipts, is where school offices lose days. Automated generation and collection removes the arithmetic and leaves a single record everyone can check.

  • Parents and teachers have no shared source of truth

    Attendance in one register, daily activities in a WhatsApp group, fees in a spreadsheet. Nothing reconciles, and every parent question becomes a search. A single portal with role-based access ends that.

  • Looking the same as every other school nearby

    In a market with sixty-plus preschools, a template website is indistinguishable. Philosophy-led, story-driven sites give parents a reason to choose you before they ever visit the campus.

More on what we build for schools & preschools

See it running

reports.littlelumosschools.com(opens in a new tab)

Need something like this for schools & preschools?

Tell us what is slowing the business down and we will tell you whether software is the right fix. If it is not, we will say so.

Ask a Quick Question on WhatsApp

Free 30 minutes · no obligation

WhatsAppCall