Realtime Firestore, tenant isolation and long AI jobs: lessons from a homeschooling platform

Engineering notes from building a multi-tenant family platform on Vue, Firestore and Cloud Functions with AI agents.

By Snap Kodex Engineering··8 min read
Case study8 min read

Key takeaways

  • Treat each family as a tenant and enforce isolation in database rules and again in server code.
  • Run long AI generation as background jobs with progress documents the UI subscribes to.
  • Keep platform-wide configuration separate from per-tenant data, and preview destructive AI changes.

Our homeschooling platform, described on its product page, is a multi-tenant system where every family is an isolated workspace and AI agents build curricula, syllabi and schedules. These are the engineering decisions that mattered most.

Tenant isolation, twice

Each family's data lives under its own path in Firestore. Security rules enforce who may read and write it, based on the signed-in user's role in that family. Server functions re-verify the family and role on every privileged action and never trust a family identifier supplied only by the client. Two independent layers mean a mistake in one does not expose data.

Realtime by default

Parents planning a week together should see each other's changes immediately. Firestore listeners keep the interface in sync, and state stores wrap the listeners so components stay thin. Counters such as point balances change through atomic increments, so simultaneous updates from two devices cannot lose one another.

Long AI work is a job, not a request

Generating a six-month syllabus takes too long for a single HTTP request. The server enqueues a background task and writes progress to a document; the interface subscribes to that document and shows subjects filling in as they complete. If the user closes the tab, the work continues, and finished subjects are kept if a run is interrupted.

Platform config versus tenant data

Model choices, system instructions and temperatures are platform configuration, editable only by administrators. A family's children, scores and schedule are tenant data, injected into a request for that family only and never mixed. Keeping these apart makes it possible to change prompts without touching family data, and to prove that one family's data never reaches another's prompt.

Agents with safe write access

Agents can read and change family data, so their actions are bounded by the caller's family and role, logged to an audit trail and, for destructive batch changes, shown as a preview that a parent must approve. The agent proposes; the parent decides.

A schema that serves the agents

Because agents query the database, we keep an index document describing which collections hold which kinds of data. An agent can fetch large sets in small chunks, following a plan, rather than loading everything into context. Designing the index alongside the schema keeps the two in step.

Child-facing views without sign-in

The same activity link serves two audiences. Signed in, a parent sees instructions, scoring and notes; signed out, the link shows only the activity. The difference is enforced by what the client is allowed to fetch, not just by what the page chooses to show.

Takeaways

  • Design tenancy first; enforce it in the database and again in functions.
  • Model long AI tasks as resumable jobs with observable progress.
  • Separate platform configuration from tenant data.
  • Give agents narrow permissions, logs and previews.

We build platforms like this for clients; see multi-tenant architecture and agentic AI development.

See it in the product

This article describes engineering behind a product we run. See the Homeschooling platform.

Want this applied to your system?

Tell us about it and an engineer will reply with questions and a realistic first step.