Arquitetura — CentralCRM Front
SPA React que opera White Labels. Não há BFF neste repositório: o browser chama duas APIs HTTP e dois namespaces Socket.IO.
Contexto
Operador (browser)
│ HTTPS
├──────────────► API Central (auth v1, companies v1, presence, portal, email-templates v1)
├──────────────► API Default (governança, companies, users, global-*, logs, tenants)
├──────────────► Socket /presence (API Central)
├──────────────► Socket /ws/logs (API Default)
└──────────────► ABECS MCC (QA/PRD) via proxy Vite /api/abecs-mcc/*
Hosts padrão de produção (overridáveis por VITE_*):
- Central:
https://centralcrmapixyz.gevtech.com.br—getApiBaseUrl() - Default:
https://defaultcrmapi.gevtech.com.br—getGovernanceApiBaseUrl()
Catálogo de rotas HTTP: api/endpoints.md. C4: architecture/c4.md. ADRs: adr/README.md.
Camadas (MVC prático)
views / directories / painel / help / systems
▲
controllers / hooks de página
▲
domain (mappers / regras puras)
▲
models/services + api/ + auth/ (HTTP e sessão)
▲
config/api.ts + utils/helpers
| Camada | Pasta | Pode fazer HTTP? |
|---|---|---|
| Views | src/views, src/directories, src/painel | Não |
| Controllers | src/controllers | Coordena; chama services |
| Domain | src/domain | Não |
| Services | src/models/services | Sim |
| Middleware HTTP | src/api, src/auth, companyApiHttp | Infra de fetch |
Mapa de pastas: .cursor/docs/architecture/pastas.md.
Autenticação e tenant
- Login
POST /api/v1/auth/login(Central, público) - JWT + user persistidos no cofre (
sessionVault, chave derivada deVITE_SESSION_VAULT_SECRET) - Pedidos autenticados:
Authorization: Bearer - Tenant:
X-Tenant-IdviagetTenantIdForApiRequest(JWT → sessão →VITE_TENANT_ID→ bootstrap UUID) - 401 em rota autenticada → interceptor
sessionExpiry→ UI de sessão expirada ProtectedRoute: sem sessão →/login;mustChangePassword→/primeiro-acesso
Duas APIs — regra rápida
| Prefixo | Host |
|---|---|
/api/v1/* (auth, companies, presence, portal, external-apis, email-templates) | Central |
/api/centralbackend/* | Central |
/api/companies/*, /api/users, /api/roles, /api/governance/*, /api/global-*, /api/tenants, /api/centralcrm, /api/logs, /api/analisestecnicas, /api/tenant-storage, /api/integration | Default |
Exceções e proxy de dev: api/README.md e vite.config.ts.
Rotas da SPA
Canônicas em src/common/constants.ts (ROUTES). Registro em src/App.tsx. Sidebar em src/common/sidebarConfig.ts. UUIDs de diretório na URL são ofuscados (directoryUrlIdCodec) — não substitui autorização no backend.
Tempo real
| Canal | Origem | Uso |
|---|---|---|
Namespace /presence, path /socket.io | Central (getSocketApiOrigin) | Sessões ativas no painel |
Namespace /ws/logs | Default (getGovernanceSocketApiOrigin) | Auditoria ao vivo por companyUuid |
Fallback HTTP de presença: GET /api/v1/presence/active-users-global.
Qualidade no código
- JSON de escrita:
stringifyGuardedJson(bloqueia padrões de SQL injection no payload) - Erros:
readJsonBody+getApiErrorMessageFromBody - i18n: nunca hardcodar copy de UI;
src/locales/{pt-BR,en}/translation.json - Tema:
src/theme+ tokens de governança por empresa