89 lines
5.3 KiB
Markdown
89 lines
5.3 KiB
Markdown
# 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.
|