Skip to content

infra: configuração Meta WhatsApp Cloud API — produção #286

Description

@arthuurw

Status: Backlog
Área: whatsapp / infra
Tipo: chore (ops/config — sem alteração de código)
Specs path: specs/specification-whatsapp.md
Nota: Configuração da Meta WhatsApp Cloud API para o ambiente PRODUTIVO. Ação MANUAL de ops (não automatizável via código). O código já está pronto e gateado — este card rastreia só a configuração externa na Meta + env vars de prod. Pré-requisito de entrega real de WhatsApp em produção.


Contexto

O subsistema WhatsApp (specification-whatsapp.md) está implementado e testado. Gate DI em InfrastructureExtensions.cs:386-406: com WhatsApp:PhoneNumberId E WhatsApp:AccessToken não-vazios → MetaWhatsAppCloudNotifier real; senão NullWhatsAppNotifier (no-op). Falta apenas a configuração externa na Meta e as env vars de produção.

Produção = docker-compose.server.yml (WhatsApp__MarcarComoTeste default false → passthrough real).

Pré-requisito físico (número)

  • eSIM de operadora real (Vivo/Claro/TIM/etc.), plano com voz + SMS (data-only não tem número → não serve).
  • Número virgem: nunca registrado no WhatsApp / WhatsApp Business App. Se tiver conta, deletar/migrar antes.
  • VoIP bloqueado pela Meta (Twilio/virtual puro falha OTP).
  • Após registro o número não pode mais ser usado no app WhatsApp Messenger → dedicado, não pessoal.
  • Guardar credencial de portabilidade do eSIM (re-verify futura da Meta exige receber OTP de novo).

Fontes oficiais: Meta — Business phone numbers · Meta — Registering phone numbers

Passo-a-passo (ops)

  • 1. Meta Business + App — Meta Business Manager → criar/usar Business; developers.facebook.com → App tipo Business → adicionar produto WhatsApp.
  • 2. Registrar número (WABA) — WhatsApp → API Setup → adicionar o número do eSIM → receber OTP (SMS/voz) → verificar. Gera o Phone Number ID (≠ o número). → WHATSAPP_PHONE_NUMBER_ID.
  • 3. Token PERMANENTE — Business Settings → System Users → criar → gerar token com whatsapp_business_messaging + whatsapp_business_management; atribuir o WABA ao System User. → WHATSAPP_ACCESS_TOKEN. ⚠️ NÃO usar o token temporário de 24h do API Setup.
  • 4. App Secret — App → Settings → Basic → App Secret. → WHATSAPP_APP_SECRET (HMAC do webhook).
  • 5. Webhook — inventar string aleatória → WHATSAPP_WEBHOOK_VERIFY_TOKEN. WhatsApp → Configuration → Webhook: Callback URL https://<dominio-prod>/webhooks/whatsapp, Verify token = mesma string, subscrever campo messages.
  • 6. Aprovar os 16 templates (BLOQUEANTE) — WhatsApp Manager → Message Templates → criar os 16 (nomes/copy/vars em specification-whatsapp.md §TEMPLATES). Categoria Utility, idioma pt_BR, vars posicionais na ordem EXATA do catálogo (WhatsAppTemplates.cs). Nomes casam 1:1 com o código. Qtd/ordem de vars divergente = Meta rejeita no runtime.
  • 7. Env vars de prod (/opt/forzion/.env):
    WHATSAPP_PHONE_NUMBER_ID=<phone-number-id>
    WHATSAPP_ACCESS_TOKEN=<system-user-token-permanente>
    WHATSAPP_API_VERSION=v21.0
    WHATSAPP_APP_SECRET=<app-secret>
    WHATSAPP_WEBHOOK_VERIFY_TOKEN=<string-aleatoria>
    WHATSAPP_MARK_AS_TEST=false
    
    WHATSAPP_REDIRECT_TO / WHATSAPP_ALLOWLIST_PHONES vazios em prod.
  • 8. Deploy + smoke — subir container; startup SEM warning do NullWhatsAppNotifier no log = notifier real ativo. Disparar 1 evento real (ex.: aprovar treinador tier≥ProPlus com telefone) → conferir entrega + status em whatsapp_delivery_logs.

Gotchas de entrega

  • Gating por tier: WhatsApp é PAGO → só envia se treinador tier ≥ ProPlus (IPlanoNotificationPolicy). Tier baixo = só e-mail.
  • Sem fallback de telefone: só alunos.Telefone/treinadores.Telefone; null = skip silencioso.
  • Meta não tem sandbox de entrega real: pra testar sem prod, usar test number Meta (destinatários pré-cadastrados) em token separado de hmg.

Ordem crítica: template aprovado (6) + número verificado (2) ANTES do 1º envio real — senão o gate liga mas todo envio vira LogWarning.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions