From b2aa1a7712175d700439ae0f8aade5345638ccb8 Mon Sep 17 00:00:00 2001 From: Rafael Lopes Date: Wed, 27 May 2026 17:23:05 -0300 Subject: [PATCH] DOCS: Adicionado README file --- README.md | 87 ++++++++++ docs/access-control.md | 351 ----------------------------------------- docs/auth.md | 268 ------------------------------- docs/chat-whatsapp.md | 132 ---------------- 4 files changed, 87 insertions(+), 751 deletions(-) create mode 100644 README.md delete mode 100644 docs/access-control.md delete mode 100644 docs/auth.md delete mode 100644 docs/chat-whatsapp.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..286aa1f --- /dev/null +++ b/README.md @@ -0,0 +1,87 @@ +# Omnichannel Backend + +![Node.js](https://img.shields.io/badge/Node.js-20.x-green) +![NestJS](https://img.shields.io/badge/NestJS-11.x-red) +![TypeScript](https://img.shields.io/badge/TypeScript-6.x-blue) +![PostgreSQL](https://img.shields.io/badge/Database-PostgreSQL-blue) +![Socket.IO](https://img.shields.io/badge/Realtime-Socket.IO-black) +![JWT](https://img.shields.io/badge/Auth-JWT-orange) +![WhatsApp](https://img.shields.io/badge/Channel-WhatsApp-25D366) + +Backend da plataforma Omnichannel da Sothis, responsavel por autenticacao, atendimento, integracao com WhatsApp, gestao administrativa, contatos, base de conhecimento e servicos de apoio ao painel web. + +Este repositorio contem apenas a API. Para subir o projeto completo com frontend, backend e configuracao de deploy, utilize o repositorio de orquestracao: + +https://chaleiradev.sothistelecom.com/Sothis/omnichannel-deploy + +## Stack + +- Node.js +- NestJS +- TypeScript +- PostgreSQL +- Socket.IO +- whatsapp-web.js +- JSON Web Token para autenticacao +- LDAP/AD e Microsoft OAuth como provedores de login configuraveis + +## Documentacao da API + +A documentacao detalhada das rotas fica disponivel no Swagger do backend no ambiente publicado. + +Para documentacao tecnica complementar do backend, decisoes, modulos e operacao, acesse a wiki: + +https://chaleiradev.sothistelecom.com/Sothis/omnichannel-backend/wiki + +## Execucao local + +Instale as dependencias: + +```bash +npm install +``` + +Crie o arquivo de ambiente a partir do exemplo: + +```bash +cp .env.example .env.development +``` + +Configure as variaveis de banco, JWT, CORS e integracoes no `.env.development`. + +Execute em modo desenvolvimento: + +```bash +npm run dev +``` + +Por padrao, a API usa a porta configurada em `PORT` ou `BACKEND_PORT`. Se nenhuma variavel for definida, utiliza `3001`. + +## Build e producao + +Gere o build: + +```bash +npm run build +``` + +Execute a versao compilada: + +```bash +npm start +``` + +## Estrutura principal + +- `src/infra`: configuracao, banco de dados, logger e infraestrutura compartilhada. +- `src/modules/auth`: autenticacao, JWT, LDAP/AD e Microsoft OAuth. +- `src/modules/admin`: recursos administrativos, base de conhecimento, contatos e controles de acesso. +- `src/modules/whatsapp`: conexao WhatsApp, QR Code, mensagens, transferencia e eventos em tempo real. +- `src/modules/attendance`: apoio as regras de atendimento. +- `src/modules/call`, `src/modules/chat` e `src/modules/home`: modulos de apoio as telas e fluxos do frontend. + +## Observacoes + +- O banco de dados nao e criado por este repositorio. A configuracao deve apontar para uma instancia PostgreSQL existente. +- Arquivos locais como `.env*`, logs, `dist`, dumps e sessoes do WhatsApp ficam fora do Git. +- Para operacao completa, deploy e atualizacao em producao, consulte o repositorio `omnichannel-deploy`. diff --git a/docs/access-control.md b/docs/access-control.md deleted file mode 100644 index 231b922..0000000 --- a/docs/access-control.md +++ /dev/null @@ -1,351 +0,0 @@ -# Controle de Acesso, Areas e Usuarios - -## Visao geral - -O backend agora usa o banco PostgreSQL para manter o usuario interno da aplicacao e suas atribuicoes operacionais. - -A autenticacao continua sendo feita por provedores externos: - -- LDAP / Active Directory -- Microsoft OAuth - -Depois que o provedor confirma a identidade, o backend sincroniza esse usuario no banco e consulta: - -- perfis de acesso -- areas vinculadas -- area principal -- status de acesso - -Esse status determina qual experiencia o frontend deve renderizar em `/home`. - ---- - -## Fluxo de login com banco - -```text -Frontend - -> POST /auth/login ou OAuth Microsoft - -> Backend autentica no provedor externo - -> Backend cria/atualiza usuarios - -> Backend cria/atualiza usuarios_provedores - -> Backend consulta usuarios_perfis e usuarios_areas - -> Backend emite JWT com perfis/areas - -> Frontend salva authToken/authUser - -> Frontend navega para /home -``` - -O provedor externo valida identidade. O banco define acesso dentro do Omnichannel. - ---- - -## Tabelas usadas - -### `usuarios` - -Representa uma pessoa autenticada no produto. - -Campos principais: - -- `id` -- `nome` -- `email` -- `ativo` -- `created_at` -- `updated_at` - -### `usuarios_provedores` - -Relaciona o usuario interno com o provedor externo usado no login. - -Exemplos: - -- `ldap` + username do AD -- `microsoft` + userPrincipalName/email - -### `perfis_acesso` - -Define os niveis de acesso. - -Perfis iniciais: - -- `Agente` -- `Supervisor` -- `Admin` - -### `usuarios_perfis` - -Relaciona usuarios e perfis. - -Hoje o frontend usa o perfil principal para decidir a experiencia em `/home`. - -### `areas` - -Representa as areas operacionais. - -Areas iniciais: - -- `Suporte` -- `Financeiro` -- `Comercial` - -### `usuarios_areas` - -Relaciona usuarios e areas. - -Um usuario pode ter mais de uma area, mas a regra atual permite no maximo uma area principal por usuario. - ---- - -## Status de acesso - -O backend devolve `accessStatus` no usuario autenticado. - -Valores: - -- `assigned`: usuario tem pelo menos um perfil e uma area -- `unassigned`: usuario existe/autenticou, mas ainda nao tem perfil ou area - -### Comportamento no frontend - -```text -assigned + Admin -> /home renderiza painel Admin -assigned + Supervisor -> /home renderiza painel Supervisor -assigned + Agente -> /home renderiza tela do Atendente -unassigned -> /home renderiza tela de acesso aguardando configuracao -``` - -Esse comportamento permite que um usuario novo entre via AD/OAuth, seja criado no banco e fique bloqueado ate um Admin atribuir perfil e area. - ---- - -## Payload do usuario autenticado - -Exemplo de resposta do login: - -```json -{ - "token": "jwt", - "user": { - "id": "1", - "databaseId": 1, - "name": "Atendente Demo", - "email": "atendente@sothis.com.br", - "username": "atendente", - "provider": "ldap", - "perfis": ["Agente"], - "profiles": ["Agente"], - "areas": ["Suporte"], - "areaPrincipal": "Suporte", - "accessStatus": "assigned" - } -} -``` - -No JWT tambem entram: - -- `name` -- `email` -- `provider` -- `username` -- `perfis` -- `profiles` -- `areas` -- `areaPrincipal` -- `accessStatus` - ---- - -## Variaveis de ambiente - -O backend le as variaveis de banco pelo `.env.development` em desenvolvimento. - -```env -DB_HOST=10.0.120.75 -DB_PORT=5432 -DB_USER=desenvolvimento -DB_PASSWORD=******** -DB_NAME=omnichannel-dev -``` - -Observacao: - -- `npm run dev` usa `NODE_ENV=development` e carrega `.env.development`. -- `npm run start` usa `NODE_ENV=production`; nesse caso, configure `.env.production` ou variaveis do ambiente. - ---- - -## Endpoints administrativos - -Base path: - -```text -/admin/access -``` - -### Listar opcoes de acesso - -```http -GET /admin/access/options -``` - -Resposta: - -```json -{ - "profiles": [ - { "id": 3, "nome": "Admin" }, - { "id": 1, "nome": "Agente" }, - { "id": 2, "nome": "Supervisor" } - ], - "areas": [ - { "id": 3, "nome": "Comercial" }, - { "id": 2, "nome": "Financeiro" }, - { "id": 1, "nome": "Suporte" } - ] -} -``` - -### Listar usuarios - -```http -GET /admin/access/users -``` - -Resposta: - -```json -[ - { - "id": 1, - "nome": "Admin Demo", - "email": "admin@sothis.com.br", - "ativo": true, - "perfis": [{ "id": 3, "nome": "Admin" }], - "areas": [{ "id": 1, "nome": "Suporte", "principal": true }], - "perfilPrincipal": { "id": 3, "nome": "Admin" }, - "areaPrincipal": { "id": 1, "nome": "Suporte", "principal": true }, - "accessStatus": "assigned" - } -] -``` - -### Atualizar acesso de usuario - -```http -PUT /admin/access/users/:id -Content-Type: application/json -``` - -Body: - -```json -{ - "perfilId": 2, - "areaId": 1 -} -``` - -Comportamento atual: - -- remove perfis anteriores do usuario -- remove areas anteriores do usuario -- cria o novo perfil informado -- cria a nova area como principal -- retorna o usuario atualizado - -Para remover atribuicoes: - -```json -{ - "perfilId": null, - "areaId": null -} -``` - ---- - -## Usuarios de demonstracao - -A migration `003_demo_access.sql` cria usuarios iniciais para demonstracao: - -| Usuario | Email | Perfil | Area | -|---|---|---|---| -| Admin Demo | `admin@sothis.com.br` | Admin | Suporte | -| Supervisor Demo | `supervisor@sothis.com.br` | Supervisor | Suporte | -| Atendente Demo | `atendente@sothis.com.br` | Agente | Suporte | - -Esses usuarios existem no banco, mas nao substituem a autenticacao real. - -Para logar pela tela de login, o usuario precisa existir no AD ou no provedor Microsoft configurado. - ---- - -## Como testar - -### Backend - -```bash -cd backend -npm run dev -``` - -Endpoints de validacao: - -```text -http://localhost:3001/admin/access/options -http://localhost:3001/admin/access/users -``` - -### Frontend sem depender de AD - -No console do navegador: - -```js -localStorage.setItem('authUser', JSON.stringify({ - username: 'admin@sothis.com.br', - name: 'Admin Demo', - email: 'admin@sothis.com.br', - perfis: ['Admin'], - profiles: ['Admin'], - areas: ['Suporte'], - accessStatus: 'assigned' -})); -localStorage.setItem('authToken', 'dev-token'); -location.href = '/home'; -``` - -Para usuario sem atribuicao: - -```js -localStorage.setItem('authUser', JSON.stringify({ - username: 'novo.usuario', - name: 'Novo Usuario', - email: 'novo.usuario@sothis.com.br', - perfis: [], - profiles: [], - areas: [], - accessStatus: 'unassigned' -})); -localStorage.setItem('authToken', 'dev-token'); -location.href = '/home'; -``` - ---- - -## Limitacoes atuais - -- Os endpoints `/admin/access/*` ainda nao possuem guard JWT nem checagem de perfil Admin. -- A alteracao de acesso substitui perfil/area atuais por um unico perfil e uma unica area principal. -- Ainda nao ha auditoria das alteracoes de acesso. -- O painel Admin consome os endpoints reais, mas ainda possui fallback visual mockado se o backend estiver indisponivel. -- A senha do banco nao deve ser commitada; arquivos `.env.*` seguem ignorados pelo Git. - ---- - -## Proximos passos sugeridos - -- Adicionar `AuthGuard` JWT. -- Proteger `/admin/access/*` para `Admin`. -- Registrar auditoria em `logs_auditoria`. -- Criar endpoints CRUD completos para `areas`. -- Permitir multiplas areas por usuario na UI, mantendo uma area principal. diff --git a/docs/auth.md b/docs/auth.md deleted file mode 100644 index 386eb56..0000000 --- a/docs/auth.md +++ /dev/null @@ -1,268 +0,0 @@ -# Módulo de Autenticação - -## Visão geral - -O módulo `auth` centraliza toda a lógica de autenticação do Omnichannel. Ele suporta múltiplos provedores de identidade e emite JWT próprio da aplicação, independente de qual provedor foi usado. - -Provedores implementados: - -- **LDAP / Active Directory** — login com usuário e senha do AD corporativo -- **Microsoft OAuth (Entra ID)** — login via conta Microsoft com redirect OAuth 2.0 - -A arquitetura foi desenhada para facilitar a adição de novos provedores no futuro. - ---- - -## Estrutura de arquivos - -``` -src/modules/auth/ -├── auth.module.ts # Registro do módulo no NestJS -├── auth.controller.ts # Rotas HTTP -├── auth.service.ts # Fachada — delega para os providers -├── auth.config.ts # Leitura de variáveis de ambiente -├── auth-token.service.ts # Emissão de JWT da aplicação -├── auth.types.ts # Interfaces TypeScript compartilhadas -└── providers/ - ├── ldap-auth.provider.ts # Autenticação LDAP/AD - ├── microsoft-oauth.provider.ts # Autenticação Microsoft OAuth - └── oauth-state.service.ts # Proteção CSRF para OAuth -``` - ---- - -## Rotas disponíveis - -| Método | Rota | Descrição | -|--------|---------------------------------|------------------------------------------------| -| GET | `/auth/config` | Retorna quais provedores estão habilitados | -| POST | `/auth/login` | Login com usuário e senha (LDAP/AD) | -| GET | `/auth/oauth/microsoft/start` | Inicia o fluxo OAuth com a Microsoft | -| GET | `/auth/oauth/microsoft/callback`| Callback que a Microsoft chama após o login | - ---- - -## Variáveis de ambiente - -```env -# Servidor -PORT=3001 -FRONTEND_URL=http://localhost:3000 - -# JWT -JWT_SECRET=uma-chave-longa-e-aleatoria -JWT_EXPIRES_IN=8h - -# Provedores ativos (separados por vírgula) -AUTH_PROVIDERS=ldap - -# LDAP / Active Directory -LDAP_ENABLED=true -LDAP_URL=ldaps://servidor-ad:636 -LDAP_DOMAIN=empresa.com.br -LDAP_USER_DN_TEMPLATE={{username}}@empresa.com.br -LDAP_SEARCH_BASE=DC=empresa,DC=com -LDAP_SEARCH_FILTER=(&(objectClass=user)(sAMAccountName={{username}})) -LDAP_TIMEOUT_MS=5000 - -# Microsoft Entra ID (desabilitado por padrão) -MICROSOFT_ENABLED=false -MICROSOFT_TENANT_ID=common -MICROSOFT_CLIENT_ID= -MICROSOFT_CLIENT_SECRET= -MICROSOFT_REDIRECT_URI=http://localhost:3001/auth/oauth/microsoft/callback -MICROSOFT_SUCCESS_REDIRECT_URL=http://localhost:3000/login -``` - -> `JWT_SECRET` deve ser uma string longa e aleatória. Em produção, nunca use o valor padrão do `.env.development`. - ---- - -## Fluxo LDAP / Active Directory - -``` -Frontend - → POST /auth/login { username, password } - → AuthController - → AuthService.loginWithLdap() - → LdapAuthProvider.authenticate() - → Conecta no servidor AD (LDAP_URL) - → Faz bind com o usuário e senha - → Se o bind falhar: UnauthorizedException - → Busca dados do usuário no diretório (se LDAP_SEARCH_BASE configurado) - → Monta objeto AuthenticatedUser - → AuthTokenService.issueToken() - → Gera JWT assinado com JWT_SECRET - → Retorna { token, user } para o frontend -``` - -O AD apenas valida a identidade. O JWT emitido é da aplicação, não do AD. - ---- - -## Fluxo Microsoft OAuth - -``` -1. Frontend redireciona para GET /auth/oauth/microsoft/start - → Backend gera um state assinado (proteção CSRF) - → Backend redireciona para login.microsoftonline.com - -2. Usuário autentica na Microsoft - -3. Microsoft chama GET /auth/oauth/microsoft/callback?code=...&state=... - → Backend valida o state (assinatura + expiração) - → Backend troca o code por access_token (chamada server-to-server) - → Backend consulta Microsoft Graph /me para obter dados do usuário - → AuthTokenService.issueToken() gera JWT próprio - → Backend redireciona para MICROSOFT_SUCCESS_REDIRECT_URL?token=... - -4. Frontend salva o token e navega para /home -``` - ---- - -## Proteção CSRF com OAuth State - -O `OAuthStateService` protege o fluxo OAuth contra ataques de CSRF. - -**Como funciona:** - -1. No início do fluxo, o backend cria um state: - - Gera um nonce aleatório + timestamp - - Converte para base64url - - Assina com HMAC-SHA256 usando o `JWT_SECRET` - - Formato final: `payload.assinatura` - -2. No callback, o backend verifica: - - O state tem os dois pedaços (`payload.assinatura`) - - A assinatura é válida (recalcula e compara com `timingSafeEqual`) - - O state não expirou (padrão: 10 minutos, configurável via `MICROSOFT_STATE_MAX_AGE_MS`) - -Se qualquer verificação falhar, o callback é rejeitado com `400 Bad Request`. - ---- - -## JWT da aplicação - -Após qualquer autenticação bem-sucedida, o `AuthTokenService` emite um JWT com o seguinte payload: - -```json -{ - "sub": "identificador-do-usuario", - "name": "Nome Completo", - "email": "usuario@empresa.com", - "provider": "ldap", - "username": "usuario" -} -``` - -O `sub` é atualmente o email ou identificador externo. Quando houver banco de dados, deve ser substituído pelo ID interno da tabela `users`. - ---- - -## Como adicionar um novo provedor - -1. Crie o arquivo em `src/modules/auth/providers/novo-provedor.provider.ts`: - -```typescript -import { Injectable } from '@nestjs/common'; -import { AuthConfigService } from '../auth.config'; -import { AuthTokenService } from '../auth-token.service'; -import { AuthResult } from '../auth.types'; - -@Injectable() -export class NovoProvedorProvider { - constructor( - private readonly authConfig: AuthConfigService, - private readonly authToken: AuthTokenService, - ) {} - - async authenticate(/* dados necessários */): Promise { - // 1. Valide as credenciais no provedor externo - // 2. Monte o objeto AuthenticatedUser - // 3. Emita o token com this.authToken.issueToken(user) - // 4. Retorne { token, user } - } -} -``` - -2. Registre o provider em `auth.module.ts`: - -```typescript -providers: [ - AuthConfigService, - AuthService, - AuthTokenService, - LdapAuthProvider, - MicrosoftOAuthProvider, - OAuthStateService, - NovoProvedorProvider, // adicione aqui -], -``` - -3. Injete no `AuthService` e exponha o método necessário: - -```typescript -constructor( - private readonly authConfig: AuthConfigService, - private readonly ldapAuthProvider: LdapAuthProvider, - private readonly microsoftOAuthProvider: MicrosoftOAuthProvider, - private readonly novoProvedorProvider: NovoProvedorProvider, // injete aqui -) {} - -loginComNovoProvedor(dados: any) { - return this.novoProvedorProvider.authenticate(dados); -} -``` - -4. Adicione a rota no `AuthController`. - -5. Se o provedor precisar de configuração, adicione as variáveis no `AuthConfigService` e no `.env`. - ---- - -## Diagnóstico de problemas - -### Login LDAP falha com `UnauthorizedException` - -- Verifique se `LDAP_URL` está acessível a partir do servidor backend -- Confirme que `LDAP_DOMAIN` ou `LDAP_USER_DN_TEMPLATE` está correto -- Teste a conectividade: `ldapsearch -H ldaps://servidor:636 -x` -- Verifique `LDAP_TIMEOUT_MS` — servidores lentos podem estar expirando -- O erro é genérico intencionalmente para não vazar informações. Adicione um `console.log(_error)` temporário no `catch` do `ldap-auth.provider.ts` para ver o erro real - -### Login Microsoft falha com `400 Bad Request` - -- O state expirou (padrão: 10 minutos). Se o usuário demorou muito na tela da Microsoft, repita o fluxo -- Verifique se `MICROSOFT_REDIRECT_URI` no `.env` é idêntico ao cadastrado no Azure App Registration -- Confirme que `MICROSOFT_CLIENT_ID` e `MICROSOFT_CLIENT_SECRET` estão corretos e não expiraram - -### Token inválido no frontend - -- Verifique se `JWT_SECRET` não mudou entre deploys — isso invalida todos os tokens emitidos anteriormente -- Confirme que o frontend está enviando o header `Authorization: Bearer ` - -### `GET /auth/config` retorna os provedores errados - -- Verifique `LDAP_ENABLED` e `MICROSOFT_ENABLED` no `.env` -- Reinicie o servidor — variáveis de ambiente são lidas na inicialização - ---- - -## O que ainda falta para produção - -- [ ] Tabela `users` no banco de dados -- [ ] Tabela `auth_identities` para vincular provedores externos ao usuário interno -- [ ] `sub` do JWT usando ID interno do banco, não email externo -- [ ] Guard NestJS para proteger rotas privadas (`@UseGuards(AuthGuard)`) -- [ ] Roles e permissões -- [ ] Auditoria de login -- [ ] Trocar token na query string por cookie HTTP-only (reduz exposição no browser) - ---- - -## Documentacao complementar - -A sincronizacao de usuarios autenticados com o banco, os perfis de acesso, as areas operacionais e os endpoints administrativos estao documentados em: - -- [`access-control.md`](./access-control.md) diff --git a/docs/chat-whatsapp.md b/docs/chat-whatsapp.md deleted file mode 100644 index a42918d..0000000 --- a/docs/chat-whatsapp.md +++ /dev/null @@ -1,132 +0,0 @@ -# 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.