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) emCartRecommendedItemsno momento da criação da recomendação. - B: Buscar tamanhos e estoques em tempo real via JOIN em
ProductStockStoresno momento do GET, filtrando porStoreId+SkucomQuantity > 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
GetRecommendedItemsAsyncinclui JOIN emProductStockStoresfiltrandoStoreId = CRI.StoreId AND Sku = P.Sku AND Quantity > 0.RecommendedItemsInfoDTOcontémList<SizeStockDTO> Sizespopulado pela query.CartRecommendedItemsnã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.