Tenant Hosting

Tenant data hosting options including dedicated databases, shared databases, and isolation strategies

MQUAD supports multiple tenant data isolation strategies to meet different compliance and scalability requirements.

Isolation Strategies

StrategyIsolationCostComplexityUse Case
Shared DatabaseRow-levelLowLowSmall tenants, SaaS
Schema-per-TenantSchema-levelMediumMediumMedium tenants
Database-per-TenantDatabase-levelHighHighEnterprise, compliance

Shared Database (Default)

All tenant data resides in the same database, isolated by tenant_id column:

# Every query filters by tenant_id
query = select(Survey).where(Survey.tenant_id == request.state.tenant_id)

Pros: Simple, low overhead, easy to manage.
Cons: No hard isolation boundary.

Database-per-Tenant

For maximum isolation, each tenant gets dedicated databases:

async def _create_tenant_databases_for_services(self, tenant_id: str):
    services = ["survey_db", "data_db", "workspace_db", ...]
    for base_db in services:
        tenant_db = f"{base_db}_tenant_{tenant_id.replace('-', '_')}"
        # CREATE DATABASE tenant_db
        # Run migrations on tenant_db
        # Register in tenant_metadata

Naming Convention

{base_db}_tenant_{tenant_id_underscored}

Example: survey_db_tenant_acme_org

Tenant Creation Flow

  1. Create tenant record in appdb.tenants
  2. Seed tenant roles (Admin, Editor, Viewer)
  3. Create tenant databases across all services
  4. Run Alembic migrations on each tenant database
  5. Create admin user for tenant

Configuration

Tenant isolation mode is configured via environment variables:

TENANCY_ENABLED=true
TENANT_DB_ISOLATION=database  # shared | database

Frontend Routing

// Dashboard layout routes by tenant status
if (isDormant && isAdmin) -> /dormant-admin
if (isDormant && !isAdmin) -> /tenant-offline
if (!is_active) -> /non-active