133 lines
4.6 KiB
Markdown
133 lines
4.6 KiB
Markdown
|
|
# Modulo de Chat WhatsApp (Backend)
|
||
|
|
|
||
|
|
## Visao geral
|
||
|
|
|
||
|
|
O modulo de WhatsApp do backend e desenvolvido em **NestJS** e utiliza a biblioteca **whatsapp-web.js** (que roda uma instancia headless do Chromium via **Puppeteer**) para integrar a aplicacao diretamente com o WhatsApp Web em tempo real.
|
||
|
|
|
||
|
|
A arquitetura e constituida por quatro pilares:
|
||
|
|
1. **Puppeteer Client**: Controla o WhatsApp Web, gera o QR Code para autenticacao e escuta eventos de novas mensagens.
|
||
|
|
2. **WebSocket Gateway**: Transmite eventos em tempo real (novas mensagens, atualizacao de status) para o frontend usando Socket.io.
|
||
|
|
3. **Persistencia Hibrida**: Mantem conversas indexadas localmente via JSON para performance e o status de atribuicao de atendimento gravado no banco relacional (PostgreSQL).
|
||
|
|
4. **Servico de Atribuicao**: Gerencia o vinculo dos chats com os atendentes (`usuarios`) e suas respectivas `areas` operacionais.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Fluxo de Eventos e Mensagens
|
||
|
|
|
||
|
|
### 1. Inicializacao e Conexao
|
||
|
|
* O backend inicia o cliente do `whatsapp-web.js` na porta configurada.
|
||
|
|
* Se nenhuma sessao ativa for encontrada na pasta `/whatsapp-session`, o cliente gera um QR Code em formato Base64.
|
||
|
|
* Esse QR Code e enviado via WebSocket (`qr`) para o frontend configurar o dispositivo.
|
||
|
|
* Uma vez conectado, o status muda para `CONNECTED` e a pasta de sessao e gravada localmente.
|
||
|
|
|
||
|
|
### 2. Captura de Mensagens (`message_create`)
|
||
|
|
Utilizamos o evento global `message_create` para capturar tanto mensagens recebidas do cliente quanto mensagens enviadas pelo proprio atendente (seja pela tela ou por outro dispositivo sincronizado):
|
||
|
|
|
||
|
|
```text
|
||
|
|
Puppeteer (Message)
|
||
|
|
-> Trata de-duplicacao ou broadcast
|
||
|
|
-> Se possuir midia, baixa os buffers em tempo real
|
||
|
|
-> Transmite via WebSocket 'message' para o frontend
|
||
|
|
-> Salva ou atualiza a conversa na persistencia local JSON
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Persistencia e Banco de Dados
|
||
|
|
|
||
|
|
### 1. Cache Local JSON (`whatsapp-chats-persist.json`)
|
||
|
|
Para evitar sobrecarregar o banco relacional e garantir latencias imperceptiveis de scroll, os chats e seus metadados de visualizacao sao armazenados de forma persistente em um arquivo JSON local na raiz do backend.
|
||
|
|
|
||
|
|
### 2. Tabela de Atribuicao de Chat (`whatsapp_chat_atribuicoes`)
|
||
|
|
O controle de quem esta atendendo qual chat e estritamente transacional e reside no banco PostgreSQL.
|
||
|
|
|
||
|
|
A estrutura da tabela e criada pela migration `004_whatsapp.sql`:
|
||
|
|
|
||
|
|
```sql
|
||
|
|
CREATE TABLE IF NOT EXISTS whatsapp_chat_atribuicoes (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
chat_id VARCHAR(255) NOT NULL,
|
||
|
|
user_id SERIAL REFERENCES usuarios(id) ON DELETE CASCADE,
|
||
|
|
area_id SERIAL REFERENCES areas(id) ON DELETE SET NULL,
|
||
|
|
assigned_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
UNIQUE(chat_id)
|
||
|
|
);
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Regras de Atribuicao:
|
||
|
|
* `chat_id`: Identificador unico da conversa no WhatsApp (ex: `5511999999999@c.us` ou `...@lid`).
|
||
|
|
* `user_id`: ID inteiro (`usuarios.id`) do atendente que assumiu.
|
||
|
|
* `area_id`: ID inteiro (`areas.id`) do setor sob o qual o atendimento esta sendo prestado (ex: `1` para Suporte).
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Endpoints do Modulo
|
||
|
|
|
||
|
|
Base path: `/whatsapp`
|
||
|
|
|
||
|
|
### 1. Enviar Mensagem
|
||
|
|
```http
|
||
|
|
POST /whatsapp/send
|
||
|
|
Content-Type: application/json
|
||
|
|
```
|
||
|
|
**Payload**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"to": "5511999999999@c.us",
|
||
|
|
"message": "Ola, tudo bem?",
|
||
|
|
"media": {
|
||
|
|
"data": "base64String...",
|
||
|
|
"mimetype": "image/png",
|
||
|
|
"filename": "comprovante.png"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Atribuir Chat
|
||
|
|
```http
|
||
|
|
POST /whatsapp/assign
|
||
|
|
Content-Type: application/json
|
||
|
|
```
|
||
|
|
**Payload**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"chatId": "5511999999999@c.us",
|
||
|
|
"userId": 4,
|
||
|
|
"areaId": 1
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Liberar Chat
|
||
|
|
```http
|
||
|
|
DELETE /whatsapp/release/:chatId
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Limitacoes e Solucoes de Bugs
|
||
|
|
|
||
|
|
### 1. Payload Too Large (Upload de Midia)
|
||
|
|
Para permitir o envio de imagens, videos e audios pesados codificados em Base64, o limite padrao de payload do NestJS foi estendido para **50MB** no `main.ts` tanto para formato JSON quanto para `urlencoded`.
|
||
|
|
|
||
|
|
### 2. Nomes Numericos do WhatsApp (Smart Name Resolution)
|
||
|
|
Devido a latencias do WhatsApp Web, as mensagens recebidas as vezes reportam apenas o telefone/JID como nome do contato. O servico de WhatsApp contem uma camada reativa de reparacao automatica:
|
||
|
|
* Checa se o nome e puramente numerico.
|
||
|
|
* Se for, faz uma chamada em background para o Puppeteer (`client.getContactById`) para obter o `notifyName` real do cliente e atualizar o cache local.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Como Rodar e Testar
|
||
|
|
|
||
|
|
### Requisitos locais
|
||
|
|
* Node.js v18+
|
||
|
|
* PostgreSQL ativo com as migrations executadas
|
||
|
|
* Google Chrome ou Chromium instalado (o Puppeteer tentara usar o bundle local se omitido)
|
||
|
|
|
||
|
|
### Executando em desenvolvimento
|
||
|
|
```bash
|
||
|
|
cd backend
|
||
|
|
npm run dev
|
||
|
|
```
|
||
|
|
|
||
|
|
Os logs do NestJS no terminal indicarao as fases de inicializacao do Puppeteer, geracao de QR Code ou recuperacao de sessao ativa.
|