Pular para conteúdo

ADR-0013: Multi-tenancy — Schema por Tenant

Status

Accepted

Context and Problem Statement

O sistema é um SaaS onde cada studio de pilates contratante é um tenant independente. Os dados de cada tenant devem ser isolados entre si, sem risco de vazamento ou colisão. A estratégia de multi-tenancy impacta modelagem, migrations, autenticação, roteamento e performance.

Decision Drivers

  • Isolamento forte de dados entre tenants (LGPD, segurança)
  • Facilidade de backup e restore por tenant
  • Capacidade de customização de schema por tenant no futuro
  • Compatibilidade com TypeORM e PostgreSQL
  • Identificação de tenant sem overhead de lookup complexo

Considered Options

  • Schema por tenant — cada tenant tem seu próprio schema PostgreSQL (tenant_{slug})
  • Shared tables com tenant_id — todas as tabelas compartilhadas, isolamento por coluna
  • Database por tenant — cada tenant em banco separado

Decision Outcome

Chosen option: Schema por tenant, porque oferece isolamento forte sem custo de banco separado, permite backup/restore granular por tenant, e é compatível com TypeORM via DataSource com schema dinâmico.

Estrutura de schemas

public              → dados globais
  tenants           → cadastro de tenants (slug, nome, plano SaaS, status)
  saas_plans        → planos do SaaS (limites, preços)
  saas_subscriptions → assinaturas dos tenants
  saas_billing      → cobrança SaaS

tenant_{slug}       → dados isolados de cada estúdio
  students, plans, classes, instructors, bookings, payments, ...

Resolução de tenant

  1. Request chega em {slug}.atenvi.com.br
  2. Middleware do BFF extrai slug do hostname
  3. Busca tenant no schema public.tenants
  4. Seta schema ativo no DataSource para o request
  5. Todas as queries subsequentes operam no schema do tenant

Migrations

  • Migrations do schema public: executadas uma vez globalmente
  • Migrations de tenant: executadas em todos os schemas tenant_* via script de propagação
  • Novo tenant: script de provisioning cria schema e roda todas as migrations

Positive Consequences

  • Isolamento total de dados por tenant (zero risco de colisão)
  • Backup/restore por tenant sem afetar outros
  • Query sem necessidade de filtro WHERE tenant_id = ? em toda tabela
  • Possibilidade de customizações de schema por tenant no futuro

Negative Consequences

  • Migrations precisam de propagação ativa para todos os schemas existentes
  • Pool de conexões mais complexo (schema switching por request)
  • Número de schemas cresce linearmente com tenants (mitigado pelo PostgreSQL suportar milhares)
  • Ferramentas de BI/analytics precisam federar múltiplos schemas

More Information

  • DNS: wildcard *.atenvi.com.br (Cloudflare ou equivalente)
  • SSL: wildcard certificate
  • Sem suporte a domínio customizado por tenant (por ora)
  • Relacionado: ADR-0004 (PostgreSQL), ADR-0002 (NestJS)