Escenario · Aplicación web a medida · Consulta médica

Una recepción que deja
de vivir al teléfono.

Agendas de varios especialistas gestionadas a mano y mañanas enteras al teléfono. Reservas online sencillas para los pacientes, recordatorios automáticos para reducir las citas perdidas y datos de salud protegidos.

Tipo de proyectoAplicación web a medida
SectorConsulta médica
Plazos habituales9–12 semanas
●Escenario
aplicación web · reservas
Consulta Médica
AGENDA ONLINE
En línea
Cardiología
Dermatología
Traumatología
Neurología
LUN
MAR
MIÉ
JUE
VIE
●
Reservado
Libre
Urgencia
MIÉ 12 JUN · 09:30
P
Paciente
Paciente desde 2022 · ECG urgente
Urgencia
30 min
Recordatorios automáticos
SMS −24h ✓ Enviado
Email −48h ✓ Enviado
SMS −2h ○ Pendiente
GESTIONAR CITA

Escenario web app — reservas para una consulta médica

Una hoja de Excel como
sistema de reservas

El escenario: una consulta médica con cuatro especialistas, decenas de citas a la semana y una recepción que pasa buena parte del día al teléfono. La agenda es totalmente manual: recepción centralizada, una hoja de Excel compartida en Google Drive y recordatorios escritos a mano.

Los problemas son evidentes: los pacientes no encuentran hueco fuera del horario de oficina, hay muchas ausencias porque nadie recuerda las citas y los informes se entregan todavía en mano o por emails dispersos. Hace falta un sistema que trabaje también cuando la recepción está cerrada.

Restricción típica: el sistema tiene que conectarse por API con el programa médico que ya se usa, sin sustituirlo: la consulta no quiere cambiar una herramienta interna que ya funciona.

Cliente Consulta médica privada, 4 especialistas (ejemplo)
Sector Sanidad privada · Ambulatorio
Año Duración típica · 9–10 semanas
Stack principal
React 18 Node.js 20 PostgreSQL Twilio SMS Redis Stripe
Rol Desarrollador full-stack · Diseño UX

Reservas en autoservicio 24/7

Los pacientes tienen que poder reservar por su cuenta, eligiendo especialista, fecha y hora, incluso a las 23:00. Ninguna llamada necesaria para los huecos estándar.

Recordatorios automáticos por SMS + email

Avisos a −48 horas (email) y a −24 y −2 horas (SMS) con enlace para confirmar o anular. Cada anulación libera el hueco en tiempo real y envía una confirmación al paciente.

Portal del paciente e informes digitales

Un área privada para cada paciente: historial de visitas, posibilidad de descargar los informes en PDF, próximas citas y gestión de los datos personales (conforme al RGPD).

Integración con el programa médico existente

Sincronización en ambos sentidos con el programa interno: las reservas nuevas entran en él y los cambios que hace el médico se reflejan en el portal en tiempo real.

Pago anticipado selectivo

Algunas visitas requieren una señal al reservar (con Stripe) para reducir los no-show. Recepción tiene que poder activar esta opción por tipo de visita.

Requisitos del portal de reservas online

Cuatro agendas, cero conflictos,
un sistema que funciona solo

El ámbito médico tiene restricciones concretas: privacidad de los datos de salud (RGPD), concurrencia en los huecos y recordatorios que, si no llegan, le cuestan dinero real a la consulta. Cada parte del sistema tiene que ser robusta por diseño, no "hacer lo que pueda".

01

Condiciones de carrera en los huecos

Dos pacientes que reservan el mismo hueco en el mismo instante pueden recibir los dos la confirmación. Sin un bloqueo, las colisiones ocurren, sobre todo en las horas punta, justo después de enviar los recordatorios.

02

Recordatorios 100% fiables

Un SMS que no llega a −24 horas es una visita perdida y un hueco vacío. La latencia del envío varía, y un servidor Node.js no puede guardar temporizadores en memoria: si se reinicia, se pierden los recordatorios.

03

Sincronización con el programa médico

A menudo la API del programa interno es REST pero está mal documentada y no tiene webhooks. Los cambios de los médicos (cambios de hora, anulaciones urgentes) tienen que llegar al portal casi en tiempo real sin un aviso del programa.

04

Datos sanitarios y art. 9 del RGPD

Los datos médicos entran en las "categorías especiales" del RGPD: consentimiento explícito, derecho de supresión, registro de accesos. El sistema tenía que ser privacy-by-design, no un añadido de última hora.

05

UX accesible y sin curva de aprendizaje

Entre los pacientes hay personas mayores poco acostumbradas a lo digital. La reserva tiene que completarse en menos de 90 segundos, sin cuenta obligatoria en el primer acceso y con accesibilidad WCAG 2.1 AA.

Retos técnicos de una agenda médica digital

Bloqueo optimista, cola de jobs
y un portal que trabaja de noche

01 / 03

Reserva atómica con bloqueo optimista en PostgreSQL

Para eliminar las reservas duplicadas se usa un bloqueo optimista: cada hueco tiene una columna version que sube con cada cambio. La reserva actualiza el hueco solo si la versión coincide con la leída; si alguien ha reservado mientras tanto, la transacción falla y se reintenta de forma guiada. Sin bloqueos mutuos y con buen rendimiento bajo carga.

En el servidor es una sola transacción de PostgreSQL: se lee el hueco, se comprueba que está libre y se actualiza con WHERE version = $expected; si no se actualiza ninguna fila, se devuelve SlotConflictError y el cliente muestra un mensaje con los huecos libres más cercanos.

// Node.js · PostgreSQL · bloqueo optimista en el hueco de agenda async function bookSlot(slotId, patientId, paymentIntentId) { const client = await pool.connect(); try { await client.query('BEGIN'); // lectura del hueco con bloqueo de fila const { rows } = await client.query( `SELECT id, version, status FROM slots WHERE id = $1 AND status = 'available' FOR UPDATE SKIP LOCKED`, [slotId] ); if (rows.length === 0) { await client.query('ROLLBACK'); throw new SlotConflictError('Hueco ya no disponible'); } // reserva atómica await client.query( `UPDATE slots SET status='booked', patient_id=$1, payment_intent=$2, version=version+1 WHERE id=$3`, [patientId, paymentIntentId, slotId] ); // encola los recordatorios en la cola de jobs await scheduleReminders(client, slotId, patientId); await client.query('COMMIT'); } catch (err) { await client.query('ROLLBACK'); throw err; } finally { client.release(); } }

02 / 03

Cola de jobs persistente para recordatorios fiables

Los recordatorios no usan setTimeout sino jobs persistentes con BullMQ + Redis. Cada reserva añade 3 jobs con el retraso adecuado: −48 horas email, −24 horas SMS, −2 horas SMS. Si el servidor se reinicia, los jobs siguen en Redis y salen en el momento justo. El servicio de SMS (p. ej. Twilio) solo recibe la petición al enviar, con reintento automático si falla la red.

La cancelación por SMS (el paciente responde "CANCELAR" al SMS) activa un webhook de Twilio que elimina el job de confirmación, libera el hueco en PostgreSQL y envía un aviso por email a la consulta, todo sin intervención humana.

BullMQ Dashboard · Cola de recordatorios
COLA DE RECORDATORIOS
● 3 activos cola de ejemplo
reminder:sms:−24h
Paciente A · cita 12/06 09:30
en 22h 14m
en espera
reminder:email:−48h
Paciente B · cita 13/06 11:00
en 46h 02m
en espera
reminder:sms:−2h
Paciente C · cita 11/06 14:00
completado 09:47
completado

03 / 03

Portal de pacientes y sincronización con el programa médico

El portal de pacientes es una app en React con acceso mediante un enlace por email: ninguna contraseña que recordar, ningún obstáculo en el primer acceso. Cada paciente ve sus visitas anteriores, descarga los informes PDF que sube el médico y gestiona sus reservas activas.

Si el programa no ofrece webhooks, la sincronización se hace con un proceso que lo consulta cada 60 segundos y compara las agendas con el estado interno. Los cambios detectados (cambios de hora, anulaciones, nueva disponibilidad) se aplican en la base de datos y llegan a los clientes React mediante Server-Sent Events: actualización en tiempo real sin WebSocket, más sencilla detrás de un proxy inverso.

Proceso de desarrollo de una app de reservas

9–10 semanas, tres actores,
un sistema que funciona solo

En el proyecto hay tres figuras: el médico responsable (decide y conoce el ámbito), la recepción (usa la agenda cada día) y los pacientes (usan el portal). Las sesiones de observación en recepción van antes que cualquier línea de código: entender el flujo real es más útil que cualquier documento de requisitos.

Semanas 1–2

Discovery y análisis del dominio

Observación del trabajo en recepción, mapa de tipos de visita y restricciones de agenda por especialista, análisis de la API del programa médico. Estructura de datos y requisitos del RGPD.

Resultado: esquema de BD, wireframe del portal, plan RGPD

Semanas 3–4

Backend principal: huecos, bloqueos y cola de jobs

Modelo de agenda en PostgreSQL, bloqueo con FOR UPDATE SKIP LOCKED, BullMQ + Redis y primer envío de recordatorios por SMS. Pruebas de carga con decenas de reservas simultáneas.

Resultado: API REST estable, ninguna reserva duplicada en las pruebas

Semanas 5–6

Frontend del portal del paciente y agenda

SPA en React con autenticación por enlace mágico, flujo de reserva en 3 pasos (especialista → hueco → confirmación), área privada con historial de visitas y descarga de informes. Foco en la accesibilidad WCAG 2.1 AA y en la usabilidad para usuarios no técnicos.

Resultado: portal probado con algunos pacientes reales

Semanas 7–8

Integración con el programa médico + Stripe + recordatorios

Proceso de sincronización con el programa médico que detecta diferencias, actualizaciones en ambos sentidos y Server-Sent Events para el frontend. Stripe para las señales en algunas visitas. Pruebas completas de la anulación por SMS.

Resultado: cadena de recordatorios probada con cientos de jobs simulados

Semanas 9–10

UAT, auditoría RGPD y go-live progresivo

Sesiones con recepción y el médico responsable, ajustes de UX en la gestión de urgencias, revisión del RGPD con el asesor legal de la consulta. Puesta en marcha en 3 fases: un especialista → un segundo → todos. Seguimiento activo las primeras 72 horas.

Objetivo: ninguna incidencia grave la primera semana

Solución: bloqueo optimista y recordatorios SMS

React + Node.js en el centro.
Cada decisión justificada.

React + TypeScript
Node.js + Express
PostgreSQL
Redis + BullMQ
Twilio SMS
Stripe Payments
Nodemailer + SES
AWS S3 (informes PDF)
Vite
Jest + Supertest
Zod (validación)
date-fns (gestión de horarios)

¿Por qué enlace mágico y no contraseña?

Entre los pacientes hay personas mayores o poco acostumbradas a lo digital. Una contraseña significa "he olvidado la contraseña" como primer contacto con el portal. El enlace por email —de un solo uso, válido 15 minutos— elimina el problema: si tienes acceso al email, tienes acceso al portal. Quien reserva por primera vez ni siquiera tiene que registrarse: los datos se recogen durante la reserva.

¿Por qué SSE y no WebSocket?

Los WebSocket necesitan una infraestructura propia (sesiones persistentes, soporte del proxy) que complica el despliegue en un hosting compartido. Los Server-Sent Events funcionan sobre HTTP normal, los admiten todos los navegadores modernos y cubren el caso real: actualizaciones en un solo sentido del servidor al cliente (hueco liberado, cita movida). Menos infraestructura, mismo resultado.

Objetivos de ejemplo — reservas médicas

Más reservas online.
La recepción deja de ser un cuello de botella.

Cifras de ejemplo, no resultados de un cliente: objetivos realistas para un escenario como este, a medir en los meses tras el lanzamiento frente al mismo periodo anterior.

×4
Reservas online
objetivo como parte del total
−50%
Tasa de no-show
objetivo con recordatorios automáticos
−60%
Llamadas a recepción
solo urgencias y casos complejos
25%+
Reservas fuera de horario
después de las 18 h o el fin de semana
4,5/5
Satisfacción de los pacientes
objetivo en la encuesta tras la visita
0
Reservas dobles
objetivo con el bloqueo optimista

«Antes pasábamos media mañana al teléfono con las reservas. Ahora solo atendemos lo que de verdad necesita nuestra atención.» Ese es el resultado al que apuntar: una recepción que hace el trabajo para el que está cualificada.

— El objetivo concreto del proyecto

Objetivos: más reservas online

Lo que aplico
en cada proyecto así.

→

Observar antes de diseñar vale el doble en el ámbito médico. Las sesiones en recepción casi siempre revelan un flujo real distinto del que dicen los requisitos. La forma en que un médico "mueve" las citas, por ejemplo, rara vez está documentada, y puede romper una agenda digital si no lo ves en persona.

→

Los recordatorios se prueban simulando el tiempo, no esperándolo. Con time mocking en las pruebas, el reloj avanza 24 horas en unos milisegundos y se comprueba que el job se lanza. Pruebas más rápidas, más cobertura.

→

El acceso con enlace por email elimina casi todas las peticiones de ayuda en el primer acceso. Nada de "cómo me registro" ni "he perdido la contraseña". Para quien tiene poca experiencia digital, bajar la barrera de entrada importa más que cualquier función avanzada.

→

El RGPD sanitario se diseña dentro de la arquitectura, no se añade al final. Registro de accesos a los informes, consentimiento explícito, plazos de conservación y derecho de supresión en la estructura de la base de datos cuestan un par de días al principio. Añadirlos después obliga a reescribir parte del sistema.

→

La puesta en marcha gradual por especialista protege la reputación del sistema. Empezar con un solo especialista saca a la luz los casos límite de la agenda (revisiones de duración variable, huecos bloqueados por reuniones internas) antes de que afecten a todos los pacientes en las primeras horas críticas.

¿Tienes un proceso que todavía depende de llamadas y Excel?

Agendas, reservas, recordatorios automáticos: si el flujo ya existe, se puede digitalizar sin ponerlo todo patas arriba.

¿Tienes en mente un proyecto parecido?

Cuéntamelo: partimos de objetivos y prioridades, y la primera llamada es gratuita.