Skip to content

feat: sink de notificações operacionais no Discord (login/re-login da sessão) (P4) #18

Description

@gvieira18

Status: épico ainda NÃO grelhado. Este issue é só o problema em si, para servir de ponto de partida do grilling. O design (user stories, decisões, testes) sai da sessão de grilling + domain-modeling, como no épico #8.

P4 (numeração da roadmap, após P1 pairing-code / P2 polls #16 / P3 auth-store #17). Relaciona-se com #8 (pairing-code / headless): fecha a lacuna do "recuperação pós-loggedOut é manual".

Problem Statement

O coletor headless (systemd --user, 24/7) não tem visibilidade proativa da saúde da sessão de WhatsApp. Quando a sessão cai (loggedOut), o serviço apenas loga FATAL no journald da VM e sai ≠ 0 — ninguém é avisado. A recuperação é manual (ADR-0003: operador roda pnpm pair e reinicia), mas só acontece quando alguém percebe que parou. Resultado: janela de coleta parada até alguém olhar os logs.

Não existe canal de push pro operador saber "a sessão morreu, precisa re-parear".

Solution (direção, a detalhar no grill)

Um sink de notificações no próprio wpp-tui que faz POST direto num incoming webhook de um canal do Discord (formato content/embeds do Discord), em paralelo ao webhook do Laravel (integration-whatsapp) já existente. Autônomo — não depende do monolito.

Escopo inicial: eventos de lifecycle de sessão/auth, derivados do connection.update do Baileys (o mesmo que src/collector/core.ts e src/pairing.ts já observam):

  • Sessão conectada (connection: 'open') — "coletor online".
  • Sessão caiu / loggedOut — "sessão morreu, precisa re-parear" (o alerta mais importante).
  • (a decidir) código de pareamento pendente / aguardando pareamento.

Este webhook é independente do contrato do Laravel: sem HMAC X-Signature, formato é o do Discord, não o {type, chat_jid, payload} interno.

A grelhar (open questions)

  • Conjunto exato de eventos: quais transições do connection.update viram notificação (open, close com/sem loggedOut, restartRequired 515 é ruído?), e se entra o prompt de pairing-code.
  • Formato: content texto simples vs embeds (cor por severidade); @role/@here em alerta crítico (loggedOut)?
  • Config: DISCORD_WEBHOOK_URL por env (opcional — ausente = sink desligado, sem quebrar o coletor).
  • Resiliência: Discord fora do ar → retry? drop? reusa a infra de outbox/backoff do webhook-sender atual ou é fire-and-forget?
  • Anti-flap: reconexões em loop (close→open) não podem spammar o canal — dedup/rate-limit/coalescing.
  • Segurança: a URL do webhook do Discord é segredo (não logar; fora do stdout do headless).

Arquivos afetados (provável)

  • src/collector/core.ts (observa connection.update, emite os eventos de lifecycle)
  • novo módulo tipo src/collector/discord-sink.ts (formata + posta no webhook do Discord)
  • .env.example (DISCORD_WEBHOOK_URL), docs de deploy

Fora do escopo (inicial — futuros épicos)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions