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>
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/:idyGET /api/leads/:id/conversacionyGET /api/leads/by-phone. Todos OK. Verificado:POST /perfilcon 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 congoogle/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:WhatsappServiceescucha unstartEmittery envía el primer mensaje (antes solo registraba la sesión y esperaba al cliente). PersisteestadoWa/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íamsg.key.remoteJidAlto 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),
getOrCreateContextbusca el lead en la BD víaGET /api/leads/by-phoney re-registra la sesión. markOnlineOnConnect: true: confalse, tras reconectar el dispositivo quedaba "no disponible" y WhatsApp no entregaba los mensajes. Contrueempezó 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; ahoraanthropic/claude-haiku-4.5yanthropic/claude-sonnet-4.5(punto). BAILEYS_AUTH_DIRconfigurable (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 verremoteJid/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 (/debug → inbound: [] 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ñaQR_TOKEN): siconnection:openperoinboundno crece cuando el cliente escribe → estás en el estado "zombi".- Para volver a recibir: sesión nueva → sube
BAILEYS_AUTH_DIRa/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.urgenciafuera dealta|media|baja, ocalidadGlobalfuera debasica|media|premium) hace que TODO elPOST /perfildé422y 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:
persistirTurnono se está llamando → revisa queclaudeService.llamarClaudedevuelvaentidad/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_KEYyFUNNEL_API_KEYen 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.