Code Review — US 196053 (zzapp — Criação de vitrines com estoque completo da loja)
Branch: feat/196053_vitrine_estoque_loja
Base: origin/develop (merge-base cf3c1caa)
Data: 2026-07-07
Escopo: 27 arquivos, +1363 / −138 linhas
Summary
A branch entrega o fluxo de Vitrine de Estoque da Loja (SellerStock) para a US 196053: bottom sheet de escolha de modalidade (CA-1), listagem v2 com hasSellerStock (CA-2), criação automática via POST sem seleção de produtos, tela de detalhe adaptada (nome fixo, produtos somente leitura, data de expiração editável), eventos Rewards 71–73 (CA-6), migração de ShowCaseType para enum string da API e suíte de testes unitários/widget para modelos, ApiUtils e ShowCaseDetailLayout.
Contra os critérios de aceite CA-1 a CA-6, o fluxo vendedor no app está majoritariamente correto: bottom sheet, bloqueio com mensagem quando já existe vitrine SellerStock, criação sem etapa de produtos e rewards integrados. Os principais riscos são bugs de navegação/back (PopScope sem handler de gesto do sistema, rota inconsistente após exclusão), impossibilidade de salvar alteração de data de expiração em SellerStock (CA-3), retry que pode criar vitrine duplicada (CA-2), e lacunas de cobertura em controllers/telas. CA-4 e a URL distinta para analytics (CA-5) dependem de web/back-end; no app, falta evento Firebase na criação SellerStock.
Veredito: Solicitar alterações antes do merge — 6 bugs identificados (navegação, persistência de expiração, retry duplicado). Nenhum bloqueio de contrato de API nos modelos testados; testes novos são sólidos nos arquivos cobertos.
Validação dos Critérios de Aceite
| Critério | Status | Evidência / Observação |
|---|---|---|
| CA-1 — Bottom sheet de modalidade | Atendido | ShowCaseTypeSelectionBottomSheet em my_show_case_controller.dart:89 com opções "Vitrine do estoque da loja" e "Criar nova vitrine". |
| CA-2 — Uma vitrine ativa por vendedor | Parcial | hasSellerStock da API v2 bloqueia opção com mensagem (show_case_type_selection_bottom_sheet.dart:60-65). Risco de duplicata no retry (Issue 3) e flag desatualizada pós-criação (Issue 10). |
| CA-3 — Regras SellerStock | Parcial | Criação sem produtos (createAndLoad), nome fixo, produtos não editáveis (hideProductActions). Data editável no header mas botão "ATUALIZAR VITRINE" oculto para SellerStock (Issue 1). |
| CA-4 — Experiência da cliente | Fora do escopo (app) | Abas "Recomendados"/"Mais produtos" são web; não avaliado neste diff. |
| CA-5 — Identificação/analytics | Parcial | showCaseType no request/response; rewards OK. URL vem da API. Sem FirebaseService.logCreateCatalog na criação SellerStock (Issue 9). |
| CA-6 — Rewards | Atendido | CreateSellerStockShowcaseRewardEvent, CopiedSellerStockShowcaseLinkRewardEvent, SharedSellerStockShowcaseLinkRewardEvent (IDs 71–73) em show_case_detail_controller.dart. |
Cobertura de Código vs develop
Comparação gerada com flutter test --coverage em ambas as branches (mesmo ambiente local).
Suite de testes
| Métrica | develop | feat/196053_vitrine_estoque_loja | Delta |
|---|---|---|---|
| Testes executados | 449 | 479 | +30 |
| Arquivos de teste novos | — | 7 | ver lista abaixo |
Novos arquivos de teste (+1181 linhas):
test/models/show_case/create_show_case_request_test.dart(61 linhas)test/models/show_case/show_case_detail_response_test.dart(124 linhas)test/models/show_case/show_case_list_v2_response_test.dart(113 linhas)test/models/show_case/show_case_type_test.dart(59 linhas)test/models/show_case/update_show_case_request_test.dart(66 linhas)test/screens/show_case/widgets/show_case_detail_layout_test.dart(130 linhas)test/shared/utils/api_utils_test.dart(628 linhas)
Cobertura global (lcov)
| Branch | Linhas cobertas | Linhas rastreadas | % |
|---|---|---|---|
develop | 3.105 | 45.991 | 6,75% |
feat/196053_vitrine_estoque_loja | 3.289 | 46.232 | 7,11% |
| Delta | +184 | +241 | +0,36 pp |
Cobertura nos arquivos alterados (lib/)
| Arquivo | develop | feat | Delta |
|---|---|---|---|
create_show_case_request.dart | 0,0% (0/14) | 100% (15/15) | +100 pp |
show_case_detail_response.dart | 0,0% (0/77) | 43,8% (35/80) | +43,8 pp |
show_case_list_v2_response.dart | — (novo) | 54,2% (13/24) | novo |
update_show_case_request.dart | 0,0% (0/16) | 100% (17/17) | +100 pp |
show_case_type.dart | — (novo) | 100% (12/12) | novo |
show_case_detail_layout.dart | 1,7% (1/58) | 89,1% (57/64) | +87,3 pp |
api_utils.dart | 98,6% (210/213) | 98,6% (210/213) | ~0 pp |
show_case_type_selection_bottom_sheet.dart | — (novo) | 0,0% (0/43) | novo |
show_case_detail_controller.dart | 0,0% (0/148) | 0,0% (0/231) | ~0 pp |
show_case_detail_screen.dart | 0,0% (0/90) | 0,0% (0/104) | ~0 pp |
my_show_case_controller.dart | 0,0% (0/35) | 0,0% (0/53) | ~0 pp |
show_case_search_products_controller.dart | 0,0% (0/304) | 0,0% (0/305) | ~0 pp |
reward_events_ids_enum.dart | 0,0% (0/64) | 0,0% (0/67) | ~0 pp |
tag.dart | 5,0% (1/20) | 3,3% (1/30) | −1,7 pp |
Análise de cobertura
Pontos fortes: modelos de request/response, enum ShowCaseType, ApiUtils (URLs v2) e ShowCaseDetailLayout com cobertura excelente (43–100%). A suíte ganhou 30 testes e +1181 linhas de teste focadas na feature.
Lacunas:
- Controllers e telas de detalhe/listagem permanecem sem cobertura (~0%) — fluxos CA-1/CA-2/CA-3 não são exercitados end-to-end.
show_case_type_selection_bottom_sheet.darte eventos Rewards SellerStock sem testes.- Cobertura global sobe pouco (+0,36 pp) porque a base do app é grande; o ganho real está nos modelos e layout extraídos.
Issues
Issue 1 — Severity: bug
- File:
lib/screens/show_case/show_case_detail/show_case_detail_screen.dart:231 - Description: CA-3 permite editar a data de expiração (máx. 30 dias) para SellerStock, mas o footer oculta "ATUALIZAR VITRINE" quando
isSellerStocké true, enquanto o campo de data permanece editável. O usuário altera a data localmente sem poder persistir, exceto via diálogo de saída. - Suggestion: Exibir "ATUALIZAR VITRINE" para SellerStock quando apenas
expirationDatemudou, ou auto-salvar na alteração de data. - Status: open
Issue 2 — Severity: bug
- File:
lib/screens/show_case/widgets/show_case_detail_layout.dart:106 - Description:
PopScopeusacanPop: falsequandoonPopScopeé fornecido, masonPopInvokedWithResultnão está ligado. Apenas o botão da app-bar chamaonPopScope; o back do sistema/gesto fica bloqueado sem handler. - Suggestion: Adicionar
onPopInvokedWithResultpara disparar o mesmo fluxo de alterações não salvas e navegação. - Status: open
Issue 3 — Severity: bug
- File:
lib/screens/show_case/show_case_detail/show_case_detail_controller.dart:227 - Description:
retryCreate()sempre chamacreateAndLoad()(novo POST). Se o POST inicial teve sucesso masloadData()falhou, o retry cria segunda vitrine SellerStock, violando CA-2. - Suggestion: Se
arguments.catalogId != null, retry deve apenas chamarloadData(arguments). - Status: open
Issue 4 — Severity: bug
- File:
lib/screens/show_case/show_case_detail/show_case_detail_controller.dart:337 - Description:
backToShowCasePage()navega paraAppRoutes.showCase, enquantoonPopScopeusaAppRoutes.storeShowCaseList. Após exclusão, o usuário pode cair na rota errada. - Suggestion: Alinhar
backToShowCasePage()comonPopScope. - Status: open
Issue 5 — Severity: bug
- File:
lib/screens/show_case/show_case_detail/show_case_detail_controller.dart:491 - Description: Em
onPopScope, ao escolher "Salvar",updateShowCaseé aguardado masGet.untilexecuta mesmo se a validação/salvamento falhar. Alterações podem ser descartadas silenciosamente. - Suggestion: Navegar somente após salvamento bem-sucedido. Replicar em
recommend_show_case_detail_controller.dart:274. - Status: open
Issue 6 — Severity: bug
- File:
lib/screens/show_case/search/show_case_search_products_controller.dart:463 - Description:
Future.delayed(Duration(seconds: 1))hard-coded antes do bottom sheet de sucesso para contornar race com loading/POST. UX lenta e ainda sujeita a falhas intermitentes. - Suggestion: Corrigir a causa raiz (ordem de dismiss do loader vs. exibição do bottom sheet) em vez de delay fixo.
- Status: open
Issue 7 — Severity: suggestion
- File:
lib/screens/show_case/widgets/show_case_type_selection_bottom_sheet.dart:62 - Description: Descrição da opção "Vitrine do estoque da loja" (quando habilitada) repete o copy de vitrine personalizada, confundindo o usuário.
- Suggestion: Copy específico sobre compartilhar o catálogo completo da loja sem curadoria manual.
- Status: open
Issue 8 — Severity: suggestion
- File:
lib/screens/show_case/show_case_detail/show_case_detail_controller.dart:130 - Description:
productCountTextpara SellerStock usa "produtos recomendados", inadequado para estoque completo da loja. - Suggestion: Usar "produtos disponíveis" ou "produtos no estoque da loja".
- Status: open
Issue 9 — Severity: suggestion
- File:
lib/screens/show_case/show_case_detail/show_case_detail_controller.dart:202 - Description: Criação de vitrine personalizada registra
FirebaseService.logCreateCatalog('fast'), mascreateAndLoad()SellerStock não registra evento equivalente (CA-5). - Suggestion: Adicionar evento Firebase/analytics distinto para criação SellerStock.
- Status: open
Issue 10 — Severity: suggestion
- File:
lib/screens/show_case/show_case/my_show_case_controller.dart:141 - Description:
hasSellerStocksó atualiza no_load()da listagem. Após criar SellerStock, o bottom sheet pode ainda permitir nova tentativa até o refetch. - Suggestion: Atualizar
hasSellerStockotimisticamente após criação bem-sucedida. - Status: open
Issue 11 — Severity: nit
- File:
lib/theme_widgets/tag/tag.dart:60 - Description: Refatoração global de
ZzTag(altura fixa,ZzTagSize.smdefault) pode alterar layout de tags existentes no app. - Suggestion: Validar regressão visual ou limitar mudança ao tema
newFeature. - Status: open
Issue 12 — Severity: nit
- File:
lib/screens/show_case/recommend_show_case_detail/recommend_show_case_detail_controller.dart:259 - Description: Indentação inconsistente no método
onPopScopeintroduzido no refactor. - Suggestion: Rodar formatter nos arquivos alterados.
- Status: open
Contagem de Issues
| Severidade | Quantidade |
|---|---|
| bug | 6 |
| suggestion | 4 |
| nit | 2 |
| Total | 12 |
Recomendações antes do merge
- Bugs de navegação e persistência — Prioridade alta: corrigir Issues 1–5 (expiração SellerStock,
PopScope, retry, rotas pós-delete, salvamento no pop). - CA-2 — Garantir que retry e flag
hasSellerStocknão permitam segunda criação (Issues 3 e 10). - Testes de controller/tela — Adicionar testes para
ShowCaseDetailController, bottom sheet e fluxo de criação SellerStock. - Escopo — Revisar impacto global da refatoração de
ZzTag(Issue 11) e removerFuture.delayed(Issue 6). - QA manual — Validar back do sistema Android, exclusão de vitrine, edição de data SellerStock e copy do bottom sheet.
Referências
- User Story: 196053.md
- Diff:
feat/196053_vitrine_estoque_lojavsorigin/develop - Review ID interno:
6fa9db99