Pesquisa — coezzion-service-showcase (API de vitrine)
Repo: /Users/alt-zz/projetos/arezzo/coezzion-service-showcase
Data: 2026-07-09
Escopo: expiração + CRUD de ShowCase
1. Visão geral
- Persistência de vitrines: Elasticsearch (Nest), não SQL migrations para
DateExpiration. - Índices:
arezzo-showcase,arezzo-showcase-brand,arezzo-showcase-brand-seller,arezzo-showcase-recommend. - Tipos:
ShowCaseType=Brand | Store | Recommendation | BrandSeller. - Sem
CONTEXT.md/ ADRs no repo. Doc útil:docs/features/feat_vitrine_recomendacao.md.
2. Modelo base de datas
Arquivo: src/ShowCase.Domain/Index/ElasticBaseIndex.cs
| Campo | Tipo | Papel |
|---|---|---|
Id | Guid | Id do documento |
DateCreated | DateTime | Criação |
DateDeleted | DateTime? | Soft-delete |
DateExpiration | DateTime? | Expiração |
public void SetDates(DateTime? date = null)
{
DateCreated = date is null ? DateTime.Now.ToBrazillianTime() : date.Value;
DateExpiration = DateCreated.AddDays(30);
}
public bool IsExpired() => DateExpiration < DateTime.Now.ToBrazillianTime();
// GetActiveObject(s): !IsDeleted && !IsExpired
Nota: comparação nullable em C# — se DateExpiration for null, IsExpired() retorna false (não expira). Porém listagens ES usam date range no campo (docs sem campo tendem a não casar).
3. Store (Minhas vitrines)
Entity
src/ShowCase.Domain/Entities/ShowCaseModel.cs:
public void SetDateExpiration(DateTime? date) =>
DateExpiration = date ?? DateCreated.AddDays(31).ToBrazillianTime();
Inconsistência: base usa +30; Store null usa +31.
Commands
| Op | HTTP | Command |
|---|---|---|
| Create | POST api/show-case-new/ | CreateShowCaseByAppCommand (DateTime? DateExpiration) |
| Update | PUT api/show-case-new/ | UpdateShowCaseByAppCommand |
| Delete | PUT api/show-case-new/delete | DeleteShowCaseCommand (soft-delete) |
| Get | GET api/show-case-new/{id} | active-only |
| Get app | GET api/show-case-new/app/{id} | app |
| List | GET api/show-case-new/store/{storeId} | ConfigureQueryActiveOnly |
Handler: ShowCaseCommandHandler — create/update chamam showcase.SetDateExpiration(command.DateExpiration).
Validação: CreateShowCaseValidator efetivamente não valida expiração (sem FluentValidation de data na Store).
Listagem ativa
ShowCaseQueryHandler.ConfigureQueryActiveOnly:
- MustNot
DateDeletedexists DateExpiration >= now/d
4. Recommendation (histórico de compras)
| Op | HTTP |
|---|---|
| Create | POST api/show-case-new/recommend |
| Update | PUT api/show-case-new/recommend/{id} |
| Delete | DELETE api/show-case-new/recommend/{id} |
| List | GET .../recommend/{storeId}/{page}/{size} |
Commands: DateExpiration como DateTime não-nullable.
Validators (CreateShowCaseRecommendValidator / Update):
RuleFor(x => x.DateExpiration)
.NotEmpty().WithMessage("Data de expiração não informada!")
.GreaterThan(DateTime.Now).WithMessage("Data de expiração deve ser futura!");
Sem teto máximo no backend.
Handler create: SetDates() depois sobrescreve com command.DateExpiration.
Unicidade ativa: FindActiveByUserCustomerCpfAndStoreAsync — user + cpf + store, com DateExpiration >= now e sem delete.
5. Brand (fora do CA, precedente crítico)
Update header:
showCaseBrand.DateExpiration = command.DateExpiration == null
? DateTime.MaxValue
: command.DateExpiration; // Elastic não aceita null em campo de data
Queries: DateExpiration == DateTime.MaxValue ? null : DateExpiration no DTO.
Status: ativo se StartDate <= now && DateExpiration >= now.
Job (via jobs service): PUT .../brand/update-status recalcula Status.
Temp create: SetDates() → +30 dias.
6. BrandSeller
Na criação, copia DateExpiration do parent Brand (snapshot).
7. Get by id / repositório
ElasticBaseRepository.GetByIdShowCase → GetActiveObject() (null se deleted ou expired).
Variante GetByIdShowCaseNoValidateActive para admin/delete.
8. Impacto da Spike neste repo
| Área | Mudança necessária? |
|---|---|
SetDateExpiration null → +31 | Sim — conflita com “null = sem prazo” |
| Validators Recommend | Sim — tornar opcional |
Commands Recommend DateTime → DateTime? | Sim |
| Map MaxValue → null nos DTOs Store/Recommend | Sim (Brand já faz) |
| Filtros ES com MaxValue | Ok sem mudança de query |
IsExpired com MaxValue | Ok (MaxValue < now é false) |
| Job product listeners | Não (estoque/preço) |
Arquivos-chave
ShowCase.Domain/Index/ElasticBaseIndex.csShowCase.Domain/Entities/ShowCaseModel.csShowCase.Api/.../ShowCaseCommand/*ShowCase.Api/.../ShowCaseRecommendCommand/*ShowCase.Api/Application/Validators/CreateShowCaseRecommendValidator.csShowCase.Api/Application/Validators/UpdateShowCaseRecommendValidator.csShowCase.Api/.../ShowCaseQuery/ShowCaseQueryHandler.csShowCase.Api/.../ShowCaseBrandCommand/ShowCaseBrandCommandHandler.cs(referência MaxValue)- Unit tests em
ShowCase.UnitTest/Application/Validators/*Recommend*
9. Constantes mágicas
| Local | Valor |
|---|---|
SetDates | +30 dias |
SetDateExpiration | +31 dias se null |
| Brand null | DateTime.MaxValue |
| “Nova” marca (count) | janela ~3 dias (não é expiração) |