Skip to main content
8Space implements a hierarchical multi-tenant architecture where organizations (tenants) contain projects, and users can belong to multiple tenants with different roles.

Tenant Isolation Model

Key Principles

Data Isolation

All project data is scoped to a tenant. Users cannot access projects from tenants they don’t belong to.

Flexible Membership

Users can be members of multiple tenants simultaneously with different roles in each.

URL-Based Routing

Tenant slug in URL provides context: /app/:tenantSlug/projects/:projectId

Hierarchical Permissions

Two-tier system: tenant-level roles and project-level roles

Tenant Schema

Tenant Table

packages/app/supabase/migrations/20260217143000_multi_tenant_onboarding.sql
Slug Requirements:
  • Lowercase alphanumeric with hyphens
  • No leading/trailing hyphens
  • Globally unique
  • URL-safe for routing

Tenant Membership

Role Hierarchy

Tenant Roles

Permissions:
  • Full control over tenant
  • Manage tenant settings (name, slug)
  • Add/remove members
  • Delete tenant
  • Create projects
Database Check:
Typical Use Case: Founder or organization admin

Project Roles

Permissions:
  • Full project control
  • Manage project members
  • Edit project settings
  • Delete project
  • Create/edit/delete tasks
Auto-Assignment: User who creates the project

Permission Matrix

* Tenant members can create projects if the tenant policy allows. This is configurable per tenant.

Creating Tenants

Database Function

packages/app/supabase/migrations/20260217143000_multi_tenant_onboarding.sql
Features:
  • Automatic slug generation from name
  • Conflict resolution with numeric suffixes
  • Creator automatically becomes owner
  • Idempotent member insertion

Slug Normalization

Examples:

Creating Projects in Tenants

Updated Function Signature

packages/app/supabase/migrations/20260217143000_multi_tenant_onboarding.sql
The function signature changed from accepting just p_name and p_description to requiring p_tenant_slug as the first parameter.

Auto-Member Addition

Role Mapping Logic:
1

Project Creator

Always gets owner role regardless of tenant role
2

Tenant Owners/Admins

Automatically get editor role in new projects
3

Tenant Members

Automatically get viewer role in new projects
4

Future Members

When new users join the tenant, they are NOT automatically added to existing projects (must be invited)

Permission Enforcement

Database Functions

The current_project_role function requires BOTH project membership AND tenant membership. This prevents access if a user is removed from the tenant.

Row Level Security

Migration Strategy

From Single-Tenant to Multi-Tenant

The migration 20260217143000_multi_tenant_onboarding.sql automatically converts existing data:
1

Add tenant_id Column

Initially nullable to allow backfill
2

Generate Temporary Mapping

Each project gets a unique tenant ID
3

Create Tenants from Projects

Tenant name derived from project name
4

Backfill tenant_id

Make column required after backfill
5

Migrate Memberships

Convert project roles to tenant roles
6

Drop Single-Tenant Triggers

Remove auto-join behavior from single-tenant mode

URL Structure

Routing Pattern

Benefits:
  • Clear tenant context in URL
  • Shareable links with implicit workspace
  • SEO-friendly for public pages
  • Simple authorization checks

Repository Interface

packages/app/src/domain/repositories/interfaces.ts
Key Points:
  • All project operations require tenantSlug
  • Tenant context passed explicitly
  • Type-safe tenant isolation

Best Practices

Always Validate Tenant Context

Never trust tenant slug from URL alone. Always verify user membership before data access.

Use Slug for Routing, ID for Data

  • URLs: Use human-readable slugs
  • Database: Use UUIDs for foreign keys
  • Convert slug to ID at API boundary

Enforce RLS at Database Level

Never rely on application-level checks alone. Database RLS provides defense-in-depth.

Handle Tenant Switching

Users can be in multiple tenants. Clear client-side caches when switching contexts.

Security Considerations

Risk: User accesses data from wrong tenant via URL manipulationMitigation:
  • RLS policies check tenant membership
  • current_project_role validates both tenant AND project membership
  • Database functions reject cross-tenant operations
Risk: Member promotes themselves to ownerMitigation:
  • RLS policies restrict role changes to owners
  • security definer functions set search_path = public
  • All mutations require explicit permission checks
Risk: Accidental tenant deletion loses all dataMitigation:
  • Soft delete via archived_at timestamp
  • Only owners can archive tenants
  • Cascade deletes handled by foreign keys
  • Consider implementing trash/recovery period

Next Steps

Architecture Overview

Return to high-level architecture concepts

Database Schema

Explore complete table definitions and relationships