Planificación

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:

  1. Especificación — criterios de aceptación en Gherkin citando la regla de negocio que operacionalizan. Toda ambigüedad se marca como ASSUMPTION, OPEN QUESTION o DECISION REQUIRED; no se resuelve en silencio.
  2. Rojo — tests derivados de esos criterios. Se ejecutan y se ven fallar.
  3. Verde — implementación mínima.
  4. Refactor — sin cambiar comportamiento.
  5. 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.
  6. Merge — un commit, marcado en el PLAN.md del 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.