- Compile docs/roadmap.md into a next-steps document (277→206 lines): R0–R5/M1–M5 tables and the delivered map/list item paragraphs compressed into 'Já entregue'; janelas, grafo and cortes list only open IDs; C10/C11/C8 fill-ins keep their original triggers; C5 moved under 'A validar'. - Record the production deploy of the destructive remodel chain (2026-07-23 Vercel builds) across roadmap, AGENTS.md, the project notebook and plans — supersedes every 'deploy pendente'; smoke pós-deploy + onboarding remain the open blockers. - Fix AGENTS.md internal contradictions: Município locked-decisions bullet (435, Camaçari whole, candidate role), campaignUser role enum, deploy-checklist item 7 as historical, access/* structure note, election-aggregates artifact + election-tse revalidate runbook. - Sync open plans to real identifiers (plaza*/nucleus* → municipality*): the intelligence program (master + E8–E15/B13/C12 with artifact/caching context and satisfied deps), B8 rescoped to Salvador ZE 1–19 only, WhatsApp D3–D5, D2, A6 (now the insight layer over stateDeputy), RS+, onda-0 smoke step. - Close items verified done in code: C8 F4 (DRY de forms) complete, filtros-auto shared pending shell, petition generateStaticParams select/depth; ledger the surviving user-visible 'Praça' copy in src as new P2 debt. - Banner delivered praça-era plans (production note + rename pointer); mark remodelagem-pracas.md superseded and remodelagem-municipios.md delivered. - TECH-DEBT smell statuses, TESTING RBAC row, README quality gates, campanha UI rules updated to current component names.
9.6 KiB
Aproximar o Mapa das Praças à região filtrada
Nota (2026-07-24): entregue na era Praças e em produção desde 2026-07-23. A remodelagem M1 renomeou os identificadores
plaza*→municipality*e as rotaspracas/→municipios/; os nomes neste plano são os da época. Nomes atuais: ver remodelagem-municipios.md.
Status: entregue 2026-07-21 (em produção desde 2026-07-23)
Atualizado em: 2026-07-21
Item do roadmap: docs/roadmap.md (Trilha B, item B12)
Impeccable: B — encaixe em PlazaMapPanel / BahiaMap (sem rota nova)
Appetite: ~0,5 dia eng; fitToKeys no Leaflet + chaves estáveis do bundle + teste/checklist
Responsável: —
Revisão 2026-07-21 (implementação): escopo ampliado com correção de três bugs de hover reportados em campo — (1) ênfase agressiva (fillOpacity + stroke grosso), (2) hover em municípios fora do filtro B7, (3) ênfase sticky no mouseout (setHoveredKey restyleava antes de limpar hoveredKey + selectedKey espelhava hover). Solução: interactiveKeys compartilhando chaves com fitToKeys (plazasByIbgeCode); hover stroke-only (fill inalterado, weight 2); clear síncrono de hoveredKey/selectedKey no mouseout desktop; touch pinned inalterado.
Design (Impeccable)
Âncoras: PRODUCT.md / DESIGN.md (register product — Field Desk) · tema data-theme='campaign' · shells existentes (PlazaMapPanel, BahiaMap).
Na implementação (implement-roadmap-item): craft compacto → critique → polish (comportamento de viewport; sem shape longo).
Brief compacto:
- Persona / contexto: Alex (coordenador) ou Assessor filtra por TI / tipo / cobertura e olha o mapa — hoje a Bahia inteira continua no frame e a região filtrada fica pequena demais para ler.
- Job principal: ao mudar o conjunto filtrado (URL ou escopo de access), o mapa aproxima o footprint geográfico desse conjunto.
- Estratégia de cor: Restrained — coroplético inalterado; só muda o viewport.
- Anti-goals: não redesenhar o painel; não esconder polígonos fora do filtro (já é contrato B7); não re-zoom a cada troca de ano/escala; não segunda interação “resetar zoom” neste item se o fit automático bastar.
Contexto
B7 (mapa-pracas-filtrado.md) alinhou os dados do mapa ao buildPlazaListWhere da lista — o coroplético só pinta o conjunto filtrado. O viewport, porém, continua em BAHIA_BOUNDS (src/components/campaign/BahiaMap.tsx): PlazaMapPanel não passa highlightKeys, e o else do render faz map.fitBounds(BAHIA_BOUNDS).
O próprio BahiaMap já sabe aproximar: quando highlightKeys tem itens, monta L.geoJSON(highlightedFeatures).getBounds() e chama fitBounds com padding: [24, 24] e maxZoom: 10. B7 adiara exatamente esse uso:
fitBoundsao footprint filtrado — revisit when coordenação filtrar TI/região e reportar que a Bahia inteira no viewport atrapalha.
Pedido de produto (2026-07-21): o gatilho disparou — ao filtrar, aproximar a região.
Objetivos
- Com filtro URL (ou escopo de assessor) que reduz o conjunto de Praças, o mapa abre/ajusta o viewport ao bounding box dos municípios (
codarea) presentes no bundle. - Sem filtro (coordenador com Bahia quase completa), o viewport permanece equivalente à Bahia inteira (fit nas chaves ≈
BAHIA_BOUNDS). - Trocar Ano / Escala / Comparar não deve re-disparar zoom (só o footprint geográfico).
- Guardrails: sem migration, sem collection, sem Consent, sem server action; sem mudar o contrato de dados do B7.
Decisões travadas
- Item próprio B12 (não reabrir B7 nem absorver em R6/B6). Gatilho explícito do B7; é UX de viewport, não filtro de dados, polish genérico nem
setStyle. (2026-07-21, roadmap-item.) Rejeitado: fill-in sem plano (edge cases de re-zoom e highlight merecem decisão); fase “entregue” do B7 (histórico as-built fica; trabalho novo ganha ID). - Prop dedicada
fitToKeys(não reusarhighlightKeys).highlightKeyshoje acopla destaque visual (borda/weight vermelhos) + fitBounds. Passar todos oscodareafiltrados como highlight pintaria a TI inteira com stroke grosso. Rejeitado:highlightKeys={Object.keys(...)}(ruído visual); esconder GeoJSON fora do filtro (muda o contrato B7 / rabbit hole). - Chaves =
Object.keys(bundle.plazasByIbgeCode)— footprint estável do conjunto já escopado (access + B7), independente deyear/scaleMode/displayValues. Rejeitado: chaves dedisplayValues(troca de ano re-zooma); só quando a URL tem filtro explícito (assessor com poucas Praças sem?region=também precisa aproximar). fitBoundssó quando a identidade defitToKeysmuda (string canônica sorted join), não a cada rebuild de layer porvalues. Separar do efeito que reaplica estilo/dados, ou early-return se o footprint não mudou. Rejeitado: deixar o fit dentro do efeito atual ligado avalues(B11/ano resetam o pan do usuário).- i18n e naming (AGENTS.md):
fitToKeys,fitKey/fitBoundsKey; strings visíveis inalteradas neste item.
Questões em aberto
- Botão “Ver Bahia toda” / reset de viewport? Opções: A) não neste item (pan/zoom Leaflet + limpar filtro bastam) | B) controle explícito. Recomendação: A — appetite; revisitar se a coordenação pedir após usar o fit automático. (assumido — validar no craft)
- Limiar para não “aproximar” (ex. >N municípios ≈ Bahia)? Opções: A) sempre
fitBoundsnas chaves (N grande ≈ Bahia) | B) sekeys.length > threshold, forçarBAHIA_BOUNDS. Recomendação: A no v1 — menos knobs; B só se profiling/UX mostrar jitter no fit de ~400 features. maxZoom/ padding? Opções: A) mantermaxZoom: 10,padding: [24, 24]do caminho highlight | B) tunar. Recomendação: A; polish só se um município único ficar apertado demais no craft.
Abordagem proposta
flowchart LR
bundle["PlazaMapBundle.plazasByIbgeCode"] --> panel["PlazaMapPanel"]
panel -->|"fitToKeys = Object.keys(...)"| map["BahiaMap"]
map -->|"fitKey mudou"| fit["map.fitBounds(features)"]
map -->|"só values/ano/escala"| style["rebuild layer / setStyle — sem re-fit"]
Componentes:
BahiaMap(src/components/campaign/BahiaMap.tsx): propsfitToKeys?: string[]einteractiveKeys?: string[](default[]= fit Bahia / tudo interativo). Efeito quandocanonicalMapKeysKey(fitToKeys)muda →fitMapToHighlights(sem alterar estilo).interactiveKeyscom gate em handlers +interactive: falsenos paths fora do set. Hover stroke-only + clear síncrono no mouseout. ReusafitMapToHighlightsecanonicalMapKeysKeyembahiaMapStyle.ts.PlazaMapPanel(src/components/campaign/PlazaMapPanel.tsx): memoscopedKeys = Object.keys(bundle.plazasByIbgeCode)→fitToKeys+interactiveKeys. Não passar as mesmas chaves emhighlightKeys.- Teste: unit do helper de chave canônica / “quando fitKey muda”; checklist manual: filtrar TI → aproxima; limpar filtros → Bahia; trocar Ano/Escala → viewport estável; assessor com poucas Praças → aproxima sem filtro URL.
- Migration: Sem migration, sem collection, sem server action.
Dependências
- Dura: R2 (mapa) + B7 (conjunto filtrado no bundle) — ambos entregues.
- Suave: nenhuma. B6 (
setStyle) e B8 (polígonos-zona) são independentes; B8 pode no futuro refinar fit em SSA/CMS, fora deste item. - Reusa:
BahiaMapfitBounds existente,plazasByIbgeCodedo B10/B7, geometriasbahiaGeometries.
Não escopo
- Filtrar / omitir dados do mapa → B7 (já entregue).
setStyleincremental / perf de rebuild → B6 (escala-dry-pos-b3.md).- Polígonos Praças-zona SSA/CMS (fit por zona) → B8 (poligonos-pracas-zona.md).
- Mover filtros acima do mapa / polish visual → R6.
- Esconder polígonos cinza fora do filtro; animação
flyToobrigatória.
Rabbit holes
- Acoplar zoom a
highlightKeys. Se alguém “só passar as chaves”: stroke vermelho em dezenas de municípios. Mitigação: propfitToKeyssó para viewport. - Re-fit a cada
values. Troca de ano/escala (B11) ou hover rebuild reseta o pan. Mitigação: dependência só da identidade defitToKeys. - Dissolver polígonos / PostGIS / clip do layer. Mitigação: só
fitBounds; geometria continua Bahia inteira. - Fit por Praça-zona em Salvador/Camaçari. Sem polígono de zona o bbox é o município. Mitigação: aceitar agregado municipal até B8.
Adiado com gatilho
- Controle “Ver Bahia toda”. Revisitar se, após B12, usuários pedirem reset sem limpar filtros.
- Threshold N→
BAHIA_BOUNDS. Revisitar se fit em ~400codareacausar jank perceptível. - Restyle diff só nos paths cujo
interactivemudou. Revisitar se troca frequente de filtro causar jank no O(n)restyleAllPaths(hoje full pass quandointeractiveKeymuda). flyTo/animate: true. Revisitar se critique pedir transição; default LeafletfitBoundsbasta no v1.
Referências
docs/roadmap.md(Trilha B, item B12; gatilho de B7)docs/plans/mapa-pracas-filtrado.md— AdiadofitBounds(gatilho disparado 2026-07-21)src/components/campaign/BahiaMap.tsx—BAHIA_BOUNDS, fit emhighlightKeys(linhas ~310–333)src/components/campaign/PlazaMapPanel.tsx—<BahiaMap>sem viewport keys hojesrc/utilities/plazaMapData.ts—PlazaMapBundle.plazasByIbgeCodesrc/lib/bahiaGeometries.ts—getMunicipalityFeature- AGENTS.md — Campaign map / naming
PRODUCT.md/DESIGN.md— Field Desk; mapa como instrumento de coordenação