Skip to main content

AS-IS — CRUD de Vitrines

Data: 2026-07-09
Spike: 198299
Glossário: CONTEXT.md
Pesquisas: research-showcase-api.md · research-zzapp.md · research-portal.md · research-showcase-web.md · research-jobs.md


1. Mapa de tipos e atores

Tipo domínioEnum APIQuem criaQuem editaUI principalÍndice ES
Vitrine de lojaStoreVendedorVendedorzzapp — Minhas vitrinesarezzo-showcase
Vitrine por históricoRecommendationVendedorVendedorzzapp — Histórico de comprasarezzo-showcase-recommend
Vitrine da marcaBrandOps/merchanOpszzportal — Vitrinesarezzo-showcase-brand
Vitrine marca–vendedorBrandSellerVendedor (share)zzapp — share da marcaarezzo-showcase-brand-seller

Campo de prazo: DateExpiration em todos (herdado de ElasticBaseIndex).
Exclusão: soft-delete via DateDeleted (ortogonal à expiração).


2. Diagrama de contexto

┌─────────────────────┐
│ coezzion-portal │ cria/edita Brand
│ (zzportal) │
└──────────┬──────────┘
│ HTTP
┌──────────────┐ ┌──────────▼──────────┐ ┌────────────────────┐
│ zzapp │───►│ service-showcase │◄───│ service-jobs │
│ Minhas │ │ Elasticsearch │ │ brand status/temp │
│ Histórico │ │ Store/Rec/Brand/* │ │ product sync SQS │
│ Marca (read) │ └──────────┬──────────┘ └────────────────────┘
└──────────────┘ │
│ GET public
┌──────────▼──────────┐
│ showcase-web │ cliente final
│ (sem UX de expira) │
└─────────────────────┘

3. CRUD — Vitrine de loja (Store / Minhas)

3.1 Create

CamadaComportamento
UI zzappDefault expirationDate = now/start + 31d; picker min amanhã, max now+31
RequestPOST api/show-case-newdateExpiration opcional (DateTime?)
HandlerSetDateExpiration(date) → se null, DateCreated + 31d
Validação APISem regra FluentValidation de data
Resultado{ id, url }

3.2 Read

Lista appGET .../store/{storeId} — só ativas (sem delete, DateExpiration >= now/d)
Detalhe appGET .../app/{id}
PúblicoGET .../{id}GetActiveObject (null se expirada/deletada)
showcase-webEmpty “Vitrine não encontrada” se null

3.3 Update

UINome, produtos, data (campo só se detail já tem data)
RequestPUT api/show-case-new — app envia dateExpiration sempre (tipo non-null no Dart update)
HandlerReconstrói modelo + SetDateExpiration

3.4 Delete

RequestPUT api/show-case-new/delete
EfeitoDateDeleted = now (soft). Documento permanece no ES

3.5 Expiração Store (AS-IS)

  • Não há job de bulk-expire.
  • Após DateExpiration, some de lista/get ativo e do link público.
  • Default/máximo prático: ~31 dias (UI + fallback server).

4. CRUD — Vitrine por histórico (Recommendation)

4.1 Create

CamadaComportamento
UICustomer → produtos → check; data obrigatória na UI; default +31; max +31
RequestPOST .../recommenddateExpiration required no command
ValidatorNotEmpty + GreaterThan(now) — sem max
HandlerSetDates() depois sobrescreve com command; checa unicidade ativa user+cpf+store
NomeDerivado do cliente (não free-text como Minhas)

4.2 Read / Update / Delete

OpEndpoint
ListGET .../recommend/{storeId}/{page}/{size} (ativas)
Detail appGET .../recommend/app/{id}
PublicGET .../recommend/{id}
UpdatePUT .../recommend/{id} — products + dateExpiration (required validator)
DeleteDELETE .../recommend/{id} soft-delete

4.3 Lista UI

Já suporta nullExpirationLabel: 'Sem data de expiração' (defensivo); create/edit ainda forçam data.


5. CRUD — Vitrine da marca (Brand) — referência

OpComportamento resumido
CreateCSV SKUs → temp + SetDates (+30)
Update headerdateExpiration opcional → null vira MaxValue; Status por janela Start/Expiration
List adminFiltros de status; portal formata data ou vazio
Job diárioUpdateStatusShowCasesBrand recalcula Status
App vendedorSomente leitura + share → BrandSeller

Precedente de “sem data de expiração”: UI portal + MaxValue no ES + null no DTO.


6. CRUD — BrandSeller

  • Create no share: copia DateExpiration da marca.
  • Sem fluxo de edição de prazo pelo vendedor.
  • Fora do CA da Spike.

7. Lifecycle unificado

[Create] ──DateExpiration set──► [Ativa]

┌───────────────┼────────────────┐
▼ ▼ ▼
[Expirada] [Soft-deleted] [Sem prazo*]
(read filter) (DateDeleted) *só Brand hoje (MaxValue)
│ │
└────── docs permanecem no ES ──┘

* Store/Recommend não têm caminho de produto “sem prazo” no AS-IS (Store null vira +31; Recommend exige data).


8. Regras de “vitrine ativa”

TipoCritério principal
Store / RecommendDateDeleted == null e !IsExpired() / ES DateExpiration >= now
Brand (app)Status == true e DateExpiration >= now (+ StartDate na lógica de status)
Brand (job)StartDate.Date <= today && DateExpiration?.Date >= today → Status true

9. Defaults e validação (comparativo)

StoreRecommendBrand
Default+31 (server se null; UI +31)UI +31; server sobrescreve com bodyTemp +30; header null → MaxValue
RequiredNão (mas null vira +31)Sim (API + UI)Não
FuturaNão enforced APISimSe preenchida, UI portal valida
Max diasUI +31UI create +31; edit sem max; API sem maxSem max no portal
Sem expiraçãoNão suportado de ponta a pontaNão (apesar de label na lista)Sim (MaxValue)

10. Jobs e efeitos colaterais

JobEfeito em vitrine
UpdateStatusShowCasesBrandSó Brand.Status
RemoveShowCasesBrandTempSó temps Brand
ShowCaseProduct*Atualiza produtos no índice (estoque/preço/disponibilidade) para todas as vitrines que referenciam produtos — não altera DateExpiration

11. O que a SP pede vs AS-IS (gap)

CAAS-ISGap
CA-1 Data opcionalRecommend obriga; Store null vira +31Tornar opcional de verdade
CA-2 Default + remoçãoDefault existe; remoção não vira “sem prazo”Null semântico + UI clearable
CA-3 Edit add/change/removeChange sim; remove “sem prazo” nãoClear + persist MaxValue
CA-4 Label “Sem data…”Recommend/Brand list ok; Minhas nãoMinhas list/detail + API null
CA-5 Outras regrasJobs product / share / estoque independentesNão regredir

12. Inconsistências relevantes

  1. 30 vs 31 dias (SP/SetDates vs SetDateExpiration/app).
  2. Brand: “sem data” = MaxValue; Store: null = +31.
  3. Cap de dias só no app (e incompleto no recommend edit).
  4. Expectativa de “job marca expiração de vendedor” não existe no código.