Commit graph

14 commits

Author SHA1 Message Date
Francisco Solla
e71b062650 feat(C139): schemas e actions de contato — criação staff e edição por célula
Fase 3 (server) do plano aprovado:
- schemas/contact.ts: contactCreateSchema (nome único via invariante, state
  obrigatório, phones opcionais C112); contactFieldUpdateSchema ganha variantes
  city e postalCode ('' → clear); mensagens das actions client-safe aqui.
- schemas/personGenders.ts: enum de gênero em módulo folha (ciclo de imports
  contact ↔ leadership detectado e quebrado).
- actions/contact.ts: createContact (gate staff + bypass justificado, lock
  contact-name:{normalized}) e updateContactField (escopo 'edita o que vê'
  via re-check user-threaded para advisor; reorder de telefone primário).
  Apagar reusa as actions C100 existentes.
- collections Contact e Supporter: label de gênero 'Outro' → 'Não binário'
  (sem migration; nenhum teste pina a label).
- 11 testes unit novos; lint, tsc e prettier limpos.
2026-08-13 14:12:53 -03:00
Francisco Solla
6de8fad8f6 feat(C112): múltiplos telefones por pessoa — Contact.phones array (ordem = prioridade)
- Contact.phone (text único) → phones (array field Payload, subcampo value):
  fonte única; principal = phones[0]; beforeValidate normaliza, filtra vazios,
  rejeita inválido e duplicado DENTRO da ficha (C111 entre fichas preservado)
- migration add_contact_phones_array: backfill phone → phones[0] (gen_random_uuid)
  antes do drop da coluna + índice em value (hand-edit documentado; snapshot .json
  gerado mantém as colunas C99/C100 já existentes)
- primaryPhoneOf / phoneValuesOf / reorderWithPrimaryPhone em src/lib/phone.ts
  (ordem = prioridade; inline edit = seta o principal preservando o resto)
- findOrCreateContactByPhone aceita phones[] (dedupe pelo primário; reuse faz
  append dos faltantes; locks em todos os números digitados)
- sync conta→ficha (CampaignUser): phone da conta faz APPEND quando a ficha não
  tem (nunca reordena nem remove); tombstone LGPD substitui TODOS os telefones
- convite redemption: telefone digitado vira principal, demais preservados
- import CSV: preview sinaliza compartilhado também por número secundário;
  bulk insere contact_phones (JOIN nas leituras, uuid no insert)
- busca por telefone (apoiadores, pickers, combobox) casa qualquer número
- UI: PhonesFieldEditor compartilhado (repetível mascarado, remover, ↑/↓,
  modo inline com Salvar) nas 5 superfícies — liderança (form/ficha/lista),
  apoiador (form/ficha), dobradinha (ficha), assessor (ficha), wizard
- UI pública (petição/WhatsApp) intocada: zod e forms ficam com phone;
  as ações mapeiam phone → phones[0]
- testes: spec novo campaignMultiPhones (aceite completo), specs C111/C99
  atualizados, e2e wizard/apoiador ajustados
2026-08-11 10:47:02 -03:00
Francisco Solla
162a518416 feat(C111): telefone não único — duas pessoas podem compartilhar o mesmo celular
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
2026-08-10 23:03:05 -03:00
Francisco Ignácio Fontoura Solla
033c270a89 feat(campanha): B163 — editar contatos das dobradinhas 2026-08-06 16:52:55 -03:00
Francisco Ignácio Fontoura Solla
4806c417c8 Engineering Pass 3: consolidate patterns and lock them with guards.
Fold duplicated campanha access, loaders, list/filter/form shells, and scripts into shared modules; reorganize utilities by domain; stabilize e2e; and document prevention-first audit workflow so the same smells cannot creep back in.
2026-07-29 06:11:29 -03:00
Francisco Ignácio Fontoura Solla
e6f7c2e70f Tooling: prettier como autoridade de formatacao (organize-imports deterministico, scripts format/format:check, normalizacao mecanica de 312 arquivos; artefatos gerados e migrations excluidos via .prettierignore) 2026-07-25 17:22:20 -03:00
Francisco Ignácio Fontoura Solla
cf6ae6c47c Pass 2 W2: correcoes de fronteira lib/utilities e client boundary
- helpers puros movidos utilities->lib: slug, phone, wordStartFilter, voteEstimate (9 inversoes lib->utilities zeradas)
- chaves de consent em src/lib/campaignConsentKeys.ts (client-safe); campaignInvite/campaignConsent re-exportam; onda0ConsentTexts referencia as constantes
- 'server-only' em 21 loaders Payload/cache (CLI segue com --conditions=react-server)
- ciclo de tipos supporterListFilters <-> supporterUi quebrado (SupporterListFilterInput estrutural; sqlFilters idem)
- votePledgeData dividido: votePledgeViews (puro, client-safe) + votePledgeData (loaders, server-only) - padrao contract-module
- predicados de role client-safe em src/lib/campaignRoles.ts; access/shared deriva deles (fonte unica); nav.ts para de importar o barrel campaignAccess (casts 'as CampaignUser' eliminados)
2026-07-25 14:38:41 -03:00
Francisco Ignácio Fontoura Solla
0407f02ce2 Import projection-sheet strategy columns into municipalities (E4R fase 2)
- pnpm db:seed:projecao now also imports SITUAÇÃO -> politicalTrend,
  DOBRADINHAS -> stateDeputy + stateDeputies + dobradinhaNotes,
  LIDERANÇAS -> name-only contact + leadership (statewide slug dedupe),
  ASSESSOR RESPONSÁVEL -> campaignUser + advisors (Edizio=coordinator,
  Solla=candidate, placeholder @planilha.invalid emails),
  ENCAMINHAMENTOS -> nextSteps, OBSERVAÇÃO -> strengths/risks (curated).
  PRIORITÁRIAS overrides MAPA GERAL when non-empty; Salvador stays skipped;
  relationships are unions; re-run is idempotent.
- parseSituationCell + splitNameCell (noise/collective/action filters,
  honorific protection, parenthetical extraction) with unit tests.
- Contact.phone optional (migration 20260724_175500_contact_phone_optional);
  phone invariant hooks skip phone-less contacts; invite flows guard.
- candidate role now eligible for municipality/action-plan advisors
  (eligibleCampaignStaffWhere) per product decision.
2026-07-24 15:58:06 -03:00
Francisco Ignácio Fontoura Solla
9ccfb3b704 Simplify C6 supporter paths and register C8 scale/DRY follow-ups.
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.
2026-07-18 22:34:55 -03:00
Francisco Ignácio Fontoura Solla
9fdbae05d7 Add C6 scale/DRY for supporters: bulk import, KPI aggregate, shared shells.
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.
2026-07-18 22:17:31 -03:00
Francisco Ignácio Fontoura Solla
bcac665cb5 Ship /campanha nuclei MVP with RBAC, invites, and vote estimates.
Adds electoral nuclei, leaderships, updates, and WhatsApp invite flows behind campaign auth, plus the consolidated schema migration that Vercel applies on deploy.
2026-07-18 15:01:56 -03:00
Francisco Ignácio Fontoura Solla
f804da60eb Including page mandato-no-whatsapp 2026-03-14 18:07:40 -03:00
Francisco Ignácio Fontoura Solla
dac78163c3 feat: add petition form config and server-action submission flow
- add  group to  collection with title, subtitle, and required consent relationship
- refactor  to:
  - use a dedicated shared zod schema
  - submit via server action (create contact + signature)
  - register RHF fields and handle pending/error states
  - load city options from selected state
- add server action
- add shared schema
- replace state source in  collection: derive select options from
- make  immutable with  and remove obsolete
- update generated payload types for petition  and consent references
2026-02-22 23:08:00 -03:00
Francisco Ignácio Fontoura Solla
14961c5fea feat: overhaul petition UX, add contact/signature data model, and refresh shadcn theming
- redesign petition page layout with responsive hero, content section, and form card
  ()
- refactor frontend theming setup:
  - add  with  in frontend layout
  - migrate/clean global style tokens and base styles in
  - adjust header/social visuals for theme-aware rendering
  (, ,
   , , )
- expand petition form with additional fields and new UI primitives
  (native select, textarea, button, state/city flow)
  (, , , )
- add new Payload collections and wire them into config:
  , ,
  (, ,
   , ,
   )
- update petition collection admin grouping and project config
  (, , )
- add supporting dependency/lockfile updates and workspace tooling tweaks
  (, , , )
2026-02-22 20:02:51 -03:00