Resumen
Un sistema de agendado que le permite a un equipo de servicios distribuido tomar reservaciones entre muchos profesionales sin jamás generar una doble reserva, manejar mal una zona horaria ni duplicar una cita en un reintento — con Google Calendar como la única fuente de verdad.
Qué se construyó
Una plataforma de reservaciones montada directamente sobre Google Workspace. Los clientes eligen un horario a partir de la disponibilidad calculada; la plataforma reserva, verifica y confirma la cita como una sola transacción idempotente, escribiendo el evento en el Google Calendar del profesional y notificando a ambas partes. No hay una base de datos de registro aparte — el calendario en el que el equipo ya vive sigue siendo la autoridad.
Para quién es
Un negocio de servicios que opera con varios profesionales, cada uno con sus propios horarios laborales, márgenes y días libres, tomando reservaciones desde un formulario web, correo electrónico y la ocasional llamada telefónica capturada después.
Contexto de negocio
El proceso manual que reemplazó perdía aproximadamente un horario por semana por dobles reservas y desfases de zona horaria — pocos en número, caros en confianza. El trabajo de la plataforma era hacer el calendario autoritativo y la reservación segura, sin agregar un segundo sistema que se desincronizara.
Arquitectura
Un coordinador delgado y sin estado frente a Google Calendar. Una reservación es una transacción corta e idempotente — reservar, verificar, confirmar — enrutada a través de una cola por profesional para que la condición de carrera que causa la doble reserva no pueda ocurrir.
Por qué una cola por profesional
La doble reserva es una condición de carrera entre escritores concurrentes por un solo recurso. En lugar de recurrir a candados distribuidos, cada solicitud para un profesional dado corre a través de una cola FIFO de un solo consumidor — una primitiva aburrida y depurable que hace la carrera imposible en vez de meramente recuperable. La concurrencia entre profesionales se mantiene alta; dentro de un mismo profesional baja a uno.
Componentes
La plataforma está construida a partir de nueve componentes. Cada uno está documentado como su propia sección de ingeniería — por qué existe, su arquitectura, las restricciones y casos límite que maneja, las disyuntivas tomadas y la implementación final. Expande cualquiera para leerlo.
›C1Flujo de reservación en varios pasos
- Por qué existe
- Convierte "encontrar una hora" en una secuencia guiada y retomable — servicio → profesional → fecha → horario → detalles → confirmar — que nunca presenta un horario que no pueda honrar.
- Arquitectura
- Un cliente sin estado impulsado por el motor de disponibilidad; cada paso se revalida contra la disponibilidad en vivo, así un horario que se llena a mitad del flujo se detecta antes del envío.
- Restricciones
- Debe funcionar desde un formulario web, un enlace de correo y una reservación telefónica capturada a mano; ningún paso puede depender del reloj del dispositivo del cliente.
- Casos límite
- Horario ocupado entre la visualización y el envío; reenvío con el botón de retroceso; un profesional que se va de descanso a mitad de sesión.
- Disyuntivas
- Revalidar cada paso cuesta una lectura extra de disponibilidad pero elimina la falla de "el horario que elegiste ya no está" al confirmar.
›C2Motor de disponibilidad
- Por qué existe
- Calcula las ventanas reservables por profesional a partir de horarios laborales, márgenes, eventos existentes y días libres — el modelo de lectura desde el que se renderiza todo el flujo.
- Arquitectura
- Precalcula las ventanas de forma programada y ante webhooks de cambio de calendario, almacenándolas en caché en Firestore; el flujo lee la caché, no la Calendar API, en la ruta caliente.
- Restricciones
- Debe mantenerse correcto mientras los profesionales editan sus propios calendarios directamente; no debe exceder la cuota de lectura de Calendar bajo carga.
- Casos límite
- Eventos superpuestos, bloqueos de día completo, retenciones recurrentes y fronteras de DST donde una ventana de "9 a. m." se recorre.
- Disyuntivas
- Un TTL de caché corto cambia unos segundos de datos obsoletos por una gran caída en llamadas a la API; el paso de confirmación es la autoridad, así que una obsolescencia breve es segura.
›C3API de reservación (reservar · verificar · confirmar)
- Por qué existe
- El núcleo transaccional: convierte una solicitud en exactamente un evento de calendario, de forma segura, incluso bajo concurrencia y reintentos.
- Arquitectura
- Cada solicitud para un profesional corre a través de la cola FIFO de un solo consumidor de ese profesional;
confirm()revisa la disponibilidad dentro de esa ventana y escribe con una llave de idempotencia direccionada por contenido. - Contrato de API
POST /booking → 201 {eventId} | 409 SlotTaken // idempotent: same intent ⇒ same eventId key = sha256(practitionerId, startUTC, clientId)
- Casos límite
- Solicitudes concurrentes por un solo horario (serializadas y resueltas); reintentos de formulario/red (colapsan a un solo evento vía el registro); falla parcial tras la inserción (el commit al registro lo hace seguro ante reejecución).
- Disyuntivas
- La serialización por profesional agrega unos cuantos ms de latencia y elimina la carrera por construcción — elegida sobre los candados distribuidos.
›C4Integración con Google Calendar
- Por qué existe
- Mantiene Google Calendar como la fuente de verdad — leyendo la disponibilidad y escribiendo eventos — para que el equipo nunca deje la herramienta que ya usa.
- Arquitectura
- Usa la consulta agregada
freebusypara la disponibilidad (sin detalle de eventos) yevents.insertpara las escrituras, etiquetando cada evento con su llave de reservación en propiedades extendidas privadas. - Restricciones
- Cuotas de lectura por minuto; alcances con privilegios mínimos; debe sobrevivir a que los profesionales editen eventos a mano.
- Casos límite
- Eventos borrados manualmente, calendarios externos compartidos y reconciliación cuando el calendario y el registro no coinciden.
›C5Manejo de zonas horarias
- Por qué existe
- Garantiza que un horario signifique el mismo instante para el cliente, el profesional y el servidor a través de los cambios de horario de verano.
- Arquitectura
- Almacena el instante en UTC y la zona IANA prevista por el usuario como un campo separado; los dos se recombinan solo al renderizar.
- Casos límite
- Huecos de adelanto/atraso de reloj, zonas que observan el DST en fechas distintas y clientes que cambian la zona de su dispositivo después de reservar.
- Disyuntivas
- Cargar una zona explícita es más para almacenar que una marca de tiempo simple, pero es la única forma de preservar la promesa "9 a. m. en Lisboa."
›C6Autenticación y permisos
- Por qué existe
- Permite que la plataforma actúe sobre los calendarios del dominio con la mínima autoridad que un equipo de seguridad aprobará.
- Arquitectura
- Una cuenta de servicio dedicada con delegación de dominio de alcance estrecho; cada cuenta se rastrea hasta un dueño y un registro de decisión.
- Restricciones
- Sin alcances amplios; llaves rotadas de forma programada; acceso revisado en un calendario, no de memoria.
- Disyuntivas
- El privilegio mínimo implica más configuración por adelantado a cambio de un modelo que pasa la revisión sin excepciones.
›C7Notificaciones
- Por qué existe
- Confirma, recuerda y cancela tanto para el cliente como para el profesional sin jamás enviar dos veces.
- Arquitectura
- Entrega al menos una vez vía Cloud Tasks con llaves de idempotencia y una cola de mensajes fallidos, para que un reintento nunca envíe por duplicado.
- Casos límite
- Limitación del proveedor, direcciones rebotadas y una reservación cancelada antes de que se dispare su recordatorio.
›C8Generación de Google Meet
- Por qué existe
- Adjunta un enlace de video funcional a cada reservación remota en el momento en que se crea el evento.
- Arquitectura
- Solicita los datos de conferencia en
events.insertpara que el enlace de Meet sea parte de la misma escritura atómica que la reservación. - Casos límite
- Fallas en la creación de la conferencia (la reservación debe tener éxito de todos modos) y eventos reagendados que conservan su enlace.
›C9Reportes en Google Sheets
- Por qué existe
- Le da al operador una vista familiar y en vivo de las reservaciones y la carga sin un tablero a la medida.
- Arquitectura
- Sincronización de solo anexado desde el registro hacia una Sheet, tratada como una réplica de lectura — nunca una fuente de verdad.
- Disyuntivas
- Una Sheet es limitada y ligeramente retrasada, pero es instantáneamente legible para alguien que no es ingeniero, que es justo el punto.
Salida visual
Lo que el sistema realmente produce para el cliente y para el operador. Estos son ejemplos del sistema en funcionamiento — cada uno con leyenda y enlazado al componente que lo crea. Coloca las capturas de pantalla reales en los marcos.
El flujo de reservación
El recorrido del cliente en tres pasos: servicio y horario → datos de contacto → fecha y hora → confirmación. Cada paso se revalida contra la disponibilidad en vivo.

Captura real del sistema en funcionamientoComponente: Flujo de reservación en varios pasos
El registro del prospecto
Dónde aterrizan las respuestas del paso de contacto: una fila anexada a la Google Sheet — nombre, empresa, correo de trabajo, origen y marca de tiempo del envío. Usa datos anonimizados o de muestra.

Captura real · datos de muestra / anonimizadosComponente: Reportes en Google Sheets
Evento de calendario creado
La API de reservación escribe directamente en el Google Calendar del profesional — título, hora, zona horaria, ambos asistentes, un enlace de Google Meet y el contexto de captación en la descripción. Prueba de que el sistema crea un artefacto de calendario nativo, no una fila de base de datos privada.

Invitación y confirmación al cliente
Lo que recibe el cliente — la invitación y confirmación de Google Calendar, con los detalles de la reunión y el enlace de Meet.

Captura real · oculta los datos del destinatarioComponente: Notificaciones · Generación de Google Meet
Notificación interna
Lo que el equipo ve cuando aterriza una reservación — la notificación interna con el contexto de calificación capturado y el flujo de trabajo de origen.
Captura real · anonimizadaComponente: Notificaciones
Falla y recuperación
Los estados que prueban el pensamiento de producción: un horario ocupado entre la visualización y el envío, y el reintento exitoso que sigue. Izquierda: conflicto. Derecha: recuperación.
Componente: API de reservación (disponibilidad y concurrencia)
Impacto
Resultados objetivos que se derivaron de poner la plataforma en producción — evidencia, no marketing.
- Negocio
- Reemplazó un stack de agendado de Calendly más Zapier con un solo sistema propio.
- Eliminó el costo recurrente de suscripción a terceros y el pegamento que conectaba las herramientas.
- Cliente
- Confirmación inmediata y confiable en el momento de la reservación.
- Menos fallas de agendado — ningún horario ofrecido que no se pueda honrar.
- Operaciones
- Reservaciones duplicadas eliminadas.
- Manejo de zonas horarias automatizado de extremo a extremo.
- Captura manual de calendario removida del día del equipo.
- Ingeniería
- Una única fuente de verdad — sin base de datos de reservaciones paralela que se desincronice.
- Escrituras idempotentes y seguras ante reintentos; menos partes móviles que operar.
- Escala
- ~4,000 reservaciones / mes.
- Cero dobles reservas desde que aterrizó la serialización v2.
Documentos técnicos
Registros de ingeniería cronológicos escritos mientras se construía la plataforma — las decisiones, los callejones sin salida y los incidentes tal como sucedieron. Los más recientes primero.
Caso de estudio
Una retrospectiva de la plataforma desde la perspectiva del negocio — por qué existe, el enfoque tomado y cómo resultó.
- Problema
- Un equipo de servicios manejaba su calendario a mano y perdía cerca de un horario por semana por dobles reservas y errores de zona horaria — barato de contar, caro en confianza del cliente.
- Objetivo
- Hacer el calendario autoritativo y la reservación segura, operable por una sola persona, sin un segundo sistema de registro.
- Restricciones
- Google Calendar sigue siendo la fuente de verdad; seguridad con privilegios mínimos; correcto bajo concurrencia y reintentos; dentro de las cuotas de la Calendar API.
- Enfoque
- Un coordinador delgado y sin estado frente a la Calendar API; serialización por profesional para eliminar la carrera; idempotencia direccionada por contenido para eliminar duplicados; UTC más intención para el tiempo.
- Arquitectura
- Captación → validación en el borde → cola FIFO por profesional → coordinador reservar/verificar/confirmar → Google Calendar, con un pequeño registro de idempotencia. Sin base de datos de reservaciones paralela.
- Disyuntivas
- Elegí una cola aburrida y demostrablemente correcta sobre los candados distribuidos; acepté segundos de obsolescencia en la disponibilidad por un gran ahorro de cuota; mantuve el estado en la plataforma que ya lo posee.
- Resultado
- En producción desde feb 2024, ~4,000 reservaciones/mes, cero dobles reservas desde que aterrizó la serialización v2; "¿mi reservación sí pasó?" se volvió un no-evento porque los reintentos son seguros.
- Lecciones
- Serializa el recurso en disputa; no bloquees el mundo entero.
- La idempotencia es una funcionalidad, no una salvaguarda.
- Deja que la plataforma conserve el estado que ya posee.
- Futuro
- Un flujo de reagendado de autoservicio, y mover la limpieza del TTL del registro de cron a la expiración de documentos.
