Files
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

15 KiB

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.

{
  "type": "welcome",
  "id": "trigger_1",
  "data": {
    "label": "Primer mensaje"
  }
}

keyword

Inicia el flujo cuando el mensaje contiene palabras clave.

{
  "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.

{
  "type": "fallback",
  "id": "trigger_3",
  "data": {
    "label": "No entendido"
  }
}

event

Se activa por eventos externos (webhook, Odoo).

{
  "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.

{
  "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.

{
  "type": "image",
  "id": "msg_2",
  "data": {
    "url": "https://example.com/producto.jpg",
    "caption": "Nuestro producto estrella"
  }
}

video

Envía un video.

{
  "type": "video",
  "id": "msg_3",
  "data": {
    "url": "https://example.com/demo.mp4",
    "caption": "Video demostrativo"
  }
}

document

Envía un documento (PDF, Excel, etc).

{
  "type": "document",
  "id": "msg_4",
  "data": {
    "url": "https://example.com/catalogo.pdf",
    "filename": "Catálogo 2024.pdf"
  }
}

location

Envía una ubicación.

{
  "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).

{
  "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).

{
  "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.

{
  "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.

{
  "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.

{
  "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.

{
  "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.

{
  "type": "delay",
  "id": "delay_1",
  "data": {
    "seconds": 3,
    "random_range": [2, 5]
  }
}

set_variable

Asigna o modifica una variable.

{
  "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.

{
  "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.

{
  "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.

{
  "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.

{
  "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.

{
  "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.

{
  "type": "validate_email",
  "id": "val_1",
  "data": {
    "input": "{{message.text}}",
    "output_variable": "email_valido",
    "outputs": ["valid", "invalid"]
  }
}

validate_phone

Valida formato de teléfono.

{
  "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.

{
  "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.

{
  "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.

{
  "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.

{
  "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.

{
  "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.

{
  "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.

{
  "type": "tag",
  "id": "act_3",
  "data": {
    "add": ["lead", "interesado"],
    "remove": ["nuevo"]
  }
}

note

Agrega nota interna.

{
  "type": "note",
  "id": "act_4",
  "data": {
    "content": "Cliente interesado en {{variables.producto}}. Presupuesto: {{variables.presupuesto}}"
  }
}

notify

Envía notificación.

{
  "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.

{
  "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.

{
  "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 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)

{
  "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