Etapa 7 — Motor de alertas (BullMQ)
Adiciona um processo worker separado do processo web (src/worker.ts, WorkerModule) com dois crons diários e processors do BullMQ para alertas de mensalidade (master→tenant) e cobrança (tenant→customer): marca faturas/parcelas atrasadas, resolve template com fallback tenant→master por canal, renderiza placeholders, dispara WhatsApp/e-mail com retry e backoff exponencial, e grava alert_logs com idempotência por dia. Módulo alerts (web) traz o CRUD de alert_templates (master e tenant) e a consulta de alert_logs com filtros. alert_templates/alert_logs não têm RLS no schema, então o isolamento entre tenants é feito manualmente (PrismaMasterService + filtro por tenant_id), coberto por teste e2e dedicado. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -26,7 +26,9 @@ Docker/Docker Compose. Multi-tenancy via banco único, isolado por
|
||||
healthcheck, e só inicia a API depois que as duas dependências estiverem
|
||||
saudáveis. `docker-compose.override.yml` é aplicado automaticamente e monta
|
||||
o código-fonte local no container, então alterações em `src/` reiniciam a
|
||||
API sozinhas (`npm run dev` / `nest start --watch`).
|
||||
API sozinhas (`npm run dev` / `nest start --watch`). O mesmo `docker
|
||||
compose up` já sobe o serviço `worker` (motor de alertas — ver seção
|
||||
própria abaixo) lado a lado com a API.
|
||||
|
||||
3. Rode as migrations do Prisma (tabelas, enums, índices) e a migration
|
||||
manual de RLS/views/checks:
|
||||
@@ -133,6 +135,41 @@ contexto usam `TenantContextService.getTx()` (ver
|
||||
`AuthController.listTenantUsers` como exemplo). Requests master usam
|
||||
`PrismaMasterService` (conexão `app_master`, sem passar pelas policies).
|
||||
|
||||
## Motor de alertas (worker)
|
||||
|
||||
O disparo automatizado de alertas (mensalidade do tenant, cobrança de
|
||||
parcelas do customer) roda num **processo separado do processo web**:
|
||||
|
||||
- `src/main.ts` (processo `app`) — só HTTP. Não importa `ScheduleModule`
|
||||
nem processa nenhuma fila.
|
||||
- `src/worker.ts` (processo `worker`) — sem HTTP. Sobe via
|
||||
`NestFactory.createApplicationContext(WorkerModule)`, que inicializa os
|
||||
dois crons diários (`AlertSchedulerService`, `@nestjs/schedule`) e os
|
||||
dois processors do BullMQ (`MensalidadeProcessor`/`CobrancaProcessor`,
|
||||
filas `alertas-mensalidade`/`alertas-cobranca` no Redis já usado pelo
|
||||
`docker-compose`).
|
||||
|
||||
Essa separação existe para poder escalar os dois processos de forma
|
||||
independente sem duplicar o disparo do cron: se o `app` rodar em várias
|
||||
réplicas (comum atrás de um load balancer), um `@Cron()` registrado nele
|
||||
dispararia o mesmo job uma vez por réplica. Como os crons vivem só no
|
||||
`worker`, escalar `worker` (`docker compose up --scale worker=3`)
|
||||
paraleliza o *processamento* das filas, não a geração dos jobs.
|
||||
|
||||
`docker compose up` já sobe os dois processos (serviço `worker` no
|
||||
`docker-compose.yml`/`docker-compose.override.yml`, mesma imagem do `app`,
|
||||
`command` diferente: `node dist/worker` em produção, `npm run worker:dev`
|
||||
em desenvolvimento). Para rodar só o worker manualmente:
|
||||
|
||||
```bash
|
||||
docker compose up worker
|
||||
```
|
||||
|
||||
Horário dos crons, antecedência do alerta e política de retry são
|
||||
configuráveis via `ALERT_CRON_MENSALIDADE`/`ALERT_CRON_COBRANCA`,
|
||||
`ALERT_DIAS_ANTECEDENCIA_MENSALIDADE`/`ALERT_DIAS_ANTECEDENCIA_COBRANCA` e
|
||||
`ALERT_JOB_MAX_ATTEMPTS`/`ALERT_JOB_BACKOFF_MS` (ver `.env.example`).
|
||||
|
||||
## Scripts
|
||||
|
||||
| Script | Descrição |
|
||||
@@ -140,6 +177,8 @@ contexto usam `TenantContextService.getTx()` (ver
|
||||
| `npm run dev` | Inicia a API em modo watch |
|
||||
| `npm run build` | Compila TypeScript para `dist/` |
|
||||
| `npm run start:prod` | Roda a build de produção (`dist/main.js`) |
|
||||
| `npm run worker:dev` | Inicia o worker de alertas em modo watch |
|
||||
| `npm run worker:prod` | Roda a build de produção do worker (`dist/worker.js`) |
|
||||
| `npm run lint` | ESLint (com `--fix`) |
|
||||
| `npm run test` | Testes unitários (Jest) |
|
||||
| `npm run test:e2e` | Testes end-to-end (Jest + Supertest) |
|
||||
@@ -152,17 +191,21 @@ contexto usam `TenantContextService.getTx()` (ver
|
||||
|
||||
```
|
||||
src/
|
||||
├── main.ts
|
||||
├── app.module.ts
|
||||
├── config/ # ConfigModule, validação de env, PrismaService/PrismaMasterService/
|
||||
│ # PrismaTenantService, TenantContextService (mecanismo de RLS por request)
|
||||
├── main.ts # processo web (HTTP)
|
||||
├── worker.ts # processo worker (crons + filas BullMQ, sem HTTP)
|
||||
├── app.module.ts # módulos do processo web
|
||||
├── config/ # ConfigModule, validação de env, PrismaService/PrismaMasterService/
|
||||
│ # PrismaTenantService, TenantContextService (mecanismo de RLS por request)
|
||||
├── worker/ # WorkerModule, AlertSchedulerService (crons), processors do BullMQ
|
||||
└── modules/
|
||||
├── health/ # GET /health
|
||||
└── auth/ # login/refresh/logout/reset, guards, decorators, JwtStrategy
|
||||
├── health/ # GET /health
|
||||
├── auth/ # login/refresh/logout/reset, guards, decorators, JwtStrategy
|
||||
└── alerts/ # CRUD de alert_templates, GET .../alertas/logs, resolver de fallback
|
||||
# e placeholders (usado pelo módulo web e pelo worker)
|
||||
prisma/
|
||||
├── schema.prisma
|
||||
└── migrations/
|
||||
Etapas/ # Prompts e controle de progresso do build faseado
|
||||
Etapas/ # Prompts e controle de progresso do build faseado
|
||||
```
|
||||
|
||||
## Progresso do build
|
||||
|
||||
Reference in New Issue
Block a user