Skip to main content

ADR-003 — JOIN em ProductStockStores para Sizes em vez de snapshot serializado em CartRecommendedItems

Data: 2026-05-14
Status: Superseded by ADR-009
Motivo: A premissa original (retornar List<SizeStockDTO> Sizes no DTO) foi alterada. O Size agora é um campo único armazenado em CartRecommendedItems.Size, selecionado pela vendedora no momento da recomendação. Não há mais JOIN em ProductStockStores no GET.

Contexto: Task #193232 — Retorno de RecommendedItemsInfoDTO com campo Sizes


Contexto

O RecommendedItemsInfoDTO precisa retornar, para cada item recomendado, a lista de tamanhos com estoque disponível na loja (Sizes: [{ size, quantity }]). Duas alternativas foram avaliadas:

  • A: Persistir os tamanhos/estoques como snapshot serializado (coluna jsonb) em CartRecommendedItems no momento da criação da recomendação.
  • B: Buscar tamanhos e estoques em tempo real via JOIN em ProductStockStores no momento do GET, filtrando por StoreId + Sku com Quantity > 0.

Pesquisa completa em pesquisa-sizes-join-vs-snapshot.md.


Decisão

Adotar a Alternativa B: JOIN em ProductStockStores no GetRecommendedItemsAsync, retornando tamanhos com estoque real no momento do GET.


Justificativa

1. Estoque exibido deve ser o mais atual possível

A janela de validade é de 1 hora. Nesse período, vendas podem ocorrer e reduzir o estoque. Exibir um snapshot desatualizado aumenta a probabilidade de o cliente ver um tamanho disponível, clicar em adicionar, e receber erro de "sem estoque" — fricção desnecessária no fluxo de upsell.

2. O snapshot não elimina a validação no POST

Em ambas as alternativas, o POST de adicionar item deve validar estoque real na API de cart. O campo Sizes é exclusivamente informativo/UX. O snapshot adicionaria complexidade na escrita sem remover a necessidade de validação na transação.

3. jsonb quebra o padrão do ORM do projeto

Todas as entidades em Core.OrgDB usam colunas de tipos primitivos. Introduzir jsonb exigiria deserialização manual no Dapper e criaria um precedente inconsistente com o padrão estabelecido.

4. CartRecommendedItems fica com schema simples e primitivo

A tabela mantém apenas: Id, CartId, ProductId, StoreId, Price, FullPrice, Discount, DiscountValue. Consistente com CartItemsModel.


Consequências

  • GetRecommendedItemsAsync inclui JOIN em ProductStockStores filtrando StoreId = CRI.StoreId AND Sku = P.Sku AND Quantity > 0.
  • RecommendedItemsInfoDTO contém List<SizeStockDTO> Sizes populado pela query.
  • CartRecommendedItems não recebe coluna de snapshot.
  • O POST de adicionar item deve validar estoque real independentemente do que foi exibido no GET.
  • Risco de race condition (tamanho some entre GET e POST) é aceito e tratado via erro 400 com mensagem clara ao cliente.

Alternativa rejeitada

Alternativa A — Snapshot serializado em CartRecommendedItems:
Descartada por introduzir jsonb fora do padrão do ORM, aumentar complexidade da escrita, e não eliminar a necessidade de validação de estoque real no POST.