Carry over pre-existing WABA outreach automation WIP

This work already existed uncommitted in the main working tree (not
authored by this branch) and is required as a runtime dependency for the
campaign outreach port (zpro-client, templates, outreach routes/UI). Copied
in as-is, untouched, so this feature branch has a working baseline; the
original uncommitted state in the main checkout is left exactly as it was.
This commit is contained in:
Gustavo
2026-08-01 10:12:25 -03:00
parent 0894ab68b3
commit 4f736562f3
33 changed files with 3537 additions and 342 deletions
+10 -3
View File
@@ -24,9 +24,12 @@ GTI-Comercial.exe → servidor Node local (porta 3900) → navegador
└── Tratamento: dashboard, filtros, relatórios e exportações Z-PRO
```
Sem n8n, sem Docker, sem serviços externos obrigatórios: tudo roda no computador
da GTI. O envio das mensagens é feito por fora (Z-PRO), a partir dos arquivos
gerados pelo módulo de tratamento.
Sem n8n, sem serviços externos obrigatórios: tudo roda no computador da GTI hoje
(e vai rodar num container Docker no Proxmox da empresa no futuro, sem mudança de
código). O primeiro contato via WhatsApp pode ser automático (ver
[08-automacao-envio.md](08-automacao-envio.md)); campanhas maiores e o
acompanhamento seguem por fora, no Z-PRO, a partir dos arquivos gerados pelo
módulo de tratamento.
## Premissas
@@ -53,3 +56,7 @@ gerados pelo módulo de tratamento.
- Acesso protegido por login (usuário/senha): o primeiro acesso vem com
`admin`/`admin`, que pode cadastrar novos usuários (comercial ou admin)
pela tela de Usuários.
- Automação de primeiro contato via WhatsApp (opcional, desligada por padrão):
manda uma mensagem com o template do produto recomendado pra cada lead ainda
não exportado, registra o que foi mandado e aplica tags no contato do Z-PRO —
ver [08-automacao-envio.md](08-automacao-envio.md).
+133
View File
@@ -0,0 +1,133 @@
# Automação de envio WhatsApp (Z-PRO)
Manda automaticamente a primeira mensagem de WhatsApp pro produto/serviço
recomendado de cada lead, usando um template por produto, e registra tudo
(quem recebeu, qual produto, quando) pra nunca mandar a mesma coisa duas
vezes pro mesmo lead.
## Como funciona
- Roda **sozinha, dentro do próprio servidor**, a cada 20 minutos, enquanto
o app estiver ligado — não depende de Agendador de Tarefas do Windows nem
de cron. Isso é de propósito: o projeto hoje roda local, mas vai ser
migrado pra um container Docker no Proxmox da empresa, e um agendador do
sistema operacional teria que ser reconfigurado nesse dia. O timer interno
funciona idêntico nos dois ambientes.
- Só considera leads **ainda não exportados** (`exported_at` vazio). Assim
que um lead vira oportunidade manual no Z-PRO (exportação normal da tela
de Tratamento), a automação para de mandar mensagem pra ele — quem assumiu
o lead foi um vendedor, não o robô.
- Cada lead tem uma lista de produtos recomendados por nicho (ex.: ERP 5⭐,
G-Delivery 3⭐). Hoje a automação só tenta o **produto principal** (o de
maior estrela), uma única vez por lead. Existe uma segunda etapa pronta
(mas desligada) pra tentar o próximo produto da lista se não houver
resposta depois de alguns dias — ver `outreach.tentarProximoProduto`
abaixo.
- Manda uma mensagem por número, com controle nosso de quem já recebeu o
quê — não pelo `bulkSendMessageWithVariable` usado na exportação manual
em massa, que depende de um CSV com substituição posicional de variável.
Cada produto tem um **canal** próprio (ver seção abaixo).
- Depois de mandar, aplica duas tags no contato do Z-PRO:
`GTI P1`/`GTI P2`/`GTI P3`/`GTI P4` (prioridade do lead) e
`GTI Oferta: <produto>` (o que foi ofertado) — pra quem for atender depois
já ver esse contexto direto na conversa.
## Canal oficial x não-oficial
Cada produto/template tem um seletor de canal em Configurações:
- **Não-oficial (texto livre)** — usa `bulkIndividual`, funciona numa
conexão QR Code/Baileys do Z-PRO. Manda o texto do template com
`{empresa}`/`{cidade}`/`{segmento}` substituídos. É o padrão, e o risco
aqui é o de sempre com WhatsApp não-oficial: possibilidade de bloqueio do
número por comportamento automatizado (por isso o limite diário e o
intervalo aleatório entre envios).
- **Oficial (Meta, template aprovado)** — usa a API oficial do WhatsApp
(Cloud API/WABA) via Z-PRO. Aqui **não dá pra mandar texto livre**: o
WhatsApp só permite iniciar uma conversa com um **template pré-aprovado**
pelo Meta Business Manager (fora da janela de 24h de uma conversa já
iniciada pelo cliente). Por isso o campo vira "Nome do template aprovado"
(tem que ser **exatamente** o nome cadastrado no Meta) + "Idioma" (ex.:
`pt_BR`).
**A aprovação do template em si é feita fora deste app** — no Meta
Business Manager (ou no painel do Z-PRO, se ele tiver essa tela) — o
Z-PRO só expõe o *envio* usando um template que já existe, não a criação.
Cadastre e espere aprovar lá antes de configurar o nome aqui.
Limitação atual: o envio oficial aqui é só nome+idioma, sem variáveis
dentro do corpo do template aprovado (a API do Z-PRO tem endpoints
`templateBody`/`templateMarketingBody` que parecem aceitar variáveis, mas
o formato exato não está documentado na collection — se for necessário,
precisa testar contra a instância real antes de automatizar).
## Configurar pela primeira vez
1. **Credenciais do Z-PRO**: no painel do Z-PRO, vá em Admin > API e gere um
token (Base URL, API ID, Token e WhatsApp ID). Na tela, abra
**⚙️ Configurações > Credenciais Z-PRO (WhatsApp)**, preencha os 4 campos
e clique em **Testar conexão** (salva e faz uma chamada real e barata pra
confirmar que as credenciais estão certas, sem mandar nenhuma mensagem).
Sem essas 4 credenciais a automação não manda nada, mesmo ligada.
Alternativa pra quem prefere não guardar o token no banco local (ex.: em
produção no Docker/Proxmox, gerenciando segredo por variável de
ambiente): deixe os 4 campos da tela em branco e defina
`ZPRO_BASE_URL`/`ZPRO_API_ID`/`ZPRO_BEARER_TOKEN`/`ZPRO_WHATSAPP_ID` no
`.env` — a tela vazia cai automaticamente pro `.env`. Se a tela tiver
algum valor preenchido, ele tem prioridade sobre o `.env`.
2. Na mesma tela, em **Automação de envio (WhatsApp)**: revise o texto de
cada template (um por produto — `{empresa}`, `{cidade}` e `{segmento}`
são substituídos automaticamente), ajuste o **limite por dia** se
quiser, e marque **Ativada**. Salve.
Antes de ativar, vale mandar um teste manual (próxima seção) pro seu
próprio WhatsApp.
## Configurações (`settings`, chave → o que faz)
| Chave | Padrão | O que faz |
|---|---|---|
| `outreach.ativo` | `false` | Interruptor geral. Começa desligado de propósito. |
| `outreach.mensagensPorDia` | `10` | Máximo de envios automáticos por dia (soma de todos os produtos). |
| `outreach.diasEntreProdutos` | `5` | Dias de espera antes de tentar o próximo produto (só usado se a cascata estiver ligada). |
| `outreach.tentarProximoProduto` | `false` | Liga a cascata: quando `false`, só tenta o produto principal uma vez. |
| `outreach.horaInicio` / `outreach.horaFim` | `08:00` / `18:00` | Só manda mensagem dentro desse horário. |
Tudo isso é editável pela tela de Configurações (os dois primeiros) ou
diretamente via `PUT /api/settings` (todos).
## Disparo manual (fora do ciclo automático)
Pra testar ou forçar um lote sem esperar o próximo ciclo de 20 min:
```bash
npm run outreach
```
Respeita as mesmas regras do ciclo automático (`outreach.ativo`, horário
comercial, limite diário) — não manda nada que a tela não mostraria.
## Enviar pra um número específico
Em **Configurações > Enviar mensagem manual**: digite o número (com DDI+DDD,
ex.: `5511999999999`), escolha o canal (texto livre ou template oficial já
aprovado) e clique em Enviar. Não depende de lead cadastrado nem de produto.
No canal **Não-oficial (texto livre)**, o app usa `createTicket` para criar uma
conversa visível no painel do Z-PRO. O ticket usa o canal informado em
`WhatsApp ID` e o usuário de `Responsável` nas configurações.
No canal **Oficial**, o app usa o endpoint de template aprovado (`template`) e
também espera um `ticketId` na resposta.
Toda tentativa fica registrada no mesmo histórico dos envios automáticos
(marcado como origem "manual") e **conta pro limite diário**, já que o risco de
bloqueio é do número de WhatsApp usado, não de quem disparou a mensagem.
## Onde fica o histórico
Toda tentativa de envio (sucesso ou erro) vira uma linha na tabela
`outreach_sends` (lead, produto, mensagem exata mandada, status, quando).
Um resumo do dia (enviados hoje, por produto, últimos 20 envios) fica
disponível em `GET /api/outreach/status`.