La situación
Un grupo médico con quince clínicas funcionaba sobre ocho cosas que no sabían unas de otras: una web, un widget de reservas aparte, un Excel para el stock, un segundo Excel para el laboratorio, un programa de contabilidad, una aplicación de fichaje, un dashboard de publicidad y un buzón compartido. Cada cifra que importaba existía en al menos dos sitios, y donde no coincidían nadie podía decir cuál era la correcta.
Eso no es un problema de tecnología. Es un problema de negocio que aparece como un problema de tecnología, y es exactamente el tipo de trabajo que mejor se me da.
Lo que construí
Una sola plataforma Django, que sirve las quince sedes: la web pública, las citas, las fichas de los pacientes, el CRM, la logística de laboratorio, el stock de varios almacenes, la contabilidad fiscal, recursos humanos y los informes sobre el gasto en publicidad. Todo detrás de un único admin, con aislamiento a nivel de clínica y de región para nueve roles de personal, de modo que una recepcionista de una ciudad no puede ver los pacientes de otra ciudad y ni siquiera tiene que pensar por qué.
Las funcionalidades son la parte banal. Tres de los sistemas que hay debajo merecen que los describa, porque son la diferencia entre un software que funciona el día del lanzamiento y un software en el que sigues confiando dos años después.
Un flujo de consentimiento que resistiría en un juzgado
El consentimiento médico bajo el RGPD no es un checkbox con un timestamp. Lo que tienes que poder producir, más tarde, es exactamente el documento con el que una persona concreta estuvo de acuerdo en un momento concreto - no tu versión de ahora.
Así que el flujo genera el documento, lo muestra en pantalla, confirma la identidad con un código enviado por SMS y almacena el PDF renderizado junto con el texto, el idioma en el que se mostró, la dirección desde la que se firmó y una cadena de hashes que lo vincula a la ficha. Si modificas la plantilla después, cambia lo que ve el siguiente paciente y nada de lo que aceptaron los anteriores.
La regla de debajo: el consentimiento se da a una frase, no a un
booleano. Si tu sistema almacena true, ha almacenado lo que no
debía.
El stock como registro, no como número
La mayoría de los sistemas de stock mantienen una columna
quantity en la que escribe el código. Esa columna acaba estando mal
en algún momento - una condición de carrera, un reintento, un clic equivocado,
una transferencia aplicada a medias - y una vez que está mal ya no tienes cómo
averiguar por qué, porque la respuesta sobrescribió la prueba.
Aquí la cantidad no se almacena. Cada recepción, transferencia, consumo y corrección es una entrada inmutable con signo, y el saldo de cualquier almacén es la suma de las entradas que lo tocan. Las correcciones añaden el inverso en lugar de editar el historial. Eso convierte la conciliación en una propiedad del diseño, no en una tarea mensual, y significa que la respuesta a "¿por qué tenemos once de estos?" está siempre disponible y siempre completa.
Más abajo en la página encuentras una versión funcional de la idea.
Un calendario que no puede solapar dos citas
Las citas de quince clínicas se solapan constantemente, y la recepción necesita ver un día entero de una vez, sin que dos citas ocupen nunca el mismo hueco. Ese es el problema de interval scheduling: ordenas por hora de inicio y después pones cada cita en el primer carril cuya cita anterior ya ha terminado.
Lo que hace que merezca la pena implementarlo bien y no de forma aproximada es que la variante greedy es demostrablemente óptima - el número de carriles que produce es exactamente el mayor número de citas que se solapan en un mismo instante, es decir, un límite inferior duro que ningún algoritmo puede batir. Puedes ver cómo se cumple en la demo de más abajo.
La realidad rumana
La facturación, el libro de caja y los drivers para las impresoras fiscales que exige la ley. Trabajos protésicos rastreados por mensajería entre la clínica y el laboratorio. Fichaje con un pequeño cliente de escritorio que envía un heartbeat. Nada de todo esto es ingeniería interesante y todo junto es la diferencia entre un sistema que las clínicas usan y uno que esquivan.
La decisión que defendería con más fuerza
Cada dependencia externa de la plataforma hace fail open. Si el proveedor de SMS está caído, si la API de publicidad limita las peticiones o si el servicio de facturación da timeout, la cita se completa igualmente, y el trabajo que queda entra en una cola y se marca para una persona.
La alternativa - rechazar una cita porque un tercero no está disponible - significa externalizar tus ingresos al uptime de otro. Las protecciones internas van al revés: los rate limits, la validación y el honeypot hacen fail closed, porque ahí no tienes a quién echarle la culpa.
Lo que haría de otra manera
Construiría la capa de informes antes. Diseñé el registro y la planificación correctamente desde el principio y dejé que los informes se fueran acumulando solos, lo que significó que los primeros tres meses de preguntas de dirección se respondieron con consultas escritas a mano por mí. Correcto, pero lento, y debería haberlo visto venir.