orquestador/specs/DOMAIN_MODEL.md

6.1 KiB
Raw Blame History

Modelo de dominio y puertos (T04)

El dominio utiliza Java 21 y no depende de Spring, serializadores, HTTP, JDBC ni JPA. Sus records son snapshots inmutables, no entidades administradas ni cuerpos REST. Las escrituras y los bloqueos pertenecen a servicios de aplicación futuros.

Paquete Modelos y responsabilidades
shared/domain Identidades UUID distintas por recurso, Actor confiable, JSON inmutable, ErrorCode y DomainException
flow/domain DSL FlowDefinition, estados/eventos, transiciones, rutas fijas o por decisión, tareas, schemas, FlowVersion y ValidationReport
decision/domain AST cerrado de condiciones/valores, reglas ordenadas, política explícita UNIQUE/FIRST, contexto y resultado
action/domain Configuración por capacidad, reintentos acotados, contexto, resultado y metadatos de catálogo confiable
request/domain RequestInstance fijada a FlowId y RequestType con activación opcional
execution/domain Estado técnico, ejecución aceptada, lease/fencing y checkpoint de acción
*/application/port DecisionEvaluator, ActionHandler y FlowDefinitionValidator
flow/api ValidationReportResponse y conversión explícita desde dominio al contrato REST

Invariantes y representación

  • Los estados y eventos de negocio son claves configurables, no enums Java por proceso. Los enums representan únicamente conceptos técnicos cerrados.
  • FlowDefinition representa el DSL; FlowVersion agrega identidad, estado de publicación, revisión, checksum y fechas. RequestInstance conserva solo FlowId, sin duplicar la versión. RETIRED es ejecutable para instancias existentes y no asignable a nuevas solicitudes.
  • List.copyOf y Map.copyOf/Set.copyOf impiden cambios por alias. Los hijos JSON también son inmutables: objetos, listas, strings, BigDecimal, boolean y null explícito. Lookup.Missing no es un valor JSON; no se confunde con NullValue.
  • Los números se construyen con BigDecimal, sin coerción implícita desde strings. La comparación numérica, resolución de pointers y límites de evaluación son T05.
  • Condiciones, acciones y rutas son variantes selladas. EXISTS recibe un path; NOT un operando; AND/OR conservan orden y requieren al menos dos argumentos. Una transición tiene ruta fija o decisión/destinos, nunca ambas.
  • Los paths de lectura se restringen a request.data, event.data, results y actor. Updates.target es relativo a request.data; /id significa data.id y no request.id. La detección de destinos solapados y la validación de datos corresponden a T06.
  • Actor solo se construirá desde identidad verificada. No incluye JWT ni secretos y no se toma del evento. EvaluationContext no expone servicios externos.
  • Optional representa campos ausentes del modelo interno; los adapters deben omitirlos o traducirlos según el contrato, no serializar el dominio directamente. Versiones de contrato/perfil y schemas pueden faltar en borradores; T06 debe resolverlos y fijarlos al publicar. SchemaVersion desconocida se diagnostica en validación, no se interpreta como otra versión del proceso.
  • ActionCapability procede del catálogo confiable. Su clasificación de efectos y schemas no forman parte de ActionDefinition editable. NO_OP solo es para simulación; T06 debe impedir publicarlo y T11 controlar su ejecución.
  • ActionResult.Completed admite resultados negativos normalizados del negocio. TechnicalFailure expresa fallo técnico TRANSIENT, PERMANENT o UNKNOWN_EFFECT. La elegibilidad de reintento también requiere revisar efectos y checkpoints; el record no autoriza por sí solo un reintento.
  • ExecutionStatus.RECONCILIATION_REQUIRED sigue activo; SUCCEEDED/FAILED liberan la exclusión. RUNNING exige lease y otros estados no lo admiten. SUCCEEDED exige resultado, aunque el resultado conserve el estado anterior del negocio.
  • Los hashes usan 64 caracteres hexadecimales en minúsculas, como SQL y API. Los contadores no son negativos y los checkpoints exitosos exigen resultado y fecha final. El worker debe verificar tokens y tiempos de PostgreSQL en T10.

Errores y adaptadores

ErrorCode mantiene códigos de máquina independientes de HTTP. DomainException expone solo el código, sin incorporar entradas ni respuestas crudas del proveedor. Los adaptadores API resolverán status, correlationId y mensajes permitidos. DecisionResult.Failure solo acepta EVALUATION_ERROR o AMBIGUOUS_DECISION; un fallo nunca se representa mediante la ruta default.

ValidationReport contiene incidencias con JSON Pointer, código y severidad. ValidationReportResponse convierte solo errores al arreglo errors del contrato; las advertencias internas no invalidan el flujo ni agregan campos no publicados. El DTO se comprueba contra api.schema.json. No hay endpoint nuevo en T04.

No hay anotaciones JPA ni entidades persistentes disfrazadas de records de dominio. Los futuros adapters de persistencia deberán mapear explícitamente sus entidades hacia estos snapshots; tampoco deben devolver entidades por REST.

Alcance verificado

DomainModelTest cubre inmutabilidad, AST, pointers, ausencia/null, clasificación de resultados, versiones, leases/checkpoints, reintentos y errores. DomainBoundaryTest comprueba el DTO contra el esquema real. DomainArchitectureTest recompila todos los archivos domain y application/port con classpath vacío y solo java.base; además prohíbe referencias java.net/java.sql. Así detecta dependencias accidentales de infraestructura, API, Spring/JPA o clientes HTTP.

No hay implementaciones ficticias de los puertos ni llamadas a proveedores. T05 implementará el evaluador; T06 el validador/publicación; T11 los handlers. Los constructors garantizan integridad local del objeto; no sustituyen validación del DSL, autorización, transacciones, canonicalización ni A01–A20.

Evaluación implementada en T05

PureDecisionEvaluator implementa el puerto de decisiones. ConditionEvaluator, JsonPointerResolver, AstLimits y IntervalOverlapAnalyzer son componentes puros. Ver semántica y límites. T06/T11 conservan la implementación del validador y handlers; no se añadió ninguna llamada HTTP ni persistencia.