mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 15:13:07 +00:00
Merge pull request #628 from fsolla/plans/plan-issue-30
plans(C111,C112,B197): telefone não único, múltiplos telefones, e-mail oculto por padrão
This commit is contained in:
commit
f44254cea5
3 changed files with 364 additions and 0 deletions
118
docs/plans/multiplos-telefones-por-pessoa.md
Normal file
118
docs/plans/multiplos-telefones-por-pessoa.md
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
# Múltiplos telefones por pessoa
|
||||
|
||||
Status: registrado (blocked até plano em main)
|
||||
Atualizado em: 2026-08-10
|
||||
Issue: #626
|
||||
Priority: P2
|
||||
Model: composer-2.5
|
||||
Impeccable: B — encaixe: formulários de criação/edição de pessoa + ficha (detalhe) + listas existentes
|
||||
Canvas UI: /home/fsolla/.cursor/projects/home-fsolla-cursor-worktrees-teqo-plans-plan-issue-30/canvases/plan-c112-ui-draft.canvas.tsx
|
||||
Appetite: ~1–2 dias eng; encaixe no modelo de pessoa existente
|
||||
Responsável: —
|
||||
|
||||
## Intenção
|
||||
|
||||
Uma pessoa pode ter mais de um celular — o pessoal e o do comitê, o número que
|
||||
troca e o antigo que ainda recebe WhatsApp. Hoje a ficha aceita um único número
|
||||
e a mesa tem de escolher qual guardar. Queremos cadastrar **N telefones por
|
||||
pessoa**, com as listas continuando compactas (mostram o principal) e a ficha
|
||||
mostrando todos. Pré-requisito: telefones deixam de ser únicos (item **C111**).
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Persona / contexto:** staff da mesa (coordenação e assessores) editando a
|
||||
ficha de uma pessoa — liderança, apoiador, dobradinha, assessor, pessoa.
|
||||
- **Job principal:** registrar todos os números de contato de uma pessoa, sem
|
||||
perder informação e sem poluir as listas.
|
||||
- **Fluxo desejado:** abre a ficha da liderança → vê os dois telefones dela →
|
||||
adiciona um terceiro → salva → a lista mostra o principal; a ficha mostra
|
||||
todos; WhatsApp e convite usam o principal.
|
||||
- **Anti-goals de produto:** não é CRUD de agenda telefônica (sem rótulos
|
||||
"casa/trabalho", sem tipo fixo/móvel, sem reordenação por arrasto); o import
|
||||
CSV continua com uma coluna de telefone (mapeia no principal).
|
||||
|
||||
### Esboço de fluxo (B — ver canvas)
|
||||
|
||||
```text
|
||||
[ficha da pessoa] → vê telefones (principal primeiro) → "+ Adicionar telefone"
|
||||
→ salva → lista: mostra o principal · ficha: mostra todos · WhatsApp/convite: principal
|
||||
```
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- Uma pessoa pode ter **2+ telefones** cadastrados e editáveis nas cinco
|
||||
superfícies de pessoa: ficha/detalhe, criação/edição de liderança, apoiador,
|
||||
dobradinha e assessor.
|
||||
- As listas de pessoas continuam mostrando **um** telefone por linha (o
|
||||
principal); a ficha mostra todos.
|
||||
- WhatsApp (`wa.me`), convite e o import CSV usam o **principal** (o import só
|
||||
tem uma coluna).
|
||||
- A busca por telefone encontra a pessoa por **qualquer** um dos números.
|
||||
- Guardrail: os telefones continuam **não únicos** entre pessoas (C111) — duas
|
||||
pessoas podem compartilhar um número, e cada uma mantém seus demais números.
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
Dados: N/A — nenhuma métrica; a mudança é de cadastro e exibição de contato.
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** `src/collections/Contact.ts` (campo de telefones),
|
||||
formulários de pessoa (`src/app/(campaign)/campanha/(app)/{liderancas,apoiadores,dobradinhas,assessores,pessoas}/`),
|
||||
fichas/detalhes, view models das listas (`src/utilities/*ViewModels`),
|
||||
`src/app/(campaign)/campanha/actions/…` (escrita), import CSV
|
||||
(`supporterImport`), `src/lib/phone.ts` (normalização).
|
||||
- **Precedente a olhar:** C99/C100 (ficha `Contact` como identidade), B163
|
||||
(edição inline de contato em dobradinhas), C6 (import de apoiadores),
|
||||
C111 (telefone não único — dependência).
|
||||
- **Risco de acoplamento:** o telefone é chave em fluxos automáticos (import,
|
||||
convite, login de liderança) — o "principal" precisa ser estável para não
|
||||
mudar de número a cada edição; e a mudança toca as mesmas páginas de lista do
|
||||
item **B197** (colunas) — não rodar em paralelo.
|
||||
|
||||
## Dependências
|
||||
|
||||
- **C111** (telefone não único) — dura: múltiplos telefones pressupõem que
|
||||
números compartilhados entre pessoas são permitidos.
|
||||
- Serializa com **B197** (mesmas páginas de lista).
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- Rótulos de telefone (casa/trabalho/whatsapp) e tipo (fixo/móvel) — sem label.
|
||||
- Reordenação visual por arrasto; "definir principal" por controle explícito
|
||||
(a ordem da lista é a prioridade).
|
||||
- Múltiplos telefones no import CSV (a planilha continua com uma coluna).
|
||||
- Trocar a chave de login da liderança (continua o principal).
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- **"Telefone com rótulo + tipo + principal explícito".** Vira CRUD de agenda
|
||||
telefônica com controle extra em todo form. **Corte neste item:** ordem =
|
||||
prioridade, sem labels, um input repetível.
|
||||
- **"Mostrar todos os telefones nas listas".** Polui a linha e fura o pedido
|
||||
implícito de lista compacta. **Corte:** lista mostra o principal; a ficha é o
|
||||
lugar de todos.
|
||||
|
||||
## Questões em aberto (produto)
|
||||
|
||||
- **O que define o telefone "principal"?** **Opções:** A) o primeiro da lista —
|
||||
ordem = prioridade, sem controle extra na UI; B) flag explícita "principal"
|
||||
com controle dedicado. **Recomendação: A** — menos UI, e trocar o principal é
|
||||
editar a ordem; se a mesa pedir reordenação, vira item futuro. _(assumido —
|
||||
validar com produto)_
|
||||
- **Onde se adiciona telefone?** **Opções:** A) nos formulários de
|
||||
criação/edição ("+ Adicionar telefone", repetível) e na ficha; B) só na ficha.
|
||||
**Recomendação: A** — quem cria a pessoa já informa os números que tem; sem
|
||||
volta à ficha para completar. _(assumido — validar com produto)_
|
||||
- **Telefones com número repetido na MESMA pessoa (dedupe interno)?**
|
||||
**Opções:** A) impede salvar o mesmo número duas vezes na mesma ficha; B)
|
||||
permite (deixar para a mesa limpar). **Recomendação: A** — custo baixo,
|
||||
evita lista suja; o bloqueio é só dentro da própria ficha, nunca entre
|
||||
pessoas. _(assumido — validar com produto)_
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue (após registro)
|
||||
- Canvas UI (gate): `plan-c112-ui-draft.canvas.tsx`
|
||||
- C111 `docs/plans/telefone-nao-unico.md` (dependência) · C99/C100 · B163
|
||||
- `src/collections/Contact.ts` · `src/lib/phone.ts`
|
||||
126
docs/plans/ocultar-email-por-padrao-listas.md
Normal file
126
docs/plans/ocultar-email-por-padrao-listas.md
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
# Ocultar a coluna de e-mail por padrão nas listas de pessoas
|
||||
|
||||
Status: registrado (blocked até plano em main)
|
||||
Atualizado em: 2026-08-10
|
||||
Issue: #627
|
||||
Priority: P2
|
||||
Model: composer-2.5
|
||||
Impeccable: B — encaixe: seletor de colunas existente (B17) + defaults por lista; sem rota nova
|
||||
Canvas UI: /home/fsolla/.cursor/projects/home-fsolla-cursor-worktrees-teqo-plans-plan-issue-30/canvases/plan-b197-ui-draft.canvas.tsx
|
||||
Appetite: ~0,5–1 dia eng; defaults + um split de coluna (pessoas) + um encaixe (assessores)
|
||||
Responsável: —
|
||||
|
||||
## Intenção
|
||||
|
||||
As listas de pessoas — pessoas, lideranças, dobradinhas, assessores e apoiadores
|
||||
— mostram o e-mail como coluna sempre visível. No dia a dia da mesa o canal real
|
||||
é telefone/WhatsApp; o e-mail é o dado menos consultado e ocupa largura em cinco
|
||||
telas. Queremos que a coluna de e-mail **comece oculta por padrão** nessas
|
||||
listas, com o usuário podendo **ligá-la manualmente** pelo seletor de colunas —
|
||||
mecânica que já existe em `/campanha` (usada em Municípios, Territórios etc.).
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Persona / contexto:** staff da mesa (coordenação e assessores) navegando as
|
||||
listas de pessoas para gestão diária.
|
||||
- **Job principal:** ler a lista sem ruído (nome + telefone), e ter e-mail à mão
|
||||
quando precisar, sem pedir para ninguém.
|
||||
- **Fluxo desejado:** abre `/campanha/liderancas` → sem coluna de e-mail → quer
|
||||
ver → abre o seletor de colunas → liga "E-mail" → a escolha fica salva naquele
|
||||
dispositivo, como já acontece hoje.
|
||||
- **Anti-goals de produto:** não reordenar colunas, não redesenhar as tabelas,
|
||||
não mexer nas fichas/detalhes, não mudar o e-mail no card mobile (não há
|
||||
colunas lá).
|
||||
|
||||
### Esboço de fluxo (B — ver canvas)
|
||||
|
||||
```text
|
||||
[lista de pessoas] → e-mail oculto por padrão → [seletor de colunas] → liga E-mail
|
||||
→ coluna aparece e fica lembrada no dispositivo → (desliga de novo quando quiser)
|
||||
```
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- Nas **cinco listas** (pessoas, lideranças, dobradinhas, assessores, apoiadores)
|
||||
a coluna de e-mail começa oculta para quem nunca mexeu no seletor de colunas.
|
||||
- Em todas, o usuário pode **religar** o e-mail manualmente (seletor de colunas
|
||||
existente), com a escolha lembrada por dispositivo — mesma mecânica atual.
|
||||
- Nas listas que já têm o seletor (lideranças, dobradinhas, pessoas, apoiadores),
|
||||
só muda o **default**; nenhuma outra coluna muda de ordem ou visibilidade.
|
||||
- Na lista de assessores, o e-mail passa a ser ocultável (hoje não há seletor);
|
||||
default oculto, religável.
|
||||
- Na lista de pessoas, o e-mail deixa de ficar embutido na coluna "Contato" e
|
||||
vira coluna própria, oculta por padrão — a coluna "Contato" fica só com o
|
||||
telefone. (Na ficha/mobile nada muda.)
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
Dados: N/A — nenhuma métrica; a mudança é de apresentação de colunas.
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** `src/lib/campaignColumnVisibility.ts` (defaults por
|
||||
lista — mecanismo B17 já existente), páginas
|
||||
`src/app/(campaign)/campanha/(app)/{liderancas,dobradinhas,pessoas,apoiadores,assessores}/`
|
||||
e os componentes de lista (`src/components/campaign/{leadership,stateDeputy,people,supporter,advisor}/`).
|
||||
- **Precedente a olhar:** B17 (`docs/plans/seletor-colunas-lista-municipios.md` —
|
||||
mecanismo de ocultar colunas), B28 (`email-celular-lista-liderancas.md` —
|
||||
coluna de e-mail em lideranças), B163 (dobradinhas), C100
|
||||
(`pessoas-lista-unificada.md` — coluna "Contato" com telefone+e-mail na mesma
|
||||
célula, decisão que este item reabre).
|
||||
- **Risco de acoplamento:** a lista de assessores usa tabela própria (sem o
|
||||
seletor); o item deve trazer a mesma mecânica de colunas para lá — sem criar
|
||||
um segundo padrão. Mesmas páginas que o item **C112** (telefones) toca — não
|
||||
rodar em paralelo.
|
||||
|
||||
## Dependências
|
||||
|
||||
- Nenhuma dura. Serializa com **C112** (múltiplos telefones — mesmas páginas de
|
||||
lista).
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- Reordenação de colunas (por arrasto ou não).
|
||||
- Redesenho das tabelas (cards mobile, larguras, densidade).
|
||||
- Ocultar e-mail nas **fichas/detalhes** ou nos cards mobile — o pedido é de
|
||||
colunas de lista.
|
||||
- Ocultar qualquer outra coluna (telefone, municípios etc.).
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- **"Já que vamos mexer, esconder também telefone/municípios".** Escopo
|
||||
explode e mexe em leitura de gestão. **Corte neste item:** só e-mail.
|
||||
- **"Redesenhar a tabela de assessores para caber no padrão".** O pedido é
|
||||
visibilidade de coluna, não refactor da superfície. **Corte:** usar a
|
||||
mecânica de ocultar/religar sem reescrever a tabela.
|
||||
|
||||
## Questões em aberto (produto)
|
||||
|
||||
- **Pessoas (C100) hoje mostra o e-mail dentro da coluna "Contato" (telefone em
|
||||
destaque, e-mail embaixo). Ocultar "a coluna de e-mail" lá = separar o e-mail
|
||||
numa coluna própria?** **Opções:** A) sim — coluna "E-mail" própria (como
|
||||
lideranças/dobradinhas), oculta por padrão; B) esconder só a linha de e-mail
|
||||
dentro da célula (fora da mecânica de colunas). **Recomendação: A** —
|
||||
consistência entre as listas; quem religa ganha coluna igual às outras.
|
||||
_(assumido — validar com produto)_
|
||||
- **Apoiadores hoje não tem coluna de e-mail na lista (só na ficha).** **Opções:**
|
||||
A) adicionar a coluna "E-mail" (oculta por padrão) — completa o pedido;
|
||||
B) nada a esconder — não mexer. **Recomendação: A** — o pedido nomeia
|
||||
apoiadores; a coluna nasce oculta e quem quiser liga. _(assumido — validar
|
||||
com produto)_
|
||||
- **Assessores não tem o seletor de colunas.** **Opções:** A) trazer a mesma
|
||||
mecânica B17 para a tabela de assessores (ocultar por padrão + religar);
|
||||
B) ocultar o e-mail fixo, sem como religar. **Recomendação: A** — sem religar,
|
||||
o "ativar manualmente se preferir" não existe nessa lista. _(assumido —
|
||||
validar com produto)_
|
||||
- **Quem já tem escolha salva no dispositivo (cookie do seletor) continua com o
|
||||
e-mail visível?** **Recomendação: sim** — o default vale para quem nunca
|
||||
tocou no seletor; a escolha existente é respeitada (contrato atual do
|
||||
mecanismo). _(assumido — validar com produto)_
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue (após registro)
|
||||
- Canvas UI (gate): `plan-b197-ui-draft.canvas.tsx`
|
||||
- B17 `docs/plans/seletor-colunas-lista-municipios.md` · B28 `docs/plans/email-celular-lista-liderancas.md` · C100 `docs/plans/pessoas-lista-unificada.md`
|
||||
- `src/lib/campaignColumnVisibility.ts` · `src/components/campaign/advisor/AdvisorsTable.tsx`
|
||||
120
docs/plans/telefone-nao-unico.md
Normal file
120
docs/plans/telefone-nao-unico.md
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
# Telefone não único: duas pessoas podem compartilhar o mesmo celular
|
||||
|
||||
Status: registrado (blocked até plano em main)
|
||||
Atualizado em: 2026-08-10
|
||||
Issue: #625
|
||||
Priority: P1
|
||||
Model: cursor-grok-4.5-medium
|
||||
Impeccable: A — N/A (nenhuma superfície nova; comportamento de escrita, sem UI)
|
||||
Canvas UI: N/A — sem UI
|
||||
Appetite: ~0,5–1 dia eng; um outcome verificável
|
||||
Responsável: —
|
||||
|
||||
## Intenção
|
||||
|
||||
Hoje o sistema recusa salvar uma pessoa cujo celular já pertence a outro contato
|
||||
("Já existe outro contato com este celular"). Na prática, números compartilhados
|
||||
são comuns — aparelho de família, número do comitê, número que passou de mão — e
|
||||
a recusa trava o fluxo de gestão da mesa: a ficha não salva, o assessor fica sem
|
||||
saída e inventa um número errado ou deixa a pessoa sem telefone. O telefone é um
|
||||
**canal de contato**, não a identidade da pessoa — a identidade é a ficha `Contact`
|
||||
(entrega C99). Queremos que duas pessoas possam ter o mesmo número, sem bloquear
|
||||
nenhum fluxo de cadastro ou edição.
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Persona / contexto:** staff da mesa (coordenação e assessores) cadastrando e
|
||||
editando pessoas — lideranças, apoiadores, dobradinhas, assessores — além do
|
||||
fluxo de importação de apoiadores por CSV.
|
||||
- **Job principal:** salvar a ficha de uma pessoa com o número real dela, mesmo
|
||||
que outra pessoa já use o mesmo número.
|
||||
- **Fluxo desejado:** a assessora salva a liderança Ana com o celular que já é do
|
||||
comitê → **salva sem erro** → a ficha fica completa com o número real. A busca
|
||||
por telefone continua encontrando as duas pessoas. Fluxos automáticos (import,
|
||||
convite) tratam números compartilhados **sem adivinhar** de quem são.
|
||||
- **Anti-goals de produto:** esta entrega não reconcilia fichas duplicadas do
|
||||
histórico (fora de escopo, pós-eleição); não muda o que as listas exibem; não
|
||||
cria um "identificador" novo para a pessoa.
|
||||
|
||||
### Esboço de fluxo (A — omitido; sem UI nova)
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- Cadastrar ou editar uma pessoa com telefone igual ao de outra pessoa **salva
|
||||
sem erro**, em qualquer um dos cinco fluxos de escrita de pessoa (liderança,
|
||||
apoiador, dobradinha, assessor, pessoa).
|
||||
- As mensagens de erro de conflito de celular ("já existe outro contato…")
|
||||
deixam de aparecer nos fluxos de gestão.
|
||||
- Fluxos automáticos que usam o telefone como chave (import CSV, convite por
|
||||
telefone, login de liderança) continuam funcionando; quando o número é
|
||||
compartilhado, eles **falham fechado com mensagem clara** ou usam a chave que
|
||||
não é ambígua — nunca "chutam" qual pessoa.
|
||||
- Nenhum outro campo de `Contact` muda; a busca por telefone continua achando
|
||||
todas as pessoas com aquele número.
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
Dados: N/A — nenhuma métrica nova; a mudança é de escrita e matching de contato.
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** `src/utilities/contactPhoneInvariant.ts` (regra de
|
||||
unicidade e locks), `src/collections/Contact.ts` (hook de validação),
|
||||
`src/collections/CampaignUser.ts` (sincronização conta↔ficha),
|
||||
`src/utilities/campaignInviteRedemption.ts` (login/convite por telefone),
|
||||
`src/app/(campaign)/campanha/actions/supporterImport.ts` (dedupe do CSV),
|
||||
forms de liderança/apoiador/dobradinha/assessor/pessoa.
|
||||
- **Precedente a olhar:** C99 (`docs/plans/pessoas-identidade-contact.md`) —
|
||||
declarou o telefone como chave de dedupe da ficha; esta entrega reabre essa
|
||||
política por pedido do produto; C100 (lista de pessoas).
|
||||
- **Risco de acoplamento:** o telefone é hoje a chave "pessoa ↔ ficha" em vários
|
||||
fluxos (import, convite, resolução de conta). Cada fluxo precisa de um
|
||||
comportamento definido para números compartilhados — sem criar identidade
|
||||
ambígua nem bloquear a gestão.
|
||||
|
||||
## Dependências
|
||||
|
||||
- Nenhuma dura. Não deve rodar em paralelo com trabalho que edite os mesmos
|
||||
arquivos de escrita de pessoa (ver `serializes` na Issue).
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- Múltiplos telefones por pessoa → item **C112** (dependente deste).
|
||||
- Reconciliação de fichas duplicadas existentes (mesma pessoa em duas fichas) —
|
||||
aceita e visível; reconciliação segue pós-eleição.
|
||||
- Mudar o que as listas mostram (telefone principal, colunas) → fora.
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- **"Já que vamos desbloquear, deduplicar as fichas existentes".** Explosão de
|
||||
escopo e risco em janela eleitoral. **Corte neste item:** só o comportamento de
|
||||
escrita; reconciliação segue pós-eleição.
|
||||
- **"Telefone vira chave solta: import passa a criar ficha nova sempre".**
|
||||
Perde o casamento pessoa↔ficha do CSV. **Corte:** matching por telefone
|
||||
continua onde existe, com falha fechada na ambiguidade.
|
||||
|
||||
## Questões em aberto (produto)
|
||||
|
||||
- **Import CSV casa linhas por telefone; com números compartilhados, o que o
|
||||
import faz?** **Opções:** A) mantém o casamento por telefone e falha fechado
|
||||
quando o número pertence a mais de um contato — a linha fica sinalizada para
|
||||
resolução manual; B) para de casar por telefone e cria fichas novas. **Recomendação:
|
||||
A** — o casamento por telefone é o jeito mais confiável de reencontrar a
|
||||
pessoa no re-import; ambiguidade pede decisão humana, nunca chute. _(assumido —
|
||||
validar com produto)_
|
||||
- **Login de liderança é pelo celular (nome de usuário da conta). Duas
|
||||
lideranças com o mesmo número: a segunda entra como?** **Opções:** A) a conta
|
||||
continua única — quem não tem número exclusivo usa e-mail para entrar;
|
||||
B) bloqueia criar a segunda conta com o mesmo número. **Recomendação: A** —
|
||||
o login é de conta, não de pessoa; o bloqueio de conta recriaria o problema
|
||||
que esta entrega resolve. _(assumido — validar com produto)_
|
||||
- **Convite por telefone para número compartilhado:** a quem o convite vincula?
|
||||
**Opções:** A) falha fechado pedindo escolher a ficha; B) vincula à ficha de
|
||||
quem gerou o convite (o convite nasce de uma ficha). **Recomendação: B** — o
|
||||
convite já é gerado a partir de uma pessoa; o número é só o canal de envio.
|
||||
|
||||
## Referências
|
||||
|
||||
- C99 `docs/plans/pessoas-identidade-contact.md` · C100 `docs/plans/pessoas-lista-unificada.md`
|
||||
- C6 `docs/plans/escala-dry-pos-c6.md` (import com dedupe por telefone)
|
||||
- `src/utilities/contactPhoneInvariant.ts` (regra atual a reavaliar)
|
||||
Loading…
Reference in a new issue