Plate I · Live

EduSuite

One platform, many schools, zero data bleed.

A live multi-tenant school information system — many schools run admissions, students, staff and academics from one platform, with each school's data strictly isolated.

React · Vite · Supabase (Postgres) · Netlify

5 / 5
Phases shipped
Shared-schema RLS
Tenancy model
Live
Status
4
Core domains
Overview

Low- and mid-tier schools can't justify per-seat SaaS pricing, and they certainly can't run a database per school. EduSuite answers that with a single multi-tenant platform where every school operates in its own logical space while sharing one codebase and one database.

The whole system — admissions, students, staff and academics — shipped across all five planned phases and runs in production. The interesting engineering isn't any one module; it's the guarantee underneath all of them: one school can never see another school's rows.

The system in motion

Animated architecture breakdown — nodes and data paths resolve in sequence.

Full architecture blueprint
EduSuite detailed architecture blueprint
Tenant-scoped request path — every query is filtered by tenant at the data layer, not in app code. · open full-size ↗
The stack — and what each part does
React + ViteSPA frontend — fast dev builds, instant HMR, lean production bundle
Supabase (Postgres)Database + auth; row-level policies enforce tenant isolation
PostgreSQL RLSTenant boundary lives in the data layer — impossible to bypass from app code
NetlifyCI build + CDN hosting for the static SPA
Under the hood

The multi-tenancy model

A database-per-tenant design is operationally hopeless for hundreds of small schools — backups, migrations and connection pools multiply until they crush you. EduSuite uses a shared schema where every tenant-owned row carries a tenant key, and Postgres row-level security policies filter every read and write by the authenticated tenant.

The consequence is that isolation is a property of the database, not a discipline the application has to remember. A future feature can forget to add a WHERE clause; it cannot forget the RLS policy, because the database enforces it on every statement.

The four domains

EduSuite covers the operational spine of a school:

  • Admissions — applicant intake, screening and enrolment.
  • Students — records, sections, guardianship, status.
  • Staff — teachers and administrators, roles and assignments.
  • Academics — classes, subjects and the academic calendar.

Deployment

The frontend is a React/Vite single-page app built in CI and served from Netlify's CDN; Supabase provides the Postgres database and authentication. It's a deliberately boring, cheap-to-run stack — the right choice for a product whose customers are price-sensitive schools.

Decisions worth defending
Why row-level isolation over a database per tenant?
A database per tenant doesn't scale operationally for small schools — you drown in backups, migrations and connections. Shared-schema with row-level policies keyed on the tenant is the right call: one school can never read another's rows, and it's enforced at the data layer.
What's the worst bug in multi-tenant, and how is it prevented?
Cross-tenant data leakage. That's exactly why isolation lives in Postgres RLS policies, not in application code that a later change could quietly forget.

Proof. Live and reachable at lingovera.com/edusuite — all five phases shipped and in production.