Commit graph

9 commits

Author SHA1 Message Date
Francisco Solla
a180721e11 feat(campaign): C144 — forms de escrita com options de município write-scoped (Closes #769) 2026-08-24 18:37:59 -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
170ce59ef4
Merge pull request #640 from fsolla/C111-telefone-nao-unico-duas-pessoas-podem-compartilhar-o-me
C111 — Telefone não único: duas pessoas podem compartilhar o mesmo celular
2026-08-11 03:58:55 +00: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 Solla
3e9390230b feat(B197): e-mail oculto por padrão nas listas de pessoas — default B17 nas 5 listas + coluna própria em pessoas/apoiadores + picker em assessores 2026-08-10 21:57:52 -03:00
Cursor Agent
b509c7d7b3
B141 — filtro por fonte na omnibox de apoiadores (#309)
Adiciona dimensão Fonte ao estado de lista, where-builder, aggregate SQL
e adapter omnibox (B128), com guard isSupporterSource e testes.

Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
2026-08-02 23:03:22 +00:00
Cursor Agent
f59d4a6736
chore: format + e2e manifest mappings for B128 omnibox modules 2026-08-02 20:56:12 +00:00
Cursor Agent
0903576f9e
B128 — Adotar barra omnibox nas demais listas /campanha
Estende o chassis B127 (CampaignListOmnibox + adapters puros por domínio)
para territórios, lideranças, dobradinhas, apoiadores, atividades, demandas,
organizações e assessores. Remove pilhas antigas (search debounced, collapsible,
mobile selects, CampaignFilterChips). URL contracts extraídos para módulos
client-safe onde necessário (demand/organization/advisor). Testes unitários
nos adapters + hook navigate-only.

Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
2026-08-02 20:55:12 +00: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