Sitemap
Gabriel Malenowitch

Gabriel Malenowitch

Como arquitetar um front-end complexo de CRM

2 min readMar 17, 2026

--

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:

PastaO que vai aquicore/Sem regra de negócio — usados em qualquer contextoshared/Com regra de negócio — compartilháveis entre telas

Get Gabriel Malenowitch’s stories in your inbox

Join Medium for free to get updates from this writer.

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 para shared/.

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

--

--