RefactKit is built multi-tenant from the ground up. Every piece of data in your application belongs to an organization, and access to that data is validated on every request — not as an optional safeguard, but as a structural guarantee baked into the architecture. Understanding how this works will help you extend RefactKit confidently without accidentally breaking tenant boundaries.Documentation Index
Fetch the complete documentation index at: https://docs.refactkit.com/llms.txt
Use this file to discover all available pages before exploring further.
What “multi-tenancy” means in RefactKit
In RefactKit, the term organization is the unit of tenancy. When a user creates or joins an organization, they get a workspace — a fully isolated environment where their data, members, and settings are completely separate from every other organization in your system. A single user account can belong to multiple organizations simultaneously. Switching between them means switching workspaces: different data, different members, potentially different roles.Isolated by design
Data never crosses organization boundaries. Each tenant’s records are scoped to their
organizationId and enforced server-side on every query.One user, many orgs
A user can be a Member of one organization, an Admin of another, and an Owner of a third — all from the same account.
How data isolation is enforced
The organizationId column
Every tenant-scoped database table includes an organizationId foreign key. This is the foundation of RefactKit’s data isolation — there is no opt-in, no middleware to wire up separately, and no chance of a table “forgetting” to be tenant-aware.
organizationId, reference it with a cascade delete, and add an index on the column since it’s queried on every tenant-scoped request.
Server-side membership validation
CarryingorganizationId in the database is necessary but not sufficient. Every server function that reads or writes tenant data also verifies that the requesting user is actually a member of that organization. This check happens before any query executes:
src/server/org-fns.ts and src/server/dashboard-fns.ts. Follow it in any server function you add.
The organization slug and URL structure
Each organization has a human-readable slug — a URL-safe identifier derived from the organization’s name (e.g.,acme-corp). The slug is globally unique and drives the workspace URL pattern:
/organizations/acme-corp/dashboard, the route loader calls getOrgBySlug("acme-corp"), which verifies membership before returning any data. If the user isn’t a member of that organization, the server returns null and the route redirects rather than leaking information about the organization’s existence.
Workspace concept: one user, multiple organizations
A user’s workspace is determined by which organization they are currently viewing. The session stores anactiveOrganizationId, and TanStack Router uses the URL slug to scope all data fetching to the correct tenant.
Switching organizations is as simple as navigating to a different slug URL. Components that display org-specific data use the slug as part of their TanStack Query cache key, so switching orgs triggers a fresh data fetch automatically:
When an organization is deleted, all of its data is automatically removed via cascade deletes. Every tenant-scoped table references
organization.id with { onDelete: 'cascade' }, so members, invitations, gallery images, and any tables you add will be cleaned up in a single database operation.