Adr
ADR-001: Multi-Tenant Isolation
Database-level tenant isolation strategy
ADR-001: Multi-Tenant Isolation
Status
Accepted
Context
Agent Studio is a SaaS platform serving multiple organizations (tenants). Each tenant must have complete isolation of their:
- Agents and workflows
- Provider API keys (BYOK)
- Call history and transcripts
- Configuration and settings
We need to decide how to implement multi-tenancy at the database level.
Options Considered
- Separate databases per tenant - Complete isolation, complex management
- Separate schemas per tenant - Good isolation, moderate complexity
- Shared schema with tenant_id - Simple, requires careful implementation
- Row-level security (RLS) - Database-enforced, PostgreSQL-specific
Decision
We will use shared schema with tenant_id foreign key on all tables, combined with:
- Application-level filtering - All queries include tenant_id filter
- Repository pattern - Centralized data access with built-in tenant scoping
- Composite indexes - (tenant_id, ...) for query performance
- Cascade deletes - Tenant deletion removes all associated data
Implementation
# All models inherit tenant relationship
class TenantScopedMixin:
tenant_id: Mapped[UUID] = mapped_column(
ForeignKey("tenants.id", ondelete="CASCADE"),
index=True
)
# Repository automatically scopes queries
class AgentRepository(BaseRepository[Agent]):
def __init__(self, session: AsyncSession, tenant_id: UUID):
super().__init__(session)
self.tenant_id = tenant_id
async def list(self) -> list[Agent]:
query = select(Agent).where(Agent.tenant_id == self.tenant_id)
return (await self.session.execute(query)).scalars().all()Consequences
Positive
- Simple to implement and understand
- Single database connection pool
- Easy cross-tenant analytics (for platform admins)
- Standard SQLAlchemy patterns work
Negative
- Requires discipline to always filter by tenant_id
- No database-level isolation guarantee
- Potential for bugs leaking data across tenants
Mitigation
- Repository pattern enforces tenant scoping
- Code review checklist includes tenant isolation
- Integration tests verify tenant boundaries