Files
mercado.clube67.com/docs/newwhats-v22.md
T

353 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# NewWhats v2.2 — Plano Real (pós-análise do cérebro)
> Documento gerado em 2026-04-18 após análise completa do motor, satélite, proxy e ProtocolEngine.
> Base: código real de `newwhats.local` + `alemaoconveniencias.local/sistema-nuvem/plugins/newwhats/`.
---
## 1. Estado atual — O que já existe (v2.1)
### Motor (`newwhats.local:8008`)
| Componente | Rota interna | Status |
|---|---|---|
| Agents CRUD | `GET/POST/PUT/DELETE /api/secretaria/agents` | ✅ operacional |
| Brain Nodes | `GET/POST/PUT/DELETE /api/secretaria/nodes` | ✅ operacional |
| Conversations | `GET/POST/PATCH /api/secretaria/conversations` | ✅ operacional |
| Chat (brain) | `POST /api/secretaria/conversations/:id/chat` | ✅ operacional |
| Finalizar protocolo | `POST /api/secretaria/conversations/:id/finalize` | ✅ operacional |
| Calendar | `GET/POST /api/secretaria/calendar` | ✅ operacional |
| sec_numbers | `GET/POST/PUT/DELETE /api/secretaria/numbers` | ✅ tabela + rotas ok |
| WebSocket stream | `UPGRADE /api/ext/v1/stream` | ✅ operacional |
| Sessions QR | `GET /api/ext/v1/sessions/:id/qr` | ✅ operacional |
### ProtocolEngine (cérebro) — arquitetura real
```
Sistema prompt = persona + knowledge + rules + calendar + escalation
(nós ativos, ordenados por sort_order)
Economia de tokens:
context_window = 8 → carrega apenas últimas 8 mensagens
summarize a cada 10 trocas → atualiza conversation.summary
system prompt nunca cresce — sempre reconstruído do zero
Fallback chain de providers:
1. openai (gpt-4o-mini) — se openai_key configurado
2. gemini (gemini-2.0-flash) — se gemini_key configurado
3. anthropic (claude-3-5-haiku) — se anthropic_key configurado
4. ollama (llama3) — sempre disponível (local)
Persona pode override o model via node_model (por nó)
```
### Satélite (`sistema-nuvem`) — o que existe hoje
```
/api/nw/v1/* → proxy REST para /api/ext/v1/* ✅
/api/nw/v1/stream → proxy WS ✅
/api/webhook/newwhats → webhook-receiver.js ✅ (só loga)
/api/admin/nw/sync-knowledge → syncKnowledge() ✅ (corrigido)
/api/admin/nw/sync-knowledge/preview → buildKnowledgeText() ✅
Rotas Alemão expostas ao motor (/nw/*):
GET /nw/cliente?telefone= → user + tickets + clubes + candidaturas ✅
GET /nw/clube?cpf= → memberships + dependentes + parceiros ✅
GET /nw/candidaturas?cpf= → candidaturas com status PT ✅
GET /nw/parceiros?clube=slug → parceiros de um clube ✅
GET /nw/vagas → vagas abertas formatadas ✅
GET /nw/sorteio → sorteio ativo + contagem ✅
GET /nw/sorteio/tickets?tel= → tickets do cliente ✅
GET /nw/promocoes → promoções ativas ✅
```
### Knowledge Node — situação atual
```
Agente: Ana — Atendente Virtual
Node ID: ed968e6c-a031-44d2-8f5b-1ab4e6f55075
Chars: 1895
Última sync: 2026-04-18T23:28:46Z
Conteúdo real (dados do banco):
- Clube Odonto (planos + parceiros)
- Clube Médico (planos + parceiros)
- Sorteio ativo (preço + disponíveis)
- Promoções ativas
- Vagas abertas
- Atendimento geral
```
### O que NÃO existe ainda
- ❌ Auto-resposta (webhook só loga, nunca envia)
- ❌ Lookup automático de dados do cliente ao receber mensagem
- ❌ UI de gerenciamento de números no admin (Frente 1 em progresso)
- ❌ Botão "Sincronizar Knowledge" no painel
- ❌ Escalação para humano com notificação
- ❌ Métricas de atendimento IA
- ❌ Modo semi-auto (IA sugere, humano confirma)
---
## 2. Frentes v2.2
### Frente 1 — Gerenciamento de Números no Admin UI
**Onde:** `admin-app/src/pages/WhatsAppInbox.tsx`
**O que fazer:**
- [x] Constantes ROLE_LABELS, ROLE_COLORS, PRIORITY_LABELS
- [x] Componente `NumberBadge` (role + prioridade visual)
- [x] Modal `AddNumberModal` — 2 etapas:
- Step 1: preenche label, role, área, prioridade, notas
- Step 2: chama `NwService.createSession(label)``NwService.saveNumber(...)` → poll QR a cada 2s
- [x] Modal `EditNumberModal` — edita metadados + toggle ativo/inativo
- [ ] Estado + `fetchNumbers()` no componente principal
- [ ] Botão "+ Novo Número" no header da aba Sessões
- [ ] Session cards: badges de categoria/prioridade (cruzar sessions × numbers por instance_id)
- [ ] Ações por sessão: botão Editar (abre EditModal) + Excluir (confirm → deleteSession + deleteNumber)
**Fluxo de dados:**
```
NwService.getNumbers() → /api/nw/v1/secretaria/numbers
→ proxy → /api/ext/v1/secretaria/numbers
→ motor → SELECT sec_numbers ORDER BY priority, label
Cruzamento visual: session.id === number.instance_id
```
**Lógica de fallback (display):**
```
Ao mostrar sessões ordená-las por: priority ASC (números sem metadado = priority 99)
Badge role: azul=notificacoes | laranja=entregas | roxo=suporte | rosa=marketing | cinza=geral
Badge prioridade: verde=Principal | amarelo=Fallback | cinza=Terciário+
```
---
### Frente 2 — Auto-resposta Inteligente
**Onde:** `sistema-nuvem/plugins/newwhats/webhook-receiver.js`
**Depende de:** Frente 1 concluída (sec_numbers deve ter roles configurados)
**Princípio de funcionamento:**
```
Motor dispara webhook → POST /api/webhook/newwhats
evento: message.new, fromMe: false
Satélite:
1. Verifica HMAC (já existe)
2. Lookup sec_numbers pelo instanceId → obtém role
3. Se role == 'notificacoes' → NUNCA responder (só logar)
4. Se role == 'suporte' | 'geral' | 'marketing' | 'entregas':
a. Lookup ou cria conversa no motor: POST /api/secretaria/conversations
b. Chama brain: POST /api/secretaria/conversations/:id/chat { message }
c. Envia resposta: POST /api/ext/v1/inbox/:chatId/send { text: reply }
d. Atualiza nw_event_logs com status='replied'
```
**Modos de operação (configurável por plugin_config):**
```
auto_reply_mode:
off → nunca responde (comportamento atual)
assistido → IA sugere na inbox, humano confirma antes de enviar
automatico → IA responde direto, sem intervenção humana
```
**Throttle / anti-loop:**
```
- Nunca responder se fromMe = true
- Cooldown: não responder ao mesmo chatId por 30s após última resposta automática
- Máximo: 5 respostas automáticas por conversa antes de escalar
- Horário: respeitar horário de atendimento (plugin_config: auto_reply_hours)
```
**Tabela nova: `nw_auto_replies`**
```sql
CREATE TABLE nw_auto_replies (
id SERIAL PRIMARY KEY,
instance_id VARCHAR(128) NOT NULL,
chat_id VARCHAR(128) NOT NULL,
conv_id UUID, -- sec_conversations.id no motor
reply TEXT,
status VARCHAR(20) DEFAULT 'sent',-- sent | failed | pending_confirm
created_at TIMESTAMPTZ DEFAULT NOW()
);
```
---
### Frente 3 — Botão "Sincronizar Knowledge" no Painel
**Onde:** `admin-app/src/pages/WhatsAppInbox.tsx` (aba Sessões) + `admin-app/src/services/api.ts`
**O que fazer:**
```typescript
// api.ts — adicionar ao NwService:
syncKnowledge: () =>
api.post('/admin/nw/sync-knowledge').then(r => r.data),
previewKnowledge: () =>
api.get('/admin/nw/sync-knowledge/preview').then(r => r.data),
```
**UI:**
- Botão `Sincronizar IA` com ícone `Brain/Zap` no header da aba Sessões (ao lado do `+Novo Número`)
- Estado: idle → syncing (spinner) → ok (checkmark verde 2s) → idle
- Toast: "✅ Base sincronizada — 1895 chars — Ana atualizada"
- Botão `Preview` (expandable) mostra o texto que será enviado ao motor
**Quando disparar automaticamente (futuro):**
Webhook interno: quando admin salva promoção, clube, vaga → dispara `syncKnowledge()` em background.
---
### Frente 4 — Escalação para Humano
**Onde:** `webhook-receiver.js` + novo endpoint no admin
**Gatilhos de escalação (detectados pelo brain):**
- Palavra-chave na resposta da IA: `[ESCALAR]`, `[HUMANO]`, `transferir para atendente`
- Mais de 5 trocas sem resolução (contador na conversa)
- Cliente digita: "falar com atendente", "humano", "responsável"
**Fluxo:**
```
Brain retorna resposta com [ESCALAR] → satélite detecta
→ marca conversa: status='escalated'
→ INSERT nw_escalations (chat_id, conv_id, reason, created_at)
→ badge vermelho na inbox do admin (unread count especial)
→ IA para de responder automaticamente para esse chatId
→ Humano assume via inbox normal
```
**Tabela nova: `nw_escalations`**
```sql
CREATE TABLE nw_escalations (
id SERIAL PRIMARY KEY,
instance_id VARCHAR(128) NOT NULL,
chat_id VARCHAR(128) NOT NULL,
conv_id UUID,
reason TEXT,
resolved BOOLEAN DEFAULT FALSE,
resolved_by VARCHAR(128),
created_at TIMESTAMPTZ DEFAULT NOW(),
resolved_at TIMESTAMPTZ
);
```
---
### Frente 5 — Métricas de Atendimento IA
**Onde:** `sistema-nuvem/server.js` + novo card no Dashboard admin
**KPIs:**
```
- Total de mensagens recebidas (nw_event_logs)
- Total respondidas pela IA (nw_auto_replies)
- Taxa de auto-atendimento: respondidas / recebidas
- Escalações hoje / semana
- Tempo médio de resposta (created_at do webhook → created_at do reply)
- Distribuição por role (suporte X entregas X geral)
- Top 5 sessões por volume
```
**Endpoint:**
```
GET /api/admin/nw/metrics?period=7d
→ { total_in, total_replied, escalations, avg_response_ms, by_role[], top_sessions[] }
```
---
## 3. Sequência de implementação recomendada
```
Semana 1:
[ ] Frente 1 — concluir WhatsAppInbox.tsx (estado + UI badges + botões)
[ ] Frente 3 — botão SyncKnowledge no painel (rápido, alto impacto)
Semana 2:
[ ] Frente 2 — webhook auto-resposta (modo 'automatico')
→ criar nw_auto_replies
→ integrar brain via fetch interno
→ throttle + anti-loop
Semana 3:
[ ] Frente 4 — escalação (detectar [ESCALAR] na resposta + tabela + badge)
[ ] Frente 5 — métricas básicas (endpoint + card dashboard)
```
---
## 4. Dependências técnicas críticas
### 4.1 O motor precisa de webhook configurado para auto-resposta funcionar
```
Motor → POST /api/webhook/newwhats (satélite)
Configurar via: POST /api/ext/v1/webhooks {
url: 'https://alemaoconveniencias.com.br/api/webhook/newwhats',
events: ['message.new', 'session.status'],
secret: '<webhook_secret do plugin_configs>'
}
```
### 4.2 Rotas do motor que o satélite usa internamente (sem auth)
```
/api/secretaria/conversations → busca/cria conversa por chatId
/api/secretaria/conversations/:id/chat → chama brain
/api/secretaria/agents → lista agentes ativos
```
### 4.3 Rota que satélite usa com auth (api key) para enviar resposta
```
POST /api/ext/v1/inbox/:chatId/send { text }
Header: x-nw-key: <integration_key>
```
### 4.4 Lookup chatId → conversa existente
O motor hoje não tem endpoint `GET /api/secretaria/conversations?chatId=`.
Precisará ser adicionado no motor ou o satélite usa `sec_conversations` via lookup próprio.
**Solução recomendada:** adicionar no motor:
```
GET /api/secretaria/conversations?chat_id=<chatId>&create=true
→ retorna conversa existente ou cria nova automaticamente
```
---
## 5. Arquivos impactados
| Arquivo | Frente | Mudança |
|---|---|---|
| `plugins/newwhats/webhook-receiver.js` | F2 | auto-resposta + throttle |
| `plugins/newwhats/sync-knowledge.js` | F3 | sem mudança (já funcional) |
| `database/database.js` | F2+F4 | CREATE TABLE nw_auto_replies, nw_escalations |
| `sistema-nuvem/server.js` | F3+F5 | /admin/nw/metrics |
| `admin-app/src/pages/WhatsAppInbox.tsx` | F1+F3 | estado numbers + modais + badges + sync btn |
| `admin-app/src/services/api.ts` | F3 | NwService.syncKnowledge + previewKnowledge |
| `newwhats.local/plugins/secretaria/routes.ts` | F4 | GET /conversations?chat_id= |
---
## 6. Riscos e mitigações
| Risco | Impacto | Mitigação |
|---|---|---|
| IA responde cliente errado (loop) | Alto | `fromMe=true` nunca dispara; cooldown 30s; max 5 auto/conversa |
| Knowledge desatualizado | Médio | Sync automático ao salvar promoção/vaga; preview antes do sync |
| Motor fora do ar | Alto | Fallback chain (openai→gemini→anthropic→ollama); modo `off` por padrão |
| Webhook sem HMAC | Médio | Em dev aceita sem secret + aviso; em prod bloqueia |
| chatId não mapeado para conversa | Médio | Criar conversa automaticamente no primeiro contato |
| QR code expirado no modal | Baixo | Poll a cada 2s, aviso "QR expira em 60s" |
| Escalação ignorada | Alto | Badge vermelho persistente + email de alerta (futuro) |
---
## 7. Glossário técnico deste projeto
| Termo | Significado |
|---|---|
| Motor | `newwhats.local:8008` — instância independente do NewWhats |
| Satélite | `sistema-nuvem` do alemão — proxy + regras de negócio |
| ProtocolEngine | Classe `brain.ts` — core de IA stateful com nós |
| Brain Node | Registro em `sec_brain_nodes` (persona/knowledge/rules/calendar/escalation) |
| sec_numbers | Tabela do motor com metadados dos números (role, priority, area) |
| nw_event_logs | Tabela do satélite com todos os eventos recebidos via webhook |
| integration_key | Chave usada no header `x-nw-key` para rotas `/api/ext/v1/*` |
| motorUrl | URL do motor, lida de `plugin_configs WHERE key='newwhats_url'` |
| sync-knowledge | Script que lê BD alemão e atualiza o nó knowledge da Ana |
| context_window | Número de mensagens recentes passadas ao LLM (padrão: 8) |
| protocol_number | Identificador único da conversa formato `DDMMAAHHmmss` |