Capa de interoperabilidad · Prueba técnica de arquitectura

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.

  1. inventory-service consume andes.catalog.products.v1 con el grupo inventory-service y guarda en su base y en Redis product:{sku} con status y channels.
  2. Al responder GET /v1/stock para un canal, un SKU va a notFound si no hay producto, si el producto está INACTIVE o si el canal no está en channels. Es la misma regla que aplica pricing-service.
  3. 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.
  4. Mientras no llega el producto, el SKU sale en notFound: se falla cerrado, como pricing-service sin precio.
  5. 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

Qué se sacrifica