8.2 KiB
Validación y administración de flujos (T06)
T06 entrega servicios internos verificables: FlowAdministration, FlowPreparation, ConfiguredFlowValidator, FlowJsonCodec y PostgresFlowStore. Todavía no hay controladores administrativos ni beans de catálogo predeterminados: T07 conectará la identidad JWT verificada y la autorización antes de exponer REST. No se ofrece un catálogo simulado en producción. Las firmas del servicio reciben Actor confiable, revisión esperada y correlationId; nunca deben mapearse esos atributos desde el body.
Operaciones
| Operación interna | Rol técnico | Efecto atómico |
|---|---|---|
| create | FLOW_EDITOR | Borrador y auditoría CREATE |
| edit | FLOW_EDITOR | Solo DRAFT, revisión esperada, identidad fija y auditoría EDIT |
| validate | FLOW_EDITOR o FLOW_PUBLISHER | Reporte de errores por JSON Pointer |
| publish | FLOW_PUBLISHER | Validar, fijar contratos/perfiles, checksum, PUBLISHED y auditoría |
| activate | FLOW_ADMIN | Flujo PUBLISHED, tipo habilitado/existente, revisión del tipo y auditoría |
| retire | FLOW_ADMIN | PUBLISHED a RETIRED, desactivar referencias activas y auditar |
Los tipos se provisionan por migración/configuración administrativa, como establece el contrato T02. Al retirar, cada tipo que aún apunta a esa versión queda sin flujo activo e incrementa revision; su clave queda en admin_audit.detail.deactivatedTypeKeys. La operación no cambia ninguna instancia existente ni desactiva tipos que ya apuntan a otra versión. Toda escritura se revierte si falla insertar la auditoría.
REVISION_CONFLICT es el código interno de revisión; el futuro adaptador REST lo traducirá al REVISION_MISMATCH contractual (412). INVALID_FLOW, RESOURCE_NOT_FOUND, ACCESS_DENIED y FlowValidationException tienen mensajes seguros. El adaptador debe traducirlos al contrato y no devolver causas SQL. No reutilizar entidades/snapshots como DTO REST. A16 tiene evidencia en servicio y DB; la comprobación HTTP con JWT real se completa al exponer las rutas en T07/T16.
Catálogo confiable y publicación
PublicationCatalog es un snapshot inmutable aportado por configuración confiable: roles de negocio, handlers y sus schemas, integraciones por clave/versiones, versiones de perfiles y políticas documentales (MIME/tamaño). No contiene endpoints, headers ni secretos; no consulta disponibilidad de proveedores durante publicación.
Versiones explícitas deben existir. Versiones omitidas en borrador se resuelven a los defaults del catálogo y se guardan dentro de la definición publicada antes del checksum. Rotar el default no cambia versiones ya guardadas. El despliegue deberá conservar los contratos/perfiles requeridos por versiones en ejecución. Las fixtures de prueba describen contratos de ejemplo; no son adapters ni respuestas de un buró.
Se validan:
- Estructura DSL, schemaVersion, límites, claves duplicadas y schemas embebidos.
- Identificadores únicos, estado inicial, destinos, alcanzabilidad, terminales, estados sin salida y una transición por pareja estado/evento.
- Roles conocidos, handlers/contratos/perfiles resolubles y prohibición de NO_OP.
- Inputs obligatorios/permitidos, referencias a resultados anteriores, tipos de mappings y literales contra su schema. No se permiten referencias adelantadas.
- Cobertura exacta de salidas de decisiones, límites del AST, tipos básicos y solapamientos UNIQUE demostrables mediante intervalos simples. FIRST conserva precedencia explícita; el evaluador conserva controles de runtime.
- Updates relativos a data, destinos existentes y no solapados. Las rutas escritas desde results se consideran datos de proveedor: no pueden ser aceptadas en initialDataSchema/eventos ni escritas luego desde un origen no confiable.
- Tareas ligadas a transición/evento y equivalencia canónica de inputSchema. DOCUMENT_UPLOAD requiere documentId UUID obligatorio, mapping desde el evento, REGISTER_DOCUMENT del mismo tipo y límites dentro de la política confiable.
Publicación exige dataSchema de objeto e inputs iniciales/de eventos con type=object expreso y additionalProperties=false. Si initialDataSchema falta se utiliza dataSchema; si este permite recibir campos de proveedor, la publicación se rechaza hasta añadir un schema inicial restrictivo. Los ejemplos estructurales de T02 no se convierten silenciosamente en flujos publicables ni sustituyen los recorridos completos T14.
La compatibilidad estática comprueba tipos y literales, no implica demostrar inclusión arbitraria entre JSON Schemas ni resolver SAT. T08 debe validar datos iniciales contra ambos schemas, T11 salidas normalizadas y T10 datos candidatos antes del commit. La existencia de mappings válidos no autoriza a omitir esas validaciones en runtime.
JSON y checksum
El decoder rechaza claves duplicadas, tokens adicionales, JSON de más de 1 MiB, nesting JSON mayor a 64 y números fuera del presupuesto. El límite de AST de T05 se aplica adicionalmente. Se rechazan NUL y surrogates aislados que no pueden conservarse de forma segura en UTF-8/JSONB. Se usan los schemas originales empaquetados en el JAR, sin duplicarlos ni aceptar referencias externas suministradas por un flujo.
El formato canónico de la aplicación ordena claves de objetos, conserva orden de arrays y normaliza decimales con BigDecimal sin ceros finales. Conjuntos del modelo (roles/MIME) se ordenan. Defaults de reintento quedan explícitos al guardar el modelo. SHA-256 se calcula sobre UTF-8 de esa representación. No se afirma conformidad JCS (RFC 8785), cuyo modelo numérico es diferente. Cambiar esta canonicalización en el futuro requiere versionar/migrar con cuidado, no recalcular versiones publicadas.
Transacciones y orden de bloqueos
PostgresFlowStore usa JDBC y TransactionTemplate con READ COMMITTED. El puerto y FlowAdministration siguen siendo Java puro. El motivo de esta decisión frente al JPA propuesto para agregados está registrado en ADR-010; no se introduce otro stack.
- Edición/publicación bloquean flow_definition y verifican revision/estado.
- Activación bloquea primero el flujo destino y después request_type; vuelve a verificar revisión/habilitación antes de escribir.
- Retiro bloquea el flujo y los tipos referenciados en orden de clave. El UPDATE solo borra referencias que todavía apuntan a la versión retirada.
- Para asignar una nueva instancia, assignableFlow lee el candidato sin bloqueo, bloquea el flujo, bloquea el tipo y vuelve a verificar la referencia, enabled y PUBLISHED. Un cambio concurrente produce conflicto, nunca una asignación ciega.
T08 deberá invocar assignableFlow e insertar solicitud, idempotencia y auditoría dentro de la misma transacción y DataSource. No obtener el FlowVersion, cerrar la transacción y usarlo después para crear la solicitud. La sesión rechaza uso después de su cierre. Si la creación gana el bloqueo, su instancia queda fijada y el retiro posterior la respeta; si gana el retiro, no se permite la nueva asignación.
No hay caché de activo. La resolución consulta PostgreSQL. No se modificaron V1/V2: los triggers y permisos existentes continúan protegiendo versiones e historial. Los administradores de DB conservan sus facultades; el servicio debe usar el rol limitado documentado en db/migration/README.md.
Ejecutar verificaciones
Con JDK 21, ./mvnw test comprueba contratos, modelo, decisiones y validación T06.
./mvnw clean verify añade las dos suites PostgreSQL con Testcontainers. Sin Docker,
usar migration-tests-external y las variables MIGRATION_TEST_DB_* descritas en RUNBOOK.
FlowPublicationIT solo opera sobre orquestador_test en un esquema t06_ propio, que elimina al finalizar. Incluye fallos reales de auditoría mediante un trigger exclusivo del esquema de pruebas, barreras de concurrencia y ambos órdenes de la carrera asignación/retiro. No ejecuta migraciones sobre orquestador ni despliega el JAR.
networknt 1.5.9 pasa de dependencia de test a runtime para validar publicación. Jackson 2 queda confinado en ese adaptador; los records de dominio no dependen de él. La configuración HTTP de Spring Boot continúa usando sus componentes existentes. La prueba de arquitectura recompila también la administración de aplicación con solo java.base, sin JDBC, Spring, serializadores ni API.