📄 Documento de Execução — Card 28: [M6] Integração WhatsApp (WAHA)
| Campo | Valor |
|---|---|
| Card Trello | [28] [M6] Integração WhatsApp (WAHA) |
| URL Trello | https://trello.com/c/rHzIJnu2 |
| Marco | M6 (IA + WhatsApp + CRM) |
| Data execução | 07/08/2026 |
| Responsável | Wellington Santiago (via ZCode) |
| Doc anterior | Card 27: Relatórios Gerenciais |
| Próximo card | Card 29: Bot com OpenAI |
| Commits | f54f5c5 |
🎯 1. O que foi implementado
O módulo WhatsApp do GENIOON foi migrado da Meta Cloud API para o WAHA (self-hosted) e totalmente integrado. A decisão foi do Wellington (07/08/2026): WAHA elimina custo por mensagem (~R$0,25/conversa da Meta), templates pré-aprovados, app review e janela de 24h.
A WAHA roda em Docker na própria VPS Oracle (porta 3100), com a sessão "anik" vinculada ao número oficial 0800 323 3000 ("Atendimento Anik"). Toda a stack foi ajustada — código, schema, docs e infra.
Camada de transporte isolada
O envio passa por src/lib/waha.ts (cliente WAHA), usado pelo worker Bull e pelo painel. Trocar de engine no futuro = mudar 1 arquivo.
✅ Critérios de aceite validados
| # | Critério | Status |
|---|---|---|
| 1 | Webhook inbound recebe mensagens WAHA (event "message") | ✅ |
| 2 | Mensagem recebida é salva em WhatsAppMessage | ✅ |
| 3 | Número 0800 323 3000 / display "Atendimento Anik" configurados | ✅ |
| 4 | Worker password-reset-whatsapp envia real via WAHA (não stub) | ✅ |
| 5 | Reset de senha por WhatsApp (RecoveryChannel.WHATSAPP) | ✅ |
| 6 | Status de entrega (message.ack) atualiza WhatsAppMessage.status | ✅ |
| 7 | Caixa de entrada lista conversas (master.whatsapp.conversations.list) | ✅ |
| 8 | Build passa + lint OK + secrets fora do git | ✅ |
| 9 | Painel admin (/master/whatsapp/config) com status + teste de envio | ✅ |
📁 2. Arquivos criados/modificados
Criados
| Arquivo | Função |
|---|---|
src/lib/waha.ts |
Cliente WAHA: sendText, sendMedia, getWahaStatus, toChatId, phoneFromChatId, tipos webhook |
src/app/api/webhook/whatsapp/route.ts |
Webhook inbound: event "message" (salva), "message.ack" (status), "session.status" (log) |
src/app/(dashboard)/master/whatsapp/config/page.tsx |
Painel admin: status WAHA, config (session/apiKey/webhookSecret), teste de envio |
src/styles/whatsapp-config.module.css |
Estilos do painel |
Modificados
| Arquivo | Mudança |
|---|---|
prisma/schema.prisma |
WhatsAppConfig +wahaSession, +wahaApiKey (campos Meta wabaId/phoneNumberId/accessToken marcados obsoletos) |
src/server/queues/workers/password-reset-whatsapp.ts |
Reescrito Meta→WAHA: texto livre, sendText via lib/waha; stub só se WAHA_BASE_URL vazio |
src/middleware.ts |
Libera /api/webhook/ (WAHA não tem JWT) |
src/server/trpc/routers/master.ts |
+sub-router whatsapp (config.get/update, test, conversations.list) |
src/components/layout/nav-config.ts |
+link "WhatsApp" no menu Master |
.env.example |
Bloco WhatsApp WAHA (WAHA_BASE_URL, WAHA_SESSION, WAHA_API_KEY, WHATSAPP_HOOK_SECRET) |
🗄️ 3. Schema do banco (mudanças)
whatsapp_configs: +wahaSession(TEXT), +wahaApiKey(TEXT)- Campos Meta (
wabaId,phoneNumberId,accessToken) — mantidos (obsoletos, ignorados pelo código WAHA) - Migration aplicada via ALTER TABLE manual na VPS (o
prisma migrate devdetectou drift histórico e sugeriu reset — evitado pra preservar dados)
🔌 4. Handoff para o próximo card (29 — Bot OpenAI)
Variáveis de ambiente (VPS Oracle .env)
WAHA_BASE_URL=http://localhost:3100WAHA_SESSION=anikWAHA_API_KEY=ce2918...(em /home/ubuntu/waha/docker-compose.yml também)WHATSAPP_HOOK_SECRET=(vazio por ora)
Helpers disponíveis (src/lib/waha.ts)
sendText({to, text, session?})→{waMessageId}sendMedia({to, filename, mimetype, base64, caption?})→{waMessageId}getWahaStatus()→{available, session?, error?}toChatId(phone)→"55XXXXXXXXX@c.us"phoneFromChatId(chatId)→"55XXXXXXXXX"
Webhook inbound
POST /api/webhook/whatsapprecebe{event, session, payload:{from,to,body,hasMedia,id}}- Eventos tratados:
message(inbound → salva),message.ack(status),session.status(log) - Para o Bot (Card 29): ler
WhatsAppMessageondedirection='inbound'eisAiHandled=truena conversa
Infra WAHA (Docker na VPS)
- Container
genioon-waha, imagemdevlikeapro/waha:arm(⚠️ tag ARM obrigatória —:latestnão tem manifest ARM64) - Porta 3100, volume
./sessions(persiste sessão) - API key exigida em toda chamada (header
X-Api-Key) - QR code pendente: Wellington precisa escanear 1x com WhatsApp do 0800 323 3000
📋 5. Deploy DEV
- WAHA Docker: ✅ rodando (
docker psmostra genioon-waha Up) - API WAHA: ✅ HTTP 200 com X-Api-Key
- GENIOON ↔ WAHA: ✅ conectividade OK (localhost:3100)
- Sessão anik: ⏳
SCAN_QR_CODE(aguardando Wellington escanear QR) - Webhook: ✅ configurado (WHATSAPP_HOOK_URL → /api/webhook/whatsapp)
- Painel: https://sistemaescolar.wellka.com.br/master/whatsapp/config
🧠 6. Contexto gerado para próximas etapas
- Card 29 (Bot OpenAI): consumir
WhatsAppMessageinbound, processar com GPT-4o, responder viasendText(). Toda infra pronta. - Card 30 (CRM): leads chegam pelo webhook inbound → criar Lead. Handler já existe.
- Jobs futuros (absence-notice, payment-reminder, birthday): usar
sendText()igual ao password-reset.
🎯 7. Próximo card
Card 29 [M6] Bot com OpenAI — Atendimento Inteligente. IA consome mensagens inbound (já salvas pelo webhook deste card), classifica intenção, responde com GPT-4o. Infra WhatsApp 100% pronta pra receber.
⚠️ Pendência: escanear QR code
A sessão WAHA "anik" está em SCAN_QR_CODE. Wellington precisa:
# No PC do Wellington:
ssh -L 3100:localhost:3100 oracle-free
# Depois abrir no browser: http://localhost:3100/dashboard
# Login com a API key, escanear QR com WhatsApp do 0800 323 3000
Até escanear, o envio real não funciona (stub). O recebimento via webhook já está plugado.