Skip to main content

Design research — coezzion-service-showcase

Data: 2026-07-09
US: 197021
Repo: /Users/alt-zz/projetos/arezzo/coezzion-service-showcase
Base spike: research-showcase-api.md

Pesquisa file-level para implementação do PR1. Nenhum código alterado nesta fase.


1. Resumo executivo

ÁreaGap principalAção design
Store create/updateSetDateExpiration(null) → +31dNormalizar null → MaxValue
Recommend commandsDateTime non-nullableDateTime?
Recommend validatorsNotEmpty obrigatórioOpcional + cap quando informado
DTOs Store/RecommendSem mapeamento MaxValue→nullMapper central (Brand já faz)
Unicidade RecommendQuery DateExpiration >= nowMaxValue já satisfaz — sem mudança de query
BrandPadrão MaxValueReferência; não alterar handlers neste PR

2. Domain

ArquivoLinha / trechoAS-ISTO-BE
src/ShowCase.Domain/Index/ElasticBaseIndex.csSetDates()+30 diasSem mudança no método — Brand temp (L167) ainda usa; Recommend deixa de chamar (D-API-11)
src/ShowCase.Domain/Index/ElasticBaseIndex.csIsExpired()DateExpiration < nowMaxValue nunca expira — OK
src/ShowCase.Domain/Entities/ShowCaseModel.csSetDateExpirationnull → +31dDelegar ao normalizer: null → MaxValue
Novo ShowCase.Domain/Common/ShowCaseExpirationNormalizer.csNormalizeForPersistence, ToApiExpiration

Precedente Brand (ShowCaseBrandCommandHandler.cs L291):

showCaseBrand.DateExpiration = command.DateExpiration == null
? DateTime.MaxValue
: command.DateExpiration;

3. Commands Store

ArquivoTipoDateExpiration hoje
CreateShowCaseByAppCommand.csJá nullableDateTime? — OK
UpdateShowCaseByAppCommand.csVerificarProvável DateTime?
ShowCaseCommandHandler.cs L50, L92HandlerChama SetDateExpiration(command.DateExpiration)

Mudança: handler ou SetDateExpiration usa ShowCaseExpirationNormalizer.NormalizeForPersistence.


4. Commands Recommend

ArquivoTipo hojeTO-BE
CreateShowCaseRecommendCommand.cs L12DateTimeDateTime?
UpdateShowCaseRecommendCommand.cs L9DateTimeDateTime?

Handler ShowCaseRecommendCommandHandler.cs:

MétodoLinhasComportamento AS-ISTO-BE
CreateL112–113SetDates() depois DateExpiration = command.DateExpirationDateCreated = Now.ToBrazillianTime() + DateExpiration = Normalize(...)sem SetDates() (D-API-11)
UpdateL180Atribuição diretaDateExpiration = Normalize(command.DateExpiration)

Verificação SetDates() (2026-07-09): apenas 2 call sites no repo — Recommend create e Brand temp CSV upload. No Recommend, DateExpiration do SetDates() é sempre sobrescrito; efeito residual = DateCreated. Store já usa DateCreated explícito (L46) sem SetDates(). Brand temp (fora do CA) ainda precisa do método até refatoração futura.


5. Validators

ArquivoRegra AS-ISTO-BE
CreateShowCaseRecommendValidator.cs L28–29NotEmpty + GreaterThan(now)Remover NotEmpty; When(HasValue) + futura + LessThanOrEqualTo(now+N)
UpdateShowCaseRecommendValidator.cs L10IdemIdem
CreateShowCaseValidator.cs (Store)Sem validação de dataAdicionar regras condicionais quando DateExpiration.HasValue

Testes a atualizar:

  • ShowCase.UnitTest/Application/Validators/CreateShowCaseRecommendValidatorTests.cs — casos DateExpirationEmpty_Executed_Fail → passar com null
  • ShowCase.UnitTest/Application/Validators/UpdateShowCaseRecommendValidatorTests.cs — idem
  • ShowCase.UnitTest/Application/Commands/ShowCaseRecommendCommandHandlerTests.cs
  • ShowCase.UnitTest/Application/Commands/UpdateShowCaseRecommendCommandHandlerTests.cs
  • ShowCase.UnitTest/Application/Querys/ShowCaseRecommend/ShowCaseRecommendQueryHandlerTests.cs — DTO com MaxValue→null

6. Queries e DTOs (sem mapeamento MaxValue hoje)

Store — ShowCaseQueryHandler.cs

MétodoLinhaDTOCampo
FindAllShowCaseFullTextQueryL68ShowcaseSummaryDTODateExpiration direto
FindByIdShowCaseQueryL99ShowcaseResponseDTOdireto
FindByIdShowCaseForAppL128ShowcaseStockResponseDTOdireto

Recommend — ShowCaseRecommendQueryHandler.cs

MétodoLinhaDTO
ListL126ShowCaseRecommendListDTO
DetailL149ShowCaseRecommendResponseDTO
Detail appL175ShowCaseRecommendFullResponseDTO

DTOs já nullable: ShowcaseSummaryDTO, ShowCaseRecommendListDTO — OK para receber null na API.

Ação: aplicar ShowCaseExpirationNormalizer.ToApiExpiration em todos os pontos acima (padrão Brand query handler).


7. Filtros Elasticsearch (sem mudança esperada)

QueryArquivoFiltro
Store ativoShowCaseQueryHandler.ConfigureQueryActiveOnly L238DateExpiration >= now/d
Recommend ativo (list)ShowCaseRecommendQueryHandlerdate range similar
UnicidadeShowCaseRecommendRepository.FindActiveByUserCustomerCpfAndStoreAsync L28–30GreaterThanOrEquals(DateMath.Now)

DateTime.MaxValue satisfaz >= now — vitrine sem expiração permanece ativa e bloqueia duplicata (RF-09).


8. Constantes mágicas (unificar no design)

LocalValor hoje
ElasticBaseIndex.SetDates+30
ShowCaseModel.SetDateExpiration fallback+31
zzapp UI+31
SP texto+30

Decisão design: ShowCaseExpirationRules.MaxDaysFromNow = 31 até alinhamento PO (D3).


9. Arquivos fora do escopo deste PR

  • ShowCaseBrandCommandHandler.cs — não alterar lógica (RF-05)
  • ShowCaseBrandQueryHandler.cs — referência apenas
  • Jobs / product listeners — regressão manual (RF-05)
  • Migrations SQL — não aplicável (ES)

10. Checklist de verificação pós-implementação

  • Documento ES never-expire contém dateExpiration = MaxValue
  • Response JSON nunca devolve ano 9999
  • Create Store com null não grava +31
  • Create Recommend com null grava MaxValue
  • Segunda Recommend mesmo CPF bloqueada se primeira é never-expire
  • Unit tests verdes