Files
reformix-hackaton/docs/handoff-whatsapp-simon.md
Carlos Narro d3189d7277 Reescribe el handoff de WhatsApp al modelo por EP + smoke test de los bot EPs
El bot de Luisa puebla la BD vía los 4 EPs HTTP (no SQL directo): conversacion,
perfil, calificacion, intento. Actualiza el handoff de Simón en consecuencia
(qué EP usa para cada cosa, enums/tipos a alinear, ya no necesita acceso a BD).

Añade api-docs/smoke-bot-eps.mjs: crea un lead de prueba, ejerce los 4 EPs por
HTTP, verifica en BD y limpia. Verificado end-to-end en produccion.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 21:07:13 +02:00

6.4 KiB

Handoff WhatsApp (Luisa) — para Simón

Cómo integra el bot de WhatsApp con la app Reformix. Una sola base de datos (la de la app; Postgres). El lead se crea siempre desde el form web, así que cuando el cliente elige WhatsApp el lead ya existe y te pasamos su leadId. No creas leads tú.

Modelo de integración (decidido): el bot no toca Postgres directamente. Toda la escritura va por endpoints HTTP autenticados (no necesitas credenciales de BD ni estar en la red de Dokploy). Ya están desplegados y probados en https://reformix.dv3.com.es.


1. Cómo arranca tu flujo

Cuando el cliente elige "WhatsApp" en el funnel, la app hace POST al webhook WHATSAPP_START_WEBHOOK_URL (lo configuras tú y nos lo pasas) con:

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

A partir de ahí Luisa escribe al telefono y trabaja siempre con ese leadId.

2. Cómo escribes en la BD: por API, no SQL

Qué guardas Endpoint
Cada turno del chat (+ estado del mensaje y paso del bot) POST /api/leads/:id/conversacion
Lo que vas extrayendo del lead (espacio, m², estilo, urgencia, presupuesto, viabilidad…) POST /api/leads/:id/perfil
Calificación del lead (score/nivel/criterios) POST /api/leads/:id/calificacion
Intento de contacto (resultado de cada intento) POST /api/leads/:id/intento
Fotos del cliente + notas/datos por zona POST /api/leads/:id/ingesta
Señalar "perfil completo" / devolver renders / cerrar y entregar POST /api/leads/:id/ingesta (flags perfilCompleto / finalizar)

Auth (todos): header Authorization: Bearer <FUNNEL_API_KEY> (te paso la clave aparte; es la misma para todos los EPs). Content-Type: application/json. :id = el leadId del §1.

Por qué por EP y no SQL: así se dispara nuestra lógica (motor de presupuesto, PDF, email, señales) y el esquema queda blindado (validación + tipos). Si escribieras las tablas a mano, esa lógica no corre y un valor inválido rompería la fila. Doc completa con campos y ejemplos curl: mvp/b2c/api-docs/README.md.

visitas y worker_jobs quedan fuera de tu integración por ahora (son cola interna / panel del reformista). Si los necesitas, lo hablamos y abrimos EP.

3. Resumen de los 4 EPs del bot

Campos completos y curls en api-docs; aquí el mínimo de cada uno.

  • conversacion{ rol: user|assistant|system, mensaje, [mediaType, mediaUrl, transcripcionAudio, estadoWa, botStep] }{ ok, id }.
  • perfil (update parcial, solo lo que mandes) — cualquier subconjunto de: botStep, estadoWa, canalOrigen, viable, espacio, rangoM2, estilo, presupuestoDeclarado, fotosSolicitadasAt, tipoReforma, m2Suelo, calidadGlobal, urgencia, presupuestoTarget, tasteText, estructural{ ok, actualizado:[...] }.
  • calificacion (upsert, 1 por lead) — { [score 0-100, nivel A|B|C|D, criterios{}, notasAgente] }{ ok }.
  • intento{ canal: formulario|whatsapp|llamada, numeroIntento, [resultado, completado, duracionSeg, notas, metadata{}] }{ ok, id }.

Errores comunes a todos: 401 (sin Bearer o clave mala), 404 (lead no existe), 422 (JSON o validación). Body de error: { ok:false, error:"..." }.

4. Enums y tipos: usa los valores de la API (esto es lo que hay que alinear en el bot)

Tu esquema reformix-full tenía otros valores. En la API mandan estos (el EP rechaza con 422 lo que no encaje):

tipoReformacocina · bano · salon · comedor · integral · otro oficina/local/otros → usa otro.

urgenciaalta · media · baja (tu inmediataalta).

estadoWa (entrega del mensaje) → sin_enviar · enviado · entregado · leido · fallido.

canalOrigenformulario_web · whatsapp · llamada · referido · anuncio.

calificacion.nivelA · B · C · D. intento.canalformulario · whatsapp · llamada. intento.resultadoexitoso · no_contesta · ocupado · rechaza · error_tecnico.

Tipos: estructural = boolean (no texto). calidadGlobal = enum basica/media/premium (no 1-10; la extracción cruda de calidad va en estilo/tasteText). m2Suelo = número (>0). presupuestoTarget = entero en céntimos. fotosSolicitadasAt = string ISO datetime.

pipeline_stage / estadono los escribas. Los gestiona nuestro funnel/EP.

5. bot_step (estado de la conversación de Luisa) — persistido

Texto libre (lo mandas en conversacion.botStep o perfil.botStep). Lo guardamos en leads.bot_step para verlo en el panel y poder retomar si el chat se corta. Valores sugeridos (puedes ajustar el vocabulario, es TEXT):

apertura → espacio → tamano → estilo → urgencia → presupuesto → pide_fotos → fotos_recibidas → completado Terminales: no_viable, abandonado.

Ojo: estadoWa es la entrega del mensaje (enviado/leído…), no el paso de la conversación. El paso es botStep.

6. Webhooks salientes de la app (los recibes/encadenas tú)

  • WHATSAPP_START_WEBHOOK_URL — inicio (§1).
  • PERFIL_WEBHOOK_URL — cuando marcas perfilCompleto en ingesta, te llega toda la data por zona para generar renders/agente (payload en api-docs §webhooks).
  • WHATSAPP_WEBHOOK_URL — entrega: cuando el PDF está listo (finalizar), te llega { pdfBase64, telefono, ... } para mandarlo por WhatsApp.

Pásanos las 3 URLs y las ponemos en producción (Dokploy).

7. Lo que hace la app sola (no lo dupliques)

pipeline_stage, cálculo del presupuesto orientativo, generación del PDF y envío del email los hace la app cuando llamas a ingesta con finalizar. Tú aportas fotos/notas, el historial del chat y el estado de la conversación; la app produce el entregable.

8. Estado: probado y en producción

Los 4 EPs están desplegados en https://reformix.dv3.com.es y verificados end-to-end (lead real → 200 con id de fila insertada, perfil reflejado en el panel, upsert de calificación correcto). Smoke test reutilizable: mvp/b2c/api-docs/smoke-bot-eps.mjs.


Resumen de lo que necesito de ti (Simón): (1) las 3 URLs de webhook (§6), (2) confirmar que el bot usa nuestros enums/tipos (§4). La conexión a la BD ya no hace falta: trabajas solo con la URL pública + FUNNEL_API_KEY.