Renan Oliveira
← todos os sistemas

▲ Caso 02 · SaaS multiempresa em produção

Nove módulos que conversam por evento

Vender um sistema solar é um revezamento entre cinco áreas. O bastão cai na troca de mãos, sempre na fronteira, que é onde ninguém é dono. A arquitetura existe para que a passagem aconteça sem alguém lembrar de avisar.

Período
2026
Meu papel
arquitetura e a maior parte do código
Linguagem
TypeScript, ponta a ponta
Estado
em produção

Como está construído

Estrutura
Monorepo com pnpm workspaces e turborepo. Nove pacotes de módulo, mais um núcleo compartilhado e um pacote de tipos.
API
tRPC 11 sobre Express 4. O tipo atravessa do servidor ao navegador sem geração de cliente nem schema duplicado.
Banco
Drizzle ORM sobre MySQL, com migrações versionadas no repositório.
Interface
React 19 com Vite 7, Tailwind v4, Radix UI para acessibilidade dos componentes, TanStack Query para o estado de servidor, wouter para rotas e recharts para os gráficos.
Campo
Aplicativo Android por Capacitor, consumindo a mesma API, com notificação por push.
Autenticação
bcryptjs com custo 12 para senha, token assinado por jose, e entrada por Google OAuth como alternativa.
Isolamento
Toda tabela de negócio carrega a empresa dona do registro. Resolução por subdomínio. O filtro por empresa é escrito à mão nas consultas. Uma checagem no CI reprova consulta nova sem o filtro, e as antigas que ainda não o têm estão congeladas numa lista para correção.
Testes
vitest, rodando a cada alteração. Os testes de ponta a ponta chamam o roteador tRPC direto, sem subir servidor HTTP.

As decisões, e o que eu descartei em cada uma

Decisão 01

Monolito modular, e não microsserviços

Nove módulos com fronteira explícita, publicados como pacotes separados, compilando e subindo como uma aplicação só.

O que eu descartei: microsserviços. Numa operação deste tamanho eles trocariam um problema de organização de código por um problema de rede, com transação distribuída, versão de contrato e rastreamento entre serviços, tudo isso sem ninguém de plantão para cuidar.

A fronteira entre módulos existe no código e é cobrada pelo compilador. O custo operacional de uma aplicação distribuída, não.

Decisão 02

Os módulos publicam eventos, em vez de chamar uns aos outros

A proposta aprovada dispara um evento, e quem escuta reage: o módulo de projeto cria o repasse, o financeiro monta o plano de pagamento. Projeto concluído aciona compras. Material disponível abre a ordem de serviço com as seis etapas. Obra concluída registra as garantias, e a nota fiscal assinada libera o pagamento.

O que eu descartei: chamada direta entre módulos. Ela funciona com três e vira um grafo impossível com nove, onde acrescentar um módulo novo obriga a editar os antigos.

Um módulo novo passa a escutar um evento que já existe, e nenhum dos outros oito é tocado.

Decisão 03

Multiempresa desde a primeira tabela

A coluna que identifica a empresa dona do registro existe desde a primeira migração, e o filtro por empresa é conferido no CI em toda consulta nova. São seis papéis de acesso por empresa, do dono ao instalador.

O que eu descartei: deixar para depois. Fazer no começo custa uma coluna. Fazer depois significa reescrever toda consulta do sistema, e conviver com o risco de esquecer exatamente uma delas, que é a que vaza dado de um cliente para outro.

Decisão 04

O campo de formulário nasce num arquivo só, e um script confere as três pontas

A visita técnica é preenchida no computador e no celular, em telas escritas separadamente. O campo é definido num arquivo único de origem, implementado nas duas telas, e um script confere as três pontas.

O que eu descartei: combinar com o time que todo mundo lembre de alterar os dois lados. Uma regra que depende de ninguém errar, todo dia, durante meses, não se sustenta.

Decisão 05

Um registro declara a origem verdadeira de cada campo de negócio

Existe um arquivo que mapeia, campo a campo, qual é a fonte canônica do dado e quais cópias são permitidas.

Por quê: sem isso, dois lugares passam a responder a mesma pergunta com números diferentes, e não há como saber qual está certo. Num sistema que calcula comissão e fluxo de caixa, isso não é inconveniência.

Decisão 06

Teste de ponta a ponta sem subir servidor

Os testes de integração chamam o roteador tRPC diretamente, em processo, em vez de levantar a aplicação e bater em HTTP.

O que eu ganho: a suíte roda em cada alteração sem depender de porta livre, de tempo de inicialização ou de limpeza de processo pendurado. Teste que demora é teste que alguém desliga.

Tela de entrada da plataforma em produção
Entrada da plataforma em produção. O interior exige acesso e contém dado de cliente.

A implantação também é engenharia

Sistema que o time não sabe usar não está implantado. Cada fluxo tem instrução escrita na linguagem de quem executa, e ela abre no celular no momento da dúvida.

Instrução de preenchimento da visita técnica
Visita técnica, para quem está no telhado.
Instrução de acompanhamento de obra pelo celular
Obra pelo celular, inclusive sem sinal.
9módulos independentes
6papéis de acesso

Contagem feita no repositório em 22/09/2026.