BE-08 Inventario y reservas
BE-08 — Inventario y reservas
Sección titulada «BE-08 — Inventario y reservas»- Depende de: BE-01, US-07, DS-03.
- Módulo:
inventory(hexagonal). - Estado: DONE (2026-09-26).
Objetivo
Sección titulada «Objetivo»Gestionar existencias y reservas de stock con liberación en fallo o cancelación.
Alcance
Sección titulada «Alcance»- Puerto
StockReservationPort:reserveStock(bloqueo pesimistaFOR UPDATE, ítems ordenados porproductId),releaseReservationyconfirmReservation. - Expiración perezosa: al reservar se liberan filas
PENDINGconexpiresAtvencido (TTLqhatu.checkout.reservation-ttl). - Compensación síncrona si la pasarela o el persist del pago fallan.
CreatePaymentIntentUseCasecancela la ordenPENDING. - BE-06 (DONE) confirma o libera en la misma transacción del webhook.
confirmReservationsolo actualiza reservasPENDING(reentrada = no-op). - Puerto
UpdateInventoryPorty operationIdupdateInventory(PUT /api/v1/admin/inventory/{productId}), solo rol ADMIN. Lo exige el matcher/api/v1/admin/**enSecurityConfig. La norma de largo plazo (GEMINI) sustituye ese prefijo por un matcher de método y ruta; no se usa@PreAuthorize.
Fuera del DoD (otro dueño)
Sección titulada «Fuera del DoD (otro dueño)»- Consumo de
orders.OrderCancelledsi el cliente cancela enPENDING: BE-07. No volver a confirmar stock al emitirOrderPaid. - Job de expiración en abandono largo: la liberación perezosa cubre el checkout; no bloquea DONE.
- Agregado
StockItemrico: no es criterio de aceptación de este nodo.
Criterios de aceptación
Sección titulada «Criterios de aceptación»- Reservar sin stock suficiente falla sin efectos parciales (transacción única; checkout cancela la orden PENDING).
updateInventorysolo para ADMIN.
Evidencia para DONE
Sección titulada «Evidencia para DONE»- test: backend/src/test/kotlin/com/qhatu/ecommerce/checkout/CreatePaymentIntentUseCaseTest.kt
- test: backend/src/test/kotlin/com/qhatu/ecommerce/SchemaIntegrationTest.kt
- test: backend/src/test/kotlin/com/qhatu/ecommerce/inventory/InventoryConcurrencyIntegrationTest.kt
- test: backend/src/test/kotlin/com/qhatu/ecommerce/inventory/AdminInventoryControllerTest.kt
- test: backend/src/test/kotlin/com/qhatu/ecommerce/inventory/InventoryDomainTest.kt
- file: backend/src/main/kotlin/com/qhatu/ecommerce/inventory/infrastructure/ExposedStockReservationAdapter.kt
- file: backend/src/main/kotlin/com/qhatu/ecommerce/inventory/application/UpdateInventoryPort.kt
- file: backend/src/main/kotlin/com/qhatu/ecommerce/inventory/infrastructure/AdminInventoryController.kt
- file: backend/src/main/kotlin/com/qhatu/ecommerce/shared/SecurityConfig.kt
- Contrato:
PUT /admin/inventory/{productId}operationIdupdateInventoryencontract/openapi.yaml(200, 401, 403, 404, 422).
Auditoría 2026-09-26: CA-1 en Testcontainers (10 hilos, 5 unidades, 5 éxitos y 5 fallos por stock, available=0, reserved=5). CA-2: ADMIN 200, CUSTOMER 403, anónimo 401, por el matcher HTTP de SecurityConfig.