Skip to main content

Multi-Tenancy Architecture

Tonnex uses a Table-Based Multi-Tenancy approach with Row Level Security (RLS). Every tenant-specific table has an org_id column that links to the organizations table. Access is enforced at the database level using Postgres RLS policies.

Key Components

1. Organization Membership Check

We use a SECURITY DEFINER function to verify if a user belongs to an organization. This bypasses RLS on the org_memberships table itself to avoid infinite recursion.

2. Drizzle Integration (Supabase)

We use drizzle-orm/supabase helpers to define RLS policies directly in the schema.

3. RLS-Aware Client

When querying from the application (Server Actions/Components), we use a wrapper that sets the RLS context for the transaction.
This sets:
  • auth.uid() via request.jwt.claim.sub
  • auth.jwt() via request.jwt.claims
  • role via set local role

Adding a New Module

When creating a new module (e.g., vehicles):
  1. Add orgId to your table schema.
  2. Add the RLS policy usage isOrgMember(table.orgId) for SELECT/UPDATE/DELETE.
  3. Use the createDrizzleSupabaseClient wrapper for all queries.