Saltar al contenido

Consultorio odontológico/Profesional

Mantener FYM en uso mientras preparo su reemplazo

Cómo asumí un sistema de diez años para un consultorio odontológico, estabilicé los despliegues, incorporé el borrado recuperable y preparé un reemplazo gradual

Rol
Responsable de mantenimiento de la aplicación legada y líder de modernización
Período
2025 hasta la actualidad

Recibir FYM

FYM es el sistema operativo de un consultorio odontológico. Conecta fichas de pacientes, turnos, historias clínicas, odontogramas, radiografías, planes de tratamiento, trabajos de laboratorio, facturación y acceso del personal. Cuando lo recibí de su desarrollador anterior, la aplicación se había mantenido prácticamente estática durante cerca de diez años, pero la empresa todavía dependía de ella para el trabajo diario.

Funcionaba con Symfony 2.8, Doctrine 2, Twig, AdminLTE 2, Bower y Assetic, con un árbol de dependencias administrado manualmente y PostgreSQL 11. Los paquetes no podían actualizarse de manera segura, las actualizaciones automáticas del esquema estaban prohibidas, y las imágenes clínicas y los registros financieros hacían que cualquier pérdida de datos fuera inaceptable.

Mi responsabilidad tenía dos partes: mantener la aplicación actual confiable y útil, y preparar una salida gradual de un stack que ya no podía actualizarse de manera convencional.

Reconstrucción de la entrega

La primera tarea fue trasladar FYM a una nueva configuración de servidor sin interrumpir el funcionamiento del consultorio. Reconstruí cómo se ejecutaba la aplicación, preservé sus dependencias congeladas y configuré PHP, Nginx, PostgreSQL, permisos, comportamiento del caché y generación de assets.

Después establecí un proceso de despliegue con GitHub Actions adaptado a la estructura de consola de Symfony 2, la gestión manual del caché, los permisos del sistema de archivos y el comportamiento de PHP y OPcache en el servidor. Esto reemplazó un estado de servidor no documentado por un proceso repetible orientado a producción. Todavía necesito recuperar los logs de la transición original y de la transferencia de la base de datos antes de presentar la migración completa como verificada de manera independiente.

Esto estableció la regla para todo lo que siguió: FYM podía mejorarse, pero cada cambio debía preservar la continuidad clínica y administrativa.

El borrado recuperable como cambio del sistema

El ejemplo más contundente fue el borrado de pacientes. Un borrado destructivo era demasiado riesgoso para un registro conectado con turnos, antecedentes de atención, tratamientos, pagos e imágenes. Ocultar a un paciente en una sola pantalla tampoco alcanzaba; el mismo paciente podía reaparecer en búsquedas, calendarios, informes o registros relacionados.

Incorporé un ciclo de vida recuperable para los registros de pacientes:

  • timestamps de borrado y recuperación;
  • el miembro del personal responsable de cada acción;
  • acciones restringidas de borrado y recuperación;
  • una vista separada para pacientes eliminados;
  • interfaces de confirmación y recuperación;
  • casos de tests funcionales que cubrían el ciclo de vida previsto.

La primera versión mostró hasta dónde llegaba el borrado. Después agregué SQL de migración compatible con PostgreSQL, registré el filtro de borrado lógico de Doctrine, saqué a los pacientes borrados de los listados comunes y corregí conteos, búsquedas, paginación y consultas de registros de atención.

Más adelante propagué el mismo límite a los selectores de profesionales, la gestión de usuarios y el catálogo de tratamientos. Fue menos un botón para borrar que una definición gradual de qué significaba que un registro estuviera "activo" en toda la aplicación.

Solicitud de borrado
       |
       v
registro marcado como borrado + responsable/momento conservados
       |
       +----> las consultas comunes lo excluyen
       |
       +----> los turnos y las vistas de atención relacionados toleran su ausencia
       |
       +----> la vista restringida de recuperación puede restaurarlo

Mejora del uso diario

Una vez que el despliegue y el comportamiento del ciclo de vida de los registros fueron más seguros, trabajé sobre problemas más pequeños que afectaban el uso cotidiano del sistema de la empresa.

  • Las pantallas de pacientes, tratamientos, laboratorio, inicio de sesión, perfil y gestión de usuarios recibieron acciones más claras, tablas y formularios más coherentes, y mejoras de presentación responsive.
  • Las vistas de turnos y los feeds de eventos se reforzaron frente a pacientes borrados o faltantes.
  • Se corrigieron la presentación de moneda argentina, el parseo de entradas y la precisión de los valores financieros.
  • La carga de turnos sin límites se reemplazó por consultas por rango de fechas que coincidían con el intervalo visible del calendario.

Estos cambios evitan modos de falla conocidos y expresan con mayor claridad los flujos de trabajo diarios. Harían falta estudios de usabilidad, conciliación contable y mediciones de rendimiento antes de afirmar un efecto cuantificado.

Elección de una migración incremental

Había tres opciones generales:

  1. Seguir aplicando parches indefinidamente. Esto protegía la continuidad a corto plazo, pero dejaba al consultorio con dependencias congeladas y conocimiento específico del servidor.
  2. Reescribirlo y reemplazarlo de una sola vez. Esto ofrecía un destino limpio, pero acoplaba el rediseño del producto, la migración de datos, la transferencia de imágenes, la paridad de flujos de trabajo y el reemplazo de infraestructura en un solo evento de alto riesgo.
  3. Separar la salida de datos del reemplazo del producto. Estabilizar la aplicación legada, exponer un límite de migración de solo lectura, verificar las copias de manera independiente y reemplazar los flujos de trabajo en incrementos controlados.

Elegí la tercera opción. Todavía no definí el stack final a propósito. Primero necesito un inventario confiable de los datos, un proceso de copia repetible y evidencia sobre los flujos de trabajo que hay que preservar. Elegir un framework no puede reemplazar una estrategia de migración.

Prueba de la interfaz de migración

Para poner a prueba ese límite, construí un prototipo local junto al repositorio legado. Un servicio independiente en TypeScript usa Hono y un esquema de PostgreSQL obtenido por introspección para brindar acceso autenticado y de solo lectura a 29 entidades legadas. Una capa de serialización traduce los nombres de la base de datos en español a nombres de API en inglés sin modificar FYM.

El prototipo también hace un inventario de los archivos subidos de pacientes y devuelve los archivos de imagen originales. Un explorador en Nuxt permite inspeccionar los conteos de entidades, campos, relaciones y registros paginados, mientras mantiene la credencial de la API en el servidor.

FYM legado
Symfony 2.8 + PostgreSQL + imágenes de pacientes
               |
               | acceso autenticado de solo lectura
               v
Prototipo de API de migración
Hono + traducción de campos + inventario de imágenes
               |
               v
Interfaz de inspección en Nuxt
esquema, relaciones, conteos, registros de muestra
               |
               v
Futuros flujos de copia verificada y reemplazo
stack de destino todavía por determinar

Esto despeja una duda de arquitectura: puedo inspeccionar los datos de FYM mediante una interfaz separada sin cambiar la aplicación ni el esquema de producción. Todavía no demuestra que la migración sea segura. Quedan pendientes los tests de contrato, una gestión de imágenes más segura, checksums, un seguimiento confiable de actualizaciones, el despliegue y una copia sanitizada de punta a punta.

La interfaz de backup planificada y el receptor de sincronización con SQLite son solamente trabajo de diseño. No se entregó ninguna GUI de backup, receptor, aplicación clínica de reemplazo ni cambio a producción mediante este workspace de modernización.

Estado actual del trabajo

Entrega de la aplicación legada

El trabajo incluyó la compatibilidad del servidor y un despliegue repetible. Está registrado en commits, publicado en el repositorio remoto y respaldado por ejecuciones exitosas de la automatización para producción.

Ciclo de vida de los registros y flujos de trabajo diarios

El trabajo incluyó borrado recuperable, filtrado de registros activos, mejoras de interfaz, correcciones financieras, arreglos de turnos y consultas acotadas del calendario. Está registrado en commits y publicado en el repositorio remoto. Todavía falta verificar el uso en producción y medir resultados.

Límite de migración

Construí una API Hono de solo lectura, traducción de campos, un inventario de imágenes y una interfaz de inspección en Nuxt. Es un prototipo local sin commit. No fue entregado ni desplegado.

Migración futura

La interfaz de backup, el receptor de sincronización, la aplicación de reemplazo y el cambio definitivo son planes de arquitectura. Ninguno está construido ni completo.

Continuidad ahora, reemplazo después

FYM ahora tiene un proceso de despliegue repetible, semántica de borrado recuperable, una gestión más segura de registros inactivos, consultas acotadas de turnos e interfaces más claras. En paralelo, el prototipo demuestra una forma de inspeccionar datos legados sin convertir a la aplicación antigua en la base de cada decisión futura.

La idea es reducir el riesgo por etapas, no ocultarlo detrás del anuncio de una reescritura. La empresa puede seguir usando FYM mientras pruebo la migración con sus datos reales y sus restricciones operativas.

Qué expuso el trabajo

La primera implementación de borrado lógico no fue la definitiva. Su SQL original usaba sintaxis específica de MySQL aunque FYM funcionaba con PostgreSQL, y al principio el filtrado no se aplicaba en todas partes. Cada flujo de trabajo relacionado expuso otra vía por la que los datos inactivos podían regresar.

El prototipo expuso brechas similares: el esquema generado tiene 29 entidades mientras que los planes anteriores describen 30, varios campos de sincronización propuestos no pueden capturar todas las actualizaciones, y la transferencia de imágenes necesita una validación de rutas y streaming más sólidos.

Estos hallazgos confirmaron la estrategia de migración: usar prototipos para encontrar incógnitas sin confundir una arquitectura posible con una transferencia verificada.

Próximos pasos

Este trabajo trata, ante todo, de cuidar un sistema con muchas restricciones. El problema no era simplemente escribir código nuevo. Había que descubrir dónde el sistema guardaba las reglas operativas reales del consultorio, mejorarlas sin perder datos y separar partes que permitieran reemplazarlo más adelante.

La próxima decisión no es simplemente "¿qué framework debería reemplazar a Symfony?". Es determinar si el límite de migración puede producir una copia completa, repetible y verificable de manera independiente. Solo entonces deberían definirse el stack de reemplazo y el cambio flujo por flujo.

Este caso de estudio seguirá siendo un borrador hasta que se confirmen mi función pública, el permiso de publicación, la evidencia del despliegue en producción y el material de validación sanitizado.

Tecnologías

  • Symfony 2.8
  • PHP
  • PostgreSQL 11
  • Doctrine
  • Twig
  • GitHub Actions
  • Hono
  • Nuxt

Habilidades aplicadas

  • Modernización de sistemas legados
  • Diseño del ciclo de vida de los datos
  • Ingeniería de despliegue
  • Diseño de interfaces
  • Arquitectura de migración
ProyectosTodos los casos de estudio

Más