Backend inteligente para contactar candidatos mediante llamadas automáticas y chatbot de WhatsApp.
- ¿Qué hace SofIA?
- Flujo Completo del Sistema
- Configuración Inicial
- Cómo Correr el Servidor
- Todos los Scripts Disponibles
- Flujo del Chatbot (JSON de Ida y Vuelta)
- Cómo Hacer la Prueba Real Completa
- Endpoints del Servidor
- Solución de Problemas
SofIA automatiza el proceso de contactar candidatos para reclutamiento:
- Llamadas automáticas (ElevenLabs): Llama a los candidatos en horarios programados.
- Chatbot de respaldo (WhatsApp): Cuando un candidato acumula 9 intentos fallidos (
intentos_llamada >= 9), SofIA activa el chatbot de la compañera, que le escribe por WhatsApp. - Actualización automática: Cuando el candidato responde en WhatsApp, el chatbot notifica a SofIA y la base de datos se actualiza (agendado, no interesado, etc.).
[SofIA] Detecta 9 llamadas fallidas
↓
[SofIA → Chatbot] Envía JSON con datos del candidato a la URL de tu compañera
↓
[WhatsApp] El candidato recibe mensaje y agenda su cita
↓
[Chatbot → SofIA] Envía JSON con resultado al webhook público de SofIA
↓
[SofIA] Actualiza la base de datos (estado, evento, nota)
npm installCrea o edita .env en la raíz del proyecto:
# ── Base de Datos (Supabase / PostgreSQL) ──────────────────────────────DATABASE_URL=postgresql://postgres:[PASSWORD]@db.[SUPABASE_ID].supabase.co:5432/postgres
# ── Servidor ────────────────────────────────────────────────────────────PORT=3000
# ── ElevenLabs (Llamadas Automáticas) ──────────────────────────────────ELEVENLABS_API_KEY=sk_...
ELEVENLABS_AGENT_ID=agent_...
ELEVENLABS_PHONE_NUMBER_ID=phnum_...
ELEVENLABS_MOCK=false # true = no hace llamadas reales (modo prueba)# ── Chatbot de WhatsApp (URL de tu compañera) ───────────────────────────CHATBOT_WEBHOOK_URL=https://su-ngrok.ngrok-free.app/solicitar-chat
# ── Control de Llamadas ─────────────────────────────────────────────────MAX_CONCURRENT_CALLS=4
STALE_CALL_MINUTES=30npm startnpm run devEl servidor queda escuchando en http://localhost:3000. Verás:
HTTP server listening on :3000
✅ SofIA Chatbot Service is running
npm run tunnelNgrok te dará una URL pública como https://a1b2.ngrok-free.app.
Dásela a tu compañera para que configure su webhook de respuesta a:
https://a1b2.ngrok-free.app/api/chatbot/webhook
| Comando | Descripción |
|---|---|
npm run dev | Servidor en modo desarrollo con auto-reinicio |
npm start | Servidor en modo producción |
npm run test:wa | Envía JSON de prueba a la URL de tu compañera (candidata ficticia "Andrea") |
npm run test:chatbot:direct -- [UUID] | Fuerza el chatbot para un candidato específico |
npm run tunnel | Abre el túnel ngrok en el puerto 3000 |
Script principal de producción. Busca todos los candidatos con intentos_llamada >= 9 y envía su JSON al chatbot en lotes de 4.
node scripts/trigger-masivo-chatbot.jsMuestra el JSON que se le enviaría al chatbot para un candidato, sin enviarlo. Útil para revisar que horarios y eventos estén bien formados.
node scripts/ver-payload-candidato.js 0dd9d7da-525f-44ad-997a-8e52103b765bMuestra el estado actual en BD de los candidatos de prueba (Maryhug, Angelo, Emmanuel, Daniela, Andrea). Confirma si la BD se actualizó tras una conversación.
node scripts/check-candidate.jsVerifica si tu túnel ngrok está activo enviando un JSON de prueba real a tu propio servidor.
node scripts/test-ngrok.js https://tu-url.ngrok-free.app
# Resultado esperado: ✅ ¡ÉXITO! El servidor local respondió correctamenteSimula que tu compañera te envía el JSON de resultado. Actualiza la BD directamente. Úsalo para probar la recepción sin que ella esté disponible.
# Candidato agendado con evento y nota
node scripts/test-webhook-respuesta.js "0dd9d7da-525f-44ad-997a-8e52103b765b""AGENDADO""3""Prefiere tarde"# Candidato no interesado
node scripts/test-webhook-respuesta.js "0dd9d7da-525f-44ad-997a-8e52103b765b""NO_INTERESADO"Resetea a Maryhug a estado PENDIENTE con 9 intentos de llamada, lista para volver a probar el flujo completo.
node scripts/reset-maryhug.jsLista los eventos disponibles en la BD (ID, fecha, tipo). Útil para saber qué evento_id usar en las pruebas.
node scripts/list-events.jsLlena la cola de llamadas simulando el horario del día. Necesario para que el sistema de llamadas tenga candidatos en cola.
node scripts/llenar-cola.jsnode scripts/resetear-bd.jsVerifica que la conexión a PostgreSQL (Supabase) funciona.
node scripts/test-db-connection.jsPOST a CHATBOT_WEBHOOK_URL (el endpoint de tu compañera):
{
"candidato_id": "0dd9d7da-525f-44ad-997a-8e52103b765b",
"telefono": "3112790495",
"nombre": "Maryhug",
"motivo": "ENTREVISTA",
"ciudad": "Bogotá",
"mensaje": "Hola Maryhug, hemos intentado contactarte...\n\n1) lunes 3:00 PM\n2) martes 7:00 AM",
"lista_horarios": "1) lunes 3:00 PM\n2) martes 7:00 AM",
"eventos_disponibles": [
{ "fecha_legible": "lunes a las 3:00 PM", "evento_id": "3" },
{ "fecha_legible": "martes a las 7:00 AM", "evento_id": "4" }
]
}POST a https://[TU_URL_NGROK]/api/chatbot/webhook:
{
"candidato_id": "0dd9d7da-525f-44ad-997a-8e52103b765b",
"telefono": "3112790495",
"resultado_agenda": "AGENDADO",
"evento_id": "3",
"nota": "La candidata prefiere horarios de tarde"
}| Campo | Obligatorio | Descripción |
|---|---|---|
candidato_id | ✅ (o telefono) | UUID del candidato |
telefono | ✅ (o candidato_id) | Teléfono sin + |
resultado_agenda | ✅ | AGENDADO o NO_INTERESADO |
evento_id | ❌ Opcional | ID del evento elegido (solo si agendó) |
nota | ❌ Opcional | Comentario de la conversación |
Necesitas 3 terminales abiertas:
npm run devDéjala abierta. Aquí verás los logs cuando llegue el JSON de tu compañera.
npm run tunnelCopia la URL pública (ej: https://a1b2.ngrok-free.app) y dásela a tu compañera.
# Paso 1: Preparar candidato de prueba
node scripts/reset-maryhug.js
# Paso 2: Verificar que el túnel funciona
node scripts/test-ngrok.js https://a1b2.ngrok-free.app
# Paso 3: Disparar el chatbot (SofIA → Compañera)
node scripts/trigger-masivo-chatbot.js
# Paso 4: Esperar a que Maryhug responda en WhatsApp...# (Cuando lo haga, verás el log en Terminal 1)# Paso 5: Verificar que la BD se actualizó
node scripts/check-candidate.jsResultado esperado en check-candidate.js:
Maryhug | AGENDADO | evento_asignado_id: 3 | nota: "..."
| Método | Ruta | Descripción |
|---|---|---|
GET | /health | Estado del servidor y la BD |
POST | /webhook | Recibe resultados de llamadas (ElevenLabs) |
POST | /api/chatbot/webhook | Recibe el resultado del chat (de tu compañera) |
POST | /api/chatbot/trigger-manual | Dispara el chatbot manualmente (body: { "candidato_id": "..." }) |
| Error | Causa | Solución |
|---|---|---|
Status 503 / endpoint offline | Ngrok se cerró o expiró | Vuelve a correr npm run tunnel y dale la nueva URL a tu compañera |
Status 404 en ngrok | URL de ngrok cambió | Ngrok gratuito cambia la URL cada sesión. Actualízala en .env y con tu compañera |
unable to verify first certificate | SSL de ngrok | Ya está corregido en el código (rejectUnauthorized: false) |
Status 403 Forbidden | Firewall corporativo bloquea ngrok | Cambia a datos del celular o usa: ssh -p 443 -R0:localhost:3000 a.pinggy.io |
Connection timeout en BD | Red inestable a Supabase | Los scripts tienen reintentos automáticos. Intenta de nuevo |
No se encontraron candidatos en trigger masivo | Ninguno tiene intentos_llamada >= 9 | Ejecuta node scripts/reset-maryhug.js |
Status 422 al enviar al chatbot | Falta campo requerido en el JSON | Verifica que CHATBOT_WEBHOOK_URL apunte al endpoint correcto de tu compañera |
Logs en npm run dev no aparecen | El JSON no está llegando a tu servidor | Tu túnel ngrok no está activo o tu compañera tiene la URL vieja |