orquestador/specs/REQUESTS.md

89 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Creación y consulta de solicitudes — T08
Implementados `POST /api/v1/requests` y `GET /api/v1/requests/{id}` según el contrato
OpenAPI. No se implementan todavía eventos, worker, historial ni tareas del front.
## Habilitación
`REQUEST_API_ENABLED=true` habilita ambas rutas y exige un runtime PostgreSQL
restringido con credenciales de migración separadas (ver SECURITY.md). Es
independiente de `FLOW_ADMIN_ENABLED`: se puede atender solicitudes sin exponer
administración ni cargar un catálogo de publicación local. Ambos interruptores
son false por defecto para conservar el despliegue previo con pgadmin hasta que
se configure la cuenta de ejecución correcta. No se modificaron cuentas remotas.
El JWT debe contener sub, audiencia, firma y ámbito válidos. Cualquier actor así
autenticado puede crear una solicitud de un tipo habilitado; propietario y ámbito
se obtienen del token. Los roles de transición serán exigidos al aceptar eventos
en T09. No se introduce un rol creador nuevo ni una ACL de tipos inexistente.
## Contrato
POST recibe exclusivamente `typeKey` y `data`, con `Idempotency-Key` obligatorio
(1–200 caracteres ASCII visibles, sin espacios; una sola cabecera). Retorna 201,
Location y ETag fuerte. UUID, estado inicial, flujo, propietario, ámbito y revisión
son asignados por el servidor. Los datos deben satisfacer initialDataSchema y
dataSchema de la versión publicada; si falta initialDataSchema se usa dataSchema.
No se aplican defaults ni conversiones implícitas. Los schemas cerrados rechazados
en publicación protegen campos provenientes de proveedores.
Límite de datos: 256 KiB de JSON canónico UTF-8; cuerpo: 256 KiB + 4096 bytes,
leído de forma acotada también sin Content-Length. Profundidad JSON máxima 64.
Se rechazan claves duplicadas, JSON adicional, Unicode incompatible con JSONB,
campos adicionales de comando y números fuera de los límites del codec T06.
Tamaño excesivo retorna 413; sintaxis/comando inválido 400; datos fuera del schema
422. Tipo inexistente: 404. Sin flujo publicado activo, deshabilitado o cambiado
concurrentemente durante la asignación: 409 INVALID_FLOW_STATE. Un comando fallido
no reserva su clave y puede reintentarse tras corregir la causa.
GET retorna versión fijada, estado, datos, revisión, fechas y activeExecutionId
si existe ejecución PENDING/RUNNING/RETRY_WAIT/RECONCILIATION_REQUIRED. La lectura
SQL obtiene instancia/flujo/ejecución activa en un solo snapshot. Exige propietario
y ámbito, incluso para FLOW_ADMIN; inexistente y ajeno retornan 404. El DTO omite
owner/scope y los campos opcionales ausentes. La creación no copia la versión de
flujo a request_instance: la consulta la obtiene de flow_id.
## Idempotencia y transacción
Identidad de la clave: actor + ámbito + Idempotency-Key. Hash SHA-256 del comando
canónico typeKey/data usando el codec T06: orden de propiedades y escala decimal
equivalente no cambian el hash. Otra identidad tiene un espacio de claves distinto.
El repositorio usa READ COMMITTED y la misma DataSource para RequestStore y
FlowStore. Antes de consultar idempotencia toma pg_advisory_xact_lock con 64 bits
de SHA-256 sobre schema/actor/ámbito/clave encuadrados por longitud. Una colisión
solo serializa claves distintas; la búsqueda y restricción única SQL siguen usando
la identidad completa. No hay locks de proceso ni caché de respuestas en memoria.
Si existe registro y coincide el hash, se verifica acceso actual a la solicitud y
se devuelve el snapshot original de creación (201, Location y ETag originales),
aunque el flujo se haya retirado, el tipo esté deshabilitado o la solicitud haya
avanzado. GET obtiene el estado actual. Un hash distinto retorna 409
IDEMPOTENCY_CONFLICT antes de resolver de nuevo el flujo activo.
Sin registro previo, la puerta T06 bloquea flujo y tipo en ese orden; luego valida
datos, inserta solicitud con revisión 0, REQUEST_CREATED e idempotencia con respuesta
original. Todo confirma o revierte junto. La auditoría incluye correlationId y
referencias, sin duplicar datos personales. No se invocan servicios externos.
Un cambio de activo detectado al tomar los bloqueos produce conflicto reintentable;
no se asigna silenciosamente el flujo leído antes de la carrera. Un retiro espera
una creación que ya tiene sus locks; una vez confirmado impide nuevas asignaciones.
## Verificación
`mvnw.cmd clean verify -Pmigration-tests-external`, con MIGRATION_TEST_DB_* solo en
entorno, ejecuta la suite contra orquestador_test. RequestCreationIT reutiliza el
fixture aislado T07 (schema t07_UUID, LOGIN temporal y JWT RSA/JWKS local) con
administración apagada y API de solicitudes encendida. No se prueba una emisión
real de Keycloak ni se despliega el servicio en server02:8787.
Casos: contrato RequestView/Problem, replay y conflicto, versiones fijadas, retiro,
separación de claves por actor/ámbito, acceso ajeno, validación/tamaño, concurrencia
misma clave y comandos distintos, activación y retiro con barreras, ejecución activa,
y rollback SQL real en auditoría/registro idempotente. RequestJsonTest verifica
parseo estricto, canonicalización decimal y límites UTF-8.
Desde T09 se implementa también POST de eventos (EVENTS.md). La referencia anterior
al carácter pendiente de eventos describe el alcance de T08; worker, tareas e
historial siguen pendientes. REQUEST_API_ENABLED habilita ambos módulos.