teqo-backup/docs/plans/encadear-ajustes-wizard.md
Cursor Agent 346949d035
B98 — Encadear ajustes do wizard após a ação principal
Após salvar (ou Pular) votos/tendência/sinal/liderança, navega ao
próximo elo da matriz v1 no mesmo município via entryAction, em vez
de voltar ao Início. Helper puro wizardActionChain + skips alinhados.

Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
2026-08-01 11:41:26 +00:00

142 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Encadear ajustes após a ação principal do wizard
Status: em implementação
Atualizado em: 2026-08-01
Issue: #106
Priority: P1
Model: cursor-grok-4.5-medium
Impeccable: C — orquestração multi-fluxo no chassis `/campanha/acoes`
Appetite: ~1–2d eng; matriz de cadeia + navegação pós-sucesso; sem migration
Responsável: —
## Design (Impeccable)
Âncoras: `PRODUCT.md` (Ação → Local → Quem; Continuity) / `DESIGN.md` · `fluxos-acao-primeiro-inicio.md` · B59/B75 chassis · tema `campaign`.
Na implementação: shape → craft → critique → polish.
Brief compacto:
- **Persona / contexto:** CG no polegar; acabou o ajuste principal (ex. votos) e ainda tem contexto do município na cabeça.
- **Job principal:** oferecer **na sequência** os ajustes que costumam vir juntos, sem voltar ao Início e reescolher município; poder **Pular** cada um.
- **Estratégia de cor:** Restrained; reusa tiles/passos já existentes.
- **Edit where you see:** writes reusam actions existentes (não segundo sistema).
- **Anti-goals:** state machine XState global; forçar todos os ajustes; reescolher município entre elos; resumo mega-commit (v1 pode gravar por elo como hoje).
### Wireframe (texto)
```text
Ajustar votos (entry)
Município → votos (X) → tendência [Pular] → sinal [Pular] → liderança [Pular] → Início
Registrar sinal (entry)
Município → sinal (X) → tendência [Pular] → votos [Pular] → liderança [Pular] → Início
Mudar tendência (entry)
Município → tendência (X) → sinal [Pular] → votos [Pular] → liderança [Pular] → Início
Atualizar liderança (entry)
Município → liderança (X) → sinal [Pular] → votos [Pular] → tendência [Pular] → Início
```
## Dados → decisão → apresentação
Dados: N/A como métrica nova — encadeia writes já existentes (votos, tendência, sinal, liderança). Decisão = “registrar agora o próximo ajuste neste município ou pular”.
## Contexto
O rascunho UX-1 ([fluxos-acao-primeiro-inicio.md](fluxos-acao-primeiro-inicio.md)) pediu continuidade no fim de A1 (“Quer também…?: sinal / tendência / liderança”). Os wizards standalone existem (votos, sinal, tendência, liderança), com `entryAction` query **já** usada para skip (sinal/liderança) e prefill de nota de tendência — mas **ninguém navega** de um fluxo ao próximo após o save.
`WizardExpectedVotesStep` tinha fase `saved` com placeholder — B98 substitui por redirect imediato ao próximo elo.
Pedido (2026-08-01): ao iniciar uma ação → município → **ajuste principal** → **encadear** outros ajustes que façam sentido (ex. votos → tendência).
## Objetivos
- Matriz v1 (travada abaixo) de `entryAction` → fila ordenada de subfluxos após sucesso da principal.
- Após Salvar da principal: ir ao **primeiro** elo da fila **no mesmo município** (URL do wizard alvo + `entryAction` + `municipio=`), não ao Início.
- Cada elo encadeado: chrome **Pular** (B96) → próximo elo ou fim; Salvar → próximo / fim.
- Fim: Início (ou tela curta de sucesso reusando copy de votos) **sem** re-pedir município.
- Guardrails: mesmas actions/access; sem migration; leader fora (layout `acoes` já gateia staff).
## Decisões travadas
- **Cadeia = navegação entre rotas/passos existentes + `entryAction`, não um mega-form único.** Reusa B61/B63/B64/B70. **Rejeitado:** um só POST transacional de tudo (caro; quebra skip parcial); checkboxes “Quer também?” sem subfluxo (raso demais vs tiles já feitos).
- **Matriz v1 (confirmada com produto 2026-08-01):** cada entry encadeia os **outros três** fluxos na ordem abaixo (a principal não se repete na fila).
| Entry (botão Início) | Principal | Encadeadas (ordem) |
| -------------------- | --------- | ----------------------------- |
| `update-votes` | votos | tendência → sinal → liderança |
| `register-signal` | sinal | tendência → votos → liderança |
| `change-trend` | tendência | sinal → votos → liderança |
| `update-leadership` | liderança | sinal → votos → tendência |
**Rejeitado:** incluir nível de envolvimento (E14) / assessor na v1 (A7/A8 do UX-1); cadeia só parcial (ex. liderança sem elos) — produto pediu os quatro caminhos completos.
- **Pular / Salvar avançam a fila; X só na principal (B96).** Encadeada nunca usa X como “pular um elo” — X abortaria o ritual inteiro só se quisermos dismiss global; **recomendação:** nas encadeadas dismiss/skip = próximo ou fim (Pular), sem X que descarte a principal já salva sem aviso. **Rejeitado:** X nas encadeadas = Início (ok como dismiss explícito se B75 mantiver — produto pediu Pular no lugar do X).
- **Gravação por elo (já existente), não commit único no fim.** **Rejeitado:** rascunho multi-collection até o CTA final (appetite + U4).
- **i18n:** `wizardChain`, `entryAction`, `nextChainHref`; copy pt-BR nos títulos de fluxo já do catálogo.
## Questões em aberto
- _(nenhuma — Option A da tela intermediária de votos fechada no craft 2026-08-01)_
## Abordagem proposta
```mermaid
flowchart LR
Entry["entryAction"] --> Main["passo principal"]
Main -->|save OK| Queue["wizardChainQueue(entry)"]
Queue --> Next["wizardHref(next, municipio, entryAction)"]
Next -->|Pular/Salvar| Queue
Queue -->|vazia| Home["Início / success"]
```
Componentes:
- **`src/lib/wizardActionChain.ts`** (puro): `wizardChainAfter(entry): CampaignWizardActionId[]`; `nextWizardChainStep(...)`; unit-pinned.
- **Pontos de sucesso:** `WizardExpectedVotesStep` (fase saved → replace por redirect ao próximo); `WizardTrendNoteStep` / signal body / leadership continue — após save, consultar fila restantes.
- **URLs:** reusar `wizardTrendHref` / `wizardSignalHref` / `wizardActionHref` com `entryAction` = dono da sessão de cadeia (o botão original).
- **B97** deve estar verde antes de encadear a partir de tendência (senão o save da tendência loopa e nunca avança).
- **Migration:** Sem migration.
## Dependências
- Duras: **B96** (Pular nas encadeadas) ✓ done/in-prod (#104), **B97** (Salvar tendência não loopa) ✓ done/in-prod (#105). Soft: B61/B63/B64/B70 ✓.
- Soft: OPS11 só para ver em prod.
## Não escopo
- Resumo multi-campo + CTA único “Registrar atualização” (UX-1 passo 8) — adiado.
- E14 / troca de assessor na cadeia.
- Demanda (A5) na matriz v1.
- Persistência de rascunho mid-Zap (B59 adiado).
## Rabbit holes
- **XState / orquestrador multi-route genérico.** **Mitigação:** array puro + hrefs.
- **Transação única multi-collection.** **Mitigação:** grava por elo.
- **Reordenar a strip do Início “porque a cadeia mudou o ritual”.** **Mitigação:** fora (B99 à parte).
## Adiado com gatilho
- **Tela de resumo antes do fim.** Revisitar se CG reportar “não sei o que gravei”.
- **Cadeia a partir de sugestão E11.** Quando E11 deep-linkar wizards com município pré-escolhido.
## Freshness audit (2026-08-01)
- Arquivos do plano existem; `entryAction` / skip resolvers / href builders batem com o código.
- B96 (#104) e B97 (#105) `done`+`in-prod`.
- Skip ainda apontava para Início — B98 redefine para o próximo elo.
- Votos não recebia `entryAction` — wiring adicionado na page do wizard.
- **Tela intermediária de votos:** Option A (redirect direto) confirmada no craft.
## Referências
- [fluxos-acao-primeiro-inicio.md](fluxos-acao-primeiro-inicio.md)
- `src/components/campaign/shared/WizardExpectedVotesStep.tsx`
- `src/lib/campaignActionRoutes.ts` · `campaignWizardCopy.ts` · `wizardActionChain.ts`
- [wizard-header-x-vs-pular.md](wizard-header-x-vs-pular.md) (B96) · [bug-salvar-tendencia-fecha-wizard.md](bug-salvar-tendencia-fecha-wizard.md) (B97)
- `PRODUCT.md` / `DESIGN.md`
Qualidade de decisão: 5/5 (matriz v1 confirmada no gate 2026-08-01)