Architecture
Organizations and multi-tenancy
Teams, workspaces, and tenant isolation in Godspeeds: the organization model, member roles, email invitations, and the access pattern that keeps one tenant out of another's data.
Godspeeds ships multi-tenancy out of the box. One running application serves many isolated organizations, each with its own members and roles — the model most B2B products need and most starter kits leave you to build.
The model
- `organizations` — the tenant itself: name, unique slug, and an owner.
- `memberships` — the join between a user and an organization, carrying their role. This is the only source of truth for access.
- `invitations` — email invitations with a seven-day lifetime, expired daily by a scheduled job.
Roles
Three roles, ranked member < admin < owner:
- member — read organization data, and leave.
- admin — everything a member can, plus rename the organization, invite people, revoke invitations, and remove members.
- owner — everything an admin can, plus change roles, remove admins, and delete the organization.
The access pattern
Every function that touches an organization-scoped table resolves access through a shared helper rather than checking inline. Queries return nothing to outsiders instead of erroring, so the existence of an organization is never leaked; mutations throw, and state the minimum role the operation requires.
// Queries: null or [] for outsiders — don't reveal the org exists
const found = await getMembership(ctx, args.orgId);
if (!found) return null;
// Mutations: throw, with the minimum role for the operation
await requireMembership(ctx, args.orgId, "admin");Following this one pattern is what keeps tenant isolation intact. Writing an ad-hoc check inside a function is how isolation bugs get introduced — see Security architecture.
Invitations
An invitation is issued against an email address and can only be accepted by someone authenticating with that same address, checked against the verified identity rather than anything the client sends. Invitations never grant the owner role, and they expire after seven days whether or not anyone acts on them.