Ir al contenido
DocuGraph

ecommerce-angular-spring

BE-08 Inventario y reservas

  • Depende de: BE-01, US-07, DS-03.
  • Módulo: inventory (hexagonal).
  • Estado: DONE (2026-09-26).

Gestionar existencias y reservas de stock con liberación en fallo o cancelación.

  • Puerto StockReservationPort: reserveStock (bloqueo pesimista FOR UPDATE, ítems ordenados por productId), releaseReservation y confirmReservation.
  • Expiración perezosa: al reservar se liberan filas PENDING con expiresAt vencido (TTL qhatu.checkout.reservation-ttl).
  • Compensación síncrona si la pasarela o el persist del pago fallan. CreatePaymentIntentUseCase cancela la orden PENDING.
  • BE-06 (DONE) confirma o libera en la misma transacción del webhook. confirmReservation solo actualiza reservas PENDING (reentrada = no-op).
  • Puerto UpdateInventoryPort y operationId updateInventory (PUT /api/v1/admin/inventory/{productId}), solo rol ADMIN. Lo exige el matcher /api/v1/admin/** en SecurityConfig. La norma de largo plazo (GEMINI) sustituye ese prefijo por un matcher de método y ruta; no se usa @PreAuthorize.
  • Consumo de orders.OrderCancelled si el cliente cancela en PENDING: BE-07. No volver a confirmar stock al emitir OrderPaid.
  • Job de expiración en abandono largo: la liberación perezosa cubre el checkout; no bloquea DONE.
  • Agregado StockItem rico: no es criterio de aceptación de este nodo.
  • Reservar sin stock suficiente falla sin efectos parciales (transacción única; checkout cancela la orden PENDING).
  • updateInventory solo para ADMIN.
  • 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} operationId updateInventory en contract/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.