Files
SeConectai_Vendas/Etapas/07-motor-de-alertas.md
T
2026-08-14 17:35:24 -03:00

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

  1. Infraestrutura de filas

    • Configurar @nestjs/bullmq conectado ao Redis já disponível no docker-compose.
    • Criar duas filas: alertas-mensalidade (master→tenant) e alertas-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.ts vs worker.ts, ou um segundo serviço no docker-compose chamado worker rodando o mesmo build com um comando diferente).
  2. Módulo alert-templates

    • CRUD de alert_templates:
      • Nível master (MasterGuard): templates padrão da plataforma (tenant_id = null), tipo mensalidade_tenant.
      • Nível tenant (TenantGuard, role tenant_admin): templates próprios, tipo cobranca_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.
    • Implementar renderização de placeholders ({{nome}}, {{valor}}, {{vencimento}}, etc — listar todos os placeholders suportados por tipo de template em um arquivo de constantes, documentado).
  3. Job diário: mensalidade_tenant

    • Cron (ex: todo dia às 8h, horário configurável via env) que:
      1. Roda a lógica equivalente ao endpoint POST /master/faturas/atualizar-atrasadas (marca faturas vencidas como atrasado, tenant vira inadimplente).
      2. Para toda tenant_faturas com vencimento em N dias (configurável, ex: 3 dias antes) ou já vencida e ainda sem alerta hoje, enfileira um job na fila alertas-mensalidade com os dados necessários.
    • Worker da fila alertas-mensalidade: busca template (mensalidade_tenant, canal whatsapp e/ou email conforme configurado), renderiza, chama AlertDispatchService, grava resultado em alert_logs, atualiza tenant_faturas.alerta_enviado_em.
  4. Job diário: cobranca_cliente (por tenant)

    • Mesmo padrão do job acima, mas iterando sale_payments de todos os tenants ativos: marca atrasadas, enfileira alerta para parcelas próximas do vencimento ou já atrasadas (respeitando alerta_enviado_em para 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.
  5. Idempotência e resiliência

    • Garantir que um mesmo job não dispare o mesmo alerta duas vezes (checar alerta_enviado_em antes 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/logs e GET /tenant/alertas/logs para consultar alert_logs com filtros (canal, status, período).

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_logs com erro
  • Endpoints de consulta de logs funcionam com os filtros esperados