teqo-backup/docs/plans/municipio-v2-rede-impl.md
2026-08-03 00:11:22 +00:00

89 lines
4.8 KiB
Markdown
Raw Permalink 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.

# Impl: Município v2 — rede (lista edit-in-place)
Status: aprovado
Atualizado em: 2026-08-03
Issue: #332
Intenção: docs/plans/municipio-v2-rede.md
Appetite restante: ~1 dia eng (herdado)
## Leitura da intenção
- **Outcome:** rede na dobra principal da v2 — lista densa (tabela desktop / lista mobile) com top-N lideranças, declarado e estimado editáveis no lugar (auto-save B9), caminho para ver todas e criar liderança; leader não vê estimado.
- **O que NÃO negociar:** assimetria estimado (staff-only); leader lockdown na página; não cards empilhados; não spreadsheet de colunas da ficha global; não substituir ficha completa (link ao detalhe).
- **O que reavaliar:** reusar `DeclareVotesForm`/`PledgeEstimateForm` (rejeitados — têm botão Salvar); twin de loaders vs composer fino; N do top-N.
## Abordagem recomendada
```mermaid
flowchart LR
Page["municipio/[slug]/v2/page.tsx"]
Loader["loadMunicipalityV2NetworkData"]
Panel["MunicipalityV2NetworkSection"]
List["MunicipalityV2NetworkList"]
Declared["MunicipalityV2DeclaredVotesCell"]
Estimated["MunicipalityV2EstimatedVotesCell"]
DeclAPI["POST municipios/pledge-declared-votes"]
EstAPI["POST municipios/pledge-estimated-votes"]
Page --> Loader --> Panel --> List
List --> Declared --> DeclAPI
List --> Estimated --> EstAPI
```
**Opções consideradas:**
| | A — Reusar panels atuais (cards + forms) | B — Lista densa + B9 cell autosave + JSON routes | C — CampaignTable completo com colunas B17 |
| --- | ---------------------------------------- | ------------------------------------------------ | ------------------------------------------ |
| | Rápido mas cards + Salvar | Alinha B9 e aceite | Overkill sem picker de colunas |
**Recomendação:** B — lista densa com `CampaignCellEditOverlay` + `useCampaignCellAutosave`; writes via `declareVotes`/`estimateVotes` existentes; revalidate v2 via `revalidateMunicipalityListPaths`.
**Rejeitadas:** A (cards + botão Salvar violam aceite). C (B17 não pedido; 4 colunas fixas).
### Decisões de engenharia
1. **Top-N = 8** — mesmo cap do dossiê (`DOSSIER_LEADERSHIP_LIMIT`). Ordenação: `effective(central)` desc, depois `declared` desc (assumido na intenção).
2. **Merge leadership × pledge** em pure `buildMunicipalityV2NetworkRows` — liderança sem pledge aparece com declarado/estimado vazios; estimado só editável quando existe `pledgeID`.
3. **JSON routes** em `municipios/pledge-declared-votes` e `municipios/pledge-estimated-votes` (paridade `expected-votes`); `safeMessages` de `votePledge` schemas.
4. **Estimado na célula** — trigger mostra média (cenário central); popover/sheet com `VoteEstimateScenarioInputs` compact (precedente `MunicipalityListExpectedVotesControl`).
5. **Declarado na célula** — popover/sheet com input numérico; autosave debounce 600ms + flush no close.
6. **CTAs** — "Ver todas" → `?tab=leaderships`; "Nova liderança" → `/campanha/liderancas/nova?municipality=` (textual, não FAB — B151).
### Componentes / mudanças
- **`loadMunicipalityV2NetworkData`** (`utilities/municipality/municipalityV2NetworkData.ts`): composer sobre `loadMunicipalityLeaderships` + `loadMunicipalityPledges`.
- **`municipalityV2NetworkView.ts`**: tipos + sort/merge puros (unit-tested).
- **`MunicipalityV2NetworkSection` + `MunicipalityV2NetworkList` + células** (`components/campaign/municipality/`).
- **Routes:** `pledge-declared-votes/route.ts`, `pledge-estimated-votes/route.ts` + `types.ts`.
- **`pledgeFormActions.ts`:** revalidate via `revalidateMunicipalityListPaths` (inclui v2).
- **Migration:** nenhuma.
- **Access:** `declareVotes`/`estimateVotes` existentes; página `noLeader`.
- **UI:** Impeccable B — lista densa; shells B9; `data-theme='campaign'`.
### Dados → forma
- Tabela 4 colunas (nome · status · declarado · estimado); mobile = mesma informação em linhas densas, não cards empilhados por pessoa com forms longos.
## Fases verificáveis
1. **Server** — view puro + loader + JSON routes + revalidate paths.
2. **UI** — section na página v2 + células autosave + CTAs.
3. **Gates** — unit sort/merge; `pnpm gate:fast`; `pnpm push`.
## Rabbit holes / Não escopo (engenharia)
- FAB B151; conta B148; agora B150; cutover B152.
- Edição de status de apoio na rede (fora das 4 colunas).
- Nota de estimativa na lista (ficha completa / popover longo).
## Riscos e mitigação
- **Conta não atualiza após edit:** `revalidateMunicipalityListPaths` busta página v2; aceite permite conta refresh posterior (B148).
- **Pledge inexistente:** declarado cria via `declareVotes`; estimado disabled até existir pledge.
## Aceite de engenharia
- [ ] Aceite de produto da intenção coberto
- [ ] Invariantes AGENTS/engineering-standards
- [ ] Unit tests em `municipalityV2NetworkView`
Self-score decision-quality: 4/5