ADR-019: inventory-service filtra el stock por el surtido del canal
Aceptado el 11/11/2026 por Andrés. Complementado por ADR-023 (llaves de Redis por servicio).
Contexto
El contrato de GET /v1/stock dice que notFound lista los SKU "inexistentes o no habilitados para el canal" (contracts/openapi/interop-api.v1.yaml). docs/to-be/05-modelo-de-lectura.md guarda product:{sku} con el estado del producto y los canales habilitados. Pero en el contrato de eventos solo pricing-service y order-service consumen andes.catalog.products.v1; inventory-service no sabe qué SKU vende cada canal.
El resultado medido en F3: GET /v1/prices responde notFound para los 129 SKU fuera del surtido de mkp-andino, y GET /v1/stock sí devuelve stock de esos mismos SKU. Las dos APIs se contradicen, y un marketplace ve disponibilidad de productos que no puede vender.
La práctica de las plataformas de comercio es la misma en todas: el surtido del canal decide qué productos existen para ese canal, y la disponibilidad se responde solo dentro de ese surtido. En commercetools, las Product Selections asignadas a una Store definen qué vende ese canal, y el inventario se consulta por canal de abastecimiento dentro de ese surtido.
Opciones
| Opción | A favor | En contra |
|---|---|---|
A. inventory-service consume andes.catalog.products.v1 y filtra al leer |
Las dos APIs dan la misma respuesta; cumple el contrato que ya existe; sin llamadas síncronas | Un consumidor y una tabla más en inventory |
| B. inventory pregunta a pricing o a catalog por REST | Sin consumidor nuevo | Viola la regla 2: los servicios de dominio no se llaman por REST |
| C. El gateway cruza las dos respuestas | Sin cambios en los servicios | Viola la regla 3: el gateway no tiene lógica |
| D. Cada canal filtra con su propio catálogo | Sin trabajo en la capa | Cada partner repite la regla; el contrato de notFound queda incumplido |
Decisión
Opción A.
- inventory-service consume
andes.catalog.products.v1con el grupoinventory-servicey guarda en su base y en Redisproduct:{sku}constatusychannels. - Al responder
GET /v1/stockpara un canal, un SKU va anotFoundsi no hay producto, si el producto estáINACTIVEo si el canal no está enchannels. Es la misma regla que aplica pricing-service. - Si el stock de un SKU llega antes que su producto, el stock se guarda igual. El filtro se aplica al leer, no al escribir, así el orden de llegada entre tópicos no importa.
- Mientras no llega el producto, el SKU sale en
notFound: se falla cerrado, como pricing-service sin precio. - Es un tópico de estado: aplica la regla de consumidor de estado de
docs/to-be/06-eventos.md(salta el mensaje inválido con métrica y alerta, pausa si falla su almacén, sin reintentos ni DLQ).
La reserva por gRPC no cambia: order-service ya rechaza con 422 UNKNOWN_SKU el SKU que no tiene precio en su vista para el canal (ADR-015).
Verificación
- Prueba de inventory: un SKU fuera de
channelsdel canal sale ennotFound; al habilitarlo en el ERP aparece enitemssin reiniciar nada. - Prueba de punta a punta: para cada partner, el conjunto de SKU en
notFoundde/v1/stockes igual al de/v1/prices.
Qué se sacrifica
- Un consumidor, una tabla y una llave de Redis más en inventory-service.
- Una lectura más por SKU (el producto) al responder; va en el mismo
MGETdel lote. - Un producto que se habilita en el ERP tarda en aparecer en stock lo mismo que tarda en aparecer en precio (frescura del catálogo).