Como arquitetar um front-end complexo de CRM
Essa é minha experiência depois de 4 anos trabalhando em um CRM complexo em uma empresa grande, mais freelancer, projetos pessoais e desenvolvimento de SaaS. Minha maior experiência é em React, então vamos focar nisso.
Lembre-se: todo sistema é diferente. Adapte o que fizer sentido para o seu contexto — crie subpastas onde precisar, ignore o que não se aplicar.
A estrutura
src/
├── app.tsx
├── pages/
├── components/
│ ├── core/
│ └── shared/
├── hooks/
│ ├── core/
│ └── shared/
├── api/
├── models/
└── utils/
app.tsx
Entrada da aplicação. É aqui que ficam os providers globais: tema, idioma, autenticação, rotas, permissionamento granular, e afins.
components/ e hooks/
Ambos seguem a mesma lógica de separação:
| Pasta | O que vai aqui |
|---|---|
core/ | Sem regra de negócio — usados em qualquer contexto |
shared/ | Com regra de negócio — compartilháveis entre telas |
Por que separar core de shared? Core tende a ser usado dezenas de vezes mais do que shared. Separar facilita manutenção e organização.
Autenticação não tem regra de negócio?
Autenticação é uma funcionalidade usada em todas as páginas — a empresa inteira segue a mesma lógica. Quando uma regra é global e não varia por página ou área, ela pode ser tratada como
core.Mas certamente existem exceções. Não existe receita de bolo — pense bem no tipo de aplicação que você está criando. E lembre-se do equilíbrio entre KISS, YAGNI e DRY.
pages/
Cada pasta dentro de pages/ representa uma página, não uma funcionalidade. Componentes, hooks e providers específicos de uma página ficam dentro da pasta daquela página — não em components/ ou hooks/.
E se eu precisar compartilhar uma página?
Aí vale criar um componente em
shared/. Se a página for grande demais, divida em componentes e mova parashared/.
api/
Camada de comunicação com o backend. Vale usar uma lib de query como React Query ou RTK Query. Cada arquivo representa uma API ou serviço, organizado da forma que fizer mais sentido dado o backend.
Regra de negócio não costuma ter lugar aqui.
models/
Tipagens e modelos da aplicação. A organização depende de como você estruturou api/ e pages/ — e isso varia bastante de projeto para projeto.
utils/
Funções utilitárias, com ou sem regra de negócio. Geralmente não precisa separar — mas separe se necessário (KISS & YAGNI).
Regras de dependência
Evite dependência circular ao máximo. Implemente lint para garantir isso, se possível.
core → não importa de shared
core → importa de api apenas em casos muito específicos
(ex: feature flags, autenticação)
shared → importa de core
pages → importa de qualquer lugar, e não exporta pra lugar nenhum
api → importa de models
models → NÃO importa de api
utils sem regra de negócio → pode ser importado por qualquer lugar
utils com regra de negócio → qualquer lugar, exceto core