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>
This commit is contained in:
Carlos Narro
2026-06-09 22:16:42 +02:00
parent 5004575768
commit face2d3d1b

View File

@@ -0,0 +1,99 @@
# 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`](../mvp/Whatsapp-bot/src/whatsapp/whatsapp.service.ts)):
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** (`/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ñ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`](../mvp/Whatsapp-bot/src/leads/leads.service.ts#L68)
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 /perfil``422` 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`](../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.