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
- Request chega em
{slug}.atenvi.com.br - Middleware do BFF extrai
slugdo hostname - Busca tenant no schema
public.tenants - Seta schema ativo no
DataSourcepara o request - 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