Resultado inicial — Spike 198299
Título SP: zzapp — Avaliar a possibilidade de a data de expiração ser opcional nas vitrines
Workitem: 51-198299-spike-vitrine-sem-expirar
Data: 2026-07-09
Tipo de entrega: Plano de implementação (sem alteração de código de produto)
Índice de contexto
| Doc | Conteúdo |
|---|---|
context/sp.md | SP e critérios de aceite |
context/CONTEXT.md | Glossário de domínio |
context/AS-IS.md | CRUD AS-IS completo |
context/grill-decisions.md | Decisões D1–D8 |
context/impacto-repos.md | Matriz de impacto detalhada |
context/research-showcase-api.md | API showcase |
context/research-zzapp.md | App vendedor |
context/research-portal.md | Portal marca (referência) |
context/research-showcase-web.md | Front público |
context/research-jobs.md | Jobs |
1. Resposta da Spike: é possível?
Sim — viável com baixo risco estrutural.
Motivos:
- O serviço de vitrines já implementa “sem data de expiração” para vitrine da marca (
DateTime.MaxValueno Elasticsearch; UI portal com placeholder “Sem data de expiração”). - Vitrines de vendedor (Store e Recommendation) usam o mesmo campo
DateExpiratione os mesmos filtros de “ativa”. - Não há job que force expiração de Store/Recommend; mudar o valor de
DateExpirationbasta para o comportamento de listagem e link público. - O zzapp já tem suporte parcial de UI (
nullExpirationLabelem listas de recommend/marca).
Principal cuidado: hoje null na Store significa “aplicar default +31”, não “sem prazo”. A US precisa inverter essa semântica (null → never) e colocar o default na UI, alinhado ao CA-2.
2. Interpretação dos critérios de aceite (TO-BE)
| CA | Interpretação operacional |
|---|---|
| CA-1 | Campo data de expiração não obrigatório em create/edit de Minhas e Histórico (não marca). |
| CA-2 | Ao criar, UI preenche prazo padrão atual (~+31 no código / “+30” na SP). Usuário pode limpar. Limpar não reaplica default no backend. Se preencher data, respeitar teto (~30/31 dias). |
| CA-3 | Em edit: adicionar, alterar ou remover data (remover = sem expiração). |
| CA-4 | Listagem e detalhe: se sem data → texto "Sem data de expiração" no lugar da data. |
| CA-5 | Estoque, preço, disponibilidade (jobs de produto), compartilhamento de links e demais regras inalterados. |
Escopo de menu (SP): Minhas vitrines + Vitrine por histórico. Fora: Vitrine da marca (zzportal).
3. AS-IS em uma página
- 4 tipos de vitrine no ES; SP mexe em 2 (Store, Recommendation).
- Persistência: Elasticsearch; soft-delete
DateDeleted; expiração por data no documento. - Store: create aceita
DateTime?mas null → +31d. - Recommend: data obrigatória (FluentValidation + UI).
- Brand: null → MaxValue (precedente).
- Jobs: status só de marca; product sync não expira vitrine.
- showcase-web: sem conceito de expiração; sumiu do API = “não encontrada”.
Detalhe: context/AS-IS.md.
4. Decisões de desenho (resumo)
| # | Decisão |
|---|---|
| D1 | “Sem expiração” = DateTime.MaxValue no ES; null na API/UI |
| D2 | Escopo Store + Recommend |
| D3 | Manter +31 numérico AS-IS; alinhar texto “+30” com PO |
| D4 | Default na UI; clear → never (sem re-default no server) |
| D5 | Reativar expiradas: fora do MVP |
| D6 | Unicidade Recommend inclui never-expire como ativa |
| D7 | Portal / web / jobs sem mudança de CA |
| D8 | Plano de US inclui cap no backend se data informada |
Detalhe: context/grill-decisions.md.
5. Serviços, módulos e repos impactados
| Repo | Precisa alterar? | Módulos |
|---|---|---|
| coezzion-service-showcase | Sim | Domain (ElasticBaseIndex / ShowCaseModel), Commands Store + Recommend, Validators Recommend, mapeamento DTO MaxValue→null, unit tests |
| coezzion_vendas_app | Sim | lib/screens/show_case/** (minhas + recommend), models create/update/list, date field clearable |
| coezzion-portal | Não | Referência UX apenas |
| coezzion-showcase-web | Não | — |
| coezzion-service-jobs | Não | Product jobs permanecem (CA-5) |
Arquivos e PRs: context/impacto-repos.md.
6. Plano de implementação (US futura)
Fase 0 — Produto (curto)
- Confirmar com PO: 30 vs 31 dias (default e máximo).
- Confirmar copy exata: "Sem data de expiração" (já usada no app/portal).
- Confirmar D1 MaxValue (recomendado; padrão marca).
Fase 1 — API (coezzion-service-showcase) — PR1
- Definir helper de normalização (idealmente compartilhado com Brand):
null→DateTime.MaxValue(sem expiração)- data → validar futura + opcional max N dias
- Store: alterar
SetDateExpiration/ create-update para não converter null em +31. - Recommend:
DateTime?nos commands; validators opcionais; handler grava MaxValue se null. - Em todos DTOs Store/Recommend de leitura:
MaxValue→null. - Testes unitários: null=never; data válida; data passada falha; max falha; unicidade com MaxValue.
- Garantir que filtros ES existentes continuam incluindo MaxValue como ativo.
Contrato a publicar para o app:
Request dateExpiration:
- <iso-date> = expira nessa data
- null / omitido com semântica never = sem expiração (preferir null explícito)
Response dateExpiration:
- null = sem data de expiração
- <iso-date> = data
Default +N não deve ser responsabilidade silenciosa do server se null = never. UI envia a data default quando o usuário não limpa.
Fase 2 — zzapp (coezzion_vendas_app) — PR2
- Minhas: picker clearable; default +N; create/update enviam null se limpo.
- Models: update e list item com
dateExpirationnullable. - List/detail: label CA-4.
- Histórico: remover bloqueio obrigatório; clearable; max no edit; default create.
- Testes de serialização null.
- Smoke manual create/edit/share.
Fase 3 — Não-código de outros repos
- Portal / web / jobs: sem PR, só checklist de não-regressão.
Fase 4 — QA
Ver seção 8.
Ordem
Fase 0 (PO) → PR1 API → PR2 App (ou paralelo com contrato fixo) → QA
7. Riscos e mitigações
| Risco | Mitigação |
|---|---|
| Null no ES some da listagem | Nunca persistir null; usar MaxValue |
| Server ainda aplica +31 em null | Remover essa coerção; testes de regressão |
| MaxValue aparece como ano 9999 na UI | Mapear sempre MaxValue→null nos DTOs |
| 30 vs 31 gera bug de “máximo” | Constante única documentada; alinhar PO |
| Recommend “prende” cliente para sempre | Documentar unicidade; vendedor pode editar/excluir |
| Mudança quebra Brand | Não alterar paths Brand; helper compartilhado com cuidado |
| App antigo envia null esperando +31 | Coordenar deploy API+app; se necessário feature flag ou aceitar mudança de contrato (avaliar clientes da API) |
Clientes da API Store create: principal é zzapp. Validar se há outros consumers (BFF, scripts) antes do merge.
8. Critérios de verificação (pós-implementação)
Funcional
- Criar Minhas sem limpar data → tem
dateExpiration~+N; some da lista após N dias (ou data forçada em QA). - Criar Minhas limpando data → lista/detalhe “Sem data de expiração”; GET público ok após N dias.
- Editar: alterar data; remover data; recolocar data.
- Mesmos cenários em Histórico.
- Segunda Recommend ativa mesmo CPF bloqueada se a primeira é never-expire.
- Vitrine da marca no portal inalterada.
- Link público de never-expire abre produtos; estoque/preço coerentes após job de produto (CA-5).
- Share/copy de link continua funcionando.
Técnico
- Unit tests API verdes.
- Documento ES de never-expire contém
dateExpiration= MaxValue (inspecionar em QA). - Response JSON nunca devolve data “9999…” para o app.
9. Fora de escopo (explícito)
- Alterar regras de vitrine da marca / portal.
- UX de expiração no showcase-web (“expirou em…”).
- Job de notificação “vai expirar”.
- Listar/reativar vitrines já expiradas no app.
- Migração em massa de vitrines existentes para never-expire.
- Hard-delete de documentos expirados no ES.
10. Estimativa relativa (ordem de grandeza)
| Fatia | Esforço relativo |
|---|---|
| API Store + Recommend + tests | M |
| zzapp Minhas + Recommend UI | M |
| QA manual / alinhamento PO | S |
| Jobs / portal / web | — |
Não é refactor amplo: reaproveita padrão Brand e widgets existentes.
11. Conclusão
| Pergunta | Resposta |
|---|---|
| É possível? | Sim |
| Onde mudar? | showcase API + zzapp (Store + Recommend) |
| Padrão técnico? | MaxValue + null na borda (como marca) |
| Jobs? | Não para expiração de vendedor; product jobs só não regredir |
| Próximo passo? | Abrir US(s) de implementação com este plano; fechar 30 vs 31 com PO |
12. Histórico da Spike
| Quando | O quê |
|---|---|
| 2026-07-09 | Pesquisa multi-repo; AS-IS; decisões D1–D8; este relatório |