docs: add comprehensive system, plugins and infrastructure wiki documentation
@@ -0,0 +1,41 @@
|
||||
# 💬 Troca do Engine Baileys
|
||||
|
||||
## 1. Problema de Renderização no WhatsApp Web
|
||||
As mensagens ricas (contendo botões interativos, listas de seleção e carrosséis) não são nativamente exibidas no WhatsApp Web utilizando a biblioteca oficial `@whiskeysockets/baileys`. O WhatsApp Web exige nós binários adicionais de metadados de negócios injetados no stanza que a biblioteca oficial descarta.
|
||||
|
||||
---
|
||||
|
||||
## 2. A Solução: InfiniteAPI Engine Swap com Fallback
|
||||
Para solucionar essa limitação e habilitar botões interativos perfeitamente no celular e na web, foi desenhada a integração do fork **InfiniteAPI** (`baileys@github:rsalcara/InfiniteAPI`), mantendo suporte e chaveamento fácil para o Baileys oficial em caso de depuração.
|
||||
|
||||
### Arquitetura de Abstração:
|
||||
A pasta `backend/src/modules/whatsapp/engine/` expõe uma interface unificada que gerencia dinamicamente o chaveamento através da variável de ambiente `BAILEYS_ENGINE`:
|
||||
|
||||
* **infinite.ts**: Re-exporta a biblioteca `baileys` (InfiniteAPI), que gerencia nativamente botões, listas e carrosséis dentro de `sock.sendMessage()`.
|
||||
* **official.ts**: Re-exporta a biblioteca `@whiskeysockets/baileys` estável do ecossistema.
|
||||
* **index.ts**: Carrega o adaptador correspondente à variável configurada.
|
||||
|
||||
---
|
||||
|
||||
## 3. Configuração no Arquivo `.env`
|
||||
Para alternar entre os motores de conexão do WhatsApp, basta editar o parâmetro no arquivo de configuração do backend:
|
||||
|
||||
```bash
|
||||
# Escolha do motor Baileys
|
||||
BAILEYS_ENGINE=infinite # Opções: 'infinite' ou 'official'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Tipos de Botões Suportados pelo InfiniteAPI
|
||||
O motor InfiniteAPI simplifica o envio de botões, tratando toda a montagem estrutural em baixo nível. O desenvolvedor passa os payloads no seguinte formato:
|
||||
|
||||
```typescript
|
||||
type NativeButton =
|
||||
| { type: 'reply'; id: string; text: string } // Resposta rápida
|
||||
| { type: 'url'; text: string; url: string } // Link externo
|
||||
| { type: 'copy'; text: string; copyText: string } // Copiar texto para área de transferência
|
||||
| { type: 'call'; text: string; phoneNumber: string } // Disparar ligação telefônica
|
||||
```
|
||||
|
||||
A troca de engine reinicia o processo do backend de forma segura e reconecta instantaneamente todas as sessões em cerca de 5 a 10 segundos, preservando o estado de autenticação guardado em disco.
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
# 🌐 Bem-vindo à Wiki do Clube67 NewWhats
|
||||
|
||||
Esta Wiki centraliza toda a documentação arquitetural, resoluções de erros de infraestrutura, controle de versionamento, gerenciamento de plugins e integrações de microsserviços do ecossistema **NewWhats**.
|
||||
|
||||
---
|
||||
|
||||
## 📂 Categorias de Documentação
|
||||
|
||||
Selecione um tópico abaixo para acessar o guia detalhado:
|
||||
|
||||
### ⚙️ 1. Infraestrutura e Rede
|
||||
* [Resolução de Erros de SSL e Proxy](SSL_Proxy_SSL_Fix.md): Como corrigimos o erro crítico de Mixed Content do SSL por proxy reverso.
|
||||
* [Contador de Versões e Painel de Deploy](Versions_Deploy_System.md): Detalhamento do controle de deploys automáticos em ambiente multi-VPS.
|
||||
|
||||
### 🔌 2. Arquitetura de Plugins e Core
|
||||
* [Sincronização de Caminhos de Plugins](Plugins_Production_Loader.md): Como configurar caminhos relativos de importação em produção (Docker vs Host) de forma automática.
|
||||
* [Troca do Engine Baileys](Baileys_Engine_Swap.md): Comparação e controle entre a engine Baileys Oficial e o fork InfiniteAPI para mensagens ricas.
|
||||
* [Correção de Wasabi Storage](Wasabi_Storage_Correction.md): Detalhes da resolução de acúmulo de arquivos de mídia locais no servidor Wasabi.
|
||||
|
||||
### 🏢 3. Integração Multi-Tenant SaaS
|
||||
* [Integração de Empresa e Plugins Clientes](Plugin_Empresa_Integration.md): Visão geral da comunicação entre o Motor NewWhats e o plugin `newwhats-client` embarcado.
|
||||
|
||||
---
|
||||
|
||||
## 🤖 Protocolo Gitea Swarm (PGS)
|
||||
O ecossistema adota segurança **Zero-Trust de movimentação lateral** (impedindo que agentes em uma VPS acessem outras máquinas via SSH automático). O Gitea atua como o **Orquestrador de Estado Assíncrono** do enxame de agentes.
|
||||
|
||||
Para mais detalhes sobre as regras de cooperação de IAs no projeto, consulte o arquivo [protocolo_agentes.md](file:///home/deploy/stack/clube67/newwhats.local/protocolo_agentes.md).
|
||||
@@ -0,0 +1,50 @@
|
||||
# 🏢 Integração de Empresa e Plugins Clientes
|
||||
|
||||
A arquitetura do NewWhats permite funcionar como um **Motor SaaS Multi-tenant** centralizado de mensagens e assistentes de Inteligência Artificial, servindo múltiplos satélites de forma isolada e segura.
|
||||
|
||||
---
|
||||
|
||||
## 1. Visão Geral do Ecossistema
|
||||
O NewWhats (servidor motor) centraliza as conexões com o WhatsApp (Baileys), logs, controle de mensagens, armazenamento remoto e o motor de Inteligência Artificial (Secretária IA).
|
||||
|
||||
Os sistemas satélites integrados (como o Alemão Conveniências ou outros ERPs/CRMs) comunicam-se de forma leve com o motor central usando o plugin `newwhats-client`, sem necessidade de rodar bibliotecas WhatsApp locais.
|
||||
|
||||
```text
|
||||
[ Servidor NewWhats ] [ Servidor da Empresa / Satélite ]
|
||||
Plugin: secretaria ←→ Plugin: newwhats-client
|
||||
- Secretária IA - CRUD de Dados Internos (Agenda)
|
||||
- WhatsApp / Baileys - Agente de consulta local
|
||||
- Inbox / Sessions - Frontend embarcado via iframe
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Autenticação e Chaves de Integração
|
||||
* A autenticação é realizada utilizando a chave compartilhada `integration_key` (JWT).
|
||||
* O cabeçalho de requisição é preenchido no formato `Authorization: Bearer <integration_key>`.
|
||||
* O isolamento multi-tenant garante que cada `integration_key` resolva apenas para o `user_id` e instâncias do WhatsApp (`allowed_sessions[]`) pertencentes àquele tenant de forma restrita.
|
||||
|
||||
---
|
||||
|
||||
## 3. Endpoints de Integração (`/api/ext/v1/*`)
|
||||
O motor expõe uma API robusta para os satélites consumirem e sincronizarem conversas:
|
||||
|
||||
* `GET /sessions`: Lista todas as conexões WhatsApp do tenant.
|
||||
* `POST /sessions`: Cria e inicia nova sessão.
|
||||
* `DELETE /sessions/:id`: Desconecta e apaga sessão.
|
||||
* `GET /inbox?session=ID`: Retorna os chats da sessão com snapshot da última mensagem.
|
||||
* `GET /inbox/:chatId/messages`: Recupera o histórico paginado de mensagens.
|
||||
* `POST /inbox/:chatId/send`: Envia mensagens simples ou ricas (botões/listas).
|
||||
* `POST /secretaria/ask`: Envia uma mensagem à Secretária IA para processamento contextual de conversação e controle de modo Handoff (IA vs Atendimento Humano).
|
||||
|
||||
---
|
||||
|
||||
## 4. Integração de Dados do Cliente (CRM/ERP)
|
||||
A Secretária IA precisa interagir com dados em tempo real da empresa (como agendar horários, buscar cadastro de clientes ou produtos). Para isso, o plugin local da empresa (`newwhats-client`) expõe uma API interna para o motor central consultar:
|
||||
|
||||
* `GET /nw/agenda?data=YYYY-MM-DD`: Consulta horários livres.
|
||||
* `POST /nw/agenda/agendar`: Grava novo agendamento no banco local da empresa.
|
||||
* `GET /nw/cliente?telefone=...`: Recupera ficha cadastral do cliente pelo número de WhatsApp.
|
||||
* `POST /nw/cliente`: Registra novo lead/contato no banco local.
|
||||
|
||||
Esta comunicação garante que dados confidenciais e críticos permaneçam seguros dentro do servidor da empresa e apenas informações autorizadas sejam repassadas em tempo real à Inteligência Artificial!
|
||||
@@ -0,0 +1,54 @@
|
||||
# 🔌 Sincronização de Caminhos de Plugins
|
||||
|
||||
Os plugins do NewWhats são compilados junto com o sistema central e carregados dinamicamente na VPS 1 de produção.
|
||||
|
||||
---
|
||||
|
||||
## 1. O Desafio dos Caminhos Relativos
|
||||
Durante o desenvolvimento local, os plugins residem na pasta `/plugins/<nome-do-plugin>/` e dependem de caminhos relativos para importar módulos do núcleo do backend, ex:
|
||||
`import { PluginContext } from '../../backend/src/core/types'`
|
||||
|
||||
No entanto, no container Docker de produção na VPS 1:
|
||||
1. O backend compilado está localizado em `/app/dist/`.
|
||||
2. A pasta `/app/backend/src/` **não existe** no container.
|
||||
3. Isso fazia com que os plugins compilados quebrassem no boot do servidor com o erro:
|
||||
`Error: Cannot find module '../../backend/src/...`
|
||||
|
||||
---
|
||||
|
||||
## 2. A Solução Dinâmica e Compatível
|
||||
Desenvolvemos uma estratégia elegante e resiliente para resolver as importações tanto em desenvolvimento quanto em produção:
|
||||
|
||||
### A) Distinção entre Tipos e Códigos de Runtime
|
||||
* No TypeScript, todas as importações que apenas utilizam **tipos** (como `import type { PluginContext }`) são inteiramente eliminadas pelo compilador durante a geração do Javascript final. Portanto, essas importações podem continuar utilizando os caminhos normais de desenvolvimento.
|
||||
* Para códigos executáveis (como helpers, caches, providers), implementamos a resolução dinâmica baseada na variável de ambiente `NODE_ENV`.
|
||||
|
||||
### B) Exemplo de Implementação de Require Dinâmico
|
||||
Para o plugin de armazenamento (`UnifiedStorageProvider`), a importação do `storageProvider` foi atualizada da seguinte forma:
|
||||
|
||||
```typescript
|
||||
let storageProvider: any;
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
storageProvider = require('../../dist/core/StorageProvider').storageProvider;
|
||||
} else {
|
||||
storageProvider = require('../../backend/src/core/StorageProvider').storageProvider;
|
||||
}
|
||||
```
|
||||
|
||||
O mesmo padrão foi aplicado com sucesso em:
|
||||
* **nanobana**: Utilizando o `PluginContext` para recuperar chaves de configuração dinamicamente e eliminando imports estáticos.
|
||||
* **leads**: Atualizando a importação de middlewares centrais de autenticação (`auth` e `rbac`).
|
||||
* **ext-api**: Atualizando a resolução das dependências `dragonfly` e `sendRichMessage` apontando para o subdiretório `dist` em produção.
|
||||
|
||||
---
|
||||
|
||||
## 3. Automação de Compilação
|
||||
Configuramos o arquivo [tsconfig.json](file:///home/deploy/stack/clube67/newwhats.local/plugins/tsconfig.json) de plugins mapeando os caminhos de dependências externas para o `node_modules` do backend:
|
||||
|
||||
```json
|
||||
"paths": {
|
||||
"*": ["../backend/node_modules/*"]
|
||||
}
|
||||
```
|
||||
|
||||
O script `deploy-prod-builder.sh` agora compila automaticamente todos os plugins em lotes utilizando o compilador TS local e realiza o sincronismo dos arquivos Javascript finais (`.js` e `.js.map`) para o diretório `/app/plugins` do container Docker, carregando todos os 8 plugins ativos de forma limpa e transparente!
|
||||
@@ -0,0 +1,29 @@
|
||||
# 🔒 Resolução de Erros de SSL e Proxy
|
||||
|
||||
## 1. O Problema
|
||||
Ao tentar efetuar login e realizar requisições no front-end em produção, o navegador retornava o seguinte erro de segurança:
|
||||
```text
|
||||
_app-d57b3f0b1dd5b1c0.js:1 Mixed Content: The page at 'https://clube67.com/login' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://newwhats.local:8008/api/auth/login'. This content should also be served over HTTPS.
|
||||
```
|
||||
|
||||
### Causa Raiz
|
||||
O frontend do NewWhats rodava sobre **HTTPS** (`https://clube67.com`). No entanto, as chamadas de API feitas pelo cliente no navegador apontavam estaticamente para `http://newwhats.local:8008`, que é um domínio local e não possui certificado SSL válido. Como os navegadores modernos bloqueiam chamadas HTTP inseguras a partir de páginas HTTPS, as requisições falhavam devido ao bloqueio de **Mixed Content**.
|
||||
|
||||
---
|
||||
|
||||
## 2. A Solução Arquitetural
|
||||
Para solucionar este erro de forma limpa e permanente sem expor portas extras e sem complexidade de múltiplos certificados SSL:
|
||||
|
||||
### Passos da Implementação:
|
||||
1. **Configuração de Proxy Reverso no Nginx**: Configurado o proxy reverso do Nginx na VPS 1 de produção de forma que qualquer chamada feita para `https://clube67.com/api` seja internamente direcionada para `http://localhost:8008/api` dentro da rede local segura.
|
||||
2. **Reconfiguração do BaseURL no Front-end**: O arquivo de configuração do Axios/Fetch foi ajustado para apontar para caminhos relativos:
|
||||
* Em produção: `/api` (que automaticamente herda `https://clube67.com/api`)
|
||||
* Em desenvolvimento: `http://localhost:8008/api`
|
||||
3. **Redirecionamento de WebSocket Seguro (`wss://`)**: Configurado o Socket.io para estabelecer conexões sobre `wss://` de forma nativa utilizando a porta padrão HTTPS.
|
||||
|
||||
---
|
||||
|
||||
## 3. Benefícios
|
||||
* **SSL Unificado**: Não há necessidade de obter ou gerenciar certificados SSL adicionais para o backend.
|
||||
* **Segurança Reforçada**: O backend não precisa ter portas adicionais (como a `8008`) expostas diretamente para a internet pública, pois todo o tráfego passa de forma segura e protegida pelo Nginx.
|
||||
* **Estabilidade**: O erro de Mixed Content foi 100% mitigado para todos os navegadores.
|
||||
@@ -0,0 +1,41 @@
|
||||
# 🔢 Contador de Versões e Painel de Deploy
|
||||
|
||||
O NewWhats conta com um sistema de versionamento automatizado e monitoramento integrado diretamente no painel administrativo (Admin settings).
|
||||
|
||||
---
|
||||
|
||||
## 1. Funcionamento do Versionamento Automático (`v1.+1`)
|
||||
|
||||
A cada ciclo de build executado na **VPS 4 (Build Server)**, o script `deploy-prod-builder.sh` incrementa automaticamente as versões e constrói o histórico de deploys:
|
||||
|
||||
1. Executa o script auxiliar `update-version.js` na raiz do projeto.
|
||||
2. Esse script lê o histórico em `deploys.json`.
|
||||
3. Incrementa o contador de builds (Ex: `#7` -> `#8`).
|
||||
4. Incrementa a versão semântica de forma menor, ex: `v1.0.7` -> `v1.0.8`.
|
||||
5. Registra metadados cruciais do commit atual do Git:
|
||||
* Código de Hash do Commit.
|
||||
* Mensagem do último commit.
|
||||
* Autor do Deploy.
|
||||
* Carimbo de data/hora exato do deploy.
|
||||
6. Grava arquivos finais:
|
||||
* `version.json` e `deploys.json` (usados pelo Backend).
|
||||
* `frontend/public/version.json` e `frontend/public/deploys.json` (consumidos pelo Frontend).
|
||||
|
||||
---
|
||||
|
||||
## 2. A Interface do Usuário (Painel de Deploys)
|
||||
|
||||
Integrado perfeitamente nas Configurações do Administrador, adicionamos uma aba dedicada a **Versões**, que exibe com design moderno e premium (gradientes vibrantes e micro-animações):
|
||||
|
||||
* **Versão Ativa**: Exibe a versão ativa atual (ex: `v1.0.8`) com o respectivo número de build (`build #8`).
|
||||
* **Último Commit**: Mostra o hash abreviado e a mensagem do último commit que disparou o deploy atual.
|
||||
* **Histórico de Deploys**: Uma tabela organizada exibindo o histórico cronológico de todos os deploys efetuados, seus status, data/hora e mensagem explicativa.
|
||||
* **Disparo Manual Webhook**: Um botão "Verificar atualizações" que consome o endpoint `/deploys/trigger` do backend, disparando de forma assíncrona o webhook de deploy automático na VPS 4 com pooling de progresso dinâmico na tela.
|
||||
|
||||
---
|
||||
|
||||
## 3. Segurança e Sincronização GitOps
|
||||
|
||||
Para garantir total consistência e impedir perda de dados:
|
||||
* O script de build executa `git fetch` e `git reset --hard origin/main` antes de compilar.
|
||||
* **Regra Fundamental**: Qualquer alteração para entrar em produção deve ser primeiramente comitada localmente e empurrada para o repositório Gitea (`git push origin main`). O script de deploy puxará as alterações atualizadas do servidor Git de forma automatizada e segura!
|
||||
@@ -0,0 +1,46 @@
|
||||
# 📦 Correção Wasabi Storage
|
||||
|
||||
## 1. Contexto e Diagnóstico
|
||||
O plugin de armazenamento `UnifiedStorageProvider` estava configurado para enviar mídias de mensagens recebidas e enviadas do WhatsApp para o Wasabi. Entretanto, os arquivos continuavam acumulando localmente no diretório do servidor (`backend/media`), consumindo espaço em disco desnecessariamente.
|
||||
|
||||
Identificamos e corrigimos 4 falhas críticas no comportamento de armazenamento:
|
||||
|
||||
### ❌ Falha 1 — Ausência de Limpeza Local
|
||||
Os arquivos de mídia eram carregados com sucesso no Wasabi S3, mas o arquivo temporário local no servidor nunca era deletado.
|
||||
* **Correção**: Implementado `fs.unlink()` assíncrono para apagar o arquivo local imediatamente após o upload remoto bem-sucedido.
|
||||
|
||||
### ❌ Falha 2 — Caminho de Mídia Inconsistente no Banco de Dados
|
||||
A coluna `mediaPath` no banco persistia com o caminho local do arquivo (`/home/deploy/...`). Como o arquivo agora é apagado da máquina após o envio para a nuvem, isso causava erros ao tentar ler mídias locally.
|
||||
* **Correção**: Quando a mídia é remota, a coluna `mediaPath` é salva como `null` no banco de dados, e a recuperação é feita de forma exclusiva pelo endereço do `mediaUrl` que aponta para o bucket remoto do Wasabi.
|
||||
|
||||
### ❌ Falha 3 — Handlers Duplicados ao Reconfigurar
|
||||
O salvamento de configurações do painel admin reativava o plugin chamando o método `activate()`. Isso registrava novas instâncias de rotas do Express na memória do servidor a cada clique em salvar.
|
||||
* **Correção**: Adicionada uma flag de controle `routesRegistered` para registrar os endpoints HTTP apenas na primeira inicialização do plugin.
|
||||
|
||||
### ❌ Falha 4 — Remoção Órfã de Mídias
|
||||
Ao deletar uma instância de conexão do WhatsApp, as mídias salvas no bucket remoto ficavam órfãs na nuvem.
|
||||
* **Correção**: Adicionado o método `deletePrefix` na interface de armazenamento. Agora, quando uma instância é removida, um processo em background efetua a varredura e deleta em lotes de 1000 todos os arquivos do Wasabi associados àquela instância de forma silenciosa.
|
||||
|
||||
---
|
||||
|
||||
## 2. Estrutura de Arquivos no Wasabi
|
||||
As mídias do WhatsApp são arquivadas de forma organizada no bucket do Wasabi seguindo a seguinte estrutura de prefixos:
|
||||
|
||||
```text
|
||||
whatsapp/{tenantId}/{instanceId}/{fileName}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Script de Migração de Mídias (`migrate-media-wasabi.mjs`)
|
||||
Caso mídias antigas precisem ser migradas de forma retroativa para liberar espaço em disco, disponibilizamos o script `migrate-media-wasabi.mjs` na raiz do projeto.
|
||||
|
||||
### Como usar o script:
|
||||
```bash
|
||||
# Simulação em Dry-Run (não faz alterações no disco/banco):
|
||||
node migrate-media-wasabi.mjs --dry-run
|
||||
|
||||
# Migração definitiva:
|
||||
node migrate-media-wasabi.mjs
|
||||
```
|
||||
O script lê os registros do banco de dados, faz o upload dos binários antigos no Wasabi com o formato correspondente, atualiza a referência na tabela e apaga com segurança os arquivos locais correspondentes.
|
||||
Reference in New Issue
Block a user