Files
WhatsAppCentralizado/docs/flow-builder/README.md
Claude AI a92a7efccc 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>
2026-01-29 09:29:57 +00:00

787 lines
15 KiB
Markdown

# 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