Arquitetura de SaaS antes de gerar codigo: o que decidir na primeira hora

As cinco decisoes de arquitetura que sao baratas agora e caras depois: tenancy, autorizacao, assincrono, estado e migrations. O agente escolhe por voce se voce nao escolher.

Arquitetura de SaaS antes de gerar codigo: o que decidir na primeira hora
Neste artigo
  1. Por que essas cinco decisões e não outras?
  2. Decisão 1: como separar os clientes?
  3. Decisão 2: onde o isolamento é garantido?
  4. Decisão 3: o que responde na hora e o que vai para fila?
  5. Decisão 4: onde mora o estado?
  6. Decisão 5: como o schema evolui?
  7. Como registrar isso para o agente respeitar?
  8. Perguntas frequentes

Antes de gerar a primeira linha de código de um SaaS, cinco decisões precisam estar fechadas: modelo de multi-tenancy, estratégia de autorização, o que é síncrono e o que vai para fila, onde mora o estado, e como o sistema evolui o schema. Todas são baratas agora e caras depois, e o agente escolhe a mais simples de escrever se você não escolher.

Por que essas cinco decisões e não outras?

O critério é o custo de desfazer. Escolher errado o framework de UI custa uma semana chata. Escolher errado o modelo de tenancy, depois de ter cem clientes com dado dentro, custa uma migração com janela de indisponibilidade e risco de vazar dado de um cliente para outro.

Coding agent não tem noção desse custo, porque ele otimiza para o código que compila agora. Essa noção é sua.

Decisão 1: como separar os clientes?

Três modelos, e a escolha muda tudo daí pra frente.

Modelo Isolamento Custo de infra Dor principal
Coluna tenant_id nas tabelas Lógico, depende do código acertar Baixo Um WHERE esquecido vaza dado entre clientes
Schema por cliente Bom Médio Migration multiplicada por N schemas
Banco por cliente Alto Alto Operação e custo crescem por cliente

Para a maioria dos SaaS que eu construo, coluna de tenant resolve, desde que o isolamento não dependa de disciplina humana. É por isso que a decisão 1 e a decisão 2 andam juntas.

Decisão 2: onde o isolamento é garantido?

Se o filtro por tenant vive espalhado em cada query, uma hora alguém esquece, e esse alguém provavelmente vai ser o agente escrevendo o vigésimo endpoint numa sexta à noite.

As opções na prática são três: filtrar na aplicação com um repositório central que sempre injeta o tenant, usar Row Level Security no Postgres, ou combinar as duas. Eu prefiro a combinação quando o dado é sensível, porque RLS transforma um esquecimento de código em erro de banco em vez de vazamento silencioso.

O ponto que importa aqui: escolha um lugar onde a regra é obrigatória, não um lugar onde ela é lembrada. Detalhei os erros de autorização em autenticação e autorização em SaaS multi-tenant.

Decisão 3: o que responde na hora e o que vai para fila?

Todo SaaS tem operações que não cabem no ciclo de request: enviar e-mail, gerar relatório, chamar LLM, processar upload grande, integrar com API lenta de terceiro.

Se isso não estiver decidido, o agente vai escrever tudo síncrono, porque é o caminho mais curto. Funciona no seu teste com um usuário e cai no primeiro pico. A decisão aqui é qual mecanismo de fila e quais operações entram nele, e não precisa ser sofisticado: uma fila simples resolve a esmagadora maioria dos casos.

A regra que eu uso: se a operação depende de um terceiro ou pode passar de dois segundos, ela é assíncrona por padrão.

Decisão 4: onde mora o estado?

Sessão, cache, upload e job em andamento precisam de um lugar definido. Se você quer poder rodar mais de uma instância da aplicação, e uma hora vai querer, nada disso pode viver na memória do processo nem no disco local do container.

Essa é a decisão que trava escala horizontal mais tarde, e é invisível enquanto tem só um container rodando. O agente não vai levantar a mão sobre isso.

Decisão 5: como o schema evolui?

Migration é código, precisa estar versionada, precisa rodar em ordem, e precisa ter caminho de volta pensado antes de rodar em produção. Decidir isso na primeira semana é o que evita o cenário em que você tem três formas diferentes de alterar tabela no mesmo projeto.

Mais detalhe em banco de dados e migrations com agentes de IA.

Como registrar isso para o agente respeitar?

As cinco decisões viram um arquivo curto no repositório, do lado do PRD. Não é diagrama bonito, é lista de restrição em texto, porque restrição em texto é o que o agente consegue seguir.

# Decisoes de arquitetura (nao reabrir sem me perguntar)

1. Tenancy: coluna tenant_id + RLS no Postgres. Nenhuma query crua
   sem filtro de tenant, nem em rota de admin.
2. Autorizacao: checada no service, nunca so no controller.
3. Assincrono: e-mail, relatorio, chamada de LLM e upload > 5 MB
   vao pra fila. Handler nunca chama terceiro direto.
4. Estado: sessao e cache no Redis. Upload em storage de objeto.
   Nada em disco local do container.
5. Schema: so muda por migration versionada. Migration com
   destructive change precisa de aprovacao manual.

Esse arquivo é referenciado na tarefa quando o assunto encosta nele, e é a primeira coisa que eu mando reler quando o agente propõe algo que contraria uma das cinco.

Perguntas frequentes

Isso não é over-engineering pra um MVP?

Não, porque nenhuma das cinco exige construir infraestrutura agora. Escrever “upload vai pra storage de objeto” é uma linha, e você pode começar com o storage mais simples que existir. O que custa caro é descobrir na hora de escalar que metade do código assume disco local.

E se eu não souber responder alguma delas?

Aí vale gastar um dia investigando, não uma semana debatendo. Sonda pequena em cima do risco real resolve mais rápido que reunião. Se depois de um dia ainda estiver em aberto, escolha a opção mais fácil de reverter e escreva no arquivo que foi uma escolha provisória.

O agente pode propor essas decisões?

Pode propor, e as propostas costumam ser razoáveis como ponto de partida. O que ele não consegue é pesar o custo de operação e o teu contexto de negócio, que é exatamente o que decide entre as três opções de tenancy. Contexto completo em como construir um SaaS com Claude Code e Codex.

WA in X