Files
reformix-hackaton/docs/handoff-bot-runtime-simon.md
Carlos Narro face2d3d1b Handoff runtime del bot para Simón: estado, 2 issues y vía Evolution API
Documenta lo que funciona (flujo conversacional end-to-end, EPs, worker), los
cambios de hoy en el bot (@lid, by-phone, markOnline, modelos, apertura, /qr,
/debug) y los 2 problemas de runtime que quedan en su lado: Baileys deja de
recibir tras reconectar (vía robusta = Evolution API, no Cloud API oficial) y
la persistencia parcial del perfil (revisar logs de persistirTurno).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 22:16:42 +02:00

6.5 KiB

Handoff runtime del bot WhatsApp (Luisa) — para Simón

Estado tras la sesión de depuración del 09-jun. El flujo conversacional funciona end-to-end; quedan dos problemas de runtime del bot que se diagnostican/cierran desde tu lado (tienes acceso a los logs en Dokploy). La parte de la app (EPs) está verificada y no es el problema.


1. Lo que está PROBADO funcionando

  • EPs de la app (en mvp/b2c): conversacion, perfil, calificacion, intento, ingesta,
    • GET /api/leads/:id y GET /api/leads/:id/conversacion y GET /api/leads/by-phone. Todos OK. Verificado: POST /perfil con el payload exacto del bot ({espacio,rangoM2,estilo,botStep}) → 200 {ok:true, actualizado:[...]} y el lead se actualiza. El EP no es el cuello de botella.
  • Bot: apertura proactiva, resolución del @lid, matching del lead por teléfono, y la conversación de cualificación de Luisa (7 turnos reales: cocina → tamaño → estilo → urgencia).
  • Worker de render (mvp/image-worker): genera renders con google/gemini-2.5-flash-image.

2. Cambios que hice hoy en el bot (mvp/Whatsapp-bot) — para que no te pillen por sorpresa

  • Apertura proactiva al recibir /whatsapp-start: WhatsappService escucha un startEmitter y envía el primer mensaje (antes solo registraba la sesión y esperaba al cliente). Persiste estadoWa/botStep + intento.
  • Resolución @lid (resolverTelefono): WhatsApp entrega los mensajes desde una dirección @lid (p.ej. 239225534443615@lid), no desde el número. Se resuelve a número vía msg.key.remoteJidAlt o el mapa LID→PN de Baileys. Esto era la causa de que el bot ignorara los mensajes entrantes.
  • Recuperación del lead por teléfono: si la sesión no está en memoria (reinicio), getOrCreateContext busca el lead en la BD vía GET /api/leads/by-phone y re-registra la sesión.
  • markOnlineOnConnect: true: con false, tras reconectar el dispositivo quedaba "no disponible" y WhatsApp no entregaba los mensajes. Con true empezó a recibir (la conversación de 7 turnos lo demuestra).
  • Modelos de Claude corregidos en el env: eran claude-haiku-4-5 (guion) → inválidos en OpenRouter; ahora anthropic/claude-haiku-4.5 y anthropic/claude-sonnet-4.5 (punto).
  • BAILEYS_AUTH_DIR configurable (subcarpeta del volumen) para empezar una sesión limpia sin perder persistencia. Hoy apunta a /app/auth_info_baileys/v2.
  • Endpoints de operación (servidor de webhooks, puerto 3001):
    • GET /qr — QR de vinculación como imagen (HTTP Basic; usuario cualquiera, contraseña = QR_TOKEN, que está en el env del bot en Dokploy).
    • GET /debug — estado de conexión + anillo de los últimos eventos entrantes (mismo auth). Útil para ver remoteJid/remoteJidAlt, si llega algo, y el resultado del matching.
  • Subido el límite de body del worker a 30 MB (las fotos en data URI rompían el 100kb por defecto).

3. Problema A — Baileys deja de recibir tras reconectar

Síntoma: justo tras un escaneo fresco del QR, el bot recibe mensajes (conversación OK). Pero tras cualquier reconexión (redeploy, o auto-reconexión de Baileys al caerse el socket), reporta connection: "open" pero no recibe nada (/debuginbound: [] aunque el cliente escriba). markOnlineOnConnect: true ayudó al primer connect pero no lo blinda contra reconexiones.

Cómo reproducir/diagnosticar:

  • GET https://reformix-bot.dv3.com.es/debug (Basic, contraseña QR_TOKEN): si connection:open pero inbound no crece cuando el cliente escribe → estás en el estado "zombi".
  • Para volver a recibir: sesión nueva → sube BAILEYS_AUTH_DIR a /app/auth_info_baileys/v3, redeploy, escanea el QR fresco en /qr. Y evita redeployar después (cada reconexión arriesga la recepción).

Camino robusto (acordado con Carlos): migrar el transporte de WhatsApp del bot a Evolution API (ya está como primaria en el stack — NO la WhatsApp Cloud API oficial). Evolution gestiona la conexión y entrega los mensajes por webhook, sin un socket Baileys en-proceso que se vuelva zombi. El bot pasaría a: (1) recibir mensajes por webhook de Evolution, (2) enviar por su REST. La lógica de Claude + los EPs de la app se quedan igual; solo cambia la capa de transporte WhatsApp.

4. Problema B — el perfil extraído no se persiste en el lead durante la conversación

Síntoma: la conversación avanza (Luisa pregunta espacio→tamaño→estilo→urgencia) pero el lead queda con botStep desfasado y espacio/rangoM2/... vacíos.

Qué sé: el EP /perfil funciona con el payload del bot (probado). Así que el fallo está en la llamada del bot. LeadsService.persistirTurno ya loguea: Lead X persistido via API: {...} → ok/fallo.

Qué mirar (logs del bot en Dokploy) durante una conversación:

  • Si aparece → fallo: mira el payload logueado. Sospechosos: un valor de enum inválido (p.ej. urgencia fuera de alta|media|baja, o calidadGlobal fuera de basica|media|premium) hace que TODO el POST /perfil422 y no persista nada de ese turno. Mapea los valores que extrae Claude a los enums de la app antes de enviar.
  • Si no aparece la línea: persistirTurno no se está llamando → revisa que claudeService.llamarClaude devuelva entidad/nuevoEstado.
  • Ojo también a si el bot se reinició a media conversación (Problema A): tras reiniciar deja de recibir y el flujo se corta.

5. Infra (referencia rápida)

Servicio App Dokploy Dominio
Bot reformix-bot (wY4F14fyEslU-4za_JIbi) reformix-bot.dv3.com.es (puerto 3001)
Worker reformix-worker (sMQd9zwoyV14q1vm8Vs8U) reformix-worker.dv3.com.es
App reformix-b2c (lzHDAuPuubbJu94OrkNS_) reformix.dv3.com.es
  • Build Dockerfile desde Gitea, autodeploy en push a main. Volumen del bot: /app/auth_info_baileys (sesión WhatsApp). OPENROUTER_API_KEY y FUNNEL_API_KEY en el env de cada app.
  • Contrato de los EPs y enums: mvp/b2c/api-docs/README.md.

Resumen: el flujo está demostrado funcionando; los 2 problemas son de la capa de transporte/runtime del bot. Recomendación: cerrar el Problema B mirando los logs de persistirTurno, y para el Problema A (estabilidad) migrar a Evolution API. Mientras tanto, para una demo: escaneo fresco + no redeployar.