Citas, eventos y no crons: cómo está montado Zutoki

Zutoki, la agenda inteligente para clínicas

Zutoki es un SaaS de citas y back-office para clínicas. Encima van agentes (chat, llamadas). El error fácil es hacer un bot con su agenda y un panel con otra. A los dos meses no coinciden.

Aquí la decisión es la inversa: un solo dominio de citas. Todo lo demás son adaptadores.

El problema

Recepción vive en WhatsApp, en el calendario y en un Excel de “por si acaso”. Los recordatorios se mandan con un cron a las 09:00 que recorre toda la tabla. Si el bot crea una cita a las 09:01, el aviso llega al día siguiente o no llega.

Hacía falta producto, no un flujo de n8n suelto: auth, roles, eventos y un sitio donde viven los datos. n8n sigue siendo útil en clínicas más pequeñas (Podología Sa Pobla); Zutoki es el caso en el que el producto es la agenda.

Quién entra vs qué pasa después

  • BetterAuth — sesiones, roles, “quién puede ver esta clínica”.
  • PostgreSQL — citas y pacientes. Fuente de verdad.
  • Inngest — “ha pasado esto”: cita creada, cita cancelada, recordatorio a T−24 h.

La request HTTP del panel no envía el SMS. Publica un evento. El worker de Inngest lo consume cuando toca. El agente de WhatsApp puede crear la misma cita: mismo caso de uso, otro adaptador de entrada.

Así no duplicas “recordar al paciente” en el bot, en el panel y en un cron.

Por qué no un cron

Un cron pregunta “¿hay citas mañana?”. Un evento dice “esta cita existe; recuérdala 24 h antes”.

El cron escala mal (recorre de más), falla en silencio y no sabe de cancelaciones salvo que vuelvas a consultar. El evento se cancela o se reprograma con la cita.

Inngest, en este stack, es esa cola con reintentos y visibilidad. No es magia: es no atar el efecto (recordatorio) al request (clic en “guardar”).

Encaje con el resto

Next.js, TypeScript, Docker, Spaces para ficheros. El detalle de producto está en la ficha de Zutoki. El lado conversacional “guiado, sin RAG” lo cuento al final de chatbots y rerank.