ADR-0018 — Notificações (alertas de imóveis)
- Status: Aceito
- Data: 2026-07-18 · Aceito em: 2026-07-18
Contexto
Os alertas (RF-08) e o ciclo de vida (RF-13: favorito vendido, queda de preço) precisam notificar o usuário. O modelo prevê canal_alerta = email | push | webhook, mas não há provedor, templates, fila nem autenticação de webhook definidos.
Decisão
- Event-driven via RabbitMQ (ADR-0005): os casos de uso publicam eventos
notificacao.*(ex.:notificacao.favorito_vendido,notificacao.queda_preco,notificacao.alerta_match); um worker de notificação consome, renderiza o template e envia. DLQ para falhas. - Escopo do MVP = somente e-mail, via provedor SMTP transacional (ex.: Amazon SES / Resend / Postmark) — configurável por env/secret.
pushewebhookficam como evolução. - Idempotência: chave por (
usuario_id,evento,imovel_id, janela) evita duplicar envio. - Templates versionados (assunto + corpo) com dados mínimos; link de descadastro.
- Webhook (evolução): assinatura HMAC no header + retries com backoff; segredo por alerta.
- Preferências/retenção: registrar consentimento e permitir opt-out (LGPD — ver política de privacidade).
Arquitetura, robustez e escala
- Transactional Outbox: o caso de uso grava o evento numa tabela
outboxna mesma transação da mudança de estado; um relay publica no RabbitMQ. Garante at-least-once sem perder evento em caso de crash (evita "publiquei mas não commitei", e vice-versa). - Idempotência de envio: chave
(usuario_id, tipo_evento, imovel_id, janela)numa tabelanotificacao_enviada; consumidor at-least-once + dedup ⇒ efeito exactly-once percebido. - Provedor plugável:
NotificacaoPortcom adapter SMTP/transacional (SES/Resend/Postmark) por env; trocar provedor sem tocar no domínio. - Deliverability: configurar SPF, DKIM e DMARC; tratar bounces/complaints (webhook do provedor) para suprimir endereços inválidos e proteger a reputação do domínio.
- Cadência anti-spam: agrupar em digest quando houver muitos matches; limite por usuário/dia; respeitar preferências e opt-out (token de descadastro assinado).
- Retry/DLQ: backoff exponencial; após N tentativas → DLQ + alerta; falha de provedor não bloqueia a fila (circuit breaker por provedor).
- Escala: workers de notificação horizontalmente escaláveis (consumo concorrente idempotente); templates versionados e renderizados fora do publisher.
- Webhook (evolução): entrega assinada por HMAC (header + timestamp anti-replay), timeout curto, retries com backoff e desativação automática de endpoints que falham cronicamente.
- Observabilidade: enviados/entregues/bounce/complaint, latência de entrega, tamanho da DLQ, taxa de opt-out (ver pilares).
Consequências
- + Desacoplado e resiliente (fila + DLQ + idempotência); MVP simples (só e-mail).
- + Fácil adicionar canais depois sem mexer nos publishers.
- − Dependência de provedor de e-mail (deliverability, SPF/DKIM/DMARC a configurar).
- − Mais um worker e um contrato de eventos a manter (ver contrato de eventos de notificação).
Alternativas consideradas
- Envio síncrono no request: acopla e trava a API; sem retry — rejeitado.
- Só push/web: exige base logada e service worker; menor alcance no MVP — adiado.