Surface brancos/nulos/abstenções as mobilization opportunity on nucleus detail and list overview, with loader aggregate and unit tests; register pending int coverage in escala-dry-pos-e2.
Extract dashboard cards into focused components (queues, upcoming plans, leadership status, recently visited, choropleth legend), compile the roadmap for outcome-oriented tracking, document the customer job and improve-app journey, and tighten roadmap skills with decision-quality gates.
Fix header alignment and rhythm, swap Megaphone for CampaignLogo, add progressive disclosure for first access, and extract shared auth shells with corrected individual-account copy; record closed critique items in RS+.
Classify nuclei as defesa/ataque/indecisa/perdida from 2022 baseline share, surface Alert + overview distribution, and register post-simplify follow-ups in A7/E7 plans.
Surface majoritarian base conversion and proportional flip opportunity on nucleus detail and list overview, precompute ticketFlip on the baseline VM, and register post-simplify scale debts in A7 F5 and E7.
Replace full Local API federal T1 loads with drizzle GROUP BY on nucleus detail, gate election reads via assertCanReadElectionData, and absorb post-simplify cleanup into the A7 plan and roadmap.
Surface taxa de conversão on nucleus detail and list overview, with loader
optimizations and unit tests; update plan/roadmap follow-ups for E7, A7, and RS+.
Extract CampaignAuthPageShell and shared copy tokens across login, forgot-password, and reset-password flows; add adaptive inputMode, credential error a11y, and roadmap skill updates from the FD2 critique pass.
Wire husky with a typecheck script, await the async avatar update guard, harden Onda 0 consent unit tests, and extend the roadmap implementation skill with Impeccable UI gates.
Align the campaign desk with quieter KPI strips, queues-first dashboard, shared shells, and advanced filters; capture Impeccable design context and the remaining simplify/critique debts on the roadmap.
Deliver self-service forgot/reset via Resend, logged-in password change, and optional avatar on /campanha/perfil; register post-simplify engineering debts as RS+.
Wire schema, UI, aggregates, and tests for scenario goals, priority filter, staff-only dobradinha notes and next steps; register E6 scale follow-ups from simplify.
Bulk import and list paths get single-round-trip locks, drizzle returning reads, pg_trgm search, shared drizzleBulk helpers, and consolidated campaign formActions; simplify debts land as C9 in the roadmap.
Add denormalized task counters with list perf migration, shared territory FormData parsing, advisory locks on task/update mutations, and a shared contact-search guard; document what is still pending in the C7 plan and roadmap.
Apply the /simplify cleanup to the C6 commit (identity maps, dead branches,
relationshipId reuse, native base64url, rowCount fix, canManageCampaignUsers
reuse) and register the unimplemented debits as roadmap item C8 with its plan.
Phase 1 UX: StrictCombobox municipality in SupporterForm, AlertDialog in
RemoveSupporterDataButton. Phase 2 DRY: campaignListUrl + CampaignListPagination
+ campaignFormFields + mapCampaignFormActionError shared across nuclei,
supporters and action plans. Phase 3: single SQL aggregate for supporter list
KPIs via drizzle in the Payload txn. Phase 4: bulk drizzle insert for CSV import
inside the existing Payload txn with ON CONFLICT DO NOTHING, plus a fail-closed
skipContactPhoneInvariant context flag. Phase 5: HMAC-signed single-use import
token backed by a new supporterImportBatch staging collection so the full ok-row
set never crosses the Server Action boundary twice.
Next.js requires every export from a 'use server' module to be async; move the import type guard into a shared util and mark createSupporterRecord async. Also mark C2 as merged in the roadmap/docs.
Ship the supporter join collection, consent-keyed create/import/remove actions, and apoiadores UI so staff can build a phone-required nominal base before mass field ops.
Replace scalar region/city/neighborhood with hasMany arrays so nuclei can span multiple Bahia municipalities while keeping neighborhoods scoped to a single city.
Staff can open recipients for gerais, coordinators, and engaged leaderships without granting access, and coordenadores/lideranças can read geral phones for contact.
Adds electoral nuclei, leaderships, updates, and WhatsApp invite flows behind campaign auth, plus the consolidated schema migration that Vercel applies on deploy.
Introduce the internal campaign-management area gated by its own
authentication, kept isolated from the Payload admin so a campaign
session and an admin session can coexist in one browser.
- Add separate `campaignUser` auth collection (not `users` + roles)
- Authenticate via an isolated httpOnly `campaign-token` cookie scoped
to /campanha, distinct from the default `payload-token`
- Add loginCampaign/logoutCampaign server actions and getCampaignUser
session verification helper
- Add public login route and a protected (app) route group whose
layout enforces the auth barrier
- Add migration 20260716_010420_add_campaign_user and document the
auth foundation in AGENTS.md
Public post pages read through the `posts`-tagged unstable_cache wrappers,
so their data is frozen at build time until revalidateTag('posts') runs in
the deployed runtime. A direct-DB seed (pnpm db:seed:posts) writes past the
Payload afterChange hooks (next/cache is stubbed), so nothing busts the tag
in prod and seeded posts never surface publicly.
Add POST /api/revalidate, guarded by a REVALIDATE_SECRET shared secret
(constant-time compare), that calls revalidatePostsListing() to refresh the
home page, all listings, and all article routes at once. Document the env var
in .env.example; it must be set in Vercel for production.