Pular para o conteúdo principal

Arquitetura — CentralCRM_back

Backend central do CentralCRM: API REST versionada, autenticação JWT, diretório multi-tenant de empresas, dados operacionais, presença em tempo real (Socket.IO) e gestão de white labels.


1. Visão geral

O CentralCRM_back é uma aplicação NestJS 11 que expõe:

SuperfíciePrefixo / pathFunção
REST/api + versionamento URI (/v1/...)CRUD de empresas, auth, operacional, presença (REST), white labels
OpenAPI/api/docsSwagger UI (Bearer + x-tenant-id)
WebSocketnamespace /presencePresença de utilizadores do CRM cliente em tempo real
HealthGET /api, GET /api/healthMetadados e liveness (rotas públicas)
flowchart TB
subgraph clients [Clientes]
CF[CentralCRM_front<br/>painel admin]
DCF[default_crm-front<br/>CRM do cliente]
end

subgraph central [CentralCRM_back]
API[REST /api/v1]
WS[Socket.IO /presence]
AUTH[JwtAuthGuard global]
end

subgraph data [Persistência]
PG1[(PostgreSQL principal<br/>cronospay / companies)]
PG2[(PostgreSQL auth<br/>G_DB_POSTGRESS / public."user")]
RD[(Redis — cache branding)]
MEM[(Map em memória<br/>sessões WebSocket)]
end

CF --> API
CF --> WS
DCF --> WS
API --> AUTH
WS --> AUTH
AUTH --> PG1
AUTH --> PG2
API --> PG1
API --> RD
WS --> PG1
WS --> MEM

Ecossistema

RepositórioPapel
CentralCRM_back (este)API central, diretório de empresas, presença, operacional agregado
CentralCRM_frontPainel admin; consome REST + WebSocket como observador admin
default-crmBackend do CRM do cliente; emite JWT (sessionHash) com tenantId
default_crm-frontAbre socket de presença após login usando centralPresenca

Fluxo de presença e integração JWT: ENTENDIMENTO.md.


2. Stack e dependências principais

CamadaTecnologia
RuntimeNode.js 20 (Alpine no Docker)
FrameworkNestJS 11, Express
ORMTypeORM 0.3 (synchronize: false)
BDPostgreSQL (pg)
AuthPassport JWT, @nestjs/jwt, bcrypt
Validaçãoclass-validator, class-transformer
Tempo real@nestjs/websockets, Socket.IO 4
CacheRedis (ioredis) — branding, não presença
MailNodemailer (SMTP)
Docs@nestjs/swagger

3. Estrutura do repositório

CentralCRM_back/
├── src/
│ ├── main.ts # Bootstrap: CORS, pipes, Swagger, IoAdapter
│ ├── app.module.ts # Módulos raiz + 2 conexões TypeORM
│ ├── bootstrap-env.ts # Carrega .ENV / .env antes do Nest
│ ├── config/ # database, jwt, defaults embutidos
│ ├── common/ # filters, decorators (@Public, tenant)
│ ├── controllers/ # app + health (version neutral)
│ └── modules/
│ ├── auth/ # JWT strategy + JwtAuthGuard global
│ ├── auth-login/ # login, registo, public."user" (BD G_DB_POSTGRESS)
│ ├── company/ # empresas, diretório, utilizadores
│ ├── company-operational/# TPV, ECs, comissões, propostas
│ ├── presence/ # REST + PresenceGateway
│ ├── white-label/
│ ├── portal-subdomain/
│ ├── external-apis/
│ ├── password-reset/
│ └── health/
├── docs/ # Documentação (este ficheiro, guias API, SQL)
├── Dockerfile # Multi-stage: build + produção
├── compose.yaml # Serviço backend + healthcheck
└── test/ # e2e Jest

4. Módulos funcionais

Cada feature Nest vive em src/modules/<nome>/. O padrão de bounded context (quando aplicável) repete camadas dentro de uma subpasta homónima — ver src/modules/company/README.md.

MóduloResponsabilidadeControllers (path base /api/v1)
AuthModuleEstratégia JWT, guard global
AuthLoginModuleLogin/registo em public."user"; permissões; lista CRM adminauth, crm-admin/users
CompanyModuleTenant, company, diretório (branding, moradas, documentos), users por empresacompanies, company/directory, company
CompanyOperationalModuleMétricas por empresa (estabelecimentos, dashboard, comissões, …)company/directory/:companyId/operational
PresenceModuleSessões online (memória) + contagens RESTpresence
WhiteLabelModuleWhite labels paginados por tenantwhite-labels/:tenantId
PasswordResetModuleReset, first-access, templates de e-mailauth/password-reset, auth/first-access, email-templates
PortalSubdomainModuleURL do portal, TLS check, ícone de tenantportal/..., /api/tenants/...
ExternalApisModuleProxies OpenCNPJ / BrasilAPIexternal-apis/...
HealthModuleHealth check(via HealthController em /api/health)

Lista HTTP completa: apis/catalogo-completo.md. ADRs: adr/index.md.

Rotas públicas (sem Bearer)

Marcadas com @Public() — o JwtAuthGuard ignora autenticação:

  • GET /api — metadados da API
  • GET /api/health
  • POST /api/v1/auth/login
  • POST /api/v1/auth/register
  • POST/GET password-reset (request, token, confirm)
  • GET/POST first-access (token, confirm)
  • GET /api/v1/portal/subdomain-url
  • GET /api/v1/portal/internal/check-host

Todas as restantes exigem Authorization: Bearer <JWT>.


5. Camadas por bounded context

Padrão usado em company (e replicável noutros recursos):

modules/company/
├── company.module.ts # Wiring Nest (imports, providers, controllers)
└── company/
├── domain/ # Portas, enums, modelos de domínio
├── application/ # Serviços / casos de uso
├── infrastructure/ # Adaptadores TypeORM (repositórios)
├── entities/ # Entidades TypeORM
└── presentation/ # Controllers v1, DTOs, mappers

Fluxo de um pedido HTTP típico:

  1. CompaniesV1Controller valida DTO (ValidationPipe global).
  2. Resolve tenantId (JWT, body ou header x-tenant-id).
  3. CompanyService aplica regras (ex.: conflito CNPJ → HTTP 409).
  4. TypeOrmCompanyRepository persiste na BD principal.

6. Bases de dados (dual connection)

O AppModule regista duas conexões TypeORM independentes:

ConexãoVariáveisUso
defaultPOSTGRES_* ou DATABASE_* ou libpq (PG*)company, tenants, operacional, user (presença), white labels
USER_PROFILES_CONNECTIONAUTH_DATABASE_* → BD G_DB_POSTGRESSpublic."user" + tabelas relacionais (login, registo, CRM admin)

Resolução centralizada em src/config/config_db.ts e database.config.ts.

  • synchronize: false — schema gerido por SQL/migrações (docs/sql/).
  • Opcional: DATABASE_SEARCH_PATH para schema PostgreSQL (ex.: cronospay,public).
  • SSL: DATABASE_SSL / AUTH_DATABASE_SSL.

Sem variáveis de BD no Docker, o bootstrap pode aplicar defaults embutidos (database-embedded-defaults.ts) ou falhar com mensagem explícita — ver ENV_CONTAINER.md.


7. Autenticação e contexto de tenant

JWT

  • Segredo: JWT_SECRET (ou JWT_SECRET_FILE).
  • Extração: header Authorization: Bearer.
  • Claims lidos em JwtStrategy.validate: sub (obrigatório), tenantId / tid, role / role_code.

Tipos de token

OrigemClaimsUso típico
POST /api/v1/auth/loginsubAPIs sem tenant; patch de permissões
Emissor externo / script / default-crmsub + tenantId (+ opcional role)Diretório, operacional, presença
Admin CentralCRMsub + role: admin (sem tenantId)Listagens globais; socket em admin:observer

Header alternativo

x-tenant-id (UUID) quando o JWT não traz tenantId — usado por decorators como TenantIdFromJwt.

Autorização por papel

  • USER_ROLE_ADMIN: pode listar empresas/presença globalmente; white labels de qualquer tenant.
  • Utilizadores normais: operações restritas ao tenantId do token ou header.

8. Versionamento e contratos HTTP

  • Prefixo global: api (main.ts).
  • Versionamento URI: VersioningType.URI → rotas em /api/v1/....
  • Erros: HttpExceptionFilter → JSON { statusCode, timestamp, path, message }.
  • Body: whitelist + forbidNonWhitelisted (campos extra → 400).

Swagger: GET /api/docs (UI), GET /api/docs-json, GET /api/docs-yaml.


9. Presença em tempo real

REST (PresenceV1Controller)

MétodoRotaDescrição
GET/presence/active-usersSessões ativas no tenant
GET/presence/active-users-globalTodas as sessões (só admin)
GET/presence/online-count/main-companiesContagem — empresas mãe
GET/presence/online-count/sub-companiesContagem — sub-empresas
GET/presence/online-count/aggregated-by-parentRede mãe + filhas

WebSocket (PresenceGateway)

  • Namespace: /presence
  • Path Socket.IO: /socket.io (padrão)
  • Auth: auth.token no handshake (mesmo JWT do CRM)
  • Estado: UserPresenceServiceMap em memória (não persistido)
  • Salas: tenant:<tenantId>, admin:observer (admins não contam como online)

Eventos emitidos (ex.): presence:sync, presence:join, presence:leave, presence:error.

Alinhamento JWT: o default-crm deve assinar com o mesmo JWT_SECRET (ou chave em JWT_EXTERNAL_SECRETS no consumidor). Detalhes em ENTENDIMENTO.md.


10. Módulo operacional

Base path:

/api/v1/company/directory/{companyId}/operational/...

Agrega dados das tabelas estabelecimentos, estabelecimento_config_financeira, transacoes_locais, propostas, etc., sempre resolvendo tenant + pertença da company ao utilizador.

Endpoints principais: estabelecimentos, dashboard, top-estabelecimentos, comissoes/resumo, alugueis/resumo, propostas.


11. Deploy e runtime

flowchart LR
DEV[Desenvolvimento<br/>npm run start:dev]
BUILD[npm run build]
IMG[Dockerfile multi-stage]
COMPOSE[docker compose]
PROD[node dist/main.js :3000]

DEV --> BUILD
BUILD --> IMG
IMG --> COMPOSE
COMPOSE --> PROD
ArtefactoNotas
DockerfileStage builder (npm ci + nest build); stage production com user nestjs
compose.yamlenv_file: .ENV, volume read-only, healthcheck em /api/health
PORTDefault 3000
CORSCORS_ORIGIN (lista separada por vírgula); sem valor, espelha origem (dev)

Checklist pós-deploy:

  1. GET /apiname: "CentralCRM API"
  2. GET /api/healthstatus: ok
  3. JWT_SECRET definido
  4. BDs acessíveis a partir do container (não localhost se Postgres é remoto)

12. Diagrama de módulos Nest

flowchart TB
AM[AppModule]

AM --> CM[ConfigModule]
AM --> T1[TypeORM default]
AM --> T2[TypeORM USER_PROFILES]
AM --> Auth[AuthModule]
AM --> AL[AuthLoginModule]
AM --> Co[CompanyModule]
AM --> CO[CompanyOperationalModule]
AM --> Pr[PresenceModule]
AM --> WL[WhiteLabelModule]
AM --> PRS[PasswordResetModule]
AM --> PT[PortalSubdomainModule]
AM --> EX[ExternalApisModule]
AM --> RD[RedisModule]
AM --> HM[HealthModule]
AM --> Guard[JwtAuthGuard APP_GUARD]

Auth --> Guard
AL --> T2
Co --> T1
CO --> T1
Pr --> T1
WL --> T1

13. Documentação relacionada

DocumentoConteúdo
README.mdCartão de visita (raiz)
docs/index.mdHome MkDocs
catalogo-completo.mdTodos os endpoints
GUIA_FRONTEND_APIS.mdContratos REST, erros, Bearer
ENV_CONTAINER.mdDocker / Swarm, variáveis, JWT
ENTENDIMENTO.mdPresença end-to-end e troubleshooting
FRONTEND_LOGIN.mdLogin
FRONTEND_REGISTER_BASE.mdRegisto
FRONTEND_POST_COMPANY.mdCriação de empresa
sql/Scripts de schema PostgreSQL
DOCKER_DB_DEBUG.mdDiagnóstico de ligação BD no container

14. Decisões de desenho (resumo)

Detalhe em ADRs.

  1. Dois PostgreSQLADR 0002.
  2. Sem synchronizeADR 0005.
  3. Guard JWT globalADR 0001.
  4. Presença em memóriaADR 0003.
  5. Admin como observador — não polui contagens de online; recebe eventos em admin:observer.
  6. Versionamento URIADR 0004.