These are notes based on the article: Ultimate guide to multi-tenant SaaS data modeling
The top most level is organization
(since it is naming, it can be called other things but will be referred to as organization in this case - which also makes sense for users).
users
table should have organization_id
which is a foreign key reference to the organization
tableusers
table and the organization
table is the Membership
tableorganization_id
, create an index on this columnorganization_id
and table_id
(organization_id, table_id). This will help if we want to clone an organization’s data into a sandbox environment for testing.organization_id
everywhere - in the URLs (ex: /org/[orgId]/projects/[projectId]
), query inputs, database calls, etc.Three implementations with varying degrees of complexity and challenges it solves.
organization_id
in the sessionaccessibleOrgs: Array<{orgId: string, role: string}>
accessibleOrgs: Array<{orgId: string, role: string}>
- synced across all user sessionsloggedInOrgsOnThisDevice: Array<{orgId: string}>
- not synced across all user sessionsaccessibleOrganizations
to the list of all their org membershipsloggedInOrgsOnThisDevice
to the same as accessibleOrganizations
but filtered by orgs that permit access with the login method (like email/password vs Google)accessibleOrganizations
, if it’s not already there, and to loggedInOrgsOnThisDevice
organization
and membership
user
user
to membership
membership
record with invitationId
, invitationExpiresAt
, and invitedEmail
membership.userId
will be null
invitationId
invitationId
matches the membership
to create the user
and attach it to the membership
role
in user session to avoid API callsorganization
level (ex: billingEmail
, stripeCustomerId
, etc)organization
can have multiple subscriptions
organization
Three types of settings:
organization
tablemembership
tableuser
tableThis post is basically notes from reading the Ultimate guide to multi-tenant SaaS data modeling article.
The article further references: