Meta Bom/Regular/Mínimo duplicated the estimate scenarios — keep a single municipality series (pessimista/média/otimista), backfill then drop the old columns, and map the spreadsheet onto expectedVotes.
- 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.
E2E-driven fixes (the suite now passes 9/9; two journeys remain
latency-flaky on cold dev compiles and pass on retry):
- leader home crashed with Forbidden since the remodel:
loadLeaderContactsPageData loaded municipality options through the
staff-scoped loader (leaders are denied municipality reads); their scope
now derives from the engaged leadership's linked municipalities
- leaders saw 'Contato — —' instead of their supporters' names:
getAccessibleContactIds now mirrors canReadSupporter for leaders
(contacts of supporters they created)
- leader nav had two items with the same /campanha href (duplicate React
keys); the leader home IS the contact tool — one entry
- RSC serialization contracts: CampaignListPagination is a server component
again (hrefForPage stays server-side; CampaignTransitionAnchor client leaf
intercepts clicks with serializable props); CampaignSearchForm takes
basePath instead of a function prop
- hasAnyEstimate moved from the 'use client' PledgeEstimateForm to
voteEstimate.ts — server components may not call client-module exports
- playwright.config honors TEQO_TEST_DATABASE_URL (parity with
vitest.setup.ts) and uses a fixed .next/e2e dist dir so Next stops
appending per-PID entries to tsconfig include; report artifacts
eslint-ignored
- .cursor/rules/engineering-standards.mdc (always applied): dead code dies
immediately (knip after every change), zero-warning gate, as-never ban with
the typed escape hatches, server-first composition and the client-safe
contract-module pattern, the caching ladder (React cache → unstable_cache +
tag → committed artifact), explicit collection access, lib vs utilities
convention, rule-of-three for abstractions
- AGENTS.md: hardening entry with pointers to the tracker/ledger/testing map;
drift fixed (TopoJSON decode is lazy, collections list post-remodel,
election-tse in the revalidate allowlist, knip in the verification
checklist); Known Gap #1 rewritten for the shipped access lockdown
- docs/roadmap.md: admin access item updated; engineering-debt section points
at TECH-DEBT.md
- tracker phases updated; removed two stale pre-rename file copies
- MunicipalityMapSelection leaf owns hover/selection: a mouseover re-renders
only the map + readout, not the whole panel (controls, legend, zone list);
Leaflet paint stays ref-based (B6)
- municípios list: MunicipalityEstimateScenarioProvider now wraps only the
results — scenario switches no longer re-render the filter controls
(dashboard already scoped it to the map)
- LeaderContactsPanel is a server component again: header + contacts table
render on the server; only LeaderContactForm (new client file) hydrates
- ledgered with rationale: map-bundle slimming deferred (gzip crushes the
repeating keys; instant year/scenario switching is a core analysis flow);
props-to-state effect mirrors reviewed and accepted as the correct
server-echo reconciliation pattern
Closes the 'Feel the action' gaps (.cursor/rules/campanha-action-feedback.mdc):
- BUG: action-plan task checkbox was optimistic but never revalidated — a
successful toggle visually reverted when the transition ended. The action
now revalidates the plan page; checkbox disables while pending
- map compare + candidate compare picker: optimistic select value +
useTransition; the map region dims with aria-busy and a live region
instead of flashing the full-page skeleton
- CampaignListPendingBoundary/CampaignListResults: one shared transition so
filters (municípios/apoiadores/planos), pagination, demandas status chips
(new CampaignFilterChips), and the name-search pages (new
CampaignSearchForm on lideranças/organizações/dobradinhas) dim the RESULTS
region, not only the control — children stay server-rendered (composition)
- streaming: dashboard map section behind Suspense (KPI shell paints first;
React cache() keeps the municipality scope shared, not reloaded);
municipality detail tabs (elections/leaderships/updates) stream below the
header; list-shaped loading.tsx for /municipios and /apoiadores
- logout button gets a pending state; BahiaMap init shows a visible spinner
(was sr-only)
- committed artifact src/lib/electionAggregates/bahia-federal-baseline.json
(Solla nominal + federal T1 valid votes per catalog municipality × TSE year,
Salvador split by zone) generated by pnpm build:election-aggregates from the
locally seeded TSE data; typed loader src/lib/bahiaElectionAggregates.ts;
snapshot spec pins artifact ↔ catalog ↔ baseline ticket
- map bundle: historical years now read the artifact (was 6 statewide
city×zone scans per dashboard visit); compare mode keeps only the OTHER
candidate on the DB path (Solla side from the artifact)
- loadMunicipalityScope (React cache()): one municipality find + pledge
aggregate per request shared by dashboard KPIs, map bundle, and the
municípios list overview (was 2-3 duplicate loads)
- unstable_cache + election-tse tag on the immutable elections-tab loaders
(baseline, candidate comparison, candidate options); tag added to the
/api/revalidate allowlist — runbook: re-seed then bust the tag
- municipalityMapContract.ts: client-safe map vocabulary/bundle types so the
client panel no longer imports the server data module (build had pulled
@payload-config into the client graph); municipalityMapData is server-only
and re-exports the contract; PLAZA_MAP_* renamed to MUNICIPALITY_MAP_*
- petition generateStaticParams enumerates bare ids (getPetitionIds)
- knip (files/deps at error level; unused exports ledgered as warn) with
config for Payload/Next entries; deleted the dead modules it confirmed:
RecentlyVisited + UpcomingActionPlansCard + actionPlanUpcomingPreview,
lazy-dialog helpers, tseZone, federalCandidateTotalsAggregate (test-only),
unused ui kit files, one-shot rename script; pruned unused radix deps and
typescript-eslint; added pg/@types/pg (pinned to drizzle's 8.10.2)
- GitHub Actions CI on the mirror: lint, typecheck, knip, unit, migrate, int
against a Postgres 17 service
- eslint: unused-vars with ^_ ignore patterns (migrations args exempt),
repo-wide ban on `as never` (no-restricted-syntax), lint gate at
--max-warnings=0; fixed all 54 pre-existing warnings (dead imports,
hooks deps, tracking-pixel img disable with impeccable config exception)
- tsconfig: include consolidated from 219 lines to 5 (wildcard covers all
.next dist variants), noUnusedLocals on
- typed replacements for every as-never: hookFilledCreateData (actions
create data completed by collection hooks), drizzle scopeColumn narrowing,
tests' stub<T> helper (property-level checking kept, completeness waived)
- test infra: leased-consent generalization used by onda0 spec (shared
leases over the stable consent keys; window race ledgered), purge fix
- docs: IMPROVE-CODE-QUALITY-PLAN.md tracker, TECH-DEBT.md ledger,
TESTING.md safety-net map (package.json also gains the Phase 2
build:election-aggregates script entry; the script lands next commit)
Replace the `Function`-typed payload param (no-unsafe-function-type lint error
blocking pre-push) with `Pick<Payload, 'find' | 'create'>`, which also surfaced
missing Lexical `version` fields in the consent fixture — now added.
Rename the operational unit "Praça"/"Núcleo" to "Município" (code identifier
`municipality`) and land the 2026-07-23 course changes:
- New `candidate` role with unrestricted visibility (`isCampaignStaff` now
includes it) alongside coordinator/advisor; leader is locked down to the
supporter contact tool only.
- Demandas become staff-only; dobradinhas modeled via a `stateDeputy` entity.
- Camaçari consolidated to a single município (ZE 170/171 aggregated);
Salvador keeps its 19 zone municípios.
- Map moves to the staff dashboard; `/campanha/municipios` is list/overview.
- Vote pledges keep the declared vs estimated (scenario) asymmetry; leaders
never see estimates.
Destructive migration for the campaign vertical (drops nucleus/plaza-era
tables, wipes campaign rows, seeds 435 municípios). Public-site data untouched.
Includes the post-delivery /simplify cleanups: shared reloadStaffActor /
reloadCoordinatorActor helpers, req.context cache for getFreshCampaignUser,
parallelized dashboard loads, candidate dashboard-copy fix, and dead
leader-dashboard / roleKind code removal.
Capture field evidence from the anchor session, update CUSTOMER/roadmap plans, and add vote-scenario and internal WhatsApp bridge specs with interview audio and transcripts.
Enables @payloadcms/plugin-import-export on signature (flattened contact/petition columns) and contact (native fields) so operations can download filtered lists for external ESP/SMS workflows.
Embeds approved literature→persona→interview research in docs/research/, adds inteligencia-campanha master plan with child specs, updates roadmap/PRODUCT/AGENTS, and extends roadmap skills with data-presentation guidance.
Dual-package setup keeps ESLint/editor on the TS 6 API while pnpm typecheck uses Go tsc 7.0.2; tsconfig drops deprecated baseUrl and adds ambient CSS module declarations.
Catch Next.js invalid-use-server-value at lint time and move shared form-error copy out of plazaStaffFormActions so the use server module only exports async actions.
Document the in-context editing default for /campanha staff surfaces in PRODUCT.md, a Cursor rule, the project notebook, and the roadmap plan template.
Unify list and /editar server actions in plazaStaffFormActions.ts so B9 inline edits and the edit page share one implementation without behavior changes.
Ship static zone-to-neighborhood mapping for Salvador/Camaçari Praças-zona, overview UI card, tests/fixture, and roadmap/plan updates including F2 prep follow-ups from capture-review-debts.
Keep GeoJSON stable across metric/scale/hover changes via pathByKeyRef and O(2) restyle; extract bahiaMapStyle helpers with unit tests and close B10/B11 perf debt refs in plans.
Promotes the deferred B7 fitBounds follow-up into its own roadmap item and plan so the map can zoom to the filtered region without re-zooming on year/scale changes.
Deduplicate pledge aggregation via loadPlazaListPageBundle, add plazaRevalidation with slug-scoped detail paths after inline saves, and document the fill-in as shipped.
Adds valid-votes denominators to the map bundle, a Total vs % dos válidos selector with fixed 0–100% coloring, and readout/legend alignment via scaleMax; updates roadmap and post-simplify debt docs.
Adds polygon highlight, vote readout, and navigation (desktop click / mobile 2nd tap) on the filtered Praças choropleth, with simplify cleanup and B6 plan updates for incremental setStyle.