4.5 KiB
4.5 KiB
Etapa 7/8 — Motor de Alertas (BullMQ)
Contexto do projeto
Continuação do SeConectai Vendas. Já existem: setup, auth com RLS,
painel master completo, integrações Evolution API/e-mail com serviço
central de envio (AlertDispatchService), CRUD de customers/produtos, e
o módulo completo de vendas/parcelas/dashboards.
Esta é a etapa que automatiza o que até agora só existia como endpoint manual: verificação de vencimentos e disparo de alertas, nos dois níveis do sistema (master→tenant e tenant→customer).
Tarefas
-
Infraestrutura de filas
- Configurar
@nestjs/bullmqconectado ao Redis já disponível nodocker-compose. - Criar duas filas:
alertas-mensalidade(master→tenant) ealertas-cobranca(tenant→customer). - Criar um processo/worker separado do processo web principal (pode
ser o mesmo container em dev, mas documentar como se separaria em
produção — ex:
main.tsvsworker.ts, ou um segundo serviço nodocker-composechamadoworkerrodando o mesmo build com um comando diferente).
- Configurar
-
Módulo
alert-templates- CRUD de
alert_templates:- Nível master (
MasterGuard): templates padrão da plataforma (tenant_id = null), tipomensalidade_tenant. - Nível tenant (
TenantGuard, roletenant_admin): templates próprios, tipocobranca_cliente(e outros tipos que fizerem sentido, ex:venda_confirmada,lembrete_vencimento). Se o tenant não tiver template próprio para um tipo/canal, usar o template padrão do master como fallback.
- Nível master (
- Implementar renderização de placeholders (
{{nome}},{{valor}},{{vencimento}}, etc — listar todos os placeholders suportados por tipo de template em um arquivo de constantes, documentado).
- CRUD de
-
Job diário:
mensalidade_tenant- Cron (ex: todo dia às 8h, horário configurável via env) que:
- Roda a lógica equivalente ao endpoint
POST /master/faturas/atualizar-atrasadas(marca faturas vencidas comoatrasado, tenant virainadimplente). - Para toda
tenant_faturascom vencimento em N dias (configurável, ex: 3 dias antes) ou já vencida e ainda sem alerta hoje, enfileira um job na filaalertas-mensalidadecom os dados necessários.
- Roda a lógica equivalente ao endpoint
- Worker da fila
alertas-mensalidade: busca template (mensalidade_tenant, canalwhatsappe/ouemailconforme configurado), renderiza, chamaAlertDispatchService, grava resultado emalert_logs, atualizatenant_faturas.alerta_enviado_em.
- Cron (ex: todo dia às 8h, horário configurável via env) que:
-
Job diário:
cobranca_cliente(por tenant)- Mesmo padrão do job acima, mas iterando
sale_paymentsde todos os tenants ativos: marca atrasadas, enfileira alerta para parcelas próximas do vencimento ou já atrasadas (respeitandoalerta_enviado_empara não notificar duas vezes no mesmo dia). - Usa a instância WhatsApp e config de e-mail do tenant dono da venda, não a do master.
- Mesmo padrão do job acima, mas iterando
-
Idempotência e resiliência
- Garantir que um mesmo job não dispare o mesmo alerta duas vezes
(checar
alerta_enviado_emantes de enfileirar, e novamente antes de enviar, dentro do worker, para lidar com concorrência). - Configurar retry com backoff exponencial no BullMQ para falhas
transitórias de envio (ex: Evolution API fora do ar), com limite de
tentativas (ex: 3) e log do erro final em
alert_logs.erro. - Endpoint de observabilidade:
GET /master/alertas/logseGET /tenant/alertas/logspara consultaralert_logscom filtros (canal, status, período).
- Garantir que um mesmo job não dispare o mesmo alerta duas vezes
(checar
Critérios de aceite
- Worker processa as duas filas de forma independente do processo web (documentado como escalar workers separadamente)
- Template do tenant sobrepõe o padrão do master quando existe; usa fallback quando não existe
- Placeholders são substituídos corretamente na renderização
- Job diário marca faturas/parcelas atrasadas corretamente
- Alerta de mensalidade chega no WhatsApp/e-mail do tenant em teste controlado (vencimento simulado para "hoje")
- Alerta de cobrança chega no WhatsApp/e-mail do customer, usando a instância/config do tenant correto (testar com 2 tenants diferentes)
- Mesmo alerta não é disparado duas vezes no mesmo dia (testar rodando o job duas vezes seguidas)
- Falha de envio é reprocessada com retry e, após esgotar tentativas,
fica registrada em
alert_logscom erro - Endpoints de consulta de logs funcionam com os filtros esperados