Plan maestro de desarrollo del LIS
Estado: documento vivo · Versión: 1 · Fecha: 2026-09-24
Este plan traduce la documentación funcional del LIS en una secuencia de construcción verificable. No repite el dominio: lo ordena. Se apoya en MARCO.md como método de trabajo, en el marco conceptual como lenguaje ubicuo, en procesos y casos de uso como fuente de requisitos y en el modelo de datos con su DDL como esquema de partida.
1. Cómo se usa este documento
| Regla | Consecuencia práctica |
|---|---|
| Solo el hito en curso está detallado | Los hitos M2 en adelante son un esbozo de alcance, no una especificación. Su detalle se escribe al empezarlos. |
Cada hito produce su propio PLAN.md en la rama |
Ese archivo lista los slices del hito y se marca conforme avanzan. Este documento no se edita a diario. El del hito en curso es PLAN.md. |
| El plan se revisa al cerrar cada hito | Lo aprendido reordena o reemplaza los hitos siguientes; se registra en la sección 12. |
| Ningún slice empieza sin criterio de aceptación verificable | Si no puede escribirse un test que lo demuestre, el slice no está listo para construirse. |
Lo que no está aquí: el detalle de la interfaz de usuario (vive en DESIGN_claude.md y queda fuera del alcance por decisión D-03), los requisitos por capacidad (se escriben por hito) y las decisiones estructurales (van a ADRs numerados).
2. Decisiones fundacionales
| ID | Decisión | Elección | Razón | Coste de revertir |
|---|---|---|---|---|
| D-01 | Alcance del primer hito | Camino clínico nominal P02→P10 | Es el flujo que justifica el sistema y atraviesa todas las capas. Configuración, calidad, finanzas, microbiología e inventario llegan después. | Bajo |
| D-02 | Tratamiento del DDL existente | Migración base V1 completa con Flyway |
El DDL es coherente e incluye restricciones, vistas y triggers que ya codifican reglas del dominio. Trocearlo destruiría trabajo válido. | Medio |
| D-03 | Interfaz de usuario | Fuera del plan. El borde del sistema es una API HTTP interna | El dominio debe estabilizarse antes de comprometer pantallas. Las pantallas ya están diseñadas en DESIGN_claude.md y esperan. Thymeleaf permanece en el pom.xml: sale barato conservarlo y la UI llegará. |
Bajo |
| D-04 | Persistencia | Solo jOOQ | Un único modelo de acceso, SQL explícito, sin lazy loading ni N+1 encubiertos. El LIS es intensivo en consultas de vista y reporte. | Alto |
| D-05 | Arquitectura | Monolito modular con puertos y adaptadores, por capacidad de negocio | Un equipo de una persona, un despliegue, límites de módulo verificables por test. | Medio |
| D-06 | Catálogo clínico en M1 | Precargado por datos de referencia, solo lectura | Registrar una orden exige pruebas, analitos y requisitos configurados. Construir P01 completo antes de M1 retrasaría la primera entrega útil sin reducir riesgo. | Bajo |
| D-07 | Origen de resultados en M1 | Solo captura manual (origen = 'manual') |
Las interfaces de equipo (mensaje_interfaz) son un problema de integración independiente del ciclo clínico. |
Bajo |
Consecuencia de D-04: spring-boot-starter-data-jpa sale del pom.xml. Una regla de dependencias es verificable cuando lo prohibido no está en el classpath.
Estructura de módulos
com.sineltek.lis
├── compartido/ identificadores tipados, errores de dominio, reloj, actor, consecutivos
├── catalogo/ prueba, perfil, analito, requisito de muestra, intervalos, tarifas (P01)
├── admision/ paciente, orden, prueba solicitada, datos clínicos, consentimiento (P02)
├── muestras/ muestra, custodia, no conformidad, alícuota, lista de trabajo (P04, P05)
├── analitica/ ejecución, resultado, versión de resultado (P07)
├── validacion/ referencia, criticidad, reglas, validación, notificación crítica (P08, P09)
├── informes/ informe, detalle, entrega, corrección (P10)
├── calidad/ control interno y externo, bloqueos, mantenimiento, calibración (P06)
├── finanzas/ cobertura, factura, pago, cartera (P03)
├── microbiologia/ cultivo, aislamiento, antibiograma (P12)
├── derivacion/ laboratorio de referencia, envío, retorno (P13)
├── inventario/ reactivo, lote, movimiento, consumo (P14)
└── seguridad/ cuentas, roles, auditoría, restricción de resultados sensibles (P15)
Cada módulo se organiza en dominio, aplicacion, infraestructura y api.
Regla de dependencias: api → aplicacion → dominio. dominio no conoce Spring, ni jOOQ, ni HTTP, ni PostgreSQL. Las clases generadas por jOOQ solo existen en infraestructura.
Regla entre módulos: la escritura nunca cruza el límite de un módulo; se invoca el caso de uso del módulo dueño. La lectura sí puede cruzarlo a través de las vistas del esquema (v_lista_trabajo, v_resultados_para_informe, v_ordenes_completas), que pertenecen al módulo que las consume.
3. Mapa de hitos
flowchart LR
M0[M0 · Cimientos] --> M1[M1 · Camino clínico nominal]
M1 --> M2[M2 · Configuración clínica]
M2 --> M3[M3 · Calidad y reglas]
M1 --> M4[M4 · Cobertura y cobro]
M1 --> M5[M5 · Microbiología y derivación]
M3 --> M6[M6 · Inventario y consumo]
M3 --> M7[M7 · Interfaces y POCT]
M1 --> M8[M8 · Confidencialidad y auditoría]
classDef hecho fill:#D3F9D8,stroke:#2B8A3E,stroke-width:2px,color:#1B4332
classDef curso fill:#D0EBFF,stroke:#1971C2,stroke-width:2px,color:#0B2E4F
classDef futuro fill:#F1F3F5,stroke:#868E96,stroke-width:1px,color:#343A40
class M0,M1 curso
class M2,M3,M4,M5,M6,M7,M8 futuro
| Hito | Objetivo verificable | Procesos | Slices | Depende de |
|---|---|---|---|---|
| M0 | El repositorio construye, migra, genera código jOOQ, pasa sus puertas de calidad y sirve un endpoint contra la base real | — | 6 tareas | — |
| M1 | Una orden recorre admisión, toma, recepción, alícuota, ejecución, validación, comunicación crítica, informe y corrección, con evidencia completa | P02, P04, P05, P07, P08, P09, P10, P11 | 22 | M0 |
| M2 | El catálogo clínico se administra desde el sistema, con vigencias y aprobación | P01 | ~10 | M1 |
| M3 | Un control fallido bloquea el proceso; una regla refleja, delta o de autovalidación se ejecuta y deja evidencia | P06, P08 avanzado | ~12 | M2 |
| M4 | Una orden se cotiza, factura, cobra y concilia; una urgencia avanza sin pago con autorización registrada | P03 | ~8 | M1 |
| M5 | Un cultivo produce lecturas, aislamientos y antibiograma; una prueba se deriva y retorna identificando al productor | P12, P13 | ~10 | M1 |
| M6 | El consumo de un lote mueve el saldo y queda ligado a su ejecución; un lote vencido se rechaza | P14 | ~6 | M3 |
| M7 | Un analizador entrega resultados por interfaz con deduplicación y cuarentena; un POCT recorre el mismo ciclo | P07 interfaz, P16 | ~10 | M3 |
| M8 | Un resultado sensible se restringe por prueba y por resultado, y toda consulta queda auditada | P15 | ~8 | M1 |
El calendario depende de la dedicación. Con la regla del marco —un slice cabe en 1 a 3 días— M0 son dos días y M1 está entre seis y ocho semanas a tiempo parcial.
4. M0 — Cimientos
Estado actual del repositorio: Spring Boot 4.1 sobre Java 25, dependencias de jOOQ, Thymeleaf, Security con WebAuthn y OpenTelemetry, docker-compose con PostgreSQL 18 y Grafana LGTM, un TestController y una SecurityConfig mínima. No hay migraciones, ni generación de código, ni tests de integración, ni puertas de calidad.
| # | Tarea | Resultado verificable | Estado |
|---|---|---|---|
| T0.1 | Incorporar Flyway y crear V1__esquema_base.sql con el DDL actual |
flyway:migrate levanta el esquema completo en una base vacía. El esquema es lis, no public: Flyway escribe su historial en lis y la conexión de la aplicación fija currentSchema=lis |
Hecho |
| T0.2 | Separar los datos del archivo de ejemplo en dos destinos | V2__catalogos_estado.sql lleva roles, estados y matrices de transición; la demostración vive en src/test/resources/db/demo/ y se carga con make demo, nunca por Flyway |
Hecho |
| T0.3 | Ampliar la matriz de transiciones en V3__transiciones_faltantes.sql |
Las ocho transiciones que la sección 7 del documento de procesos declara ausentes existen y tienen test | Hecho |
| T0.4 | Generar el código jOOQ contra una base ya migrada | Perfil manual -Pjooq-codegen: migra el Postgres local y genera en com.sineltek.lis.jooq, dentro de src/main/java. Las fuentes se versionan, así que un build normal, un docker build o un runner de CI no necesitan Postgres. Razón en ADR-0002 |
Hecho en el pom |
| T0.5 | Retirar spring-boot-starter-data-jpa; añadir Testcontainers, ArchUnit, JaCoCo y formateador |
Las dependencias y las puertas están en el pom.xml; falta el primer test de integración que las ejerza |
Hecho en el pom |
| T0.6 | Walking skeleton end-to-end | GET /api/v1/sedes atraviesa api → aplicación → dominio → adaptador jOOQ → PostgreSQL. La traza OTel en Grafana queda como deuda declarada |
Hecho |
Verificaciones que T0.1 y T0.4 deben resolver antes de avanzar: que Flyway 12.4 y jOOQ 3.21 —las versiones que gestiona Boot 4.1— traten correctamente uuidv7(), btree_gist, las restricciones de exclusión, la tabla particionada evento_auditoria y el esquema lis. Son incompatibilidades plausibles y baratas de descubrir el primer día, caras en la semana ocho.
Regla derivada de T0.4: ninguna migración se da por terminada hasta que el código jOOQ regenerado que la acompaña está en el mismo commit. Un esquema y un código generado desincronizados rompen el build de cualquiera que clone el repositorio.
ADRs de M0, escritos en docs/adr/: ADR-0001 monolito modular por capacidad · ADR-0002 generación jOOQ en perfil manual con fuentes versionadas · ADR-0003 el DDL como migración base · ADR-0004 solo jOOQ, sin JPA.
5. M1 — Camino clínico nominal
Objetivo: que una orden real recorra el ciclo completo con la evidencia que exige el dominio. Lo que M1 deja deliberadamente fuera: gestión del catálogo, cobertura y facturación, control de calidad, reglas reflejas y de autovalidación, microbiología, derivación, inventario, interfaces de equipo y POCT.
Precondición de datos (D-06): el catálogo clínico se carga con los datos de referencia y M1 solo lo lee. La primera pantalla de administración de catálogo es M2.
Slices
| ID | Entrega | Trazabilidad | Resultado verificable |
|---|---|---|---|
| S1.01 | Contexto de ejecución: identificadores tipados, errores de dominio, reloj, organización, sede y actor operativo | §2 actores | Una petición resuelve organización, sede y cuenta_usuario sin consultarlos dentro del dominio |
| S1.02 | Consecutivos de documento sobre siguiente_numero_documento |
RN-18, PO-02.3 | Cien solicitudes concurrentes producen cien números distintos y sin huecos por año |
| S1.03 | Motor de transiciones de estado | §7 matriz | Una transición ausente de la matriz se rechaza; una que exige motivo sin motivo se rechaza; estado e historial se escriben en la misma transacción |
| S1.04 | Paciente: búsqueda por historia e identificador, alta, detección de duplicado | CU-01, RN-01, RN-20 | Un identificador repetido no crea un segundo paciente; el candidato a duplicado se marca para resolución auditada |
| S1.05 | Registro de orden | CU-02, RN-02, PO-02 | Orden con número, sede de registro, prioridad y estado registrada con su historial |
| S1.06 | Pruebas solicitadas y expansión de perfiles | CU-02, RN-03, RN-04 | El perfil expande sin duplicar; código, nombre, método y precio quedan congelados; una prueba cancelada libera el hueco |
| S1.07 | Datos clínicos de la orden | RN-26, PO-02.5 | Peso, talla o gestación se guardan estructurados con su momento de observación, no como texto del diagnóstico |
| S1.08 | Consentimiento del paciente | CU-04 | Una prueba con requiere_consentimiento y sin consentimiento vigente no avanza a procesamiento ni a divulgación |
| S1.09 | Toma de muestra y cadena de custodia | CU-07, RN-05 | Código de barras único en la organización, evento de toma append-only, muestra temporizada completa o ausente |
| S1.10 | Recepción técnica: aceptación, no conformidad, rechazo y nueva toma | CU-08, RN-06 | Las cuatro decisiones del modelo funcionan; la excepción exige autorizador; la nueva muestra apunta a la reemplazada y ambas cadenas siguen consultables |
| S1.11 | Alícuotas y vínculo con la prueba | CU-09, PO-05 | Una prueba sin alícuota no puede ejecutarse; la alícuota principal identifica la muestra de la prueba |
| S1.12 | Lista de trabajo por sección | PO-05.4 | Lectura sobre v_lista_trabajo con prioridad y estado; una prueba sin alícuota principal aparece sin muestra identificada |
| S1.13 | Prueba agregada a una orden existente | CU-03, RN-22 | Reutiliza la muestra si su estabilidad sigue vigente; exige nueva toma cuando expiró |
| S1.14 | Ejecución analítica manual, resultado y versión | CU-11, RN-07, RN-08 | El tipo de valor corresponde al analito; una versión tiene un solo tipo principal de valor; version_vigente_id apunta a la versión que se lee |
| S1.15 | Repetición y selección de versión vigente | CU-12 | La ejecución anterior se conserva; desde la versión 2 el motivo es obligatorio; una versión creada y no apuntada no aparece en los informes |
| S1.16 | Intervalo de referencia, banderas y criticidad | RN-09, PO-08.1 | La selección usa analito, método, unidad, sexo biológico y edad sobre una fecha base declarada; sin coincidencia única la versión queda en referencia_no_resuelta y nunca se interpreta como normal |
| S1.17 | Validación técnica y profesional sobre la versión | CU-15, RN-10 | La validación apunta a una versión concreta; admite devolución y aprobación sucesivas, con una sola aprobación vigente por tipo |
| S1.18 | Notificación crítica | CU-16, RN-11, RN-28 | Un crítico bloquea la liberación automática; la notificación cierra confirmada o escalada, con emisor, receptor, canal, hora y evidencia |
| S1.19 | Emisión de informe | CU-17, RN-13 | Número propio, firmante profesional, hash_sha256, detalle ordenado sin repeticiones y solo con versiones liberadas de la propia orden |
| S1.20 | Entrega y reimpresión | RN-14 | Cada entrega registra canal, destinatario y evidencia; reimprimir no crea versión clínica nueva |
| S1.21 | Corrección de un resultado publicado | CU-18, RN-12 | Nueva versión con motivo, revalidada; informe con reemplaza_a_id; ambos informes y ambas entregas siguen reproducibles; la prueba no se reabre |
| S1.22 | Tiempos de respuesta y observabilidad del flujo | §8 | iniciada_en y completada_en se fijan en los hitos correctos; v_tiempos_respuesta compara contra tat_objetivo_minutos; las trazas cubren los puntos de decisión sin PII |
Orden de construcción dentro de cada slice
Tipos de dominio → puertos → caso de uso con tests → adaptador jOOQ → API → observabilidad. Un slice deja el sistema compilando y en verde, y cabe en un commit.
Escenarios de aceptación del hito
De los quince escenarios mínimos del documento de procesos, M1 debe superar el 1, el 2, el 8, el 10 y el 14 completos, y el 6 salvo su parte de alertas operativas. Los restantes pertenecen a hitos posteriores y no se dan por cubiertos antes.
6. Trazabilidad
La documentación existente ya provee la cadena de identificadores; el plan no inventa una nueva taxonomía.
RN-xx (marco conceptual §16) → PO-xx / CU-xx (procesos y casos de uso) → S1.xx (slice) → test
Cada test de aceptación cita en su nombre el identificador que verifica. Con eso, la pregunta ¿qué regla de negocio no tiene test? se responde con una búsqueda, no con una opinión. Al cerrar cada hito se ejecuta esa búsqueda y su resultado se anota en el PLAN.md del hito.
Las reglas que el hito en curso no cubre se declaran explícitamente como no cubiertas. Una regla sin test y sin declaración es un defecto de proceso.
7. Qué debe garantizar la aplicación
El DDL resuelve inmutabilidad de versiones y libros, tipo de valor y unidad, prohibición de autovalidar un crítico, matriz de transiciones, coherencia de orden y paciente, unicidad de código de barras, bloqueo de lotes vencidos y consecutivos. Todo lo demás es responsabilidad del código, y este plan lo asigna:
| Responsabilidad | Slice o hito |
|---|---|
| Permisos y mínimo privilegio | S1.01 (base) · M8 (por recurso y por resultado) |
| Consentimiento exigible | S1.08 |
| Selección inequívoca de intervalo de referencia | S1.16 |
| Estabilidad de muestra antes de reutilizarla | S1.13 |
| Estado actual y su historial en una sola operación coherente | S1.03 |
Mantenimiento de version_vigente_id |
S1.14, S1.15 |
| Política de publicación e informe parcial | S1.19 |
| Comunicación crítica y escalamiento | S1.18 |
| Resolución de duplicados de paciente | S1.04 (detección) · M8 (fusión auditada) |
| Vigencia del control de calidad antes de liberar | M3 |
| Cálculo del saldo de inventario y serialización por lote | M6 |
| Conciliación de factura, pagos y cartera | M4 |
| Auditoría de consultas sensibles | M8 |
Calendario de particiones de evento_auditoria |
M0 (documentado) · M8 (automatizado) |
8. Puertas de calidad
Desde M0, el build falla si alguna no pasa:
build: sin warnings nuevos sin justificación
formato: formateador en modo verificación
tests: unitarios + integración con Testcontainers sobre PostgreSQL 18
cobertura: dominio y aplicación ≥ 90 %
arch-test: ArchUnit — dominio sin Spring, sin jOOQ, sin HTTP; sin escritura entre módulos
migraciones: esquema reconstruible desde cero; ninguna migración aplicada se edita
codegen: el código jOOQ generado corresponde a las migraciones vigentes
secretos: escaneo sobre el diff
dependencias: CVEs y licencias
9. Definición de terminado por slice
[ ] Cada criterio del slice verificado por un test que cita su identificador (RN, CU o PO).
[ ] Vi los tests fallar antes de pasar, por la razón correcta.
[ ] Casos de error, borde y concurrencia cubiertos.
[ ] `make verify` en verde, incluidas arch-test y migraciones desde cero.
[ ] Migración nueva si el esquema cambió; ninguna migración previa editada.
[ ] Trazas y métricas en los puntos de decisión. Sin PII, sin identificadores de paciente en logs.
[ ] Revisión adversarial en sesión limpia, con hallazgos concretos.
[ ] ADR escrito si hubo decisión estructural.
[ ] La documentación que describe esta configuración se actualizó en el mismo commit.
[ ] Un slice, un commit. Revisé el diff completo.
10. Ritmo de trabajo
Por slice, con los roles y prompts de MARCO.md parte VII, cada uno en sesión nueva:
- Especificación — criterios de aceptación en Gherkin citando la regla de negocio que operacionalizan. Toda ambigüedad se marca como
ASSUMPTION,OPEN QUESTIONoDECISION REQUIRED; no se resuelve en silencio. - Rojo — tests derivados de esos criterios. Se ejecutan y se ven fallar.
- Verde — implementación mínima.
- Refactor — sin cambiar comportamiento.
- Revisión adversarial — sesión limpia, rol de revisor escéptico, con foco en concurrencia, fallos a mitad de operación, autorización por recurso y consultas sin índice.
- Merge — un commit, marcado en el
PLAN.mddel hito.
Por hito, antes del primer slice: requisitos de la capacidad (docs/02-requirements/), diseño de dominio y datos si hace falta, y el PLAN.md de la rama.
11. Riesgos
| Riesgo | Señal temprana | Mitigación |
|---|---|---|
| Flyway o jOOQ incompatibles con PostgreSQL 18 | T0.1 o T0.4 fallan | Cerrado. Flyway 12.4.0 aplica el DDL completo sobre PostgreSQL 18.4 y jOOQ 3.21.5 genera 94 clases de tabla y vista contra el esquema resultante |
| El DDL de 90 tablas arrastra a modelar todo el dominio de golpe | Slices que tocan diez tablas | La tabla existe, el modelo de dominio no. Cada slice modela únicamente lo que su criterio de aceptación exige |
| Regenerar jOOQ tras cada migración rompe compilaciones en cadena | Builds rojos sin cambios de código | El codegen forma parte del build y falla temprano; no se commitea código generado desincronizado |
| El dominio clínico invita a abstracciones especulativas | Interfaces con una sola implementación que no son puertos | Prohibido por el marco; verificable en revisión |
| El estado y su historial se desincronizan | Historial con huecos | S1.03 centraliza la transición; ningún otro código escribe estado |
| Anemia del dominio por usar jOOQ | Casos de uso que orquestan SQL y nada más | Las invariantes viven en tipos de dominio probados sin base de datos; el adaptador solo persiste |
| La interfaz de usuario llega tarde y obliga a rehacer el borde | Casos de uso con firmas pensadas para JSON | Los casos de uso reciben y devuelven tipos de aplicación, no DTOs HTTP |
12. Bitácora de revisiones del plan
| Fecha | Hito cerrado | Cambio al plan |
|---|---|---|
| 2026-09-25 | — | Autenticación fuera del servicio (ADR-0009). La identidad la emite un proveedor externo y el LIS es un resource server; passkeys, OTT, MFA y login federado son configuración del IdP. Salen spring-security-webauthn y thymeleaf-extras-springsecurity6. Se precisa D-03: Thymeleaf se conserva para rellenar plantillas de mensaje, no para servir páginas. |
| 2026-09-25 | — | Observabilidad de primera clase (ADR-0006, ADR-0007). Las tres señales llegan al backend y las convenciones de instrumentación se fijan antes de que 22 slices las improvisen. |
| 2026-09-25 | S1.01a | M1 empieza por el contexto de ejecución: identificadores tipados y alcance por organización, que es lo que más se encarece con cada commit. Requisitos en docs/02-requirements/CAP-01. |
| 2026-09-24 | — | Versión 1. Decisiones D-01 a D-07 tomadas. |
| 2026-09-24 | — | pom.xml alineado con M0: Flyway, Testcontainers, ArchUnit, JaCoCo, Spotless y perfil jooq-codegen. JPA retirado (D-04). T0.4 y T0.5 resueltos en el pom. |
| 2026-09-24 | — | Entorno de trabajo: Makefile, Dockerfile, .dockerignore, .env.example y docker-compose con pgAdmin y healthcheck. Verificado que Flyway 12.4.0 conecta con PostgreSQL 18.4 y crea el esquema lis. |
| 2026-09-24 | T0.6 | Walking skeleton y ArquitecturaTest. M0 cerrado: 35 tests en verde. La regla de dependencias deja de ser una frase y pasa a romper el build. |
| 2026-09-24 | T0.3 | V3__transiciones_faltantes.sql y el primer test de integración con Testcontainers: 16 casos sobre PostgreSQL 18 real. publicada y entregada siguen terminales por decisión. |
| 2026-09-24 | T0.2 | V2__catalogos_estado.sql separa datos de referencia de datos de demostración. Frontera: V2 lleva solo lo que el esquema necesita y no depende de la institución. Reparto verificado línea a línea contra el archivo original. |
| 2026-09-24 | T0.1 | V1__esquema_base.sql aplicada, reconstruida desde cero y leída por jOOQ. Dos desviaciones respecto al DDL original: sin begin;/commit; y con btree_gist with schema lis. |
| 2026-09-24 | — | application.yaml: defaults de desarrollo en toda variable, URL compuesta con currentSchema=lis, Flyway de runtime apuntado al esquema lis, timeouts explícitos de pool y transacción, namespace lis.* para parámetros institucionales, destino OTLP parametrizado y Actuator reducido a health,info. Arranque verificado contra PostgreSQL 18.4. |