Planificación

PLAN — M0 · Cimientos

Plan del hito en curso. Se marca conforme avanza. El mapa completo de hitos vive en docs/PLAN_MAESTRO.md; las reglas de cómo se escribe código, en docs/00-agents.md.

Objetivo del hito: el repositorio construye, migra, genera código jOOQ, pasa sus puertas de calidad y sirve un endpoint contra la base real.

Tareas

  • T0.4 · Generación jOOQ — perfil manual -Pjooq-codegen, fuentes versionadas en com.sineltek.lis.jooq. Ver ADR-0002.
  • T0.5 · Dependencias y puertas — JPA fuera (ADR-0004); Flyway, Testcontainers, ArchUnit, JaCoCo y Spotless dentro. Falta el primer test de integración que las ejerza.
  • Entorno de trabajo — Makefile, Dockerfile, .dockerignore, .env.example, docker-compose con pgAdmin y healthcheck, application.yaml con defaults de desarrollo, y .tool-versions versionado.
  • T0.1 · Migración base — el DDL como V1__esquema_base.sql, con dos desviaciones documentadas en su cabecera: sin begin;/commit; (Flyway ya abre transacción) y con btree_gist fijado al esquema lis. Ver ADR-0003.
  • T0.2 · Catálogos frente a demostración — V2__catalogos_estado.sql lleva los nueve roles, los cuatro catálogos de estado y las dos matrices de transición: lo que el esquema necesita para funcionar y no depende de la institución. El resto del archivo de ejemplo es src/test/resources/db/demo/datos_demostracion.sql, que Flyway no ve y se carga con make demo. Lo institucional —tipos de muestra, unidades, secciones, pruebas, tarifas— es configuración clínica y le corresponde a M2.
  • T0.3 · Transiciones faltantes — V3__transiciones_faltantes.sql añade 8 transiciones (2 de orden, 6 de prueba), todas con motivo obligatorio. MatrizTransicionesTest las verifica sobre un PostgreSQL real migrado desde cero: 16 casos, incluidos el rechazo sin motivo, el rechazo de lo que no figura en la matriz y que publicada y entregada siguen siendo terminales.
  • T0.6 · Walking skeleton — GET /api/v1/sedes atraviesa api → aplicación → dominio → adaptador jOOQ → PostgreSQL. El módulo compartido estrena las cuatro capas, y ArquitecturaTest convierte la regla de dependencias en cinco reglas de ArchUnit que rompen el build. Verificado introduciendo una violación a propósito.

Hecho en este hito

  • ADR-0001 a ADR-0009 escritos.
  • Flyway 12.4.0 conecta con PostgreSQL 18.4 y crea el esquema lis (verificado).
  • V1 aplicada y reconstruida desde cero con make db-reset: 90 tablas, 6 vistas, 12 funciones, 18 triggers, 9 restricciones de exclusión, 259 índices y 2 particiones.
  • make jooq-codegen genera las clases del esquema y make verify pasa en verde. Las 212 funciones de soporte de btree_gist quedan fuera del código generado.
  • V2 cargada: 9 roles, 8+8+8+6 estados, 11 transiciones de orden y 10 de prueba. Verificado contra los triggers: una transición válida entra, registrada → completada se rechaza por no estar en la matriz, y registrada → en_toma sin motivo se rechaza por exigirlo.
  • make demo carga la jornada completa de demostración sobre la base local.
  • Primer test de integración con Testcontainers: 16 casos sobre PostgreSQL 18 real, sin un solo mock, porque las reglas que verifica viven en triggers. Matriz final: 13 transiciones de orden y 16 de prueba.
  • La aplicación arranca y responde /actuator/health con las sondas liveness y readiness.
  • Actuator expone dos endpoints: health e info.
  • Las tres señales llegan al backend. Los logs necesitaban un appender de Logback que el starter no trae: sin él la tubería OTLP estaba configurada y vacía (ADR-0006). Verificado en Grafana → Loki con el mismo traceId que la traza de la petición; el procedimiento y su resultado están en wiki/TELEMETRIA.md.
  • La observabilidad deja de ser un endpoint de salud. El SLO de 00-agents.md pasa a ser medible (histograma y cubetas sobre http.server.requests), el muestreo deja de ser un literal de desarrollo, los límites de atributos acotan lo que puede escaparse y las métricas de pool y de contenedor quedan publicadas. Las convenciones de instrumentación —nombres, cardinalidad, nada de PII en ninguna de las tres señales, el dominio no loguea— están en ADR-0007, para que los 22 slices de M1 las hereden en lugar de improvisar una cada uno.

M0 cerrado

Las seis tareas están hechas. El repositorio construye, migra desde cero, genera su código jOOQ, pasa cinco reglas de arquitectura y sirve un endpoint real contra PostgreSQL 18. make verify: 40 tests en verde.

La API se puede ejercer a mano: make dev-full levanta todo con el perfil dev y make curls corre los .http de wiki/http con sus aserciones.

Deudas declaradas

Salieron de revisar la salida real de make curls. Ninguna bloquea M1; las dos tienen dueño.

La tercera —traza OTel sin observar— está pagada: las trazas y los logs se miraron en Grafana el 2026-09-25 y ExportacionLogsOtelTest impide que el cableado de logs se caiga en silencio, que era la forma en que este fallo se esconde.

Deuda Qué falta Dónde se paga
Sin contrato de errores propio El 404 devuelve el cuerpo por defecto de Spring (timestamp, status, error, path) y el 401 no trae cuerpo. Faltan los errores tipados del dominio y su traducción a HTTP en api/ S1.01
Sin identificador de correlación Ninguna respuesta lleva traceparent ni X-Trace-Id, así que no hay forma de saltar de una petición fallida a su traza S1.01

Las dos restantes son la arquitectura de errores que el marco pide decidir antes de implementar: la semántica se fija una vez y los veinte endpoints siguientes la heredan. Si se deja para después, lo que se hereda es el formato por defecto de Spring.

Siguiente acción

Empieza M1. El primer slice es S1.01: contexto de ejecución —identificadores tipados, errores de dominio, reloj, organización, sede y actor—, que es también lo que le falta a SedeRepositorio para filtrar por organización y donde caen las dos deudas que siguen abiertas.

Sus requisitos están en docs/02-requirements/CAP-01-contexto-de-ejecucion.md, y su primera mitad ya está construida: identificadores tipados, actor resuelto desde la credencial, alcance por organización en la lectura de sedes y reloj inyectable. 57 tests en verde y make curls en verde contra la aplicación real. Se empezó por ahí porque es el trabajo cuyo coste crece más rápido con cada commit: el alcance por organización atraviesa las cuatro capas de los trece módulos, y su omisión no se nota —devuelve datos, no un error—.

Queda de S1.01 la parte «sede», bloqueada por DR-02: ni cuenta_usuario ni cuenta_rol llevan sede, así que «un empleado accede a los de su sede» no es hoy expresable con este esquema.

Lo siguiente, en orden:

  1. Hecho: ADR-0009 · identidad externa. La autenticación sale del servicio: passkeys, OTT, MFA y login federado son configuración del proveedor de identidad, y el LIS valida tokens. SecurityConfig sigue siendo Basic con usuario dev como andamiaje hasta M8.
  2. Hecho: ADR-0008 · arquitectura de errores. Catálogo de los 22 rechazos del esquema con su regla y su familia, y la decisión: un SQLSTATE propio de clase LS por regla, errores de dominio tipados, y RFC 9457 en el borde. Lo que sigue es implementarlo: la migración que reasigna los 22 códigos con su regeneración de jOOQ, la tabla de traducción en el adaptador, el @RestControllerAdvice y el test que impide que un rechazo nazca con SQLSTATE estándar.
  3. El PLAN.md propio de M1 con los 22 slices, que es transcripción de PLAN_MAESTRO.md §5. Este archivo sigue siendo el de M0 y ya debería relevarse.
  4. RLS como red del aislamiento, en su ADR: coste plano, pero exige antes un rol de aplicación sin privilegios de dueño, porque hoy la app conecta como postgres y una política sería inerte.
  5. Retirar TestController y WebPaths, y reescribir con ellos la receta de comprobación de wiki/TELEMETRIA.md, que depende de /api/v1/public/test.