From c12fc0787c37e96bbaf701558798056312105ca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Ign=C3=A1cio=20Fontoura=20Solla?= Date: Sat, 18 Jul 2026 20:59:36 -0300 Subject: [PATCH] Register C7 scale/DRY follow-ups after the C3 action-plan simplify pass. --- .cursor/rules/projects/nucleos-eleitorais.mdc | 1 + docs/plans/escala-dry-pos-c2.md | 1 + docs/plans/escala-dry-pos-c3.md | 127 ++++++++++++++++++ docs/plans/eventos-agenda-mobilizacao.md | 1 + docs/roadmap.md | 37 ++--- 5 files changed, 151 insertions(+), 16 deletions(-) create mode 100644 docs/plans/escala-dry-pos-c3.md diff --git a/.cursor/rules/projects/nucleos-eleitorais.mdc b/.cursor/rules/projects/nucleos-eleitorais.mdc index e65eee22..1dcab560 100644 --- a/.cursor/rules/projects/nucleos-eleitorais.mdc +++ b/.cursor/rules/projects/nucleos-eleitorais.mdc @@ -11,6 +11,7 @@ alwaysApply: false - **Ciclo 2 entregue, mesclado e deployado (2026-07-18):** A1 território multi-município/bairro, A3 baseline TSE 2022 (modelo + import), B1 overview da lista, C1 compartilhar página e D1 PWA — detalhes no item datado abaixo. - **A2 entregue e mesclado em `main` (2026-07-18):** cadastro estático município↔ZE (`bahiaTseZones`, TSE 2024) + chips opt-in no formulário (`NucleusTerritoryAndZonesFields` / `territorySuggestions`); sem migration. Plano: [`docs/plans/zonas-por-municipio.md`](../../../docs/plans/zonas-por-municipio.md). - **C3 Planos de Ação implementado (2026-07-18):** collection `actionPlan` + vertical `/campanha/planos` (lista com tabs Próximos/Todos/Realizados/Rascunhos, detalhe com tabs Visão geral/Tarefas/Atualizações, forms novo/editar), blocos "Próximos eventos" no overview de núcleos e no dashboard; `startAt` opcional só em rascunho; access por `coordinators`/`leadership`; migration `20260718_222832_add_action_plan`. +- **C7 registrado (2026-07-18):** débitos de escala/DRY pós-C3 do `/simplify` (território/contato compostos, helpers FormData/URL, leituras por aba, RMW/índice) — plano [`docs/plans/escala-dry-pos-c3.md`](../../../docs/plans/escala-dry-pos-c3.md); não bloqueia o MVP da agenda. - Fluxos operacionais cobertos: login isolado, CRUD/arquivo de núcleos por slug, designação de coordenador (`geral`), CRM de lideranças, estimativas sugerir/confirmar com versão UUID, feed de atualizações, convites WhatsApp (`wa.me` + hash de uso único), dashboard com agregados só de núcleos ativos. - Pendência operacional (não de código): Consent `lideranca-autopreenchimento` + lote jurídico LGPD antes de dados reais; smoke pós-deploy Vercel. Ver Onda 0 em [`docs/roadmap.md`](../../../docs/roadmap.md). - Em 2026-07-17, a listagem de Núcleos passou a aplicar filtros automaticamente pelo estado da URL, sem botão de confirmação, com comboboxes territoriais estritos compartilhados com o formulário. diff --git a/docs/plans/escala-dry-pos-c2.md b/docs/plans/escala-dry-pos-c2.md index 99e0af65..9329d3de 100644 --- a/docs/plans/escala-dry-pos-c2.md +++ b/docs/plans/escala-dry-pos-c2.md @@ -105,6 +105,7 @@ flowchart TD - Reabrir decisões de v1 do C2 (telefone obrigatório, kit mínimo, import só `geral`, etc.) — [cadastro-nominal-apoiadores.md](cadastro-nominal-apoiadores.md). - Agregado de apoiadores no overview de núcleos — follow-up de B1. - GOTV / dia D — C5. +- Escala/DRY de planos de ação (`actionPlan`) — C7 / [escala-dry-pos-c3.md](escala-dry-pos-c3.md) (consome `campaignListUrl` da Fase 2 deste plano quando existir). - Push/notificações — D2 / [notifications.md](notifications.md). - Índices `pg_trgm` / FTS em `contact` (mencionado na review de perf; só se busca ILIKE virar gargalo medido). diff --git a/docs/plans/escala-dry-pos-c3.md b/docs/plans/escala-dry-pos-c3.md new file mode 100644 index 00000000..3a5543c5 --- /dev/null +++ b/docs/plans/escala-dry-pos-c3.md @@ -0,0 +1,127 @@ +# Escala e DRY pós-C3 (planos de ação) + +Status: rascunho +Atualizado em: 2026-07-18 +Item do roadmap: [docs/roadmap.md](../roadmap.md) (Trilha C, item C7) +Responsável: — + +## Contexto + +O C3 ([eventos-agenda-mobilizacao.md](eventos-agenda-mobilizacao.md)) entregou a vertical `/campanha/planos` (`actionPlan`, lista/detalhe/forms, blocos "Próximos eventos"). A passagem `/simplify` de 2026-07-18 aplicou limpezas pontuais (alias de access, labels a partir do schema, paginação via `getNucleusPaginationPages`, snapshot de campos staff para liderança, loaders/overview em paralelo), mas **deixou de fora** débitos que os revisores (quality / reuse / performance) marcaram como importantes e maiores que cleanup: + +1. Compor território: `NucleusTerritoryAndZonesFields` forcou um fork quase completo em `NucleusTerritoryFields` (~319 linhas). +2. Unificar o picker assíncrono de contato (`ContactCombobox` vs `PrimaryContactCombobox`). +3. Extrair `validateTerritoryFormData` / parse de território FormData (hoje clone núcleo ↔ plano). +4. Consumir (ou espelhar) helpers de URL de lista — C6 Fase 2 já prevê `campaignListUrl`; `actionPlanUi` ainda clona o maquinário de `nucleusUi`. +5. Leituras caras: detalhe/edit sempre carregam `tasks`+`updates` em `depth: 1`; lista hidrata todas as tasks só para progresso; form prefetcha até 200 lideranças. +6. Escritas amplificadas: toggle de tarefa / append de update fazem read-modify-write do documento inteiro. +7. Índice composto ausente para a query quente `status IN (…) AND startAt >= now ORDER BY startAt`. + +Este plano é o registro canônico desses follow-ups. Sem ele, a agenda funciona em volume baixo, mas o DRY com núcleos e o custo por plano crescem com o feed de atualizações e a lista de "Próximos". + +## Objetivos + +- Território Bahia (sem ZE) é um único componente/core; o formulário de núcleo só adiciona `TseZoneInput` + chips de ZE. +- Contatos remotos usam um shell assíncrono; `PrimaryContactCombobox` adapta a API legada `{ current, options }`. +- Validação/parse de território FormData e (quando C6 F2 existir) URL de lista deixam de ser triplicados entre núcleo / apoiador / plano. +- Detalhe de plano carrega arrays por aba; lista não faz join de todas as tasks para contar progresso; liderança no form é typeahead (não prefetch 200×`depth: 1`). +- Toggle/append não reescrevem o documento inteiro; query "Próximos" tem índice adequado. +- Guardrails: `overrideAccess: false` com `user`; escritas multi-step continuam em `withPayloadTransaction`; liderança continua restrita a `tasks.done` + append `updates`; sem novo `Consent`. + +## Decisões travadas + +- **Um item C7, cinco fases ordenadas.** Mesmo racional do C6: um ID de roadmap, PRs por fase. Ordem: DRY barato → DRY helpers → leituras → escritas/índice. +- **Dependência dura de C3.** Não reabre o escopo de v1 do `actionPlan` (território próprio, arrays embutidos no MVP, access por `coordinators`/`leadership`). +- **Dependência suave de C6 Fase 2** para `campaignListUrl` / pagination shell. Se C6 F2 ainda não existir, C7 Fase 3 extrai só o necessário para `actionPlanUi` **ou** espera o helper do C6 — não inventar um terceiro `*ListUrl`. +- **Cortável se a agenda permanecer pequena.** Fases 4–5 (leituras pesadas, RMW, índice) podem escorregar se houver poucos planos/updates; Fases 1–2 (composição de UI) continuam baratas e reduzem risco de drift com A2. +- **Arrays embutidos no MVP; collection `actionPlanUpdate` só se a Fase 5 medir necessidade.** Preferir patch de linha em `action_plan_tasks` / `action_plan_updates` (drizzle ou Local API alvo) antes de nova collection. +- **Contadores de progresso na lista:** preferir campos derivados `taskDoneCount` / `taskTotal` mantidos no `beforeChange` (migration pequena) a hidratar `tasks: { done: true }` em toda página. +- **i18n e naming** (AGENTS.md): identificadores em inglês (`CampaignTerritoryFields`, `AsyncContactCombobox`, `validateCampaignTerritoryFormData`, `taskDoneCount`, `searchActionPlanLeadershipOptions`), strings visíveis em pt-BR. + +## Questões em aberto + +- **Renomear `NucleusTerritoryFields` → `CampaignTerritoryFields` neste item?** **Recomendação:** sim no PR da Fase 1 (nome deixa de mentir); manter re-export temporário `NucleusTerritoryFields` se algum import externo ainda existir. +- **Patch de array via drizzle vs Local API?** **Recomendação:** começar com update Local API que envia só `{ tasks: nextTasks }` (já é o caso) + select mínimo no `findByID` (`tasks` only / `updates` only); só cair para SQL direto se o `beforeChange` continuar varrendo arrays grandes. +- **Índice `(status, start_at)` na mesma migration dos contadores?** **Recomendação:** sim — uma `pnpm migrate:create action_plan_list_perf` com colunas derivadas + índice; evita duas deploys de schema. +- **Typeahead de liderança reusa `ContactCombobox` ou `NativeSelect` + search?** **Recomendação:** Server Action `searchActionPlanLeadershipOptions(query)` + combobox (mesmo shell da Fase 2), `depth: 0`, label a partir do contact id/nome já resolvido. +- **Migrar timestamps de núcleos para `formatBahiaDateTimeLabel`?** **Recomendação:** fill-in separado (não bloqueia C7); o helper date-only foi removido no simplify e só volta se a UI precisar. + +## Abordagem proposta + +```mermaid +flowchart TD + F1["Fase 1 — DRY território UI
core + AndZones compõe"] + F2["Fase 2 — DRY contact picker
shell assíncrono único"] + F3["Fase 3 — DRY form/URL território
+ consumir campaignListUrl"] + F4["Fase 4 — Leituras
tabs · contadores · typeahead"] + F5["Fase 5 — Escritas + índice
RMW mínimo · status+startAt"] + + C3["C3 actionPlan ✓"] --> F1 + F1 --> F2 + F2 --> F3 + F3 --> F4 + F4 --> F5 + C6["C6 F2 campaignListUrl"] -.suave.-> F3 +``` + +### Fase 1 — Território UI composto + +- Extrair o bloco regions/cities/neighborhoods/locality/notes (+ chips) para um core compartilhado (hoje duplicado em `NucleusTerritoryFields.tsx` ≈ `NucleusTerritoryAndZonesFields.tsx`). +- **`NucleusTerritoryAndZonesFields`**: compõe o core + `TseZoneInput` + sugestões de ZE (`buildTerritorySuggestions` / `outsideZones`). +- **`ActionPlanForm`**: continua importando só o core (sem ZE). + +### Fase 2 — Contact picker único + +- Shell assíncrono (debounce, `requestId`, CommandDialog, loading/erro) a partir de `ContactCombobox.tsx`. +- **`PrimaryContactCombobox`**: adapta `{ current, options }` / search de inteligência de núcleo para o shell (sem segundo Dialog). +- Estado controlado (`value` + `onChange`); eliminar espelho pai/filho que o simplify apontou. + +### Fase 3 — Helpers FormData / URL + +- **`validateCampaignTerritoryFormData` / `parseCampaignTerritoryFields`**: extrair de `nucleusFormData.ts` e `actionPlanFormData.ts` (entityLabel `núcleo` | `plano`). +- **URL de lista:** se C6 F2 já tiver `campaignListUrl.ts`, migrar `actionPlanUi.ts` para consumi-lo; senão, extrair o mínimo compartilhado **no módulo do C6** (não criar `actionPlanListUrl.ts` paralelo) ou adiar esta fatia até C6 F2. +- Opcional: `actionPlanDetailTabUi` parametrizado com o helper genérico de tabs do detalhe de núcleo (só se o PR já tocar URL). + +### Fase 4 — Leituras + +- **`[slug]/page.tsx`**: selects por aba (overview sem arrays; tarefas sem `updates`; atualizações com `depth: 0` + batch de autores) — espelhar o padrão de loaders por aba do detalhe de núcleo. +- **Lista:** `taskDoneCount` / `taskTotal` (hook) + `depth: 0` para `responsible` com batch de nomes; dropar `tasks: { done: true }` de `actionPlanListSelect`. +- **`getActionPlanLeadershipOptions` → search:** lazy no open do campo; `limit` baixo; sem `depth: 1` em massa. +- **`ContactCombobox`:** não fetch com query vazia (mín. 2 chars ou dígitos), alinhado ao custo de N comboboxes no form de tarefas. + +### Fase 5 — Escritas + índice + +- **`toggleActionPlanTaskRecord` / `appendActionPlanUpdateRecord`:** `findByID` com `select` só do array tocado; evitar rewalk desnecessário; avaliar patch de linha se ainda houver amplificação. +- **Migration** `action_plan_list_perf`: índice `(status, start_at)` (+ colunas de contador da Fase 4 se ainda não migradas). +- Só então considerar collection `actionPlanUpdate` append-only (fora do MVP C3; só com evidência de corrida/tamanho). + +**Migration:** Fases 1–3 sem schema. Fase 4/5: `pnpm migrate:create action_plan_list_perf` (contadores + índice). Sem Consent novo. + +## Dependências + +- **Dura:** C3 Planos de Ação (código em `actionPlan*` / `/campanha/planos`). +- **Suave:** C6 Fase 2 (`campaignListUrl`) — evita terceiro clone de URL helpers. +- Reusa: `NucleusTerritoryAndZonesFields.tsx`, `NucleusTerritoryFields.tsx`, `PrimaryContactCombobox.tsx`, `ContactCombobox.tsx`, `nucleusFormData.ts`, `actionPlanFormData.ts`, `actionPlanUi.ts`, `actionPlanPageData.ts`, `actionPlanViewModels.ts`, `campanha/actions/actionPlan.ts`, padrão de loaders por aba do detalhe de núcleo, C6 plano [escala-dry-pos-c2.md](escala-dry-pos-c2.md). + +## Não escopo + +- Reabrir decisões de v1 do C3 (`startAt` só obrigatório fora de rascunho, território sem link a núcleo, updates embutidos no MVP) — [eventos-agenda-mobilizacao.md](eventos-agenda-mobilizacao.md). +- Escala/DRY de apoiadores (import bulk, KPI SQL, preview token) — C6 / [escala-dry-pos-c2.md](escala-dry-pos-c2.md). +- Demandas / relação opcional `actionPlan` — C4. +- Notificações de agenda — D2 / [notifications.md](notifications.md). +- Calendário visual / mapa de eventos / recorrência — fora do horizonte pré-16/08. +- Migrar todos os `Intl.DateTimeFormat` de núcleos para Bahia — fill-in. + +## Referências + +- `docs/roadmap.md` — Trilha C, item C7; sequência Janela 2 +- [eventos-agenda-mobilizacao.md](eventos-agenda-mobilizacao.md) — C3 v1 entregue +- [escala-dry-pos-c2.md](escala-dry-pos-c2.md) — precedente C6 + `campaignListUrl` +- Review `/simplify` 2026-07-18 (quality / reuse / performance) — origem das fases +- `src/components/campaign/NucleusTerritoryFields.tsx` / `NucleusTerritoryAndZonesFields.tsx` +- `src/components/campaign/ContactCombobox.tsx` / `PrimaryContactCombobox.tsx` +- `src/utilities/actionPlanFormData.ts` / `nucleusFormData.ts` / `actionPlanUi.ts` +- `src/utilities/actionPlanPageData.ts` / `actionPlanViewModels.ts` / `actionPlanLeadershipOptions.ts` +- `src/app/(campaign)/campanha/actions/actionPlan.ts` — toggle/append RMW +- `src/migrations/20260718_222832_add_action_plan.ts` — índices atuais `status` / `start_at` separados +- AGENTS.md — `overrideAccess: false`, transações, naming, território Bahia diff --git a/docs/plans/eventos-agenda-mobilizacao.md b/docs/plans/eventos-agenda-mobilizacao.md index 6ab89a20..0c606d59 100644 --- a/docs/plans/eventos-agenda-mobilizacao.md +++ b/docs/plans/eventos-agenda-mobilizacao.md @@ -61,3 +61,4 @@ Cada documento `actionPlan` é uma ação/evento calendarizável (caminhada, com ## Não escopo - Collection dedicada `actionUpdate`, captura nominal de presentes, calendário/mapa, link a `electoralNucleus`, recorrência, notificações (D2). +- Escala/DRY pós-entrega (território/contato compostos, selects por aba, RMW de tasks/updates, índice `status+startAt`) — C7 / [escala-dry-pos-c3.md](escala-dry-pos-c3.md). diff --git a/docs/roadmap.md b/docs/roadmap.md index 09732f8b..7bae2ea4 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -1,6 +1,6 @@ # Roadmap — Teqo -Atualizado em: 2026-07-18 (MVP + Ciclo 2 deployados; A2 entregue; C2 engenharia pronta; C3 Planos de Ação implementado; C6 registrado — escala/DRY pós-C2) +Atualizado em: 2026-07-18 (MVP + Ciclo 2 deployados; A2 entregue; C2 engenharia pronta; C3 Planos de Ação implementado; C6/C7 registrados — escala/DRY pós-C2 e pós-C3) Registro canônico no repositório dos planos futuros e débitos conhecidos. Status operacional do ciclo atual de Núcleos fica em [`.cursor/rules/projects/nucleos-eleitorais.mdc`](../.cursor/rules/projects/nucleos-eleitorais.mdc); este arquivo lista o que ainda é futuro ou bloqueador, **em ordem de execução**, com dependências e paralelismo explícitos. @@ -75,6 +75,7 @@ Os designs gerados pelo UX Pilot para os próximos ciclos estão em [`docs/desig | C2 Cadastro nominal de apoiadores | `Apoiadores-Lista`, `Apoiador-Ficha`, `Importar-CSV-Apoiadores` | [cadastro-nominal-apoiadores.md](plans/cadastro-nominal-apoiadores.md) | | C6 Escala e DRY pós-C2 | — (sem design novo; reusa os de C2 + padrões de núcleos) | [escala-dry-pos-c2.md](plans/escala-dry-pos-c2.md) | | C3 Eventos / agenda de mobilização | `Planos-de-Acao`, `Novo-Plano-de-Acao` | [eventos-agenda-mobilizacao.md](plans/eventos-agenda-mobilizacao.md) | +| C7 Escala e DRY pós-C3 | — (sem design novo; reusa os de C3 + padrões de núcleos/C6) | [escala-dry-pos-c3.md](plans/escala-dry-pos-c3.md) | | D2 Notificações (sino) | `Notificacoes-PWA` (central de notificações) | [notifications.md](plans/notifications.md) | | D1 PWA `/campanha` | `Notificacoes-PWA` (banner "Instale o app da campanha") | [pwa-campanha.md](plans/pwa-campanha.md) | | C5 Operação dia D / GOTV | `Dia-D-GOTV` | sem plano ainda — o design é a primeira materialização do item (check-off de apoiadores por seção/zona, progresso "62% da base", filtro "Ainda não confirmados", estado "Sincronizado" offline-tolerante) | @@ -113,6 +114,7 @@ flowchart TD C2["C2 Cadastro nominal de apoiadores"] C6["C6 Escala e DRY pós-C2
(import/listas/forms)"] C3["C3 Eventos / agenda de mobilização ✓"] + C7["C7 Escala e DRY pós-C3
(território/contato/leituras)"] C4["C4 Demandas"] C5["C5 Operação dia D / GOTV
(proposto, a validar)"] end @@ -136,7 +138,9 @@ flowchart TD B3 --> B4 A1 --> C3 A1 --> C4 + C3 --> C7 C3 -.relação actionPlan opcional.-> C4 + C6 -.campaignListUrl.-> C7 JUR --> C2prod["C2 em produção
(dados reais)"] C2 --> C2prod C2 --> C6 @@ -146,7 +150,7 @@ flowchart TD JUR -.chave de push.-> D2 ``` -Itens sem seta de entrada (**paralelizáveis a qualquer momento**): B2, C2 (engenharia — produção espera o jurídico), além dos fill-ins (visitados recentemente, listas globais, reset de senha, higiene PascalCase). **Entregues em 2026-07-18** (✓ no grafo): A1, A2, A3, B1, C1, C3 e D1 — ver "Ciclo 2" acima e C3 abaixo. Destravados por eles: A4 (A2/A3 + B1 prontos), C4 (A1 + C3 prontos), C6 (após merge de C2) e D2 push (D1 pronto; falta a chave jurídica). +Itens sem seta de entrada (**paralelizáveis a qualquer momento**): B2, C2 (engenharia — produção espera o jurídico), além dos fill-ins (visitados recentemente, listas globais, reset de senha, higiene PascalCase). **Entregues em 2026-07-18** (✓ no grafo): A1, A2, A3, B1, C1, C3 e D1 — ver "Ciclo 2" acima e C3 abaixo. Destravados por eles: A4 (A2/A3 + B1 prontos), C4 (A1 + C3 prontos), C6 (após merge de C2), C7 (após C3; suave: C6 F2) e D2 push (D1 pronto; falta a chave jurídica). ### Sequência de execução por janela do calendário @@ -165,29 +169,30 @@ Itens sem seta de entrada (**paralelizáveis a qualquer momento**): B2, C2 (enge | Ordem | Item | Plano | Depende de | Paralelizável com | | ----- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | -------------------------------- | ----------------- | -| 7 | C2 Cadastro nominal de apoiadores _(engenharia pronta 2026-07-18 — merge/deploy + Consent keys ainda pendentes)_ | [detalhes](plans/cadastro-nominal-apoiadores.md) | produção: lote jurídico (Onda 0) | A4, C3, C6 | -| 8 | C6 Escala e DRY pós-C2 (import em massa, KPI, shells compartilhados com núcleos) | [detalhes](plans/escala-dry-pos-c2.md) | C2 (merge) | A4, C3 | -| 9 | A4 Baseline no produto + insight Gap vs 2022 | [detalhes](plans/baseline-eleitoral-tse.md) | A3 + B1 (suave: A2) | C2, C3, C6 | -| 10 | C3 Eventos / agenda de mobilização (`actionPlan`) **(implementado 2026-07-18)** | [detalhes](plans/eventos-agenda-mobilizacao.md) | A1 | C2, A4, C6 | +| 7 | C2 Cadastro nominal de apoiadores _(engenharia pronta 2026-07-18 — merge/deploy + Consent keys ainda pendentes)_ | [detalhes](plans/cadastro-nominal-apoiadores.md) | produção: lote jurídico (Onda 0) | A4, C3, C6, C7 | +| 8 | C6 Escala e DRY pós-C2 (import em massa, KPI, shells compartilhados com núcleos) | [detalhes](plans/escala-dry-pos-c2.md) | C2 (merge) | A4, C3, C7 | +| 9 | A4 Baseline no produto + insight Gap vs 2022 | [detalhes](plans/baseline-eleitoral-tse.md) | A3 + B1 (suave: A2) | C2, C3, C6, C7 | +| 10 | C3 Eventos / agenda de mobilização (`actionPlan`) **(implementado 2026-07-18)** | [detalhes](plans/eventos-agenda-mobilizacao.md) | A1 | C2, A4, C6, C7 | +| 11 | C7 Escala e DRY pós-C3 (território/contato compostos, leituras por aba, RMW/índice) | [detalhes](plans/escala-dry-pos-c3.md) | C3 (suave: C6 F2) | A4, C6 | **Janela 3 — 16/08 → set (campanha de rua): inteligência ampliada, visualização e engajamento.** | Ordem | Item | Plano | Depende de | Paralelizável com | | ----- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | ----------------- | -| 11 | A5 Insights derivados do baseline (5 itens, paralelizáveis entre si; conversão e classificação exigem limiares de produto) | [conversão](plans/insight-taxa-conversao.md) · [classificação](plans/insight-classificacao-territorial.md) · [alavancagem](plans/insight-alavancagem-chapa.md) · [mobilização](plans/insight-mobilizacao-brancos-nulos.md) · [competitiva](plans/insight-inteligencia-competitiva.md) | A4 | B2/B3, C4, D1 | -| 12 | B2 + B3 Mapa da Bahia (geometrias + Leaflet) | [detalhes](plans/mapa-bahia-geometrias.md) | B3 ← B1+B2 (suave: A4 para coroplético de baseline/classe) | A5, C4, D1 | -| 13 | C4 Demandas | [detalhes](plans/demandas-campanha.md) | A1 (suave: C3 para a relação `actionPlan`) | A5, B3, D1 | -| 14 | D1 PWA `/campanha` **(entregue antecipado em 2026-07-18)** | [detalhes](plans/pwa-campanha.md) | — | tudo | -| 15 | D2 Notificações (push + sino) — sino não depende do PWA; push sim | [detalhes](plans/notifications.md) | D1 ✓ (push) + chave `campanha-notificacoes-push` do lote jurídico | A5, B3, C4 | +| 12 | A5 Insights derivados do baseline (5 itens, paralelizáveis entre si; conversão e classificação exigem limiares de produto) | [conversão](plans/insight-taxa-conversao.md) · [classificação](plans/insight-classificacao-territorial.md) · [alavancagem](plans/insight-alavancagem-chapa.md) · [mobilização](plans/insight-mobilizacao-brancos-nulos.md) · [competitiva](plans/insight-inteligencia-competitiva.md) | A4 | B2/B3, C4, D1 | +| 13 | B2 + B3 Mapa da Bahia (geometrias + Leaflet) | [detalhes](plans/mapa-bahia-geometrias.md) | B3 ← B1+B2 (suave: A4 para coroplético de baseline/classe) | A5, C4, D1 | +| 14 | C4 Demandas | [detalhes](plans/demandas-campanha.md) | A1 (suave: C3 para a relação `actionPlan`) | A5, B3, D1 | +| 15 | D1 PWA `/campanha` **(entregue antecipado em 2026-07-18)** | [detalhes](plans/pwa-campanha.md) | — | tudo | +| 16 | D2 Notificações (push + sino) — sino não depende do PWA; push sim | [detalhes](plans/notifications.md) | D1 ✓ (push) + chave `campanha-notificacoes-push` do lote jurídico | A5, B3, C4 | **Janela 4 — set → 04/10 (reta final): dobradinha, dia D e estabilização.** | Ordem | Item | Plano | Depende de | | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | -| 16 | A6 Insight dobradinha 2026 | [detalhes](plans/insight-dobradinha-2026.md) | A4 + TSE publicar candidaturas 2026 (externo, após 15/08) + taxonomia de alinhamento (produto) | -| 17 | B4 Camada de zonas TSE no mapa | ciclo seguinte do [plano do mapa](plans/mapa-bahia-geometrias.md) | A2 + B3 | -| 18 | C5 **Operação dia D / GOTV** _(item proposto nesta revisão — validar com produto)_: confirmação de comparecimento da base nominal em 04/10 (lista de apoiadores por núcleo/zona com marcação "confirmou que vai votar / votou", visão de cobertura para a coordenação). É o uso final da base construída em C2; a literatura de campanha trata a mobilização do dia como onde eleições apertadas se decidem. Sem plano ainda. | design: [`Dia-D-GOTV`](design-refs/latest/Dia-D-GOTV.png) | C2 (suave: C6 para escala da base) | -| 19 | Congelamento: a partir de ~20/09, só correção de bug e dados; nada de migration arriscada perto do dia D. | — | — | +| 17 | A6 Insight dobradinha 2026 | [detalhes](plans/insight-dobradinha-2026.md) | A4 + TSE publicar candidaturas 2026 (externo, após 15/08) + taxonomia de alinhamento (produto) | +| 18 | B4 Camada de zonas TSE no mapa | ciclo seguinte do [plano do mapa](plans/mapa-bahia-geometrias.md) | A2 + B3 | +| 19 | C5 **Operação dia D / GOTV** _(item proposto nesta revisão — validar com produto)_: confirmação de comparecimento da base nominal em 04/10 (lista de apoiadores por núcleo/zona com marcação "confirmou que vai votar / votou", visão de cobertura para a coordenação). É o uso final da base construída em C2; a literatura de campanha trata a mobilização do dia como onde eleições apertadas se decidem. Sem plano ainda. | design: [`Dia-D-GOTV`](design-refs/latest/Dia-D-GOTV.png) | C2 (suave: C6 para escala da base) | +| 20 | Congelamento: a partir de ~20/09, só correção de bug e dados; nada de migration arriscada perto do dia D. | — | — | **Fill-ins (qualquer janela, quando houver folga; nenhum bloqueia nada):** @@ -196,7 +201,7 @@ Itens sem seta de entrada (**paralelizáveis a qualquer momento**): B2, C2 (enge - **Reset de senha self-service + foto de perfil** (UX adiada do ciclo 1). _(plano MVP)_ - **Higiene de código:** varredura PascalCase dos componentes legados. _(notebook Núcleos)_ -**Cortes seguros se o prazo apertar** (nesta ordem): B4 camada de zonas, B3 mapa Leaflet, C4 demandas, D2 push (mantendo o sino), C6 fases 3–5 (import bulk / preview token / KPI — só se a base nominal permanecer pequena), fill-ins (D1 PWA já entregue, saiu da lista de cortes). Preferir manter C6 fases 1–2 (UX + DRY) se houver folga. **Não cortáveis:** Onda 0 (jurídico/Consent), C2 cadastro de apoiadores, C3 eventos/agenda, A4 baseline + gap — são respectivamente o risco legal, a base de dados, a operação da propaganda e o instrumento de alocação de esforço. +**Cortes seguros se o prazo apertar** (nesta ordem): B4 camada de zonas, B3 mapa Leaflet, C4 demandas, D2 push (mantendo o sino), C6 fases 3–5 (import bulk / preview token / KPI — só se a base nominal permanecer pequena), C7 fases 4–5 (leituras/RMW/índice — só se a agenda permanecer pequena), fill-ins (D1 PWA já entregue, saiu da lista de cortes). Preferir manter C6 fases 1–2 e C7 fases 1–2 (DRY de UI) se houver folga. **Não cortáveis:** Onda 0 (jurídico/Consent), C2 cadastro de apoiadores, C3 eventos/agenda, A4 baseline + gap — são respectivamente o risco legal, a base de dados, a operação da propaganda e o instrumento de alocação de esforço. ### Itens consolidados/removidos nesta revisão (2026-07-17)