Pular para o conteúdo

ADR 0003 — Monorepo da empresa, e não um repositório por produto

Status: canônico · Escopo: Onde novos produtos nascem e como as responsabilidades são separadas · Atualizado em: 2026-08-10

Registra por que os próximos produtos da Tactflow nascem dentro de um repositório só, por que não haverá repositório-modelo, e o que separa responsabilidade de fato. Existe porque a pergunta foi feita ao planejar CRM interno, front-end do usuário e o produto de leitura de documentos.

Hoje são dois repositórios: voltron (quatro apps, dois pacotes, dois Workers publicáveis — ver ADR 0002) e tactflow-site (o site de marketing, Astro em Cloudflare Pages). Três produtos estão previstos: CRM interno, front-end do usuário e leitura de documentos.

O custo de manter dois repositórios já é observável, não é hipótese:

  • src/scripts/talk-api.ts, no site, copia à mão o contrato do backend — mesmos campos, mesmos setores, mesma derivação da perda. A divergência entre as duas cópias é considerada provável a ponto de o servidor re-derivar o número e responder 422 quando as contas não batem. Isso é uma guarda contra um problema que só existe porque são dois repositórios.
  • Renomear o hostname de chat.tactflow.io para api.tactflow.io (#65) exigiu dois PRs coordenados, com ordem de deploy pensada à mão para não quebrar quem estivesse no meio do funil. Com quatro repositórios, seria quatro.

Um repositório da empresa — tactflow-platform — com vários publicáveis dentro. Não um repositório por produto, não um serviço único.

tactflow-platform/
apps/ api-worker · site · crm · app · docs-ai
packages/ contracts · db · ui

Não haverá repositório-modelo. O que mantém os projetos parecidos é código compartilhado de verdade (packages/) mais a regra de camadas cobrada pelo dependency-cruiser. Um modelo copiado desalinha no primeiro projeto que diverge, e aí existem duas convenções em vez de uma.

Separar responsabilidade é a regra de camadas, não a fronteira de repositório. Repositório separado dá a sensação de fronteira sem cobrar nada; a regra de camadas reprova o build.

Fica mais fácil: contrato existe uma vez e é importado, não copiado; mudança que atravessa produtos cabe num PR revisável; uma CI, um lint, uma versão de cada dependência — o que importa para uma pessoa só mantendo tudo.

Fica mais difícil: o repositório cresce e o git log mistura produtos; alguém que só cuida do CRM clona o que não usa; a regra de camadas precisa ser mantida viva, senão vira decoração.

Passa a ser proibido: criar repositório novo para produto novo da Tactflow sem revisar esta ADR. E copiar contrato entre apps em vez de extrair para packages/.

O que isto não resolve: um deploy continua passando por cima de todos os publicáveis do repositório. É aceitável enquanto os clientes são testers. O gatilho para separar publicáveis está escrito na #65 — existir cliente pagante cuja ligação não pode ser arriscada por um deploy de marketing — e é gatilho de publicável, não de repositório.

AlternativaPor que perdeu
Um repositório por produtoDá fronteira de verdade e deploys independentes, mas cobra contrato versionado entre repositórios, cliente gerado e mudança atravessada em N PRs coordenados. Os dois repositórios de hoje já pagam esse preço — a cópia manual do contrato e os dois PRs da renomeação são a fatura. Multiplicar por cinco produtos com um desenvolvedor é trocar acoplamento de deploy por acoplamento de calendário.
Repositório-modelo (template)Resolve o primeiro dia e nada depois. No instante em que o segundo projeto diverge, passam a existir duas convenções e nenhuma ferramenta reclamando. Código compartilhado e regra cobrada no CI fazem o que o modelo promete e continuam fazendo no sexto mês.
Um serviço únicoSimplifica o deploy e destrói o isolamento: o produto de documentos derrubaria a ligação de voz. Publicáveis separados dentro de um repositório dão o isolamento sem o custo de coordenação.
  • Ferramenta de monorepo e enforcement: ADR 0002
  • Regras de boundary e o self-test: ARCHITECTURE.md
  • As três camadas de nome e o gatilho para separar publicáveis: issue #65