ELETECH Solutions
Insight

Multi-tenant when every tenant wants a different schema

Published
Reading time
7 min
Topics
  • SaaS
  • Multi-tenancy
  • Access Control

Serving many schools from one platform means no two of them track the same fields — and the permission model has to follow relationships, not role names.

Every school we onboarded wanted to track something the last one did not. House colours. Bus routes. A second guardian with different pickup rights. Individually trivial; collectively, the thing that turns one product into a fork per client.

Dynamic entities instead of migrations

The usual answers are both bad. Add every field anyone asks for and the schema becomes a swamp of nullable columns. Fork per client and you are maintaining a codebase per tenant with one team.

Instead we let a tenant define the entities and fields it actually uses, and stored that definition as data. Bringing a new school online became configuration rather than a migration and a deploy — which is where most of the per-tenant setup time had been going.

The discipline this requires is validation. Schema-as-data without validation is just an untyped blob, so every tenant-defined field carries its type and constraints, and writes are checked against them at the boundary.

Roles are not the permission model

The harder half was access control. Role-based access sounds sufficient until you write the actual rule. A teacher can see grades — for their own students. A parent can see records — for their own children, and only the ones the other guardian has not restricted.

None of that is expressible as 'role = teacher'. The permission depends on the relationship between the person asking and the record, which is exactly what a school hierarchy is made of. So we used Relationship-Based Access Control and derived permission from the graph.

  • Enforce at the data layer, never in the UI. A hidden button is not a permission boundary.
  • Make the relationship explicit and queryable, so an access decision can be explained after the fact.
  • Default to deny, and make a missing relationship a denial rather than an error.
  • Test the negative cases hardest — the bug you cannot afford is a parent seeing another child's record.

That last point is why this is worth the effort. The cost of getting multi-tenancy wrong here is not a bad review. It is a child's records in front of the wrong adult.

Next note

5 min read

Offline-first is an architecture, not a feature

You cannot add offline support at the end. It decides where your data lives and who is allowed to be authoritative — which means it decides almost everything.

Read the note
Start here

Tell us what the process costs you today.

That number decides whether any of this is worth building. Bring it to the call and we can get to a straight answer inside half an hour.

30 min · no charge

Pick a time and we’ll talk it through.

  • 30 min, and no charge for it
  • Bring the process and what it costs you today
  • A straight answer — including “don’t build this”
Or book directly on cal.com