The data model
You don't query the database directly, but understanding its shape makes every integration — roster sync, SSO, branding — make sense. Here's the model in the few concepts that matter.
Tenant: the institution
An institution is the tenant root. It has a stable slug (the identity the
apps resolve by), a name, a timezone, a residency, a brand configuration, and an SSO
configuration. Everything tenant-owned carries an institution_id.
Tenancy is resolved from the slug, not the domain — which is why a custom subdomain is an optional convenience rather than a prerequisite. See custom subdomains.
The actor model
A signed-in identity maps to exactly one actor — a student or a staff record
— per institution:
- Each actor row has an
auth_user_id(who signed in) and aninstitution_id(which tenant they belong to). - SSO links to an existing actor; it never creates one. A first-time sign-in attaches to the student or staff record already present from the roster. The consequence: the roster has to exist before sign-in works.
- Staff additionally carry a role (
institution_admin,content_editor,support_responder) and a scope (which courses, programs, campuses, or cohorts they cover).
The teaching shape: cohorts and weeks
- A cohort is an intake (a term) belonging to an institution, with a week count and an intake start; it can be archived.
- A week belongs to a cohort and carries the dates and labels everything anchors to.
- A student belongs to a cohort; program and campus describe where they sit.
- Content — events, week blocks, to-dos — hangs off weeks and is targeted by audience. Wellbeing check-ins and help requests belong to students.
The perimeter: row-level security
Isolation is enforced in the database, not in app code. Every tenant-owned row
carries its institution_id, and
row-level securityRow-level security: Postgres policies that filter which rows a session may read, enforced by the database itself.
policies key off it. A handful of server-only paths use a service-role credential
that bypasses RLS (roster import is one) and must re-impose tenant scoping by hand —
they're treated as the highest-risk code in the system. The institution-facing
account is data residency and tenant isolation.
Common questions
Can I get direct database or SQL access?
No. Integration is through the defined endpoints (roster sync, SSO). Direct database access would bypass the tenant perimeter, which is exactly what the model is built to prevent.
What's the difference between auth_user_id and the actor?
auth_user_id is the authenticated identity from sign-in; the actor (student or
staff) is the First Six record it links to within an institution. One identity
maps to one actor per tenant.
How are two apps consistent if they're separate?
They're separate front ends over the same database — see the two apps. Consistency comes from sharing one source of truth, not from syncing two stores.
Related
The fastest answer is usually one question away.