Initial commit: Documentación completa del proyecto WhatsApp Centralizado

- README principal con descripción del proyecto
- Documento de diseño completo (arquitectura, DB, flujos)
- Documentación de API REST y WebSocket
- Guía del Flow Builder (30+ tipos de nodos)
- Documentación de integración con Odoo
- Guía de despliegue con Docker
- Esquema de base de datos
- Estructura de carpetas del proyecto
- Archivo .env.example con todas las variables

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Claude AI
2026-01-29 09:29:57 +00:00
commit a92a7efccc
17 changed files with 4475 additions and 0 deletions

109
.env.example Normal file
View File

@@ -0,0 +1,109 @@
# =============================================================================
# WhatsApp Centralizado - Variables de Entorno
# =============================================================================
# Copiar este archivo a .env y configurar los valores
# -----------------------------------------------------------------------------
# Base de Datos PostgreSQL
# -----------------------------------------------------------------------------
DB_USER=whatsapp_admin
DB_PASSWORD=cambiar_por_password_seguro_32_caracteres
DB_HOST=postgres
DB_PORT=5432
DB_NAME=whatsapp_central
# URL completa de conexión (generada automáticamente en docker-compose)
# DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}
# -----------------------------------------------------------------------------
# Redis
# -----------------------------------------------------------------------------
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_URL=redis://redis:6379
# -----------------------------------------------------------------------------
# JWT / Autenticación
# -----------------------------------------------------------------------------
# Generar con: openssl rand -base64 64
JWT_SECRET=cambiar_por_secreto_aleatorio_64_caracteres
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=60
JWT_REFRESH_TOKEN_EXPIRE_DAYS=7
# -----------------------------------------------------------------------------
# Dominio / URLs
# -----------------------------------------------------------------------------
DOMAIN=localhost
FRONTEND_URL=http://localhost:3000
API_URL=http://localhost:8000
WHATSAPP_CORE_URL=http://whatsapp-core:3001
# -----------------------------------------------------------------------------
# WhatsApp Core (Node.js)
# -----------------------------------------------------------------------------
NODE_ENV=production
WS_PORT=3001
# -----------------------------------------------------------------------------
# Odoo (Opcional)
# -----------------------------------------------------------------------------
# Configurar después de instalar
ODOO_URL=https://odoo.tuempresa.com
ODOO_DB=production
ODOO_USER=api-whatsapp@tuempresa.com
ODOO_API_KEY=
# -----------------------------------------------------------------------------
# OpenAI / IA (Opcional)
# -----------------------------------------------------------------------------
# Para nodos de AI Response
OPENAI_API_KEY=
OPENAI_MODEL=gpt-4
# Anthropic Claude (alternativa)
ANTHROPIC_API_KEY=
ANTHROPIC_MODEL=claude-3-sonnet-20240229
# Ollama local (alternativa)
OLLAMA_URL=http://localhost:11434
OLLAMA_MODEL=llama2
# -----------------------------------------------------------------------------
# Email (Opcional - para notificaciones)
# -----------------------------------------------------------------------------
SMTP_HOST=smtp.tuempresa.com
SMTP_PORT=587
SMTP_USER=notificaciones@tuempresa.com
SMTP_PASSWORD=
SMTP_FROM=WhatsApp Central <notificaciones@tuempresa.com>
# -----------------------------------------------------------------------------
# Webhooks
# -----------------------------------------------------------------------------
# Secret para validar webhooks entrantes de Odoo
ODOO_WEBHOOK_SECRET=cambiar_por_secreto_aleatorio
# -----------------------------------------------------------------------------
# Seguridad
# -----------------------------------------------------------------------------
# Bcrypt rounds para passwords
BCRYPT_ROUNDS=12
# Rate limiting
RATE_LIMIT_REQUESTS=100
RATE_LIMIT_WINDOW=60
# CORS (separado por comas)
CORS_ORIGINS=http://localhost:3000,https://chat.tuempresa.com
# -----------------------------------------------------------------------------
# Logging
# -----------------------------------------------------------------------------
LOG_LEVEL=INFO
LOG_FORMAT=json
# -----------------------------------------------------------------------------
# Desarrollo (solo para dev)
# -----------------------------------------------------------------------------
DEBUG=false
RELOAD=false

197
.gitignore vendored Normal file
View File

@@ -0,0 +1,197 @@
# =============================================================================
# WhatsApp Centralizado - Git Ignore
# =============================================================================
# -----------------------------------------------------------------------------
# Environment
# -----------------------------------------------------------------------------
.env
.env.local
.env.*.local
*.env
# -----------------------------------------------------------------------------
# Python
# -----------------------------------------------------------------------------
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
.pytest_cache/
.coverage
htmlcov/
.tox/
.nox/
.hypothesis/
.mypy_cache/
.ruff_cache/
*.cover
# Virtual environments
venv/
ENV/
env/
.venv/
# -----------------------------------------------------------------------------
# Node.js
# -----------------------------------------------------------------------------
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.npm
.yarn-integrity
.pnpm-store/
# Build outputs
dist/
build/
.next/
out/
# -----------------------------------------------------------------------------
# IDE / Editors
# -----------------------------------------------------------------------------
.idea/
.vscode/
*.swp
*.swo
*~
.project
.classpath
.settings/
*.sublime-workspace
*.sublime-project
# -----------------------------------------------------------------------------
# OS
# -----------------------------------------------------------------------------
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
*.bak
*.tmp
*.temp
# -----------------------------------------------------------------------------
# Docker
# -----------------------------------------------------------------------------
# No ignorar docker-compose.yml ni Dockerfiles
# Solo ignorar archivos temporales
*.log
docker-compose.override.yml
# -----------------------------------------------------------------------------
# Sessions / Data
# -----------------------------------------------------------------------------
sessions/
*.session
*.session.json
# WhatsApp Baileys sessions
services/whatsapp-core/sessions/
auth_info*/
# -----------------------------------------------------------------------------
# Uploads / Media
# -----------------------------------------------------------------------------
uploads/
media/
*.mp3
*.mp4
*.wav
*.ogg
*.webm
*.pdf
*.doc
*.docx
*.xls
*.xlsx
# Excepto archivos de ejemplo/docs
!docs/**/*.pdf
# -----------------------------------------------------------------------------
# Logs
# -----------------------------------------------------------------------------
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# -----------------------------------------------------------------------------
# Database
# -----------------------------------------------------------------------------
*.sql
*.sqlite
*.db
!database/migrations/*.sql
# -----------------------------------------------------------------------------
# Backups
# -----------------------------------------------------------------------------
backups/
*.bak
*.backup
*.dump
# -----------------------------------------------------------------------------
# Secrets / Certificates
# -----------------------------------------------------------------------------
*.pem
*.key
*.crt
*.p12
*.pfx
secrets/
nginx/ssl/
# -----------------------------------------------------------------------------
# Test
# -----------------------------------------------------------------------------
coverage/
.nyc_output/
test-results/
playwright-report/
# -----------------------------------------------------------------------------
# Misc
# -----------------------------------------------------------------------------
.cache/
*.pid
*.seed
*.pid.lock
.grunt
.lock-wscript
.eslintcache
.stylelintcache
*.tsbuildinfo
# Temporary files
tmp/
temp/
.tmp/
.claude/

141
README.md Normal file
View File

@@ -0,0 +1,141 @@
# WhatsApp Centralizado
Plataforma de mensajería centralizada con automatización de chatbots, gestión multi-agente e integración profunda con Odoo.
## Descripción
WhatsApp Centralizado es una solución empresarial similar a Kommo, Wasapi, ManyChat y Brevo, diseñada para:
- **Automatizar conversaciones** con un potente Flow Builder visual (drag & drop)
- **Gestionar equipos de agentes** con colas inteligentes, SLA y métricas
- **Integrar con Odoo** de forma bidireccional (CRM, Ventas, Inventario, Helpdesk, etc.)
- **Conectar múltiples números** de WhatsApp desde una sola plataforma
## Características Principales
### Flow Builder Visual
- 30+ tipos de nodos (mensajes, lógica, validación, acciones)
- Editor drag & drop con React Flow
- Variables y contexto de conversación
- A/B Testing integrado
- Integración con IA (GPT, Claude, Ollama)
- Sub-flujos reutilizables
### Gestión Multi-Agente
- Sistema de colas (Ventas, Soporte, etc.)
- Asignación inteligente (round-robin, least-busy, skill-based)
- Transferencia bot → humano → bot
- Panel de supervisor en tiempo real
- SLA tracking con alertas
- Encuestas CSAT integradas
### Integración Odoo
- Conexión bidireccional via XML-RPC
- 8 módulos soportados (Contactos, CRM, Ventas, Inventario, Helpdesk, Facturación, Calendario, Productos)
- 20+ acciones disponibles en flujos
- Automatizaciones Odoo → WhatsApp
- Módulo Odoo con widget de chat
## Stack Tecnológico
| Componente | Tecnología |
|------------|------------|
| WhatsApp Core | Node.js + TypeScript + Baileys |
| API Gateway | Python + FastAPI |
| Flow Engine | Python |
| Frontend | React + TypeScript |
| Base de Datos | PostgreSQL + Redis |
| Despliegue | Docker + Docker Compose |
## Arquitectura
```
┌─────────────────────────────────────────────────────────────────┐
│ FRONTEND (React) │
│ Dashboard │ Inbox Chat │ Flow Builder (React Flow) │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ API GATEWAY (FastAPI) │
│ JWT Auth │ REST API │ WebSocket (tiempo real) │
└─────────────────────────────────────────────────────────────────┘
┌───────────────┼───────────────┐
▼ ▼ ▼
┌──────────────────┐ ┌──────────────┐ ┌──────────────────────────┐
│ WHATSAPP CORE │ │ FLOW ENGINE │ │ INTEGRATIONS │
│ (Node.js) │ │ (Python) │ │ (Python) │
│ Baileys │ │ Motor bot │ │ Odoo, Webhooks │
└──────────────────┘ └──────────────┘ └──────────────────────────┘
┌─────────┴─────────┐
▼ ▼
┌──────────┐ ┌──────────┐
│PostgreSQL│ │ Redis │
└──────────┘ └──────────┘
```
## Inicio Rápido
### Requisitos
- Docker 24.0+
- Docker Compose 2.20+
- 4GB RAM mínimo (8GB recomendado)
### Instalación
```bash
# Clonar repositorio
git clone https://git.consultoria-as.com/tu-usuario/WhatsAppCentralizado.git
cd WhatsAppCentralizado
# Copiar configuración
cp .env.example .env
# Editar variables de entorno
nano .env
# Iniciar servicios
docker-compose up -d
# Aplicar migraciones
docker-compose exec api-gateway alembic upgrade head
# Crear usuario admin
docker-compose exec api-gateway python scripts/create_admin.py
```
### Acceso
- Frontend: http://localhost:3000
- API: http://localhost:8000
- Docs API: http://localhost:8000/docs
## Documentación
- [Diseño del Sistema](docs/plans/2026-01-29-whatsapp-centralizado-design.md)
- [Arquitectura](docs/architecture/README.md)
- [API Reference](docs/api/README.md)
- [Flow Builder](docs/flow-builder/README.md)
- [Integración Odoo](docs/odoo-integration/README.md)
- [Guía de Despliegue](docs/deployment/README.md)
## Roadmap
- [x] Diseño y arquitectura
- [ ] Fase 1: Fundación (WhatsApp Core + API + Frontend básico)
- [ ] Fase 2: Flow Engine Básico
- [ ] Fase 3: Inbox Avanzado + Multi-agente
- [ ] Fase 4: Flow Engine Avanzado
- [ ] Fase 5: Integración Odoo Completa
- [ ] Fase 6: Módulo Odoo
- [ ] Fase 7: Reportes y Analytics
- [ ] Fase 8: Multi-canal (Email, SMS)
## Licencia
Propietario - Todos los derechos reservados.
## Contacto
Desarrollado para uso interno empresarial.

View File

746
docs/api/README.md Normal file
View File

@@ -0,0 +1,746 @@
# API Reference
## Información General
- **Base URL:** `https://tu-dominio.com/api`
- **Autenticación:** Bearer Token (JWT)
- **Content-Type:** `application/json`
## Autenticación
### Login
```http
POST /auth/login
```
**Request:**
```json
{
"email": "usuario@empresa.com",
"password": "tu_password"
}
```
**Response:**
```json
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"token_type": "bearer",
"user": {
"id": "uuid",
"email": "usuario@empresa.com",
"name": "Usuario",
"role": "admin"
}
}
```
### Refresh Token
```http
POST /auth/refresh
```
### Logout
```http
POST /auth/logout
```
### Usuario Actual
```http
GET /auth/me
```
---
## Usuarios
### Listar Usuarios
```http
GET /api/users
```
**Query Parameters:**
| Parámetro | Tipo | Descripción |
|-----------|------|-------------|
| role | string | Filtrar por rol (admin, supervisor, agent) |
| status | string | Filtrar por estado (online, offline, away) |
| page | int | Página (default: 1) |
| limit | int | Límite por página (default: 20) |
### Crear Usuario
```http
POST /api/users
```
**Request:**
```json
{
"email": "nuevo@empresa.com",
"password": "password123",
"name": "Nuevo Usuario",
"role": "agent"
}
```
### Obtener Usuario
```http
GET /api/users/{user_id}
```
### Actualizar Usuario
```http
PUT /api/users/{user_id}
```
### Eliminar Usuario
```http
DELETE /api/users/{user_id}
```
### Cambiar Estado
```http
PUT /api/users/{user_id}/status
```
**Request:**
```json
{
"status": "away"
}
```
---
## Cuentas WhatsApp
### Listar Cuentas
```http
GET /api/whatsapp/accounts
```
### Crear Cuenta (Iniciar conexión)
```http
POST /api/whatsapp/accounts
```
**Request:**
```json
{
"name": "Ventas Principal"
}
```
**Response:**
```json
{
"id": "uuid",
"name": "Ventas Principal",
"status": "disconnected",
"qr_code": null
}
```
### Obtener QR Code
```http
GET /api/whatsapp/accounts/{account_id}/qr
```
**Response:**
```json
{
"qr_code": "data:image/png;base64,..."
}
```
### Estado de Cuenta
```http
GET /api/whatsapp/accounts/{account_id}/status
```
### Desconectar Cuenta
```http
POST /api/whatsapp/accounts/{account_id}/disconnect
```
### Reconectar Cuenta
```http
POST /api/whatsapp/accounts/{account_id}/reconnect
```
---
## Contactos
### Listar Contactos
```http
GET /api/contacts
```
**Query Parameters:**
| Parámetro | Tipo | Descripción |
|-----------|------|-------------|
| search | string | Buscar por nombre, teléfono o email |
| tags | string[] | Filtrar por etiquetas |
| has_odoo | boolean | Filtrar sincronizados con Odoo |
| page | int | Página |
| limit | int | Límite |
### Crear Contacto
```http
POST /api/contacts
```
**Request:**
```json
{
"phone_number": "+525551234567",
"name": "Juan Pérez",
"email": "juan@email.com",
"company": "Empresa ABC",
"tags": ["lead", "interesado"],
"metadata": {
"producto_interes": "Laptop Pro"
}
}
```
### Obtener Contacto
```http
GET /api/contacts/{contact_id}
```
### Actualizar Contacto
```http
PUT /api/contacts/{contact_id}
```
### Agregar Etiquetas
```http
POST /api/contacts/{contact_id}/tags
```
**Request:**
```json
{
"tags": ["vip", "cliente"]
}
```
### Sincronizar con Odoo
```http
POST /api/contacts/{contact_id}/sync-odoo
```
---
## Conversaciones
### Listar Conversaciones
```http
GET /api/conversations
```
**Query Parameters:**
| Parámetro | Tipo | Descripción |
|-----------|------|-------------|
| status | string | bot, waiting, active, resolved |
| queue_id | uuid | Filtrar por cola |
| assigned_to | uuid | Filtrar por agente |
| priority | string | low, normal, high, urgent |
| page | int | Página |
| limit | int | Límite |
### Obtener Conversación
```http
GET /api/conversations/{conversation_id}
```
**Response:**
```json
{
"id": "uuid",
"contact": {
"id": "uuid",
"name": "Juan Pérez",
"phone_number": "+525551234567"
},
"whatsapp_account": {
"id": "uuid",
"name": "Ventas Principal"
},
"status": "active",
"priority": "normal",
"assigned_to": {
"id": "uuid",
"name": "María García"
},
"queue": {
"id": "uuid",
"name": "Ventas"
},
"current_flow": null,
"sla_first_response_met": true,
"last_message_at": "2024-01-15T14:30:00Z",
"created_at": "2024-01-15T14:25:00Z"
}
```
### Asignar Conversación
```http
POST /api/conversations/{conversation_id}/assign
```
**Request:**
```json
{
"user_id": "uuid"
}
```
### Transferir a Cola
```http
POST /api/conversations/{conversation_id}/transfer
```
**Request:**
```json
{
"queue_id": "uuid"
}
```
### Resolver Conversación
```http
POST /api/conversations/{conversation_id}/resolve
```
**Request:**
```json
{
"resolution_note": "Problema resuelto"
}
```
### Reabrir Conversación
```http
POST /api/conversations/{conversation_id}/reopen
```
---
## Mensajes
### Listar Mensajes de Conversación
```http
GET /api/conversations/{conversation_id}/messages
```
**Query Parameters:**
| Parámetro | Tipo | Descripción |
|-----------|------|-------------|
| before | uuid | Mensajes antes de este ID |
| limit | int | Límite (default: 50) |
### Enviar Mensaje
```http
POST /api/conversations/{conversation_id}/messages
```
**Request (texto):**
```json
{
"type": "text",
"content": "Hola, ¿en qué te puedo ayudar?"
}
```
**Request (imagen):**
```json
{
"type": "image",
"media_url": "https://example.com/image.jpg",
"content": "Caption opcional"
}
```
**Request (botones):**
```json
{
"type": "buttons",
"content": "¿Qué necesitas?",
"metadata": {
"buttons": [
{"id": "ventas", "text": "Ventas"},
{"id": "soporte", "text": "Soporte"},
{"id": "otro", "text": "Otro"}
]
}
}
```
**Request (lista):**
```json
{
"type": "list",
"content": "Selecciona una opción:",
"metadata": {
"button_text": "Ver opciones",
"sections": [
{
"title": "Productos",
"rows": [
{"id": "laptop", "title": "Laptops", "description": "Ver laptops disponibles"},
{"id": "telefono", "title": "Teléfonos", "description": "Ver teléfonos"}
]
}
]
}
}
```
### Enviar Nota Interna
```http
POST /api/conversations/{conversation_id}/notes
```
**Request:**
```json
{
"content": "Cliente interesado, dar seguimiento"
}
```
---
## Flujos
### Listar Flujos
```http
GET /api/flows
```
### Crear Flujo
```http
POST /api/flows
```
**Request:**
```json
{
"name": "Bienvenida",
"description": "Flujo de bienvenida para nuevos contactos",
"trigger_type": "welcome",
"trigger_value": null,
"nodes": {
"nodes": [...],
"edges": [...],
"viewport": {...}
},
"is_active": true
}
```
### Obtener Flujo
```http
GET /api/flows/{flow_id}
```
### Actualizar Flujo
```http
PUT /api/flows/{flow_id}
```
### Duplicar Flujo
```http
POST /api/flows/{flow_id}/duplicate
```
### Activar/Desactivar Flujo
```http
PUT /api/flows/{flow_id}/toggle
```
### Probar Flujo
```http
POST /api/flows/{flow_id}/test
```
**Request:**
```json
{
"phone_number": "+525551234567",
"initial_message": "Hola"
}
```
---
## Colas
### Listar Colas
```http
GET /api/queues
```
### Crear Cola
```http
POST /api/queues
```
**Request:**
```json
{
"name": "Ventas",
"description": "Cola de atención de ventas",
"assignment_method": "least_busy",
"max_per_agent": 8,
"sla_first_response": 180,
"sla_resolution": 3600,
"business_hours": {
"monday": {"start": "09:00", "end": "18:00"},
"tuesday": {"start": "09:00", "end": "18:00"},
"wednesday": {"start": "09:00", "end": "18:00"},
"thursday": {"start": "09:00", "end": "18:00"},
"friday": {"start": "09:00", "end": "17:00"},
"saturday": {"start": "10:00", "end": "14:00"},
"sunday": null
},
"fallback_flow_id": "uuid"
}
```
### Obtener Cola
```http
GET /api/queues/{queue_id}
```
### Actualizar Cola
```http
PUT /api/queues/{queue_id}
```
### Agregar Agente a Cola
```http
POST /api/queues/{queue_id}/agents
```
**Request:**
```json
{
"user_id": "uuid",
"is_supervisor": false,
"skills": ["ventas", "ingles"]
}
```
### Remover Agente de Cola
```http
DELETE /api/queues/{queue_id}/agents/{user_id}
```
### Estadísticas de Cola
```http
GET /api/queues/{queue_id}/stats
```
**Response:**
```json
{
"waiting": 5,
"active": 12,
"resolved_today": 47,
"avg_first_response": 142,
"avg_resolution": 1823,
"sla_compliance": 0.91,
"agents": [
{
"user_id": "uuid",
"name": "María García",
"status": "online",
"active_conversations": 5,
"resolved_today": 12
}
]
}
```
---
## Respuestas Rápidas
### Listar Respuestas Rápidas
```http
GET /api/quick-replies
```
### Crear Respuesta Rápida
```http
POST /api/quick-replies
```
**Request:**
```json
{
"shortcut": "/saludo",
"content": "¡Hola {{contact.name}}! Soy {{agent.name}}, ¿en qué te puedo ayudar?",
"queue_id": null
}
```
### Actualizar Respuesta Rápida
```http
PUT /api/quick-replies/{id}
```
### Eliminar Respuesta Rápida
```http
DELETE /api/quick-replies/{id}
```
---
## Odoo
### Probar Conexión
```http
POST /api/odoo/test-connection
```
### Sincronizar Contactos
```http
POST /api/odoo/sync-contacts
```
### Buscar Partner
```http
GET /api/odoo/partners/search
```
**Query Parameters:**
| Parámetro | Tipo | Descripción |
|-----------|------|-------------|
| phone | string | Buscar por teléfono |
| email | string | Buscar por email |
| name | string | Buscar por nombre |
### Buscar Pedidos
```http
GET /api/odoo/orders
```
**Query Parameters:**
| Parámetro | Tipo | Descripción |
|-----------|------|-------------|
| partner_id | int | ID del partner en Odoo |
| state | string | Estado del pedido |
| limit | int | Límite |
### Consultar Stock
```http
GET /api/odoo/products/{product_id}/stock
```
### Crear Lead
```http
POST /api/odoo/leads
```
**Request:**
```json
{
"name": "Interés en Producto X",
"contact_name": "Juan Pérez",
"phone": "+525551234567",
"email": "juan@email.com",
"description": "Cliente interesado en laptops",
"expected_revenue": 5000
}
```
---
## WebSocket
### Conexión
```javascript
const socket = io('wss://tu-dominio.com', {
auth: {
token: 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...'
}
});
```
### Eventos del Servidor
**Nuevo mensaje:**
```javascript
socket.on('new_message', (data) => {
// data: { conversation_id, message }
});
```
**Estado de mensaje:**
```javascript
socket.on('message_status', (data) => {
// data: { message_id, status: 'delivered' | 'read' }
});
```
**Conversación asignada:**
```javascript
socket.on('conversation_assigned', (data) => {
// data: { conversation_id, assigned_to }
});
```
**QR Code:**
```javascript
socket.on('qr_code', (data) => {
// data: { account_id, qr_code }
});
```
**Estado de conexión WhatsApp:**
```javascript
socket.on('connection_status', (data) => {
// data: { account_id, status: 'connected' | 'disconnected' }
});
```
### Eventos del Cliente
**Unirse a conversación:**
```javascript
socket.emit('join_conversation', { conversation_id: 'uuid' });
```
**Escribiendo:**
```javascript
socket.emit('typing', { conversation_id: 'uuid' });
```
---
## Códigos de Error
| Código | Descripción |
|--------|-------------|
| 400 | Bad Request - Datos inválidos |
| 401 | Unauthorized - Token inválido o expirado |
| 403 | Forbidden - Sin permisos |
| 404 | Not Found - Recurso no encontrado |
| 409 | Conflict - Conflicto de datos |
| 422 | Unprocessable Entity - Validación fallida |
| 429 | Too Many Requests - Rate limit excedido |
| 500 | Internal Server Error |
**Formato de error:**
```json
{
"detail": {
"code": "VALIDATION_ERROR",
"message": "El campo email es requerido",
"field": "email"
}
}
```

227
docs/architecture/README.md Normal file
View File

@@ -0,0 +1,227 @@
# Arquitectura del Sistema
## Visión General
WhatsApp Centralizado está diseñado como una arquitectura de microservicios, donde cada componente tiene una responsabilidad específica y se comunica con los demás a través de APIs REST y WebSocket.
## Diagrama de Arquitectura
```
┌─────────────────┐
│ NGINX │
│ (Reverse Proxy)│
│ :80 / :443 │
└────────┬────────┘
┌────────────────────────┼────────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Frontend │ │ API Gateway │ │ WhatsApp Core │
│ (React) │ │ (FastAPI) │ │ (Node.js) │
│ :3000 │ │ :8000 │ │ :3001 │
└───────────────┘ └───────┬───────┘ └───────┬───────┘
│ │
│ │
┌──────────────────┼──────────────────┐ │
│ │ │ │
▼ ▼ ▼ │
┌─────────────────┐ ┌─────────────────┐ ┌──────────────────┐
│ Flow Engine │ │ Integrations │ │ Redis │
│ (Python) │ │ (Python) │ │ (Cache/PubSub)│
│ :8001 │ │ :8002 │ │ :6379 │
└────────┬────────┘ └────────┬────────┘ └──────────────────┘
│ │ ▲
│ │ │
└─────────┬─────────┘ │
│ │
▼ │
┌─────────────────┐ │
│ PostgreSQL │────────────────────┘
│ (Database) │
│ :5432 │
└─────────────────┘
```
## Componentes
### Frontend (React + TypeScript)
- **Puerto:** 3000
- **Responsabilidad:** Interfaz de usuario
- **Tecnologías:**
- React 18
- TypeScript
- React Flow (editor visual)
- Ant Design / shadcn/ui
- TanStack Query
- Zustand (estado)
- Socket.io-client
**Módulos:**
- Dashboard con métricas
- Inbox de conversaciones
- Flow Builder visual
- Gestión de números WhatsApp
- Panel de supervisor
- Configuración
### API Gateway (Python + FastAPI)
- **Puerto:** 8000
- **Responsabilidad:** Punto de entrada único, autenticación, orquestación
- **Tecnologías:**
- FastAPI
- SQLAlchemy
- Pydantic
- python-jose (JWT)
- Celery (tareas async)
**Endpoints principales:**
- `/auth/*` - Autenticación
- `/api/conversations/*` - Conversaciones
- `/api/messages/*` - Mensajes
- `/api/flows/*` - Flujos de chatbot
- `/api/contacts/*` - Contactos
- `/api/users/*` - Usuarios
- `/api/queues/*` - Colas
- `/api/whatsapp/*` - Gestión WhatsApp
- `/ws/*` - WebSocket
### WhatsApp Core (Node.js + TypeScript)
- **Puerto:** 3001
- **Responsabilidad:** Conexión con WhatsApp via Baileys
- **Tecnologías:**
- Node.js 20
- TypeScript
- Baileys
- Socket.io
**Funcionalidades:**
- Gestión de sesiones multi-número
- Generación de QR
- Envío/recepción de mensajes
- Manejo de media
- Reconexión automática
- Estados de mensajes
### Flow Engine (Python)
- **Puerto:** 8001 (interno)
- **Responsabilidad:** Ejecutar flujos de chatbot
- **Tecnologías:**
- Python
- Motor de ejecución propio
**Funcionalidades:**
- Parsear definición de flujos (JSONB)
- Ejecutar nodos secuencialmente
- Manejar bifurcaciones y condiciones
- Gestionar variables y contexto
- Integrar con IA (OpenAI, Claude, Ollama)
### Integrations (Python)
- **Puerto:** 8002 (interno)
- **Responsabilidad:** Conexión con sistemas externos
- **Tecnologías:**
- Python
- xmlrpc.client (Odoo)
- httpx (webhooks)
**Integraciones:**
- Odoo via XML-RPC
- Webhooks entrantes/salientes
- Email (futuro)
- SMS (futuro)
### PostgreSQL
- **Puerto:** 5432
- **Responsabilidad:** Persistencia de datos
- **Datos almacenados:**
- Usuarios y roles
- Conversaciones y mensajes
- Contactos
- Flujos de chatbot
- Configuración
- Logs de auditoría
### Redis
- **Puerto:** 6379
- **Responsabilidad:** Cache, colas, pub/sub
- **Usos:**
- Sesiones de usuario
- Cache de datos frecuentes
- Cola de mensajes salientes
- Pub/Sub para tiempo real
- Rate limiting
## Comunicación entre Servicios
### HTTP/REST
- Frontend → API Gateway
- API Gateway → Flow Engine
- API Gateway → Integrations
- WhatsApp Core → API Gateway
### WebSocket
- Frontend ↔ API Gateway (tiempo real)
- API Gateway ↔ WhatsApp Core (eventos)
### Pub/Sub (Redis)
- Eventos de nuevos mensajes
- Cambios de estado
- Notificaciones
## Flujo de Datos
### Mensaje Entrante
```
WhatsApp → Baileys → WhatsApp Core → API Gateway → Flow Engine
PostgreSQL
Frontend (via WebSocket)
```
### Mensaje Saliente (Bot)
```
Flow Engine → API Gateway → WhatsApp Core → Baileys → WhatsApp
PostgreSQL
```
### Mensaje Saliente (Agente)
```
Frontend → API Gateway → WhatsApp Core → Baileys → WhatsApp
PostgreSQL
```
## Escalabilidad
### Horizontal
- WhatsApp Core: Múltiples instancias para más números
- API Gateway: Load balancer con múltiples instancias
- Flow Engine: Workers independientes
### Vertical
- PostgreSQL: Aumentar recursos según carga
- Redis: Cluster para alta disponibilidad
## Seguridad
### Autenticación
- JWT con access tokens (1h) y refresh tokens (7d)
- Refresh tokens en httpOnly cookies
- Bcrypt para passwords (cost 12)
### Autorización
- RBAC: Admin, Supervisor, Agente
- Permisos granulares por endpoint
### Red
- HTTPS obligatorio
- Rate limiting
- Validación de entrada con Pydantic
### Datos
- Encriptación en reposo (PostgreSQL)
- Secrets en variables de entorno
- No logs de datos sensibles

452
docs/database/README.md Normal file
View File

@@ -0,0 +1,452 @@
# Esquema de Base de Datos
## Diagrama ER
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ users │ │ queues │ │ whatsapp_accounts│
├─────────────────┤ ├─────────────────┤ ├─────────────────┤
│ id (PK) │ │ id (PK) │ │ id (PK) │
│ email │ │ name │ │ phone_number │
│ password_hash │ │ description │ │ name │
│ name │ │ assignment_method │ status │
│ role │ │ max_per_agent │ │ session_data │
│ status │ │ sla_first_resp │ │ qr_code │
│ is_active │ │ sla_resolution │ │ created_at │
│ created_at │ │ business_hours │ └────────┬────────┘
│ updated_at │ │ fallback_flow_id│ │
└────────┬────────┘ │ is_active │ │
│ └────────┬────────┘ │
│ │ │
│ ┌────────────────────┼─────────────────────────┤
│ │ │ │
│ ▼ ▼ ▼
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ │ queue_agents │ │ conversations │ │ contacts │
│ ├─────────────────┤ ├─────────────────┤ ├─────────────────┤
│ │ id (PK) │ │ id (PK) │ │ id (PK) │
│ │ queue_id (FK)───┼──│ queue_id (FK)───│ │ phone_number │
├──│ user_id (FK) │ │ whatsapp_acc_id─┼──│ name │
│ │ is_supervisor │ │ contact_id (FK)─┼──│ email │
│ │ skills │ │ assigned_to (FK)│ │ company │
│ └─────────────────┘ │ status │ │ metadata │
│ │ priority │ │ tags │
│ │ current_flow_id │ │ odoo_partner_id │
│ │ flow_context │ │ created_at │
│ │ sla_* │ └─────────────────┘
│ │ csat_* │
│ │ created_at │
│ └────────┬────────┘
│ │
│ │
│ ▼
│ ┌─────────────────┐
│ │ messages │
│ ├─────────────────┤
│ │ id (PK) │
│ │ conversation_id │
│ │ direction │
│ │ type │
│ │ content │
└───────────────────────│ sent_by (FK) │
│ is_internal_note│
│ status │
│ created_at │
└─────────────────┘
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ flows │ │ message_templates│ │ quick_replies │
├─────────────────┤ ├─────────────────┤ ├─────────────────┤
│ id (PK) │ │ id (PK) │ │ id (PK) │
│ name │ │ name │ │ shortcut │
│ description │ │ content │ │ content │
│ trigger_type │ │ attachments │ │ attachments │
│ trigger_value │ │ variables │ │ queue_id (FK) │
│ nodes (JSONB) │ │ created_at │ │ created_by (FK) │
│ variables │ └─────────────────┘ │ created_at │
│ is_active │ └─────────────────┘
│ version │
│ created_at │ ┌─────────────────┐ ┌─────────────────┐
└─────────────────┘ │ odoo_config │ │odoo_automations │
├─────────────────┤ ├─────────────────┤
┌─────────────────┐ │ id (PK) │ │ id (PK) │
│ tags │ │ url │ │ name │
├─────────────────┤ │ database │ │ odoo_model │
│ id (PK) │ │ username │ │ odoo_trigger │
│ name │ │ api_key_enc │ │ odoo_condition │
│ color │ │ is_active │ │ template_id (FK)│
│ created_at │ │ last_sync_at │ │ is_active │
└─────────────────┘ └─────────────────┘ │ created_at │
└─────────────────┘
```
---
## Tablas Detalladas
### users
Usuarios del sistema (admins, supervisores, agentes).
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | UUID | Identificador único |
| email | VARCHAR(255) | Email único |
| password_hash | VARCHAR(255) | Hash bcrypt |
| name | VARCHAR(100) | Nombre completo |
| role | ENUM | admin, supervisor, agent |
| status | ENUM | online, offline, away, busy, lunch, on_call |
| is_active | BOOLEAN | Usuario activo |
| created_at | TIMESTAMP | Fecha creación |
| updated_at | TIMESTAMP | Última modificación |
**Índices:**
- `idx_users_email` (email)
- `idx_users_role` (role)
- `idx_users_status` (status)
---
### whatsapp_accounts
Números de WhatsApp conectados.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | UUID | Identificador único |
| phone_number | VARCHAR(20) | Número con código país |
| name | VARCHAR(100) | Alias (ej: "Ventas") |
| status | ENUM | connected, disconnected, banned |
| session_data | JSONB | Datos de sesión Baileys |
| qr_code | TEXT | QR para reconexión |
| created_at | TIMESTAMP | Fecha creación |
**Índices:**
- `idx_wa_phone` (phone_number)
- `idx_wa_status` (status)
---
### contacts
Contactos (clientes que escriben).
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | UUID | Identificador único |
| phone_number | VARCHAR(20) | Teléfono único |
| name | VARCHAR(100) | Nombre |
| email | VARCHAR(255) | Email |
| company | VARCHAR(100) | Empresa |
| metadata | JSONB | Datos personalizados |
| tags | VARCHAR[] | Array de etiquetas |
| odoo_partner_id | INTEGER | ID en Odoo |
| created_at | TIMESTAMP | Primer contacto |
**Índices:**
- `idx_contacts_phone` UNIQUE (phone_number)
- `idx_contacts_email` (email)
- `idx_contacts_odoo` (odoo_partner_id)
- `idx_contacts_tags` GIN (tags)
---
### queues
Colas de atención.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | UUID | Identificador único |
| name | VARCHAR(100) | Nombre de cola |
| description | TEXT | Descripción |
| assignment_method | ENUM | round_robin, least_busy, skill_based, sticky |
| max_per_agent | INTEGER | Máx. conversaciones por agente |
| sla_first_response | INTEGER | Segundos para primera respuesta |
| sla_resolution | INTEGER | Segundos para resolución |
| business_hours | JSONB | Horario de atención |
| fallback_flow_id | UUID | Flujo fuera de horario |
| is_active | BOOLEAN | Cola activa |
---
### queue_agents
Relación agentes-colas.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | UUID | Identificador único |
| queue_id | UUID | FK a queues |
| user_id | UUID | FK a users |
| is_supervisor | BOOLEAN | Es supervisor de cola |
| skills | VARCHAR[] | Habilidades del agente |
**Índices:**
- `idx_qa_queue` (queue_id)
- `idx_qa_user` (user_id)
- `idx_qa_unique` UNIQUE (queue_id, user_id)
---
### conversations
Conversaciones.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | UUID | Identificador único |
| whatsapp_account_id | UUID | FK a whatsapp_accounts |
| contact_id | UUID | FK a contacts |
| queue_id | UUID | FK a queues (nullable) |
| assigned_to | UUID | FK a users (nullable) |
| status | ENUM | bot, waiting, active, resolved |
| priority | ENUM | low, normal, high, urgent |
| current_flow_id | UUID | Flujo en ejecución |
| flow_context | JSONB | Estado del flujo |
| sla_first_response_at | TIMESTAMP | Hora primera respuesta |
| sla_first_response_met | BOOLEAN | SLA cumplido |
| resolved_at | TIMESTAMP | Hora resolución |
| csat_score | INTEGER | Calificación 1-5 |
| csat_feedback | TEXT | Feedback del cliente |
| last_message_at | TIMESTAMP | Último mensaje |
| created_at | TIMESTAMP | Inicio conversación |
**Índices:**
- `idx_conv_contact` (contact_id)
- `idx_conv_status` (status)
- `idx_conv_assigned` (assigned_to)
- `idx_conv_queue` (queue_id)
- `idx_conv_last_msg` (last_message_at)
- `idx_conv_created` (created_at)
---
### messages
Mensajes de conversaciones.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | UUID | Identificador único |
| conversation_id | UUID | FK a conversations |
| direction | ENUM | inbound, outbound |
| type | ENUM | text, image, audio, video, document, buttons, list, location, contact, sticker |
| content | TEXT | Contenido del mensaje |
| media_url | VARCHAR(500) | URL de media |
| metadata | JSONB | Datos adicionales (botones, etc.) |
| sent_by | UUID | FK a users (si fue agente) |
| is_internal_note | BOOLEAN | Nota interna |
| status | ENUM | pending, sent, delivered, read, failed |
| created_at | TIMESTAMP | Fecha envío/recepción |
**Índices:**
- `idx_msg_conv` (conversation_id)
- `idx_msg_created` (created_at)
- `idx_msg_direction` (direction)
- `idx_msg_status` (status)
**Particionamiento:** Por fecha (mensual) para alto volumen.
---
### flows
Flujos de chatbot.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | UUID | Identificador único |
| name | VARCHAR(100) | Nombre del flujo |
| description | TEXT | Descripción |
| trigger_type | ENUM | welcome, keyword, fallback, event, schedule, manual |
| trigger_value | VARCHAR(255) | Valor del trigger |
| nodes | JSONB | Definición del flujo |
| variables | JSONB | Variables del flujo |
| is_active | BOOLEAN | Flujo activo |
| version | INTEGER | Versión del flujo |
| created_at | TIMESTAMP | Fecha creación |
**Índices:**
- `idx_flows_trigger` (trigger_type, is_active)
- `idx_flows_active` (is_active)
---
### message_templates
Templates de mensajes reutilizables.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | UUID | Identificador único |
| name | VARCHAR(100) | Nombre del template |
| content | TEXT | Contenido con variables |
| attachments | JSONB | Archivos adjuntos |
| variables | VARCHAR[] | Variables usadas |
| created_at | TIMESTAMP | Fecha creación |
---
### quick_replies
Respuestas rápidas para agentes.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | UUID | Identificador único |
| shortcut | VARCHAR(50) | Atajo (/saludo) |
| content | TEXT | Contenido |
| attachments | JSONB | Archivos adjuntos |
| queue_id | UUID | FK a queues (opcional) |
| created_by | UUID | FK a users |
| created_at | TIMESTAMP | Fecha creación |
**Índices:**
- `idx_qr_shortcut` (shortcut)
- `idx_qr_queue` (queue_id)
---
### tags
Etiquetas para contactos.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | UUID | Identificador único |
| name | VARCHAR(50) | Nombre único |
| color | VARCHAR(7) | Color hex (#FF5733) |
| created_at | TIMESTAMP | Fecha creación |
---
### odoo_config
Configuración de conexión Odoo.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | UUID | Identificador único |
| url | VARCHAR(255) | URL de Odoo |
| database | VARCHAR(100) | Nombre de BD |
| username | VARCHAR(100) | Usuario API |
| api_key_encrypted | TEXT | API key encriptada |
| is_active | BOOLEAN | Conexión activa |
| last_sync_at | TIMESTAMP | Última sincronización |
| created_at | TIMESTAMP | Fecha creación |
---
### odoo_automations
Automatizaciones Odoo → WhatsApp.
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | UUID | Identificador único |
| name | VARCHAR(100) | Nombre |
| odoo_model | VARCHAR(100) | Modelo Odoo (sale.order) |
| odoo_trigger | VARCHAR(100) | Evento trigger |
| odoo_condition | JSONB | Condiciones |
| message_template_id | UUID | FK a templates |
| is_active | BOOLEAN | Automatización activa |
| created_at | TIMESTAMP | Fecha creación |
---
## Migraciones
### Crear migración
```bash
docker compose exec api-gateway alembic revision --autogenerate -m "descripcion"
```
### Aplicar migraciones
```bash
docker compose exec api-gateway alembic upgrade head
```
### Revertir migración
```bash
docker compose exec api-gateway alembic downgrade -1
```
### Ver historial
```bash
docker compose exec api-gateway alembic history
```
---
## Índices Recomendados
```sql
-- Búsqueda full-text en mensajes
CREATE INDEX idx_messages_content_fts ON messages
USING gin(to_tsvector('spanish', content));
-- Búsqueda en metadata JSONB
CREATE INDEX idx_contacts_metadata ON contacts
USING gin(metadata);
-- Queries frecuentes
CREATE INDEX idx_conv_active ON conversations (status, assigned_to)
WHERE status IN ('active', 'waiting');
CREATE INDEX idx_msg_recent ON messages (conversation_id, created_at DESC);
```
---
## Mantenimiento
### Vacuum
```sql
-- Vacuum manual
VACUUM ANALYZE conversations;
VACUUM ANALYZE messages;
-- Configurar autovacuum agresivo para messages
ALTER TABLE messages SET (
autovacuum_vacuum_scale_factor = 0.05,
autovacuum_analyze_scale_factor = 0.02
);
```
### Archivado de mensajes antiguos
```sql
-- Mover mensajes > 1 año a tabla de archivo
INSERT INTO messages_archive
SELECT * FROM messages
WHERE created_at < NOW() - INTERVAL '1 year';
DELETE FROM messages
WHERE created_at < NOW() - INTERVAL '1 year';
```
### Estadísticas
```sql
-- Tamaño de tablas
SELECT
relname as table,
pg_size_pretty(pg_total_relation_size(relid)) as size
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC;
-- Mensajes por día
SELECT
DATE(created_at) as date,
COUNT(*) as count
FROM messages
GROUP BY DATE(created_at)
ORDER BY date DESC
LIMIT 30;
```

539
docs/deployment/README.md Normal file
View File

@@ -0,0 +1,539 @@
# Guía de Despliegue
## Requisitos del Servidor
### Hardware Mínimo
- **CPU:** 2 cores
- **RAM:** 4 GB
- **Disco:** 50 GB SSD
### Hardware Recomendado
- **CPU:** 4 cores
- **RAM:** 8 GB
- **Disco:** 100 GB SSD
### Software
- Ubuntu 22.04 LTS (recomendado) o Debian 12
- Docker 24.0+
- Docker Compose 2.20+
- Git
---
## Instalación
### 1. Preparar Servidor
```bash
# Actualizar sistema
sudo apt update && sudo apt upgrade -y
# Instalar Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Agregar usuario al grupo docker
sudo usermod -aG docker $USER
# Instalar Docker Compose
sudo apt install docker-compose-plugin -y
# Verificar instalación
docker --version
docker compose version
```
### 2. Clonar Repositorio
```bash
cd /opt
sudo git clone https://git.consultoria-as.com/tu-usuario/WhatsAppCentralizado.git
sudo chown -R $USER:$USER WhatsAppCentralizado
cd WhatsAppCentralizado
```
### 3. Configurar Variables de Entorno
```bash
cp .env.example .env
nano .env
```
**Variables requeridas:**
```bash
# Base de datos
DB_USER=whatsapp_admin
DB_PASSWORD=<password_seguro_32_caracteres>
# JWT Secret (generar aleatorio)
JWT_SECRET=<secreto_aleatorio_64_caracteres>
# Dominio
DOMAIN=chat.tuempresa.com
# Odoo (opcional, configurar después)
ODOO_URL=https://odoo.tuempresa.com
ODOO_DB=production
ODOO_USER=api-whatsapp@tuempresa.com
ODOO_API_KEY=<api_key_de_odoo>
# OpenAI (opcional, para AI Response)
OPENAI_API_KEY=sk-...
```
**Generar secrets:**
```bash
# Generar password DB
openssl rand -base64 32
# Generar JWT secret
openssl rand -base64 64
```
### 4. Construir e Iniciar
```bash
# Construir imágenes
docker compose build
# Iniciar servicios
docker compose up -d
# Ver logs
docker compose logs -f
```
### 5. Inicializar Base de Datos
```bash
# Aplicar migraciones
docker compose exec api-gateway alembic upgrade head
# Crear usuario admin
docker compose exec api-gateway python scripts/create_admin.py
```
### 6. Configurar SSL con Let's Encrypt
```bash
# Instalar certbot
sudo apt install certbot -y
# Obtener certificado
sudo certbot certonly --standalone -d chat.tuempresa.com
# Los certificados quedan en:
# /etc/letsencrypt/live/chat.tuempresa.com/fullchain.pem
# /etc/letsencrypt/live/chat.tuempresa.com/privkey.pem
# Copiar a directorio del proyecto
sudo cp /etc/letsencrypt/live/chat.tuempresa.com/fullchain.pem nginx/ssl/cert.pem
sudo cp /etc/letsencrypt/live/chat.tuempresa.com/privkey.pem nginx/ssl/key.pem
# Reiniciar nginx
docker compose restart nginx
```
### 7. Configurar Renovación Automática
```bash
# Crear script de renovación
sudo nano /etc/cron.d/certbot-renew
```
```
0 3 * * * root certbot renew --quiet --post-hook "cp /etc/letsencrypt/live/chat.tuempresa.com/*.pem /opt/WhatsAppCentralizado/nginx/ssl/ && docker compose -f /opt/WhatsAppCentralizado/docker-compose.yml restart nginx"
```
---
## Configuración de Nginx
### nginx/nginx.conf
```nginx
events {
worker_connections 1024;
}
http {
upstream frontend {
server frontend:80;
}
upstream api {
server api-gateway:8000;
}
upstream websocket {
server whatsapp-core:3001;
}
# Redirect HTTP to HTTPS
server {
listen 80;
server_name chat.tuempresa.com;
return 301 https://$server_name$request_uri;
}
# HTTPS Server
server {
listen 443 ssl http2;
server_name chat.tuempresa.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Frontend
location / {
proxy_pass http://frontend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# API
location /api {
proxy_pass http://api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Timeouts para operaciones largas
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_send_timeout 300;
}
# Auth endpoints
location /auth {
proxy_pass http://api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# WebSocket
location /ws {
proxy_pass http://websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 86400;
}
# Webhook de Odoo
location /api/odoo/webhook {
proxy_pass http://api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# Media files
location /media {
alias /var/www/media;
expires 30d;
add_header Cache-Control "public, immutable";
}
}
}
```
---
## Backups
### Script de Backup
```bash
#!/bin/bash
# /opt/WhatsAppCentralizado/scripts/backup.sh
BACKUP_DIR="/opt/backups/whatsapp"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=30
mkdir -p $BACKUP_DIR
# Backup PostgreSQL
docker compose exec -T postgres pg_dump -U $DB_USER whatsapp_central | gzip > $BACKUP_DIR/db_$DATE.sql.gz
# Backup sesiones WhatsApp
tar -czf $BACKUP_DIR/sessions_$DATE.tar.gz -C /var/lib/docker/volumes whatsapp_sessions
# Backup configuración
tar -czf $BACKUP_DIR/config_$DATE.tar.gz .env docker-compose.yml nginx/
# Eliminar backups antiguos
find $BACKUP_DIR -type f -mtime +$RETENTION_DAYS -delete
echo "Backup completado: $DATE"
```
### Programar Backup
```bash
# Editar crontab
crontab -e
```
```
# Backup diario a las 3 AM
0 3 * * * /opt/WhatsAppCentralizado/scripts/backup.sh >> /var/log/whatsapp-backup.log 2>&1
```
### Restaurar Backup
```bash
# Restaurar base de datos
gunzip -c backup/db_20240115.sql.gz | docker compose exec -T postgres psql -U $DB_USER whatsapp_central
# Restaurar sesiones
docker compose down
tar -xzf backup/sessions_20240115.tar.gz -C /var/lib/docker/volumes
docker compose up -d
```
---
## Monitoreo
### Logs
```bash
# Ver todos los logs
docker compose logs -f
# Ver logs de servicio específico
docker compose logs -f api-gateway
docker compose logs -f whatsapp-core
# Ver últimas 100 líneas
docker compose logs --tail=100 api-gateway
```
### Healthchecks
```bash
# Estado de contenedores
docker compose ps
# Uso de recursos
docker stats
```
### Verificar Servicios
```bash
# API
curl -s https://chat.tuempresa.com/api/health | jq
# Frontend
curl -I https://chat.tuempresa.com
# WebSocket
wscat -c wss://chat.tuempresa.com/ws
```
---
## Actualización
### Proceso de Actualización
```bash
cd /opt/WhatsAppCentralizado
# Hacer backup primero
./scripts/backup.sh
# Obtener cambios
git pull origin main
# Reconstruir imágenes
docker compose build
# Aplicar migraciones
docker compose exec api-gateway alembic upgrade head
# Reiniciar servicios
docker compose up -d
# Verificar logs
docker compose logs -f
```
### Rollback
```bash
# Volver a versión anterior
git checkout <commit_anterior>
# Reconstruir
docker compose build
docker compose up -d
# Restaurar base de datos si es necesario
gunzip -c backup/db_<fecha>.sql.gz | docker compose exec -T postgres psql -U $DB_USER whatsapp_central
```
---
## Troubleshooting
### Problemas Comunes
#### Contenedor no inicia
```bash
# Ver logs detallados
docker compose logs <servicio>
# Verificar configuración
docker compose config
```
#### Error de conexión a PostgreSQL
```bash
# Verificar que postgres está corriendo
docker compose ps postgres
# Verificar credenciales
docker compose exec postgres psql -U $DB_USER -d whatsapp_central
```
#### WhatsApp no conecta
```bash
# Verificar logs de whatsapp-core
docker compose logs whatsapp-core
# Verificar sesiones
ls -la volumes/whatsapp_sessions/
# Reiniciar servicio
docker compose restart whatsapp-core
```
#### Frontend no carga
```bash
# Verificar build
docker compose logs frontend
# Reconstruir frontend
docker compose build frontend
docker compose up -d frontend
```
### Comandos Útiles
```bash
# Reiniciar todo
docker compose restart
# Reiniciar servicio específico
docker compose restart api-gateway
# Reconstruir sin cache
docker compose build --no-cache
# Limpiar volúmenes (¡CUIDADO!)
docker compose down -v
# Ver uso de disco
docker system df
# Limpiar imágenes no usadas
docker image prune -a
```
---
## Seguridad
### Firewall
```bash
# Instalar ufw
sudo apt install ufw
# Configurar reglas
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Activar
sudo ufw enable
```
### Fail2ban
```bash
# Instalar
sudo apt install fail2ban
# Configurar para nginx
sudo nano /etc/fail2ban/jail.local
```
```ini
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 3600
```
### Actualizaciones de Seguridad
```bash
# Habilitar actualizaciones automáticas
sudo apt install unattended-upgrades
sudo dpkg-reconfigure unattended-upgrades
```
---
## Escalamiento
### Múltiples Números WhatsApp
Para manejar muchos números, escalar whatsapp-core:
```yaml
# docker-compose.override.yml
services:
whatsapp-core:
deploy:
replicas: 3
volumes:
- whatsapp_sessions:/app/sessions
```
### Alta Disponibilidad
Para producción de alta disponibilidad:
1. **Load Balancer** externo (HAProxy, AWS ALB)
2. **PostgreSQL** en cluster (Patroni) o managed (RDS)
3. **Redis** en cluster o managed (ElastiCache)
4. **Storage** compartido para sesiones (NFS, EFS)
---
## Contacto
Para soporte técnico, contactar al equipo de desarrollo.

786
docs/flow-builder/README.md Normal file
View File

@@ -0,0 +1,786 @@
# Flow Builder - Guía Completa
## Introducción
El Flow Builder es el editor visual para crear chatbots sin código. Permite diseñar flujos de conversación arrastrando y conectando nodos.
## Interfaz
```
┌─────────────────────────────────────────────────────────────────────┐
│ Flujo: Bienvenida [Guardar] [Probar] [Activar] │
├───────────┬─────────────────────────────────────────────────────────┤
│ NODOS │ CANVAS │
│ ───────── │ │
│ 📨 Mensaje│ [Nodos conectados con líneas] │
│ 🔘 Botones│ │
│ 📋 Lista │ │
│ ❓ Input │ │
│ ⑂ Condición │
│ ... │ │
├───────────┼─────────────────────────────────────────────────────────┤
│ │ PANEL DE PROPIEDADES (al seleccionar un nodo) │
└───────────┴─────────────────────────────────────────────────────────┘
```
---
## Tipos de Nodos
### Nodos de Trigger (Inicio)
#### welcome
Inicia el flujo cuando un contacto escribe por primera vez.
```json
{
"type": "welcome",
"id": "trigger_1",
"data": {
"label": "Primer mensaje"
}
}
```
#### keyword
Inicia el flujo cuando el mensaje contiene palabras clave.
```json
{
"type": "keyword",
"id": "trigger_2",
"data": {
"keywords": ["precio", "costo", "cuanto"],
"match_type": "contains"
}
}
```
**Match types:**
- `exact` - Coincidencia exacta
- `contains` - Contiene la palabra
- `starts_with` - Empieza con
- `regex` - Expresión regular
#### fallback
Se activa cuando ningún otro flujo coincide.
```json
{
"type": "fallback",
"id": "trigger_3",
"data": {
"label": "No entendido"
}
}
```
#### event
Se activa por eventos externos (webhook, Odoo).
```json
{
"type": "event",
"id": "trigger_4",
"data": {
"event_type": "odoo_order_confirmed",
"filters": {
"amount_total": { "gt": 1000 }
}
}
}
```
---
### Nodos de Mensaje
#### text
Envía un mensaje de texto.
```json
{
"type": "text",
"id": "msg_1",
"data": {
"content": "¡Hola {{contact.name}}! 👋\n\n¿En qué te puedo ayudar?",
"typing_delay": 1500
}
}
```
**Variables disponibles:**
- `{{contact.name}}` - Nombre del contacto
- `{{contact.phone}}` - Teléfono
- `{{agent.name}}` - Nombre del agente
- `{{variables.xxx}}` - Variables capturadas
#### image
Envía una imagen.
```json
{
"type": "image",
"id": "msg_2",
"data": {
"url": "https://example.com/producto.jpg",
"caption": "Nuestro producto estrella"
}
}
```
#### video
Envía un video.
```json
{
"type": "video",
"id": "msg_3",
"data": {
"url": "https://example.com/demo.mp4",
"caption": "Video demostrativo"
}
}
```
#### document
Envía un documento (PDF, Excel, etc).
```json
{
"type": "document",
"id": "msg_4",
"data": {
"url": "https://example.com/catalogo.pdf",
"filename": "Catálogo 2024.pdf"
}
}
```
#### location
Envía una ubicación.
```json
{
"type": "location",
"id": "msg_5",
"data": {
"latitude": 19.4326,
"longitude": -99.1332,
"name": "Nuestra Oficina",
"address": "Av. Reforma 123, CDMX"
}
}
```
#### buttons
Envía mensaje con botones (máximo 3).
```json
{
"type": "buttons",
"id": "msg_6",
"data": {
"content": "¿Qué necesitas?",
"buttons": [
{ "id": "ventas", "text": "Ventas" },
{ "id": "soporte", "text": "Soporte" },
{ "id": "otro", "text": "Otro" }
]
}
}
```
#### list
Envía mensaje con lista de opciones (máximo 10).
```json
{
"type": "list",
"id": "msg_7",
"data": {
"content": "Selecciona una categoría:",
"button_text": "Ver opciones",
"sections": [
{
"title": "Productos",
"rows": [
{ "id": "laptops", "title": "Laptops", "description": "Computadoras portátiles" },
{ "id": "phones", "title": "Teléfonos", "description": "Smartphones" }
]
},
{
"title": "Servicios",
"rows": [
{ "id": "soporte", "title": "Soporte Técnico" },
{ "id": "garantia", "title": "Garantías" }
]
}
]
}
}
```
#### template
Usa un mensaje guardado como template.
```json
{
"type": "template",
"id": "msg_8",
"data": {
"template_id": "uuid-del-template",
"variables": {
"producto": "{{variables.producto_seleccionado}}"
}
}
}
```
---
### Nodos de Lógica
#### condition
Bifurca según condiciones.
```json
{
"type": "condition",
"id": "cond_1",
"data": {
"conditions": [
{
"groups": [
{
"field": "{{message.text}}",
"operator": "contains",
"value": "precio"
}
],
"logic": "AND"
}
],
"outputs": ["true", "false"]
}
}
```
**Operadores:**
- Texto: `equals`, `not_equals`, `contains`, `not_contains`, `starts_with`, `ends_with`, `regex`
- Número: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `between`
- Lista: `in`, `not_in`, `is_empty`, `is_not_empty`
- General: `exists`, `not_exists`, `is_null`, `is_not_null`
#### switch
Múltiples salidas según valor.
```json
{
"type": "switch",
"id": "switch_1",
"data": {
"field": "{{variables.departamento}}",
"cases": [
{ "value": "ventas", "output": "ventas" },
{ "value": "soporte", "output": "soporte" },
{ "value": "cobranza", "output": "cobranza" }
],
"default_output": "default"
}
}
```
#### wait_input
Espera respuesta del usuario y la guarda.
```json
{
"type": "wait_input",
"id": "input_1",
"data": {
"variable": "nombre_cliente",
"timeout_seconds": 300,
"timeout_output": "timeout",
"validation": {
"type": "text",
"min_length": 2,
"max_length": 100
},
"error_message": "Por favor ingresa un nombre válido."
}
}
```
#### delay
Pausa antes de continuar.
```json
{
"type": "delay",
"id": "delay_1",
"data": {
"seconds": 3,
"random_range": [2, 5]
}
}
```
#### set_variable
Asigna o modifica una variable.
```json
{
"type": "set_variable",
"id": "set_1",
"data": {
"variable": "contador",
"operation": "increment",
"value": 1
}
}
```
**Operaciones:**
- `set` - Asignar valor
- `increment` - Incrementar
- `decrement` - Decrementar
- `append` - Agregar a lista
- `concat` - Concatenar texto
#### random
A/B Testing - bifurca aleatoriamente.
```json
{
"type": "random",
"id": "ab_1",
"data": {
"test_name": "Test saludo",
"variants": [
{ "name": "A", "weight": 50, "output": "variant_a" },
{ "name": "B", "weight": 50, "output": "variant_b" }
],
"track_metric": "response_rate"
}
}
```
#### loop
Repetir bloque.
```json
{
"type": "loop",
"id": "loop_1",
"data": {
"max_iterations": 3,
"condition": {
"field": "{{variables.confirmado}}",
"operator": "not_equals",
"value": "si"
},
"outputs": ["continue", "exit"]
}
}
```
#### go_to
Salta a otro flujo o nodo.
```json
{
"type": "go_to",
"id": "goto_1",
"data": {
"target_type": "flow",
"target_id": "uuid-del-flujo",
"pass_context": true
}
}
```
#### sub_flow
Ejecuta un sub-flujo y retorna.
```json
{
"type": "sub_flow",
"id": "sub_1",
"data": {
"flow_id": "uuid-del-subflujo",
"input_variables": {
"producto_id": "{{variables.producto}}"
},
"output_variable": "resultado_subflujo"
}
}
```
#### javascript
Ejecuta código JavaScript personalizado.
```json
{
"type": "javascript",
"id": "js_1",
"data": {
"code": "const total = variables.precio * variables.cantidad;\nreturn { total, descuento: total > 1000 ? 0.1 : 0 };",
"output_variable": "calculo"
}
}
```
---
### Nodos de Validación
#### validate_email
Valida formato de email.
```json
{
"type": "validate_email",
"id": "val_1",
"data": {
"input": "{{message.text}}",
"output_variable": "email_valido",
"outputs": ["valid", "invalid"]
}
}
```
#### validate_phone
Valida formato de teléfono.
```json
{
"type": "validate_phone",
"id": "val_2",
"data": {
"input": "{{message.text}}",
"country": "MX",
"output_variable": "telefono_valido",
"outputs": ["valid", "invalid"]
}
}
```
#### validate_number
Valida número en rango.
```json
{
"type": "validate_number",
"id": "val_3",
"data": {
"input": "{{message.text}}",
"min": 1,
"max": 100,
"output_variable": "cantidad",
"outputs": ["valid", "invalid"]
}
}
```
#### validate_date
Valida formato de fecha.
```json
{
"type": "validate_date",
"id": "val_4",
"data": {
"input": "{{message.text}}",
"format": "DD/MM/YYYY",
"min_date": "today",
"max_date": "+30days",
"output_variable": "fecha",
"outputs": ["valid", "invalid"]
}
}
```
#### validate_options
Valida contra lista de opciones.
```json
{
"type": "validate_options",
"id": "val_5",
"data": {
"input": "{{message.text}}",
"options": ["1", "2", "3", "uno", "dos", "tres"],
"case_insensitive": true,
"output_variable": "opcion",
"outputs": ["valid", "invalid"]
}
}
```
#### retry_input
Reintenta captura con mensaje de error.
```json
{
"type": "retry_input",
"id": "retry_1",
"data": {
"max_retries": 3,
"error_message": "No entendí tu respuesta. Por favor intenta de nuevo.",
"final_fallback": "transfer",
"outputs": ["continue", "max_retries"]
}
}
```
---
### Nodos de Acción
#### transfer
Transfiere a agente humano.
```json
{
"type": "transfer",
"id": "act_1",
"data": {
"target_type": "queue",
"target_id": "uuid-de-cola",
"priority": "high",
"message": "Te comunico con un agente. Por favor espera."
}
}
```
#### close
Cierra la conversación.
```json
{
"type": "close",
"id": "act_2",
"data": {
"resolution": "resolved",
"send_csat": true,
"message": "¡Gracias por contactarnos! ¿Hay algo más en que pueda ayudarte?"
}
}
```
#### tag
Agrega o quita etiquetas.
```json
{
"type": "tag",
"id": "act_3",
"data": {
"add": ["lead", "interesado"],
"remove": ["nuevo"]
}
}
```
#### note
Agrega nota interna.
```json
{
"type": "note",
"id": "act_4",
"data": {
"content": "Cliente interesado en {{variables.producto}}. Presupuesto: {{variables.presupuesto}}"
}
}
```
#### notify
Envía notificación.
```json
{
"type": "notify",
"id": "act_5",
"data": {
"type": "email",
"recipients": ["admin@empresa.com"],
"subject": "Nuevo lead VIP",
"message": "El cliente {{contact.name}} está interesado en {{variables.producto}}"
}
}
```
#### webhook
Llama API externa.
```json
{
"type": "webhook",
"id": "act_6",
"data": {
"url": "https://api.example.com/leads",
"method": "POST",
"headers": {
"Authorization": "Bearer {{secrets.api_key}}"
},
"body": {
"name": "{{contact.name}}",
"phone": "{{contact.phone}}",
"product": "{{variables.producto}}"
},
"output_variable": "api_response",
"retry": {
"max_attempts": 3,
"delay_seconds": 5
}
}
}
```
#### ai_response
Genera respuesta con IA.
```json
{
"type": "ai_response",
"id": "act_7",
"data": {
"provider": "openai",
"model": "gpt-4",
"system_prompt": "Eres un asistente de ventas amable. Productos: {{odoo.products}}",
"include_context": {
"last_messages": 10,
"contact_info": true,
"odoo_data": true
},
"allowed_actions": ["transfer", "create_lead"],
"output_variable": "ai_response",
"fallback_on_error": "transfer"
}
}
```
---
### Nodos de Odoo
Ver [Integración Odoo](../odoo-integration/README.md) para documentación completa.
---
## Variables del Sistema
```
# Contacto
{{contact.id}}
{{contact.name}}
{{contact.phone}}
{{contact.email}}
{{contact.company}}
{{contact.tags}}
{{contact.odoo_id}}
{{contact.created_at}}
{{contact.custom.xxx}}
# Conversación
{{conversation.id}}
{{conversation.status}}
{{conversation.assigned_to}}
{{conversation.queue}}
{{conversation.started_at}}
# Mensaje actual
{{message.id}}
{{message.text}}
{{message.type}}
{{message.media_url}}
# Sistema
{{system.date}}
{{system.time}}
{{system.datetime}}
{{system.day_of_week}}
{{system.business_hours}}
{{system.timestamp}}
# Agente (si asignado)
{{agent.id}}
{{agent.name}}
{{agent.email}}
# Odoo (si conectado)
{{odoo.partner.id}}
{{odoo.partner.name}}
{{odoo.partner.email}}
{{odoo.partner.balance}}
{{odoo.last_order.name}}
{{odoo.last_order.total}}
{{odoo.last_order.state}}
# Variables capturadas
{{variables.xxx}}
```
---
## Estructura de Flujo (JSON)
```json
{
"id": "uuid",
"name": "Bienvenida",
"description": "Flujo de bienvenida",
"trigger_type": "welcome",
"trigger_value": null,
"nodes": {
"nodes": [
{
"id": "trigger_1",
"type": "welcome",
"position": { "x": 100, "y": 100 },
"data": { "label": "Inicio" }
},
{
"id": "msg_1",
"type": "text",
"position": { "x": 100, "y": 200 },
"data": { "content": "¡Hola!" }
}
],
"edges": [
{
"id": "e1",
"source": "trigger_1",
"target": "msg_1",
"sourceHandle": "default"
}
],
"viewport": {
"x": 0,
"y": 0,
"zoom": 1
}
},
"variables": {
"producto": { "type": "string", "default": "" },
"cantidad": { "type": "number", "default": 1 }
},
"is_active": true,
"version": 1
}
```
---
## Mejores Prácticas
1. **Nombra los nodos claramente** para fácil identificación
2. **Usa sub-flujos** para lógica repetida (validaciones, etc.)
3. **Siempre incluye fallback** para respuestas no entendidas
4. **Valida inputs** antes de usarlos en acciones
5. **Limita reintentos** para evitar loops infinitos
6. **Usa A/B testing** para optimizar mensajes
7. **Transfiere a humano** cuando el bot no puede resolver
8. **Guarda contexto** para conversaciones que se retoman después

View File

@@ -0,0 +1,572 @@
# Integración con Odoo
## Visión General
La integración con Odoo es bidireccional:
- **WhatsApp → Odoo**: Crear leads, consultar pedidos, verificar stock, etc.
- **Odoo → WhatsApp**: Notificaciones automáticas de eventos (pedido enviado, factura vencida, etc.)
## Configuración
### 1. Crear Usuario API en Odoo
1. En Odoo, ir a **Configuración → Usuarios y Compañías → Usuarios**
2. Crear nuevo usuario:
- Nombre: `API WhatsApp`
- Email: `api-whatsapp@tuempresa.com`
- Tipo de usuario: `Usuario interno`
3. Asignar permisos según módulos a usar:
- CRM: Usuario
- Ventas: Usuario
- Inventario: Usuario (lectura)
- Helpdesk: Usuario
- Facturación: Contable (lectura)
4. Generar API Key:
- Ir a Preferencias del usuario
- En "Claves API", crear nueva clave
- Guardar la clave de forma segura
### 2. Configurar en WhatsApp Central
```bash
# .env
ODOO_URL=https://odoo.tuempresa.com
ODOO_DB=production
ODOO_USER=api-whatsapp@tuempresa.com
ODOO_API_KEY=tu_api_key_aqui
```
### 3. Probar Conexión
```http
POST /api/odoo/test-connection
Authorization: Bearer {token}
```
---
## Módulos Soportados
### Contactos (res.partner)
| Acción | Nodo | Descripción |
|--------|------|-------------|
| Buscar | `odoo_search_partner` | Buscar por teléfono, email o nombre |
| Crear | `odoo_create_partner` | Crear nuevo contacto |
| Actualizar | `odoo_update_partner` | Modificar datos |
| Sincronizar | Automático | Sync bidireccional |
**Ejemplo: Buscar cliente**
```json
{
"type": "odoo_search_partner",
"data": {
"search_by": "phone",
"value": "{{contact.phone}}",
"output_variable": "odoo_partner"
}
}
```
**Variables resultantes:**
```
{{odoo_partner.id}}
{{odoo_partner.name}}
{{odoo_partner.email}}
{{odoo_partner.phone}}
{{odoo_partner.street}}
{{odoo_partner.city}}
{{odoo_partner.credit}} // Saldo a favor
{{odoo_partner.debit}} // Deuda
```
---
### CRM (crm.lead)
| Acción | Nodo | Descripción |
|--------|------|-------------|
| Crear lead | `odoo_create_lead` | Nueva oportunidad |
| Actualizar etapa | `odoo_update_lead_stage` | Mover en pipeline |
| Agregar nota | `odoo_add_lead_note` | Agregar actividad/nota |
**Ejemplo: Crear lead**
```json
{
"type": "odoo_create_lead",
"data": {
"name": "Interés en {{variables.producto}}",
"contact_name": "{{contact.name}}",
"phone": "{{contact.phone}}",
"email": "{{variables.email}}",
"description": "Cliente contactó por WhatsApp.\nProducto: {{variables.producto}}\nPresupuesto: {{variables.presupuesto}}",
"expected_revenue": "{{variables.presupuesto}}",
"team_id": 1,
"user_id": 5,
"output_variable": "lead"
}
}
```
**Ejemplo: Mover etapa**
```json
{
"type": "odoo_update_lead_stage",
"data": {
"lead_id": "{{lead.id}}",
"stage": "qualified"
}
}
```
Etapas disponibles:
- `new` - Nuevo
- `qualified` - Calificado
- `proposition` - Propuesta
- `negotiation` - Negociación
- `won` - Ganado
- `lost` - Perdido
---
### Ventas (sale.order)
| Acción | Nodo | Descripción |
|--------|------|-------------|
| Buscar pedidos | `odoo_search_orders` | Pedidos del cliente |
| Crear cotización | `odoo_create_quotation` | Nueva cotización |
| Confirmar pedido | `odoo_confirm_order` | Cotización → Pedido |
| Enviar PDF | `odoo_send_quotation_pdf` | Enviar por WhatsApp |
**Ejemplo: Buscar pedidos**
```json
{
"type": "odoo_search_orders",
"data": {
"partner_id": "{{odoo_partner.id}}",
"states": ["sale", "done"],
"limit": 5,
"output_variable": "orders"
}
}
```
**Variables resultantes:**
```
{{orders}} // Array de pedidos
{{orders[0].id}}
{{orders[0].name}} // SO-2024-001
{{orders[0].state}}
{{orders[0].amount_total}}
{{orders[0].date_order}}
{{orders[0].commitment_date}} // Fecha compromiso
```
**Ejemplo: Crear cotización**
```json
{
"type": "odoo_create_quotation",
"data": {
"partner_id": "{{odoo_partner.id}}",
"lines": [
{
"product_id": "{{variables.producto_id}}",
"quantity": "{{variables.cantidad}}"
}
],
"validity_days": 30,
"output_variable": "quotation"
}
}
```
**Ejemplo: Enviar PDF**
```json
{
"type": "odoo_send_quotation_pdf",
"data": {
"order_id": "{{quotation.id}}",
"message": "Aquí está tu cotización {{quotation.name}}"
}
}
```
---
### Inventario (stock)
| Acción | Nodo | Descripción |
|--------|------|-------------|
| Verificar stock | `odoo_check_stock` | Disponibilidad |
| Estado envío | `odoo_tracking_status` | Tracking de pedido |
**Ejemplo: Verificar stock**
```json
{
"type": "odoo_check_stock",
"data": {
"search_by": "name",
"value": "{{variables.producto}}",
"location_id": 8,
"output_variable": "stock"
}
}
```
**Variables resultantes:**
```
{{stock.product_id}}
{{stock.product_name}}
{{stock.qty_available}} // Stock disponible
{{stock.virtual_available}} // Stock proyectado
{{stock.incoming_qty}} // Por recibir
{{stock.outgoing_qty}} // Por enviar
```
**Ejemplo: Estado de envío**
```json
{
"type": "odoo_tracking_status",
"data": {
"order_id": "{{order.id}}",
"output_variable": "tracking"
}
}
```
**Variables resultantes:**
```
{{tracking.state}} // assigned, done, cancel
{{tracking.carrier}} // Nombre paquetería
{{tracking.tracking_ref}} // Número de guía
{{tracking.tracking_url}} // URL de rastreo
{{tracking.scheduled_date}}
{{tracking.date_done}}
```
---
### Helpdesk (helpdesk.ticket)
| Acción | Nodo | Descripción |
|--------|------|-------------|
| Crear ticket | `odoo_create_ticket` | Nuevo ticket soporte |
| Estado ticket | `odoo_ticket_status` | Consultar estado |
**Ejemplo: Crear ticket**
```json
{
"type": "odoo_create_ticket",
"data": {
"name": "{{variables.asunto}}",
"description": "Reporte desde WhatsApp:\n\n{{variables.descripcion}}\n\n---\nConversación: {{conversation.id}}",
"partner_id": "{{odoo_partner.id}}",
"team_id": 1,
"priority": "2",
"attach_conversation": true,
"output_variable": "ticket"
}
}
```
**Variables resultantes:**
```
{{ticket.id}}
{{ticket.number}} // TICKET-001
{{ticket.name}}
{{ticket.stage}} // Nombre de etapa
{{ticket.user_id}} // Asignado a
{{ticket.priority}}
```
---
### Facturación (account.move)
| Acción | Nodo | Descripción |
|--------|------|-------------|
| Saldo cliente | `odoo_check_balance` | Deuda/crédito |
| Enviar factura | `odoo_send_invoice_pdf` | PDF por WhatsApp |
**Ejemplo: Verificar saldo**
```json
{
"type": "odoo_check_balance",
"data": {
"partner_id": "{{odoo_partner.id}}",
"output_variable": "balance"
}
}
```
**Variables resultantes:**
```
{{balance.total_due}} // Total adeudado
{{balance.total_overdue}} // Vencido
{{balance.credit}} // A favor
{{balance.last_payment_date}}
{{balance.last_payment_amount}}
{{balance.invoices}} // Lista de facturas pendientes
```
**Ejemplo: Enviar factura**
```json
{
"type": "odoo_send_invoice_pdf",
"data": {
"invoice_id": "{{variables.invoice_id}}",
"message": "Aquí está tu factura. Total: ${{invoice.amount_total}}"
}
}
```
---
### Productos (product)
| Acción | Nodo | Descripción |
|--------|------|-------------|
| Buscar productos | `odoo_search_products` | Catálogo |
| Detalles producto | `odoo_product_details` | Info completa |
**Ejemplo: Buscar productos**
```json
{
"type": "odoo_search_products",
"data": {
"search": "{{message.text}}",
"category_id": null,
"available_only": true,
"limit": 5,
"output_variable": "products"
}
}
```
**Variables resultantes:**
```
{{products}} // Array
{{products[0].id}}
{{products[0].name}}
{{products[0].list_price}}
{{products[0].qty_available}}
{{products[0].image_url}}
{{products[0].description}}
```
---
### Calendario (calendar.event)
| Acción | Nodo | Descripción |
|--------|------|-------------|
| Disponibilidad | `odoo_check_availability` | Horarios libres |
| Crear cita | `odoo_create_appointment` | Agendar evento |
**Ejemplo: Verificar disponibilidad**
```json
{
"type": "odoo_check_availability",
"data": {
"user_id": 5,
"date_from": "{{system.date}}",
"date_to": "{{system.date}}+7days",
"duration_hours": 1,
"output_variable": "slots"
}
}
```
**Variables resultantes:**
```
{{slots}} // Array de horarios
{{slots[0].date}}
{{slots[0].start_time}}
{{slots[0].end_time}}
```
**Ejemplo: Crear cita**
```json
{
"type": "odoo_create_appointment",
"data": {
"name": "Cita con {{contact.name}}",
"start": "{{variables.fecha}} {{variables.hora}}",
"duration": 1,
"partner_id": "{{odoo_partner.id}}",
"user_id": 5,
"description": "Cita agendada desde WhatsApp",
"send_invitation": true,
"output_variable": "appointment"
}
}
```
---
## Automatizaciones Odoo → WhatsApp
### Configuración de Webhooks
1. Instalar módulo de webhooks en Odoo o usar Automated Actions
2. Configurar URL de webhook:
```
https://chat.tuempresa.com/api/odoo/webhook
```
3. Configurar secret para validación
### Eventos Disponibles
#### Pedido Confirmado
```json
{
"event": "sale.order.confirmed",
"trigger": "state changed to 'sale'",
"template": {
"message": "✅ ¡Tu pedido ha sido confirmado!\n\nPedido: {{order.name}}\nTotal: ${{order.amount_total}}\n\nTe notificaremos cuando sea enviado.",
"attach_pdf": true
}
}
```
#### Pedido Enviado
```json
{
"event": "stock.picking.done",
"trigger": "state changed to 'done'",
"template": {
"message": "🚚 ¡Tu pedido está en camino!\n\nNúmero de guía: {{picking.tracking_ref}}\nPaquetería: {{picking.carrier}}\n\nRastrear: {{picking.tracking_url}}"
}
}
```
#### Pago Recibido
```json
{
"event": "account.payment.posted",
"trigger": "state changed to 'posted'",
"template": {
"message": "💰 ¡Gracias por tu pago!\n\nMonto: ${{payment.amount}}\nReferencia: {{payment.name}}\n\nTu saldo actual es: ${{partner.balance}}"
}
}
```
#### Factura Vencida
```json
{
"event": "account.move.overdue",
"trigger": "invoice_date_due < today AND state = 'posted'",
"delay": "3 days",
"template": {
"message": "⚠️ Recordatorio de pago\n\nFactura: {{invoice.name}}\nMonto: ${{invoice.amount_residual}}\nVencimiento: {{invoice.invoice_date_due}}\n\n¿Necesitas ayuda con el pago?"
},
"retry": {
"interval_days": 7,
"max_attempts": 3
}
}
```
#### Recordatorio de Cita
```json
{
"event": "calendar.event.reminder",
"trigger": "start - 24 hours",
"template": {
"message": "📅 Recordatorio: Tienes una cita mañana\n\n📍 {{event.location}}\n🕐 {{event.start_time}}\n\n¿Confirmas tu asistencia?",
"buttons": [
{"id": "confirm", "text": "Confirmar"},
{"id": "reschedule", "text": "Reagendar"},
{"id": "cancel", "text": "Cancelar"}
]
}
}
```
#### Ticket Resuelto
```json
{
"event": "helpdesk.ticket.closed",
"trigger": "stage.is_close = true",
"template": {
"message": "✅ Tu ticket #{{ticket.number}} ha sido resuelto.\n\n¿Cómo calificarías la atención recibida?",
"send_csat": true
}
}
```
---
## Sincronización de Contactos
### WhatsApp → Odoo
- Al recibir mensaje de número nuevo, buscar en Odoo
- Si no existe, opcionalmente crear partner
- Vincular `contact.odoo_partner_id`
### Odoo → WhatsApp
- Importar partners con campo `mobile` lleno
- Filtrar por categoría/etiqueta si se desea
- Ejecutar sync programado o manual
### Mapeo de Campos
| WhatsApp | Odoo |
|----------|------|
| phone_number | mobile |
| name | name |
| email | email |
| company | parent_id.name |
| tags | category_id |
| custom.rfc | vat |
| custom.direccion | street + city |
---
## Módulo Odoo
### Instalación
```bash
# Copiar módulo a addons
cp -r odoo_whatsapp_hub /odoo/addons/
# Actualizar lista de apps
# En Odoo: Apps → Actualizar lista de aplicaciones
# Instalar módulo
# Buscar "WhatsApp Hub" e instalar
```
### Funcionalidades
1. **Tab WhatsApp en Partner**
- Ver conversaciones del cliente
- Historial de mensajes
- Enviar mensaje rápido
2. **Widget de Chat**
- Chat en tiempo real desde Odoo
- Ver estado de conversación
- Transferir a agente
3. **Acciones Automáticas**
- Enviar WhatsApp al confirmar pedido
- Notificar cambios de estado
- Recordatorios automáticos
4. **Envío Masivo**
- Seleccionar partners
- Usar templates
- Programar envío
---
## Mejores Prácticas
1. **Usa cache** para consultas frecuentes (productos, stock)
2. **Limita llamadas** a Odoo para no saturar
3. **Maneja errores** con fallback a agente humano
4. **Valida permisos** del usuario API
5. **Loguea transacciones** para auditoría
6. **Sincroniza en horarios** de baja demanda

View File

@@ -0,0 +1,706 @@
# WhatsApp Centralizado - Documento de Diseño
**Fecha:** 2026-01-29
**Versión:** 1.0
**Estado:** Aprobado para implementación
---
## 1. Resumen Ejecutivo
Plataforma de mensajería centralizada con automatización de chatbots, gestión multi-agente e integración profunda con Odoo. Similar a Kommo, Wasapi, ManyChat y Brevo pero con enfoque en integración empresarial.
### Decisiones Clave
| Aspecto | Decisión |
|---------|----------|
| **Enfoque** | Chatbots + Multi-agente + Multi-canal |
| **Canal inicial** | WhatsApp (Baileys) |
| **Stack backend** | Node.js (WhatsApp) + Python/FastAPI (API) |
| **Stack frontend** | React + TypeScript |
| **Base de datos** | PostgreSQL + Redis |
| **Editor chatbot** | Visual drag & drop (React Flow) |
| **Modelo** | Single-tenant |
| **Despliegue** | Docker Compose en servidores propios |
| **Integración principal** | Odoo (bidireccional) |
---
## 2. Arquitectura General
```
┌─────────────────────────────────────────────────────────────────┐
│ FRONTEND (React) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ Dashboard │ │ Inbox Chat │ │ Flow Builder (React │ │
│ │ │ │ (Agentes) │ │ Flow) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ API GATEWAY (Python/FastAPI) │
│ • Autenticación JWT • REST API • WebSocket para tiempo real │
└─────────────────────────────────────────────────────────────────┘
┌───────────────┼───────────────┐
▼ ▼ ▼
┌──────────────────┐ ┌──────────────┐ ┌──────────────────────────┐
│ WHATSAPP CORE │ │ FLOW ENGINE │ │ INTEGRATION SERVICE │
│ (Node.js + │ │ (Python) │ │ (Python) │
│ Baileys) │ │ Motor de │ │ • Webhooks │
│ • Multi-número │ │ chatbot │ │ • Odoo XML-RPC │
│ • Sesiones │ │ │ │ • APIs externas │
└──────────────────┘ └──────────────┘ └──────────────────────────┘
│ │ │
└───────────────┼───────────────┘
┌──────────────────┐
│ PostgreSQL+Redis │
└──────────────────┘
```
---
## 3. Estructura del Proyecto
```
WhatsAppCentralizado/
├── docker-compose.yml
├── .env.example
├── services/
│ ├── whatsapp-core/ # Node.js + Baileys
│ │ ├── Dockerfile
│ │ ├── package.json
│ │ └── src/
│ │ ├── index.ts
│ │ ├── sessions/ # Gestión de sesiones WhatsApp
│ │ ├── handlers/ # Procesamiento de mensajes
│ │ └── api/ # API interna
│ │
│ ├── api-gateway/ # Python + FastAPI
│ │ ├── Dockerfile
│ │ ├── requirements.txt
│ │ └── app/
│ │ ├── main.py
│ │ ├── routers/
│ │ ├── models/
│ │ ├── schemas/
│ │ └── services/
│ │
│ ├── flow-engine/ # Python - Motor de chatbot
│ │ ├── Dockerfile
│ │ └── app/
│ │ ├── engine.py
│ │ ├── nodes/
│ │ └── context.py
│ │
│ └── integrations/ # Python - Integraciones
│ ├── Dockerfile
│ └── app/
│ ├── odoo.py
│ └── webhooks.py
├── frontend/ # React + TypeScript
│ ├── Dockerfile
│ ├── package.json
│ └── src/
│ ├── pages/
│ │ ├── Dashboard/
│ │ ├── Inbox/
│ │ └── FlowBuilder/
│ ├── components/
│ └── hooks/
└── database/
└── migrations/
```
---
## 4. Modelo de Datos
### 4.1 Tablas Principales
```sql
-- Usuarios y Autenticación
users
id (UUID, PK)
email (UNIQUE)
password_hash
name
role (admin, supervisor, agent)
status (online, away, busy, offline)
is_active
created_at
updated_at
-- Números de WhatsApp conectados
whatsapp_accounts
id (UUID, PK)
phone_number
name (alias)
status (connected, disconnected, banned)
session_data (JSONB)
qr_code (TEXT)
created_at
-- Contactos
contacts
id (UUID, PK)
phone_number (UNIQUE)
name
email
company
metadata (JSONB)
tags (ARRAY)
odoo_partner_id (INT)
created_at
-- Colas de atención
queues
id (UUID, PK)
name
description
assignment_method (round_robin, least_busy, skill_based)
max_per_agent (INT)
sla_first_response (INT, segundos)
sla_resolution (INT, segundos)
business_hours (JSONB)
fallback_flow_id (FK)
is_active
-- Agentes en colas
queue_agents
id (UUID, PK)
queue_id (FK)
user_id (FK)
is_supervisor
skills (ARRAY)
-- Conversaciones
conversations
id (UUID, PK)
whatsapp_account_id (FK)
contact_id (FK)
queue_id (FK, nullable)
assigned_to (FK users, nullable)
status (bot, waiting, active, resolved)
priority (low, normal, high, urgent)
current_flow_id (FK, nullable)
flow_context (JSONB)
sla_first_response_at (TIMESTAMP)
sla_first_response_met (BOOLEAN)
resolved_at (TIMESTAMP)
csat_score (INT, 1-5)
csat_feedback (TEXT)
last_message_at
created_at
-- Mensajes
messages
id (UUID, PK)
conversation_id (FK)
direction (inbound, outbound)
type (text, image, audio, video, document, buttons, list, location, contact)
content (TEXT)
media_url
metadata (JSONB)
sent_by (FK users, nullable)
is_internal_note (BOOLEAN)
status (pending, sent, delivered, read, failed)
created_at
-- Flujos de chatbot
flows
id (UUID, PK)
name
description
trigger_type (keyword, welcome, fallback, manual, event)
trigger_value
nodes (JSONB)
variables (JSONB)
is_active
version (INT)
created_at
-- Templates de mensajes
message_templates
id (UUID, PK)
name
content (TEXT)
attachments (JSONB)
variables (ARRAY)
created_at
-- Respuestas rápidas
quick_replies
id (UUID, PK)
shortcut
content
attachments (JSONB)
queue_id (FK, nullable)
created_by (FK)
created_at
-- Etiquetas
tags
id (UUID, PK)
name
color
created_at
-- Configuración Odoo
odoo_config
id (UUID, PK)
url
database
username
api_key_encrypted
is_active
last_sync_at
created_at
-- Automatizaciones Odoo → WhatsApp
odoo_automations
id (UUID, PK)
name
odoo_model (sale.order, stock.picking, etc.)
odoo_trigger (state change, field change)
odoo_condition (JSONB)
message_template_id (FK)
is_active
created_at
```
---
## 5. Flow Builder
### 5.1 Tipos de Nodos
#### Nodos de Trigger
- `welcome` - Primer mensaje del contacto
- `keyword` - Palabras clave específicas
- `fallback` - Cuando ningún otro flujo coincide
- `event` - Evento externo (webhook, Odoo)
- `schedule` - Horario programado
#### Nodos de Mensaje
- `text` - Texto con variables y formateo
- `image` - Imagen con caption
- `video` - Video con caption
- `audio` - Audio/nota de voz
- `document` - PDF, Excel, Word
- `location` - Ubicación
- `contact` - Tarjeta de contacto
- `sticker` - Stickers
- `buttons` - Hasta 3 botones
- `list` - Lista con secciones (hasta 10 opciones)
- `template` - Mensaje reutilizable
- `carousel` - Múltiples tarjetas
#### Nodos de Lógica
- `condition` - Condiciones múltiples (AND/OR/NOT)
- `switch` - Múltiples ramas según valor
- `wait_input` - Esperar respuesta con timeout
- `wait_event` - Esperar evento externo
- `delay` - Delay fijo o aleatorio
- `schedule` - Ejecutar en horario específico
- `random` - A/B testing
- `loop` - Repetir bloque
- `set_variable` - Asignar/modificar variables
- `javascript` - Código custom
- `go_to` - Saltar a otro flujo/nodo
- `sub_flow` - Ejecutar sub-flujo
#### Nodos de Validación
- `validate_email` - Formato email
- `validate_phone` - Formato teléfono
- `validate_number` - Rango numérico
- `validate_date` - Fecha/hora
- `validate_regex` - Expresión regular
- `validate_options` - Lista de opciones
- `retry_input` - Reintentar con mensaje error
#### Nodos de Acción
- `transfer` - Transferir a agente/cola
- `close` - Cerrar conversación
- `tag` - Agregar/quitar etiquetas
- `note` - Nota interna
- `assign` - Asignar a agente
- `notify` - Notificar a agente/admin
- `webhook` - HTTP request
- `odoo_action` - Acciones Odoo
- `email` - Enviar email
- `sms` - Enviar SMS (futuro)
- `ai_response` - Respuesta con IA
- `human_takeover` - Pausar bot
### 5.2 Sistema de Variables
```
{{contact.name}} - Nombre del contacto
{{contact.phone}} - Teléfono
{{contact.email}} - Email
{{contact.tags}} - Etiquetas
{{contact.odoo_id}} - ID en Odoo
{{contact.custom.*}} - Campos personalizados
{{conversation.id}} - ID conversación
{{conversation.channel}} - Canal
{{conversation.agent}} - Agente asignado
{{conversation.status}} - Estado actual
{{message.text}} - Texto del último mensaje
{{message.type}} - Tipo de mensaje
{{system.date}} - Fecha actual
{{system.time}} - Hora actual
{{system.day_of_week}} - Día de la semana
{{system.business_hours}} - Si está en horario
{{odoo.partner.*}} - Datos del partner
{{odoo.last_order.*}} - Último pedido
{{odoo.balance}} - Saldo del cliente
```
### 5.3 A/B Testing
- Distribución configurable entre variantes
- Métricas: tasa de respuesta, conversión, CSAT
- Auto-selección de ganador
- Duración por tiempo o número de contactos
---
## 6. Inbox y Gestión de Agentes
### 6.1 Sistema de Colas
- **Round-robin**: Distribuir equitativamente
- **Least-busy**: Al agente con menos conversaciones
- **Skill-based**: Según habilidades del agente
- **Sticky**: Mismo agente si contacto fue atendido antes
- **Priority**: VIPs primero, luego por tiempo
### 6.2 Configuración de Cola
- Nombre y descripción
- Método de asignación
- Máximo conversaciones por agente
- Re-asignación por timeout
- Horario de atención
- Flujo fuera de horario
- SLA primera respuesta
- SLA resolución
### 6.3 Estados de Agente
- 🟢 **Online** - Recibe nuevas conversaciones
- 🟡 **Ausente** - No recibe nuevas, mantiene activas
- 🔴 **Ocupado** - Atendiendo urgente
- 🍽️ **Almuerzo** - Pausa temporal
- 📞 **En llamada** - No recibe nuevas
-**Offline** - Desconectado
### 6.4 Panel de Supervisor
- Estado de todos los agentes
- Conversaciones en cola
- SLA en tiempo real
- Conversaciones críticas (alerta)
- Métricas por agente
- Re-asignación manual
- Actividad en tiempo real
### 6.5 CSAT
- Encuesta después de resolución
- Escala 1-5 con emojis
- Pregunta de feedback si negativo
- Notificación a supervisor
- Métricas por agente/cola
---
## 7. Integración Odoo
### 7.1 Módulos Soportados
| Módulo | Modelo | Acciones |
|--------|--------|----------|
| Contactos | res.partner | Buscar, crear, actualizar, sincronizar |
| CRM | crm.lead | Crear lead, actualizar etapa, agregar nota |
| Ventas | sale.order | Consultar, crear cotización, confirmar, enviar PDF |
| Inventario | stock.* | Consultar stock, disponibilidad |
| Helpdesk | helpdesk.ticket | Crear ticket, estado, asignar |
| Facturación | account.move | Consultar, enviar PDF, estado pago |
| Calendario | calendar.event | Disponibilidad, crear cita |
| Productos | product.* | Buscar, detalles, precio |
| Envíos | stock.picking | Estado, tracking |
### 7.2 Nodos Odoo en Flow Builder
**Contactos:**
- `odoo_search_partner` - Buscar cliente
- `odoo_create_partner` - Crear cliente
- `odoo_update_partner` - Actualizar cliente
**CRM:**
- `odoo_create_lead` - Crear oportunidad
- `odoo_update_lead_stage` - Mover en pipeline
- `odoo_add_lead_note` - Agregar nota
**Ventas:**
- `odoo_search_orders` - Buscar pedidos
- `odoo_create_quotation` - Crear cotización
- `odoo_confirm_order` - Confirmar pedido
- `odoo_send_quotation_pdf` - Enviar PDF
**Inventario:**
- `odoo_check_stock` - Consultar disponibilidad
- `odoo_tracking_status` - Estado de envío
**Helpdesk:**
- `odoo_create_ticket` - Crear ticket
- `odoo_ticket_status` - Estado de ticket
**Productos:**
- `odoo_search_products` - Buscar productos
- `odoo_product_details` - Información detallada
**Facturación:**
- `odoo_check_balance` - Saldo del cliente
- `odoo_send_invoice_pdf` - Enviar factura
**Calendario:**
- `odoo_check_availability` - Disponibilidad
- `odoo_create_appointment` - Crear cita
### 7.3 Automatizaciones Odoo → WhatsApp
- Pedido confirmado → Mensaje de confirmación
- Pedido enviado → Mensaje con tracking
- Pago recibido → Agradecimiento
- Factura vencida → Recordatorio
- Recordatorio de cita → 24h antes
- Ticket resuelto → Encuesta satisfacción
### 7.4 Módulo Odoo
```
odoo_whatsapp_hub/
├── __manifest__.py
├── models/
│ ├── res_partner.py # Campos WhatsApp en partner
│ ├── whatsapp_account.py
│ ├── whatsapp_conversation.py
│ └── whatsapp_message.py
├── controllers/
│ ├── webhook.py # Eventos de WhatsApp Central
│ └── api.py
├── wizards/
│ ├── send_whatsapp.py # Enviar mensaje
│ └── mass_whatsapp.py # Envío masivo
├── views/
│ ├── res_partner_views.xml # Tab WhatsApp
│ └── whatsapp_*.xml
├── static/src/
│ ├── js/chat_widget.js # Widget de chat
│ └── css/whatsapp.css
└── security/ir.model.access.csv
```
---
## 8. Autenticación y Roles
### 8.1 Roles
| Rol | Permisos |
|-----|----------|
| **Admin** | Todo acceso: config, flujos, usuarios, integraciones |
| **Supervisor** | Ver todas las conversaciones, reasignar, reportes equipo |
| **Agente** | Solo conversaciones asignadas, responder, transferir |
### 8.2 JWT
- Access token: 1 hora
- Refresh token: 7 días (httpOnly cookie)
- Permisos en payload
---
## 9. Docker Compose
```yaml
version: '3.8'
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: whatsapp_central
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
ports:
- "6379:6379"
whatsapp-core:
build: ./services/whatsapp-core
environment:
NODE_ENV: production
API_GATEWAY_URL: http://api-gateway:8000
REDIS_URL: redis://redis:6379
volumes:
- whatsapp_sessions:/app/sessions
ports:
- "3001:3001"
api-gateway:
build: ./services/api-gateway
environment:
DATABASE_URL: postgresql://${DB_USER}:${DB_PASSWORD}@postgres:5432/whatsapp_central
REDIS_URL: redis://redis:6379
JWT_SECRET: ${JWT_SECRET}
ports:
- "8000:8000"
flow-engine:
build: ./services/flow-engine
environment:
DATABASE_URL: postgresql://${DB_USER}:${DB_PASSWORD}@postgres:5432/whatsapp_central
REDIS_URL: redis://redis:6379
integrations:
build: ./services/integrations
environment:
DATABASE_URL: postgresql://${DB_USER}:${DB_PASSWORD}@postgres:5432/whatsapp_central
ODOO_URL: ${ODOO_URL}
ODOO_DB: ${ODOO_DB}
ODOO_USER: ${ODOO_USER}
ODOO_PASSWORD: ${ODOO_PASSWORD}
frontend:
build: ./frontend
ports:
- "3000:80"
nginx:
image: nginx:alpine
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
ports:
- "80:80"
- "443:443"
volumes:
postgres_data:
redis_data:
whatsapp_sessions:
```
---
## 10. Roadmap de Implementación
### Fase 1: Fundación
- Estructura proyecto + Docker Compose
- whatsapp-core: Baileys, sesiones, multi-número
- api-gateway: Auth JWT, roles
- Frontend: Login, Dashboard, gestión números
- Inbox básico: Lista conversaciones, chat
### Fase 2: Flow Engine Básico
- Motor de ejecución de flujos
- Nodos básicos: mensaje, botones, wait_input, condición
- Sistema de variables
- Frontend: Flow Builder con React Flow
- Triggers: welcome, keyword, fallback
### Fase 3: Inbox Avanzado + Multi-agente
- Sistema de colas
- Asignación inteligente
- Transferencia bot → humano → bot
- Estados de agente
- Respuestas rápidas
- Notas internas
- Panel supervisor
- SLA tracking
### Fase 4: Flow Engine Avanzado
- Nodos avanzados: switch, loop, random, sub-flow
- Nodos validación
- Templates reutilizables
- Variables globales
- Nodo JavaScript
- A/B Testing
- Nodo AI Response
### Fase 5: Integración Odoo Completa
- Conexión XML-RPC
- Sincronización contactos
- Todos los nodos Odoo
- Eventos Odoo → WhatsApp
- Envío de PDFs
### Fase 6: Módulo Odoo
- Módulo odoo_whatsapp_hub
- Widget de chat en partner
- Historial conversaciones
- Enviar WhatsApp desde Odoo
- Acciones automáticas
- Envío masivo
### Fase 7: Reportes y Analytics
- Dashboard analytics
- Métricas por agente/cola/flujo
- CSAT
- Exportación
- Reportes programados
### Fase 8: Multi-canal (Futuro)
- Email (SMTP/IMAP)
- SMS (Twilio)
- Inbox unificado
- WhatsApp Business API oficial
---
## 11. Requisitos de Servidor
- **RAM**: 4GB mínimo, 8GB recomendado
- **CPU**: 2 cores mínimo
- **Disco**: SSD, 50GB+
- **SO**: Linux (Ubuntu 22.04 recomendado)
- **Docker**: 24.0+
- **Docker Compose**: 2.20+
---
## 12. Consideraciones de Seguridad
- Passwords con bcrypt (cost 12)
- JWT con refresh tokens en httpOnly cookies
- Rate limiting en auth
- HTTPS obligatorio (Let's Encrypt)
- Secrets en variables de entorno
- No commitear .env
- Backup automatizado de PostgreSQL y sesiones
- Futuro: 2FA para admins
---
*Documento generado durante sesión de brainstorming.*
*Aprobado para iniciar implementación.*

0
frontend/src/.gitkeep Normal file
View File

0
scripts/.gitkeep Normal file
View File

View File

View File

View File

View File