Contact.phone deixa de ser único em enforcement (nunca houve constraint DB):
- remove o hook enforceUniqueContactPhone e os asserts assertContactPhone*
(conflicts/ambiguity) — os 5 fluxos de escrita de pessoa salvam com número
compartilhado; rename contactPhoneInvariant.ts -> contactPhoneLocks.ts
(locks passam a significar serialização, não unicidade)
- findOrCreateContactByPhone: 0 fichas cria, 1 reusa (dedupe C6/C99),
2+ cria ficha nova (a identidade da pessoa em criação é a ficha nova)
- convite autofill/login: ficha ancorada pode compartilhar o phone; o lado
conta permanece fail-closed (username DB-unique; check de 2+ contas)
- import CSV: preview sinaliza telefone_compartilhado (resolução manual);
confirm/bulk abortam fail-closed se um phone ganhar 2+ fichas (race)
- fix de achado de execução: supporter_import_batch.actor_id NOT NULL com
FK ON DELETE set null derrubava o delete de campaignUser com batch
órfão (23502) — CampaignUser.beforeDelete limpa batches + fixture
cleanup descobre/deleta batches dos accounts owned
436 seeded Praças (municipality-based; per-TSE-zone in Salvador/Camaçari) become
the operational unit; roles renamed to coordinator/advisor/leader with advisors
scoped to administered Praças. Leadership is one record per person across many
Praças/organizations; vote pledges split leader-declared vs staff-estimated
(estimates never serialized to leaders). Adds organizations, demand workflow
with staff-only cost/receipts, action-plan results with deputy presence, manual
political trend, multi-candidate comparison and the diverging red/white/blue
map mode. Migration 20260721_020109_remodel_plazas deliberately resets the
campaign vertical in production (public site untouched); test suite ported to
the new model (unit 187 / int 306 / e2e 9 green).
Adds electoral nuclei, leaderships, updates, and WhatsApp invite flows behind campaign auth, plus the consolidated schema migration that Vercel applies on deploy.