Files
reformix-hackaton/docs/arquitectura-integracion.md
Carlos Narro ad87e45892 Lleva las preferencias del cliente (estilo, color, material) al render
Hasta ahora el render solo se condicionaba con tipo/m²/calidad + notas de texto
libre por zona; lo que el cliente decía hablando con Luisa o en la llamada
(estilo, colores, materiales) se guardaba en estilo/tasteText pero NO viajaba al
generador de imagen, así que el render no lo representaba.

- b2c (perfil.ts): el payload de PERFIL_WEBHOOK_URL incluye ahora
  preferencias:{estilo, gustos} (gustos = tasteText). Claves vacías se omiten.
- worker (webhook.dto): nuevo PreferenciasDto opcional.
- worker (prompt-builder): construirUserContent (función pura) inyecta el estilo
  y los gustos del cliente como bloque dedicado y omite el "modern" por defecto
  cuando hay preferencias; el system prompt prioriza colores/materiales del
  cliente sobre un estilo genérico.
- worker (pipeline): enhebra preferencias hasta generarPrompt.
- worker (sandbox): acepta estilo/gustos para poder probarlos.
- docs/arquitectura-integracion: documenta el campo preferencias.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 18:17:45 +02:00

28 KiB

Arquitectura de Integración — Reformix

Índice

  1. Visión general del sistema
  2. Landing pública y captura del lead (sitio web)
  3. El funnel B2C — pipeline de 7 pasos
  4. Elección de canal: formulario, llamada o WhatsApp
  5. Sistema de webhooks salientes (app → bot/worker)
  6. Sistema de endpoints de bot (app ← bot/worker)
  7. El agente de WhatsApp (Luisa)
  8. Workers: render de imágenes y presupuesto
  9. El presupuesto como entregable final
  10. Diagrama de flujo completo
  11. Estado actual vs lo que falta
  12. Guía de conexión: cómo integrar Luisa + Workers con la app

1. Visión general del sistema

Reformix es un SaaS multi-tenant para empresas de reformas. Tiene dos caras:

  • B2B (reformista): el reformista se registra, configura su perfil, catálogo de materiales, precios, y pone un widget en su web.
  • B2C (cliente final): el cliente llega a la landing del reformista, pide presupuesto, sube fotos, y recibe un presupuesto con render "antes/después" en < 7 minutos.

Componentes del sistema

┌─────────────────────────────────────────────────────────────────┐
│                    SITIO WEB (Next.js)                          │
│  Landing → Formulario → Elección canal → Pipeline → Entrega     │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  App Reformix (mvp/b2c/)                                │   │
│  │  - Landing pública /[slug]                               │   │
│  │  - Funnel B2C /solicitud/[id]/*                         │   │
│  │  - Panel reformista /panel/*                             │   │
│  │  - API endpoints para bot (mvp/b2c/src/app/api/leads/)  │   │
│  │  - Motor de presupuesto (mvp/b2c/src/budget/)           │   │
│  │  - Generación de PDF (mvp/b2c/src/lib/pdf/)             │   │
│  │  - Envío de email (mvp/b2c/src/lib/email/)              │   │
│  │  - Webhooks salientes (mvp/b2c/src/lib/webhooks.ts)     │   │
│  └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│  AGENTE WHATSAPP (Luisa) — EXTERNO                             │
│  (mvp/Whatsapp-bot/)                                           │
│  - Conexión WhatsApp via Baileys                               │
│  - Pipeline Claude 4-capas para cualificar leads               │
│  - DEBE usar API HTTP de la app (hoy escribe directo a BD)     │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│  WORKERS (Render + Análisis) — NO IMPLEMENTADO AÚN             │
│  - Generación de renders "después" (Nano Banana 2 / Image 2)   │
│  - Análisis de fotos con IA                                    │
│  - DEBE recibir webhook PERFIL_WEBHOOK_URL y devolver vía API  │
└─────────────────────────────────────────────────────────────────┘

2. Landing pública y captura del lead (sitio web)

Flujo de captura

Usuario llega a /[slug] (landing del reformista)
         │
         ▼
  Rellena formulario Hero:
  - nombre + email + teléfono
  - consentimiento privacidad + contratación (RGPD obligatorio)
         │
         ▼
  crearLead(slug, data) → Server Action
         │
         ├── Valida con Zod schema
         ├── Busca tenant por slug
         ├── INSERT en leads (pipelineStage: 'form_completado', estado: 'nuevo')
         └── INSERT en leadPipelineEventos (stage: 'form_completado')

Lo que crea la base de datos

El lead se crea con:

  • id (UUID) — este es el leadId que usará todo el sistema
  • tenantId (UUID) — referencia al reformista
  • nombre, email, telefono — datos del cliente
  • pipelineStage: 'form_completado' — dónde está en el pipeline
  • estado: 'nuevo' — estado comercial

Importante: El lead NO tiene aún tipoReforma, m2Suelo, calidadGlobal, etc. Esos se rellenan después, cuando el cliente pasa por el canal elegido.


3. El funnel B2C — pipeline de 7 pasos

Definido por el enum pipelineStage en src/db/schema.ts:

# Stage Qué ocurre Quién lo dispara
1 form_completado Lead creado con datos básicos Server Action crearLead()
2 fotos_subidas Cliente describe reforma + sube fotos por zona Server Action guardarDetallesYFotos() o API ingesta
3 prellamada_enviada Notificación SMS/WhatsApp previa a llamada Orchestrator procesarLead() o bot
4 llamada_completada Agente IA (Retell) cualifica al lead Orchestrator (simulado) o webhook Retell (real)
5 render_generado Render "después" generado por IA Orchestrator (simulado con imagen demo)
6 presupuesto_generado Presupuesto calculado con motor real Orchestrator procesarLead()
7 whatsapp_entregado PDF entregado al cliente finalizarYEntregar()

Pipeline automático (procesarLead)

Cuando el cliente completa el formulario detallado (con zonas, fotos, etc.), la app ejecuta:

guardarDetallesYFotos(leadId, formData)
  ├── Guarda fotos (momento: 'antes') en leadFotos
  ├── Guarda notas en leadNotas
  ├── Calcula tipoReforma, m2Suelo, calidadGlobal desde las zonas
  ├── UPDATE lead (pipelineStage: 'fotos_subidas')
  
  └── procesarLead(leadId)  ORQUESTRADOR
       ├── Paso 4: Evento prellamada_enviada
       ├── Paso 5: Llamada Retell (real si configurado, sino simulada con transcript ficticio)
       ├── Paso 6a: Render demo (imagen estática, NO IA real)
       ├── Paso 6b: Presupuesto REAL con motor (computeBudget)
       ├── UPDATE lead (pipelineStage: 'presupuesto_generado')
       └── Paso 7: Si envio=automatico  lead pasa a 'whatsapp_entregado'

4. Elección de canal: formulario, llamada o WhatsApp

Después de crear el lead, el cliente llega a /solicitud/[id]/ donde elige cómo continuar:

Canal formulario (/solicitud/[id]/formulario)

El cliente rellena un formulario multi-zona: tipo de reforma, m², calidad, notas, sube fotos. Esto dispara guardarDetallesYFotos() que ejecuta el pipeline completo (incluyendo llamada simulada, render demo, presupuesto real).

Canal llamada (/solicitud/[id]/llamada)

El cliente pide que le llamen (ahora o programado). Se le envía un email con enlace para subir fotos después. Dispara pedirLlamada() que inicia llamada Retell saliente (si configurado). El cliente recibe la llamada del agente IA, y después puede subir fotos via el enlace del email.

Canal WhatsApp (/solicitud/[id]/whatsapp)

El cliente elige continuar por WhatsApp. La app dispara iniciarWhatsapp() que:

iniciarWhatsapp(leadId)
  └── POST a WHATSAPP_START_WEBHOOK_URL
       Payload: { leadId, telefono, nombre, empresa }
        El bot de WhatsApp (Luisa) recibe esto y empieza la conversación

Este es el punto de entrada del bot de WhatsApp. El bot recibe el leadId y a partir de ahí debe escribir los datos extraídos de la conversación usando los endpoints de la app.


5. Sistema de webhooks salientes (app → bot/worker)

La app envía 3 señales HTTP a sistemas externos. Todas son best-effort (nunca lanzan error, devuelven boolean).

5.1 WHATSAPP_START_WEBHOOK_URL — Arranque de conversación WhatsApp

Disparado por: iniciarWhatsapp() (cuando el lead elige canal WhatsApp)

POST {url}
{
  "leadId": "uuid",
  "telefono": "+34...",
  "nombre": "...",
  "empresa": "Reformas Ejemplo"
}

La app espera que: el bot de WhatsApp reciba esto y comience la conversación con el lead. El bot debe usar el leadId para escribir los datos vía los endpoints de la app.

5.2 PERFIL_WEBHOOK_URL — Perfil completo para generar renders

Disparado por:

  • señalarPerfilCompleto() en guardarDetallesYFotos() (formulario)
  • señalarPerfilCompleto() en subirFotos() (fotos por email)
  • API ingesta con flag perfilCompleto: true (bot/worker)
POST {url}
{
  "leadId": "uuid",
  "cliente": { "nombre": "...", "telefono": "...", "email": "...", "provincia": "..." },
  "reforma": { "tipo": "cocina", "m2Suelo": 12, "calidad": "media",
               "estructural": false, "urgencia": "media", "presupuestoTarget": 800000 },
  "preferencias": { "estilo": "nórdico", "gustos": "tonos azules, muebles de madera, encimera clara" },
  "empresa": { "tenantId": "uuid", "nombre": "Reformas Ejemplo" },
  "zonas": [
    { "zona": "cocina",
      "notas": ["encimera de cuarzo"],
      "fotos": { "antes": ["data:image/..."], "despues": [] } }
  ]
}

preferencias (opcional): gustos estéticos del cliente capturados en la conversación (estilo = campo estilo del lead; gustos = tasteText, resumen en texto libre de colores/materiales/acabados que pidió). Cada clave se omite si está vacía. El worker los inyecta como bloque dedicado en el prompt de imagen para que el render los represente; si no llegan, infiere un estilo neutro.

La app espera que: el worker externo genere renders "después" a partir de las fotos "antes" respetando las preferencias del cliente, y los devuelva haciendo POST al endpoint /api/leads/:id/ingesta con momento: "despues" y opcionalmente finalizar: true.

5.3 WHATSAPP_WEBHOOK_URL — Entrega del PDF

Disparado por: finalizarYEntregar() (cuando el PDF está listo)

POST {url}
{
  "leadId": "uuid",
  "telefono": "+34...",
  "nombre": "...",
  "empresa": "Reformas Ejemplo",
  "pdfBase64": "JVBERi0xLj...",
  "filename": "presupuesto-nombre.pdf"
}

La app espera que: el bot de WhatsApp reciba esto y envíe el PDF al cliente por WhatsApp.


6. Sistema de endpoints de bot (app ← bot/worker)

La app expone 5 endpoints bajo /api/leads/:id/. Todos requieren Authorization: Bearer <FUNNEL_API_KEY>.

Endpoint Qué hace Tabla que escribe
POST /api/leads/:id/conversacion Guarda un turno del chat conversacion_whatsapp
POST /api/leads/:id/perfil Actualiza datos extraídos del lead leads (campos: espacio, rangoM2, estilo, tipoReforma, m2Suelo, etc.)
POST /api/leads/:id/calificacion Upsert de calificación lead_calificacion
POST /api/leads/:id/intento Registra intento de contacto intentos_contacto
POST /api/leads/:id/ingesta Sube fotos/notas + flags de perfilCompleto/finalizar lead_fotos, lead_notas

Flujo de uso típico del bot

1. Bot recibe WHATSAPP_START_WEBHOOK → leadId, telefono, nombre
2. Bot inicia conversación por WhatsApp
3. Por cada interacción:
   a. Bot llama POST /conversacion (guarda el turno)
   b. Bot llama POST /perfil (actualiza datos extraídos: espacio, m2, estilo, etc.)
   c. Cuando tiene datos suficientes, llama POST /calificacion
   d. Cuando pide fotos, el cliente las envía, bot las guarda vía POST /ingesta
4. Cuando el perfil está completo:
   - Bot marca perfilCompleto: true en POST /ingesta
   - Esto dispara PERFIL_WEBHOOK_URL → worker genera renders
   - Worker devuelve renders vía POST /ingesta con momento: "despues" + finalizar: true
   - finalizar:true dispara WHATSAPP_WEBHOOK_URL → bot recibe PDF y lo envía al cliente

7. El agente de WhatsApp (Luisa)

Estado actual (código en mvp/Whatsapp-bot/)

El bot de Luisa es un servicio NestJS independiente que:

  1. Se conecta a WhatsApp usando la librería Baileys (WebSocket no oficial)
  2. Orquesta un pipeline Claude de 4 capas:
    • Capa 1 — Clasificador (Haiku): extrae intención y valor del mensaje
    • Capa 2 — Validador: valida contra valores permitidos
    • Capa 3 — Generador (Sonnet): produce el borrador de respuesta
    • Capa 4 — Reglas (Haiku): corrige tono e identidad
  3. Mantiene una máquina de estados de 7 pasos para cualificar al lead: nuevo → apertura → espacio → tamano → estilo → urgencia → presupuesto → fin
  4. Tiene un scheduler que cada 5 minutos busca leads "nuevos" en BD y les envía el mensaje de apertura
  5. Soporta multimedia: transcripción de audio (Gemini), análisis de imágenes (Claude Vision)

Problema actual

El bot escribe directamente a Postgres usando TypeORM con sus propias entidades (Lead y Conversacion), en lugar de usar los endpoints HTTP de la app. Esto causa:

  • Incompatibilidad de IDs: el bot usa id numérico autoincremental, la app usa UUID
  • Tablas duplicadas: el bot tiene su propia tabla conversacion, la app tiene conversacion_whatsapp
  • Enums desalineados: el bot usa urgente/medio_plazo/frio, la app usa alta/media/baja
  • synchronize: true en TypeORM puede alterar el schema de la BD real
  • El scheduler crea leads desde cero, pero según la arquitectura los leads ya existen (creados desde el form web)

Lo que DEBE hacer el bot

  1. No crear leads. Recibirlos vía WHATSAPP_START_WEBHOOK_URL con el leadId UUID.
  2. No escribir a BD directamente. Usar los 5 endpoints HTTP (conversacion, perfil, calificacion, intento, ingesta).
  3. No tener scheduler propio. El arranque lo hace la app vía webhook.
  4. Usar los enums correctos según la app (alta/media/baja, cocina/bano/salon/comedor/integral/otro, etc.).
  5. No mantener estado propio. El estado de la conversación (botStep) se persiste vía /perfil.

Dónde está el código

Elemento Ruta
Código del bot (NestJS) mvp/Whatsapp-bot/src/
Prompts de Luisa mvp/Whatsapp-bot/prompts/
Configuración (.env) mvp/Whatsapp-bot/.env
Documentación del bot mvp/Whatsapp-bot/README.md

8. Workers: render de imágenes y presupuesto

Estado actual

Los workers no están implementados. Existe:

  • La tabla worker_jobs en la BD (mvp/b2c/src/db/schema.ts:515-537) con tipos: analisis_fotos, render, presupuesto_ia
  • El webhook PERFIL_WEBHOOK_URL listo para enviar el perfil completo al worker
  • El endpoint ingesta listo para recibir los renders de vuelta
  • Renders simulados con imágenes estáticas en procesarLead() (usa /despues.webp, /despues-bano.webp, etc.)

Lo que DEBE hacer el worker de renders

1. Recibe POST a PERFIL_WEBHOOK_URL con:
   { leadId, cliente, reforma, empresa, zonas: [{ zona, notas, fotos: { antes: [...], despues: [] } }] }

2. Para cada zona:
   a. Toma las fotos "antes" del cliente
   b. Genera render "después" usando modelo de IA (Nano Banana 2, Image 2, Stable Diffusion, etc.)
   c. Convierte el render a data URI base64

3. Devuelve los renders haciendo POST a /api/leads/:id/ingesta:
   { items: [{ tipo: "foto", zona: "cocina", momento: "despues", imagen: "data:image/..." }],
     finalizar: true }
   (finalizar:true dispara la construcción del PDF + email + señal WhatsApp)

Stack planeado para renders

Según la documentación:

  • Nano Banana 2 o Image 2 (Google Gemini) — modelos image-to-image
  • Alternativa: Replicate SDXL + ControlNet (~0,02€/imagen)
  • Alternativa: DALL-E 3 HD (~0,08€/imagen)

Dónde implementar los workers

Los workers son servicios externos independientes. Pueden ser:

  • n8n workflows (orquestación visual)
  • Un worker Node.js/Python que escucha webhooks y se comunica con APIs de IA
  • Cloud Functions (Vercel, Cloudflare Workers, AWS Lambda)

No hay código de workers en este repositorio. El repositorio solo define el contrato (webhooks + API).


9. El presupuesto como entregable final

El entregable final es un PDF de presupuesto que incluye:

  1. Cabecera con datos del reformista (logo, nombre, CIF, dirección)
  2. Datos del cliente y tipo de reforma
  3. Tabla de presupuesto con partidas calculadas por el motor:
    • Demolición, impermeabilización, alicatado, fontanería, electricidad, carpintería, mano de obra, extras, licencia
  4. Render "después" generado por IA
  5. Galería por zona con fotos "antes" y "después"
  6. Footer legal

El motor de presupuesto (mvp/b2c/src/budget/)

Es real, no simulado. Calcula presupuestos basado en:

  • Catálogo de materiales del reformista (precios por calidad: básica/media/premium)
  • Configuración de precios (factores por zona, mano de obra, extras fijos)
  • Inputs del lead: tipo de reforma, m², calidad, urgencia, estructural, provincia

Flujo de entrega

finalizarYEntregar(leadId)
  ├── construirPresupuestoPdf(leadId)
  │    ├── Carga lead completo + fotos + notas + catálogo + config
  │    ├── Renderiza PDF con @react-pdf
  │    └── Devuelve buffer PDF + filename
  │
  ├── UPDATE lead (pdfUrl)
  │
  ├── enviarPresupuestoEmail() → SMTP (opcional)
  │
  ├── notificarFlujoWhatsapp() → WHATSAPP_WEBHOOK_URL
  │    └── Bot recibe pdfBase64 y lo envía por WhatsApp
  │
  └── UPDATE lead (pipelineStage: 'whatsapp_entregado', estado: 'presupuesto_enviado')

10. Diagrama de flujo completo

                  LANDING PÚBLICA /[slug]
                        │
                   crearLead()
                        │
                        ▼
            ┌───────────────────────┐
            │   Lead CREADO         │
            │   pipelineStage:       │
            │   form_completado      │
            │   estado: nuevo        │
            └───────────┬───────────┘
                        │
                        ▼
           ┌────────────────────────┐
           │  ELECCIÓN DE CANAL     │
           │  /solicitud/[id]/      │
           └──────┬────────┬───────┘
                  │        │
         ┌────────┘        └────────┐
         ▼                          ▼
   ┌──────────────┐         ┌──────────────┐
   │  FORMULARIO  │         │  WHATSAPP    │
   │  + fotos     │         │              │
   └──────┬───────┘         │ iniciar      │
          │                 │ Whatsapp()   │
          │                 └──────┬───────┘
          │ guardarDetalles        │
          │ YFotos()               │ POST WHATSAPP
          │                        │ START WEBHOOK
          ├── Guarda fotos         │
          ├── Guarda notas          ▼
          │                 ┌──────────────┐
          └── procesarLead() │  BOT WHATSAPP │
               │            │  (Luisa)      │
               │            │               │
               ├── Simula    │ Inicia        │
               │   llamada   │ conversación  │
               │             │               │
               ├── Render    │ Por cada msg: │
               │   demo      │ POST /perfil  │
               │   (img fija)│ POST /conv.   │
               │             │               │
               ├── Presup.   │ Cuando listo: │
               │   REAL      │ POST /ingesta │
               │             │ perfilCompleto│
               │             │               │
               └── Estado    └──────┬────────┘
                   intermedio       │
                        │          │
                        ▼          │
               ┌────────────────────┘
               │ PERFIL_WEBHOOK_URL
               ▼
        ┌──────────────────┐
        │  WORKER RENDER   │
        │  Genera imágenes │
        │  "después"       │
        └────────┬─────────┘
                 │ POST /api/leads/:id/ingesta
                 │ { items: [{tipo:"foto", momento:"despues",...}],
                 │   finalizar: true }
                 ▼
        ┌──────────────────────────────┐
        │  finalizarYEntregar()        │
        │  - Construye PDF             │
        │  - Envía email               │
        │  - WHATSAPP_WEBHOOK_URL      │
        └────────┬─────────────────────┘
                 │
                 ▼
        ┌──────────────────┐
        │  BOT WHATSAPP    │
        │  Recibe pdfBase64│
        │  y lo envía al   │
        │  cliente         │
        └──────────────────┘

11. Estado actual vs lo que falta

Componente Estado Notas
Landing pública / formulario Implementado Multi-zona, fotos, notas
Motor de presupuesto Implementado Real, con catálogo y config
PDF Implementado Con @react-pdf
Email Implementado SMTP, best-effort
Endpoints API del bot Implementado y en producción 5 endpoints en dv3.com.es
Webhooks salientes Implementado 3 webhooks listos
Autenticación bot Implementado Bearer token con FUNNEL_API_KEY
Bot WhatsApp (Luisa) Por reconectar Hoy escribe directo a BD, debe usar APIs HTTP
Workers render No implementado Existe solo tabla y webhook, sin worker real
Renders IA Simulado Usa imágenes estáticas /despues.webp
Llamada Retell real ⚠️ Parcial Código listo, depende de config de vars de entorno
n8n workflows No existe Mencionado en docs pero sin implementar

12. Guía de conexión: cómo integrar Luisa + Workers con la app

12.1 Lo que necesita el bot de WhatsApp (Luisa)

El bot DEBE:

  1. Recibir leads por webhook (WHATSAPP_START_WEBHOOK_URL), no buscarlos en BD.
  2. Usar los endpoints HTTP de la app en lugar de TypeORM:
    • POST /api/leads/:id/conversacion — para cada turno del chat
    • POST /api/leads/:id/perfil — para actualizar datos extraídos
    • POST /api/leads/:id/calificacion — para calificar al lead
    • POST /api/leads/:id/intento — para registrar intentos
    • POST /api/leads/:id/ingesta — para subir fotos y marcar perfil completo
  3. Usar los enums correctos de la app:
    • urgencia: alta, media, baja
    • tipoReforma: cocina, bano, salon, comedor, integral, otro
    • calidadGlobal: basica, media, premium
    • estadoWa: sin_enviar, enviado, entregado, leido, fallido
    • canalOrigen: formulario_web, whatsapp, llamada, referido, anuncio
  4. Trabajar con UUIDs (el leadId que recibe del webhook).
  5. No tener scheduler interno — la app controla cuándo arrancar.

12.2 Lo que necesita el worker de renders

El worker DEBE:

  1. Escuchar en la URL que configures como PERFIL_WEBHOOK_URL (POST /perfil-completo).
  2. Recibir el payload con leadId, cliente, reforma, zonas (con fotos "antes").
  3. Generar renders para cada zona: Etapa 1 (Claude Haiku → prompt), Etapa 2 (Gemini Flash → imagen), Etapa 3 (Claude Haiku Vision → validación). Todo via OpenRouter.
  4. Devolver los renders llamando a POST /api/leads/:id/ingesta con:
  5. Autenticarse con Authorization: Bearer <FUNNEL_API_KEY>.
    {
      "items": [
        {
          "tipo": "foto",
          "zona": "cocina",
          "momento": "despues",
          "imagen": "data:image/..."
        }
      ],
      "finalizar": true
    }
    
  6. Autenticarse con Authorization: Bearer <FUNNEL_API_KEY>.

12.3 Variables de entorno necesarias en la app

# Para que el bot pueda escribir en la BD:
FUNNEL_API_KEY=<clave-compartida>

# URLs donde escuchan el bot y el worker:
WHATSAPP_START_WEBHOOK_URL=https://url-del-bot/whatsapp-start
PERFIL_WEBHOOK_URL=https://url-del-worker/perfil-completo
WHATSAPP_WEBHOOK_URL=https://url-del-bot/whatsapp-pdf

12.4 Secuencia de integración recomendada

Paso 1 — Reconectar Luisa a los endpoints HTTP (prioridad alta)

  • Eliminar TypeORM y las entidades propias del bot
  • Implementar llamadas HTTP a los 5 endpoints de la app
  • Ajustar enums y tipos para que coincidan con la app
  • Eliminar el scheduler interno
  • Configurar las 3 URLs de webhook en la app

Paso 2 — Implementar worker de renders (prioridad media)

  • Crear servicio que escuche PERFIL_WEBHOOK_URL
  • Elegir modelo de IA para image-to-image
  • Integrar con el endpoint ingesta para devolver resultados

Paso 3 — Conectar llamada Retell real (prioridad baja)

  • Configurar variables de entorno de Retell
  • El bot de WhatsApp o el formulario pueden complementar la llamada