Pular para o conteúdo principal

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.brgetApiBaseUrl()
  • Default: https://defaultcrmapi.gevtech.com.brgetGovernanceApiBaseUrl()

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
CamadaPastaPode fazer HTTP?
Viewssrc/views, src/directories, src/painelNão
Controllerssrc/controllersCoordena; chama services
Domainsrc/domainNão
Servicessrc/models/servicesSim
Middleware HTTPsrc/api, src/auth, companyApiHttpInfra de fetch

Mapa de pastas: .cursor/docs/architecture/pastas.md.

Autenticação e tenant

  1. Login POST /api/v1/auth/login (Central, público)
  2. JWT + user persistidos no cofre (sessionVault, chave derivada de VITE_SESSION_VAULT_SECRET)
  3. Pedidos autenticados: Authorization: Bearer
  4. Tenant: X-Tenant-Id via getTenantIdForApiRequest (JWT → sessão → VITE_TENANT_ID → bootstrap UUID)
  5. 401 em rota autenticada → interceptor sessionExpiry → UI de sessão expirada
  6. ProtectedRoute: sem sessão → /login; mustChangePassword/primeiro-acesso

Duas APIs — regra rápida

PrefixoHost
/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/integrationDefault

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

CanalOrigemUso
Namespace /presence, path /socket.ioCentral (getSocketApiOrigin)Sessões ativas no painel
Namespace /ws/logsDefault (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