
inite.rent: como reconstruímos um CRM de 318 000 linhas em 4 semanas
CRM de aluguel de carros em produção, 318 000 linhas, 4 anos de regras — movido para plataforma multi-tenant em 4 semanas. Operadores nunca pararam.
Do que se trata este case
Estamos construindo uma família de produtos SaaS que compartilham a maior parte de seu encanamento. Login, billing, mensageria com clientes em canais, audit log, internacionalização, runner de assistente IA, primitivos de segurança, rate limiting - tudo isso é genérico. Escrevemos uma vez como um conjunto de pacotes compartilhados e reusamos entre produtos. Cada produto vertical (um CRM de aluguel de carros, um CRM imobiliário, um backend de e-commerce, um sistema de ticketing de eventos, um app de operações de restaurante, uma plataforma de reservas de clube esportivo, e assim por diante) só escreve a parte que é genuinamente específica de sua indústria. A aposta é que a maior parte de um produto SaaS é substrato que dá para compartilhar, e uma camada domain-específica pequena mas real é o que diferencia uma vertical da outra.
Este case é sobre a primeira vez que provamos isso com um codebase real. Pegamos nosso CRM de aluguel de carros em produção - 318 000 linhas de TypeScript, quatro anos de regras de negócio acumuladas, operadores ao vivo rodando negócios reais de aluguel nele - e o movemos para a plataforma compartilhada em quatro semanas calendário. Os operadores continuaram usando o app o tempo todo. No fim da semana 3 já rodavam suas reservas diárias reais na versão reconstruída.
O ponto de escrever isto não é o trabalho de engenharia em si. O ponto é a resposta a uma pergunta real de negócio: quando você tenta compartilhar código entre produtos muito diferentes, quanto você de fato economiza, e onde o compartilhamento quebra?
Como a migração foi de fato
Antes da migração: um CRM de aluguel standalone. Anos de código, seu próprio sistema de login, sua própria wrapper de billing, sua própria integração de mensageria com WhatsApp e Telegram, seu próprio audit log, seu próprio rate limiter. Tudo escrito especificamente para o produto de aluguel, nada reusável.
Depois da migração: as mesmas 318 000 linhas de lógica de negócio específica de aluguel - veículos, reservas, tarifas, inspeções, multas, fidelidade, relatórios para co-investidores de frota - agora sentam em cima da plataforma compartilhada. O login, billing, mensageria, audit log, rate limiter, internacionalização, assistente IA - tudo isso roda em pacotes compartilhados que escrevemos uma vez e reusamos entre produtos.
Medimos a fronteira com precisão. Das 1 872 linhas de schema do banco, cerca de 220 linhas (12%) são o substrato multi-tenant genérico - as tabelas de usuário, empresa, role, chave de API; o inbox de mensageria com clientes; o audit log. Cerca de 1 650 linhas (88%) são o domínio genuinamente específico de aluguel - 67 tabelas diferentes para veículos, reservas, tarifas, inspeções e o resto.
Essa proporção de 12-vs-88 é a resposta à pergunta de negócio. Os 12% se revelam boilerplate suficiente para tornar o compartilhamento valoroso - porque cada um dos nossos 15 produtos verticais planejados teria escrito sua própria versão desses 12% senão. Escrever uma vez e reusar entre 15 produtos é a matemática que justifica o investimento em plataforma compartilhada. Os 88% são a parte que genuinamente difere entre aluguéis, imobiliária e restaurantes, e tentar compartilhá-la seria um erro.
Quatro semanas, semana a semana
| Semana | O que foi construído |
|---|---|
| 1 | Fundação. O projeto de aluguel entrou no workspace compartilhado. As cinco tabelas multi-tenant obrigatórias do banco foram alinhadas ao pacote de login compartilhado. O login em si foi religado pelo pacote compartilhado. No fim da semana, o validador confirmou que a camada de tenancy casava com a especificação da plataforma. |
| 2 | Serviços compartilhados. Mensageria com clientes via web, WhatsApp e Telegram rodando pelo pacote compartilhado de inbox. Runner do assistente IA substituindo a wrapper LLM local. Camada de API compartilhada substituindo o rate limiter e error reporter locais. Conversas com clientes fluindo end-to-end pela plataforma no fim da semana. |
| 3 | Superfícies de operador. Todas as 34 rotas multi-tenant estabilizadas. Preset de storefront, superfície AEO para visibilidade em busca IA, dashboard de KPI. Operadores usando o app reconstruído para reservas diárias reais a partir de quarta-feira. |
| 4 | Hardening. Payment adapters integrados. A superfície de API para agentes IA externos (ChatGPT, Claude, customizados) live para operações de aluguel. Dados pessoais criptografados em repouso. Audit log totalmente conectado. |
O gargalo nas quatro semanas não foi o trabalho de engenharia. Foi que os dados de produção de aluguel ficavam contradizendo nossas suposições sobre como a plataforma compartilhada deveria ser especificada. Três vezes na semana 2 tivemos que escolher: reescrever o modelo de dados de aluguel para casar com a especificação da plataforma, ou reescrever a especificação da plataforma para casar com os dados de aluguel. Toda vez reescrevemos a especificação. A razão é principista - se a especificação da plataforma não sobrevive ao contato com um produto SaaS real, de quatro anos, em produção, então a especificação é o que está errado. O codebase de aluguel é a referência empírica. Uma plataforma que não o carrega limpamente ainda não é uma plataforma.
O que aprendemos sobre a plataforma
Três coisas mudaram por causa desta migração. Uma delas se revelou a decisão arquitetural mais importante de toda a plataforma.
O problema da franquia - e a quinta tabela multi-tenant.
Tínhamos especificado quatro tabelas multi-tenant obrigatórias: usuários, empresas, roles conectando-os, chaves de API. Pensávamos que permissões poderiam ser derivadas só do mapeamento de role. O codebase de aluguel tinha um padrão de franquia que quebrava essa suposição: um Manager específico em uma filial específica de aluguel precisa de acesso a relatórios de investidores. A role Manager normalmente não tem. A tabela padrão de roles não podia expressar isso.
Adicionamos uma quinta tabela obrigatória para overrides de permissão per-company. Toda vertical conforming agora a herda. O gatilho foi específico de aluguel; a solução é genérica.
Mensageria com clientes - o modelo mais rico vence.
Nosso pacote compartilhado de mensageria começou com um modelo mais simples que algumas das nossas outras verticais piloto usavam. Aluguéis precisavam de semântica mais rica: vários agentes de support trabalhando um canal ao mesmo tempo, com assignment e handoff adequados. Mantivemos o modelo mais rico. As outras piloto migrarão para ele no próximo ciclo. O princípio: o pacote compartilhado tem que ser o superset estrito do que seus consumidores precisam. Se o piloto de aluguel precisa de uma feature, o pacote compartilhado a ganha, e toda outra piloto se beneficia.
O acidente valioso - tornar agentes IA seguros de usar.
Nossa especificação de plataforma tem uma seção que chamamos de 'obligations' - invariantes de negócio como 'sem entrega de veículo até que o contrato seja assinado e o depósito seja liquidado' ou 'sem liberação de depósito até que a inspeção pós-aluguel seja registrada'. Originalmente tratávamos isso como documentação. O runtime não forçava; o código da aplicação deveria.
Durante a semana 4 da migração, ligamos essas obligations diretamente na camada de API que agentes IA externos chamam. O resultado: quando ChatGPT ou Claude chama nossa API criar reserva em nome de um cliente, a plataforma automaticamente se recusa a deixar o agente pular o contrato ou o depósito. O agente não precisa nem saber que a regra existia; o runtime retorna um erro estruturado apontando exatamente qual invariante de negócio foi violada.
Esta é a parte do trabalho que, em retrospecto, mais importou. Deixar um agente IA externo dirigir sua API de reservas devia ser a parte assustadora do SaaS agêntico - o agente vai bagunçar as regras, pular o depósito, entregar chaves sem contrato, deixar você com a exposição legal. Nós não deixamos. As regras são forçadas uma camada abaixo do agente, em código que o agente não pode contornar. Toda vertical que entregamos a partir de agora ganha essa mesma camada de segurança de graça. Não planejamos assim; a migração de aluguel nos forçou.
Onde isto se encaixa no plano mais amplo
inite.rent é um dos 15 produtos SaaS verticais da família Inite. Mais duas migrações estão rodando em paralelo agora (imobiliária e e-commerce), e mais quatro estão na fila (ticketing de eventos, restaurantes, viagens, clubes esportivos). Cada uma parte de um codebase legacy diferente mas segue o mesmo padrão de migração que o case de aluguel estabeleceu. O motor por trás disso está descrito em um motor, várias peles e a separação spec/runtime em constituição vs runtime.
Este case é também um exemplo trabalhado da nossa metodologia de transformação em 6 etapas aplicada ao nosso próprio trabalho de engenharia. Break audita o código legacy. Hold estabiliza o schema para que a migração tenha inputs consistentes. Track instrumenta os call patterns para que o comportamento da plataforma compartilhada possa ser comparado ao legacy. Cut remove o código horizontal duplicado localmente que a plataforma compartilhada agora fornece. Cast entrega a reconstrução aos operadores usando diariamente. Form são os três meses de ajuste de fronteiras depois que produziram a forma de plataforma que temos hoje.
A metodologia funciona da mesma forma no trabalho de engenharia que em engajamentos de automação B2B com clientes pagantes. Isso em si é uma prova útil. A metodologia não é só um documento de vendas; rodamos ela em nós mesmos.
Em uma frase
A reconstrução do CRM de aluguel de carros de 318 000 linhas provou que nossa plataforma multi-tenant compartilhada consegue carregar um produto SaaS real, de quatro anos, com carga de produção; a migração calibrou quais partes da plataforma acertamos, quais erramos, e produziu uma camada de segurança acidental para chamadas de API agênticas que agora esperamos ser a peça mais valiosa da plataforma nos próximos dois anos.
Os aluguéis são reais. As 318 000 linhas são reais. A migração é a referência para o que vem a seguir.
01Em que isto difere de um pnpm workspace ou monorepo Nx normal?+
Um workspace dá compartilhamento de código. Precisávamos de um contrato em cima do compartilhamento de código. Os pacotes compartilhados declaram o que toda vertical consumidora tem que implementar (cinco tabelas de tenancy, o modelo de inbox, a forma do wrapper de API). Um validador roda em CI e quebra o build se uma vertical desvia do contrato. Sem isso, uma família de 15 produtos forka silenciosamente os pacotes compartilhados em seis meses, e você acaba com 15 cargas de manutenção em vez de uma. O contrato é o que para o desvio.
02O que acontece quando uma vertical precisa de algo que a plataforma compartilhada ainda não tem?+
Dois caminhos. Se a necessidade é claramente genérica (várias verticais a querem), vai para a plataforma compartilhada no próximo release e a vertical espera. Se a necessidade é genuinamente específica da indústria, fica no código daquela vertical. A decisão é tomada contra a spec compartilhada, não por quem grita mais alto. O próprio piloto de aluguel produziu três adições à plataforma compartilhada; verticais futuras produzirão outras. A plataforma cresce por demanda de uso em produção, não por especulação.
03Como vocês lidam com breaking changes na plataforma compartilhada sem quebrar 15 produtos?+
Versionamento semântico em cada pacote compartilhado, mais um validador de contrato que compara a versão de dependência declarada por cada vertical com o que ela de fato usa. Breaking changes entram numa versão major que requer migração explícita; verticais na major antiga continuam funcionando até migrarem. O validador pega o desvio em CI. A parte mais difícil não é o tooling - é a disciplina de recusar patches pontuais que ajudariam uma vertical mas distorceriam o contrato para as outras 14.
04Por que não usar Stripe, Auth0, Twilio para o substrato em vez de construí-lo?+
Usamos provedores externos onde eles são claramente os melhores - Stripe para processamento de cartão, Twilio para SMS, LLMs de terceiros para o runner do assistente. A plataforma compartilhada é a camada acima deles: o modelo de dados multi-tenant que mapeia um cliente Stripe para uma das nossas empresas, o grafo de permissões que decide quem vê qual inbox, o audit log que sobrevive entre provedores. SaaS externo resolve problemas de vendor único; a plataforma resolve as preocupações transversais que nenhum vendor único possui. Ambas as camadas são reais e ambas pertencem.
05Outras empresas podem usar esta plataforma compartilhada ou é só Inite?+
Só Inite por enquanto. A plataforma é calibrada contra a forma específica dos produtos SaaS que construímos - multi-tenant B2B com integração de assistente IA, superfícies de API agênticas, nosso modelo específico de regras de segurança. Uma plataforma SaaS compartilhada de propósito geral precisaria de tradeoffs diferentes (contratos mais soltos, mais superfície de configuração, ciclos de release mais lentos) e não é o que estamos construindo. O artefato reutilizável interessante deste trabalho não é o código, mas a metodologia - o protocolo de transformação em 6 etapas e o padrão contract-then-share. Ambos estão documentados e são aplicáveis fora da família Inite.

Um motor, várias peles: 15 SaaS verticais sobre um runtime único

Como Uma Única Equipe Entrega 18 Produtos SaaS Diferentes
