DocsCore FeaturesMulti-tenancy

Multi-tenancy

Shipfastai supports multi-tenant architectures with organizations and team management.

Architecture

We use a shared database with Row Level Security (RLS) for tenant isolation.

Users

└── Organizations (tenants)

└── Members (users in org)

└── Data (isolated per org)

Database Schema

Organizations Table

CREATE TABLE organizations (

id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

name TEXT NOT NULL,

slug TEXT UNIQUE NOT NULL,

owner_id UUID REFERENCES auth.users(id),

created_at TIMESTAMPTZ DEFAULT now()

);

Members Table

CREATE TABLE organization_members (

id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

organization_id UUID REFERENCES organizations(id),

user_id UUID REFERENCES auth.users(id),

role TEXT DEFAULT 'member',

UNIQUE(organization_id, user_id)

);

Row Level Security

Isolate data per organization:

-- Enable RLS

ALTER TABLE documents ENABLE ROW LEVEL SECURITY;

-- Policy: Users can only see their org's documents

CREATE POLICY "Org isolation" ON documents

USING (

organization_id IN (

SELECT organization_id

FROM organization_members

WHERE user_id = auth.uid()

)

);

Frontend Usage

Get Current Organization

const { organization } = useOrganization();

Switch Organizations

const { setOrganization, organizations } = useOrganization();

// Switch to different org

setOrganization(organizations[1].id);

Create Organization

const createOrg = async (name: string) => {

const { data, error } = await supabase

.from('organizations')

.insert({ name, slug: slugify(name) })

.select()

.single();

};

Invite Team Members

const inviteMember = async (email: string, role: string) => {

// 1. Send invitation email

await sendInviteEmail(email, organization.id);

// 2. Create pending invitation

await supabase.from('invitations').insert({

email,

organization_id: organization.id,

role,

});

};