docs: add comprehensive system, plugins and infrastructure wiki documentation

Antigravity AI Agent
2026-05-11 05:47:34 +02:00
commit c88b08a046
7 changed files with 289 additions and 0 deletions
+41
@@ -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).
+50
@@ -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!
+54
@@ -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!
+29
@@ -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.
+41
@@ -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!
+46
@@ -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.