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
| Área | Gap principal | Ação design |
|---|---|---|
| Store create/update | SetDateExpiration(null) → +31d | Normalizar null → MaxValue |
| Recommend commands | DateTime non-nullable | DateTime? |
| Recommend validators | NotEmpty obrigatório | Opcional + cap quando informado |
| DTOs Store/Recommend | Sem mapeamento MaxValue→null | Mapper central (Brand já faz) |
| Unicidade Recommend | Query DateExpiration >= now | MaxValue já satisfaz — sem mudança de query |
| Brand | Padrão MaxValue | Referência; não alterar handlers neste PR |
2. Domain
| Arquivo | Linha / trecho | AS-IS | TO-BE |
|---|---|---|---|
src/ShowCase.Domain/Index/ElasticBaseIndex.cs | SetDates() | +30 dias | Sem mudança no método — Brand temp (L167) ainda usa; Recommend deixa de chamar (D-API-11) |
src/ShowCase.Domain/Index/ElasticBaseIndex.cs | IsExpired() | DateExpiration < now | MaxValue nunca expira — OK |
src/ShowCase.Domain/Entities/ShowCaseModel.cs | SetDateExpiration | null → +31d | Delegar ao normalizer: null → MaxValue |
Novo ShowCase.Domain/Common/ShowCaseExpirationNormalizer.cs | — | — | NormalizeForPersistence, ToApiExpiration |
Precedente Brand (ShowCaseBrandCommandHandler.cs L291):
showCaseBrand.DateExpiration = command.DateExpiration == null
? DateTime.MaxValue
: command.DateExpiration;
3. Commands Store
| Arquivo | Tipo | DateExpiration hoje |
|---|---|---|
CreateShowCaseByAppCommand.cs | Já nullable | DateTime? — OK |
UpdateShowCaseByAppCommand.cs | Verificar | Provável DateTime? |
ShowCaseCommandHandler.cs L50, L92 | Handler | Chama SetDateExpiration(command.DateExpiration) |
Mudança: handler ou SetDateExpiration usa ShowCaseExpirationNormalizer.NormalizeForPersistence.
4. Commands Recommend
| Arquivo | Tipo hoje | TO-BE |
|---|---|---|
CreateShowCaseRecommendCommand.cs L12 | DateTime | DateTime? |
UpdateShowCaseRecommendCommand.cs L9 | DateTime | DateTime? |
Handler ShowCaseRecommendCommandHandler.cs:
| Método | Linhas | Comportamento AS-IS | TO-BE |
|---|---|---|---|
| Create | L112–113 | SetDates() depois DateExpiration = command.DateExpiration | DateCreated = Now.ToBrazillianTime() + DateExpiration = Normalize(...) — sem SetDates() (D-API-11) |
| Update | L180 | Atribuição direta | DateExpiration = 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
| Arquivo | Regra AS-IS | TO-BE |
|---|---|---|
CreateShowCaseRecommendValidator.cs L28–29 | NotEmpty + GreaterThan(now) | Remover NotEmpty; When(HasValue) + futura + LessThanOrEqualTo(now+N) |
UpdateShowCaseRecommendValidator.cs L10 | Idem | Idem |
CreateShowCaseValidator.cs (Store) | Sem validação de data | Adicionar regras condicionais quando DateExpiration.HasValue |
Testes a atualizar:
ShowCase.UnitTest/Application/Validators/CreateShowCaseRecommendValidatorTests.cs— casosDateExpirationEmpty_Executed_Fail→ passar com nullShowCase.UnitTest/Application/Validators/UpdateShowCaseRecommendValidatorTests.cs— idemShowCase.UnitTest/Application/Commands/ShowCaseRecommendCommandHandlerTests.csShowCase.UnitTest/Application/Commands/UpdateShowCaseRecommendCommandHandlerTests.csShowCase.UnitTest/Application/Querys/ShowCaseRecommend/ShowCaseRecommendQueryHandlerTests.cs— DTO com MaxValue→null
6. Queries e DTOs (sem mapeamento MaxValue hoje)
Store — ShowCaseQueryHandler.cs
| Método | Linha | DTO | Campo |
|---|---|---|---|
FindAllShowCaseFullTextQuery | L68 | ShowcaseSummaryDTO | DateExpiration direto |
FindByIdShowCaseQuery | L99 | ShowcaseResponseDTO | direto |
FindByIdShowCaseForApp | L128 | ShowcaseStockResponseDTO | direto |
Recommend — ShowCaseRecommendQueryHandler.cs
| Método | Linha | DTO |
|---|---|---|
| List | L126 | ShowCaseRecommendListDTO |
| Detail | L149 | ShowCaseRecommendResponseDTO |
| Detail app | L175 | ShowCaseRecommendFullResponseDTO |
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)
| Query | Arquivo | Filtro |
|---|---|---|
| Store ativo | ShowCaseQueryHandler.ConfigureQueryActiveOnly L238 | DateExpiration >= now/d |
| Recommend ativo (list) | ShowCaseRecommendQueryHandler | date range similar |
| Unicidade | ShowCaseRecommendRepository.FindActiveByUserCustomerCpfAndStoreAsync L28–30 | GreaterThanOrEquals(DateMath.Now) |
DateTime.MaxValue satisfaz >= now — vitrine sem expiração permanece ativa e bloqueia duplicata (RF-09).
8. Constantes mágicas (unificar no design)
| Local | Valor 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