diff --git a/docs/plans/demandas-responsaveis-ui-draft-criacao.png b/docs/plans/demandas-responsaveis-ui-draft-criacao.png new file mode 100644 index 00000000..403c969f Binary files /dev/null and b/docs/plans/demandas-responsaveis-ui-draft-criacao.png differ diff --git a/docs/plans/demandas-responsaveis-ui-draft-detalhe.png b/docs/plans/demandas-responsaveis-ui-draft-detalhe.png new file mode 100644 index 00000000..f3611090 Binary files /dev/null and b/docs/plans/demandas-responsaveis-ui-draft-detalhe.png differ diff --git a/docs/plans/demandas-responsaveis-ui-draft.html b/docs/plans/demandas-responsaveis-ui-draft.html new file mode 100644 index 00000000..df1afcaa --- /dev/null +++ b/docs/plans/demandas-responsaveis-ui-draft.html @@ -0,0 +1,126 @@ + + + + + + + UI draft — Demandas: responsáveis explícitos + + +
+

+ Demanda só aparece para candidato/coordenador e para quem está marcado como responsável — + nem assessor do município vê fora disso. Cenas: detalhe com seção Responsáveis + editor, + formulário de criação com sugestão. +

+ + +
+
+
+
+
+ Material de campanha + Em aberto +
+
Cartazes para a caminhada do fim de semana
+
Ilhéus · liderança: Nome da liderança
+
+
+ +
+
+
Descrição
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor + incididunt ut labore et dolore magna aliqua. +
+
+
Custo estimado
+
R$ 1.200,00
+
+
+
Comprovantes
+
2 anexos
+
+
+
Visível para
+
Responsáveis · Candidato · Coordenador
+
+
+ +
+
+
Responsáveis pela demanda
+
Só quem é responsável vê esta demanda
+
+
+ Assessora de campo + Outro assessor + +2 +
+
Adicionar responsável…
+
+ Criador já entra como responsável automaticamente. Assessores do município aparecem + como sugestão, mas só quem for marcado enxerga. +
+
+
+ +
+ Assessor do município que não é responsável: a demanda não aparece na lista dele nem abre + por URL — mesmo com permissão "Visão Tudo". +
+
+
+ + +
+
+
Nova demanda
+ +
+
+
+
Título
+
Cartazes para a caminhada do fim de semana
+
+
+
Município
+
+ Ilhéus + ▾ +
+
+
+
Tipo
+
+ Material de campanha + ▾ +
+
+
+ +
+
Responsáveis pela demanda
+
+ Você (criador) + Assessora de campo +
+
Buscar assessor…
+
+ Sugestões: assessores do município. Se ninguém for marcado além de você, só você, + candidato e coordenador verão a demanda. +
+
+
+ +
+
Cancelar
+
Criar demanda
+
+
+
+
+ + diff --git a/docs/plans/demandas-responsaveis.md b/docs/plans/demandas-responsaveis.md new file mode 100644 index 00000000..b85629ef --- /dev/null +++ b/docs/plans/demandas-responsaveis.md @@ -0,0 +1,88 @@ +# Demandas visíveis apenas para responsáveis explícitos + candidato/coordenador + +Status: aguardando execução +Atualizado em: 2026-08-19 +Issue: #106 +Priority: P1 +Model: cursor-grok-4.5-high +Impeccable: B — encaixe no detalhe de demanda (`/campanha/demandas/[slug]`) e na criação +Rascunho UI: docs/plans/demandas-responsaveis-ui-draft.html +Appetite: ~1–1,5 dias eng; campo de responsáveis + regra de visibilidade fail-closed +Responsável: — + +## Intenção + +Demandas carregam custo estimado e comprovantes (controle interno de gastos). Hoje **qualquer assessor que administra o município da demanda a vê** — e a mesa descobriu que isso é amplo demais: a demanda deve ser vista **só por quem é responsável por ela**, pelo candidato e pelo coordenador geral. Mesmo um assessor do município relacionado, se não estiver marcado como responsável, não vê. Decidido no gate (2026-08-19, opção B): responsável é **vínculo explícito por demanda**. + +## Persona e fluxo + +- **Persona / contexto:** Alex (Coordenador Geral) e o Candidato acompanhando custos e decisões; assessores responsáveis acompanhando "suas" demandas; assessores do município que NÃO devem esbarrar em demandas que não são deles. +- **Job principal:** quem cria a demanda (ou a coordenação) define os responsáveis; só eles — além de candidato/coordenador — enxergam e tocam a demanda. +- **Fluxo desejado:** + 1. Um assessor cria uma demanda no município da carteira: o formulário pede "Responsáveis pela demanda" (criador já vem marcado; sugestões = assessores do município). + 2. No detalhe da demanda, quem pode atualizá-la adiciona/remove responsáveis. + 3. Um assessor do município que não é responsável: a demanda não aparece na lista dele, não abre por URL e não aparece em buscas — sem erro "sem permissão", simplesmente não existe para ele. +- **Anti-goals de produto:** responsável herdado automaticamente do município (a decisão do gate foi explícita); visibilidade por município como default; auditoria de quem viu (fora de escopo). + +### Esboço de fluxo (B/C/D) + +```text +[criar demanda] → [campo "Responsáveis" — criador pré-marcado, sugestão do município] + → [criar] → [criador vira responsável; lista só para responsáveis + candidato/coordenador] +[detalhe] → [responsáveis gerenciam responsáveis] +[assessor não-responsável] → [demanda invisível: lista, URL e busca] +``` + +### Rascunho UI (B/C/D) + +![Rascunho UI — detalhe da demanda com seção Responsáveis](demandas-responsaveis-ui-draft-detalhe.png) + +![Rascunho UI — criação com campo Responsáveis](demandas-responsaveis-ui-draft-criacao.png) + +## Objetivo e aceite + +- A demanda tem um conjunto de **responsáveis** (pessoas da campanha); candidato e coordenador sempre a veem, responsável ou não. +- **Visibilidade fail-closed:** sem responsável marcado além do criador, a demanda é visível só ao criador + candidato/coordenador. Assessor do município relacionado, se não for responsável, **não vê** — nem na lista, nem por URL, nem na busca. +- O **criador** entra automaticamente como responsável (garante pelo menos um dono e que a criação não suma do criador). +- Quem pode **atualizar** a demanda pode gerenciar os responsáveis (mesma regra de visibilidade: responsáveis + candidato/coordenador). +- A criação pede os responsáveis (sugestão = assessores do município da demanda), mas não obriga além do criador. +- Guardrails: leader lockdown intacto (liderança nunca vê demandas); decisão de escalada continua candidato/coordenador; custo/comprovantes seguem a visibilidade da demanda. + +## Dados (intenção) + +- **Vou apresentar dados?** Não — regra de visibilidade e controle de acesso. +- **Decisões desbloqueadas:** coordenação decide quem acompanha cada demanda. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** campo de responsáveis na demanda em `src/collections/CampaignDemand.ts`; regra de leitura/atualização em `src/utilities/access/demands.ts` (hoje `canReadCampaignDemand` = escopo do município — passa a ser "unrestricted ou responsável"); server actions `src/app/(campaign)/campanha/actions/demand.ts`; UI do detalhe `src/components/campaign/demand/` e do fluxo de criação (registrar pedido). +- **Precedente a olhar:** o fragmento de escopo P3-D (não re-escrever o `{ municipality: { in: ids } }` por aí — a regra nova substitui o escopo municipal de demandas); `getFreshCampaignUser`/`memoizePerRequest` para a leitura por request; o padrão de "membership" de `municipality.advisors` para o controle de responsáveis. +- **Risco de acoplamento:** atividades geram demandas (C90) e a lista/omnibox de demandas filtra por escopo — a regra nova muda o que assessores veem em todos os pontos; o Sollinha usa as mesmas queries de demanda (escopo por user). + +## Dependências + +- Nenhuma dura. **Guardrail:** C141 (perfis por assessor) nunca contorna esta regra — Visão "Tudo" não abre demandas fora da responsabilidade. + +## Fora de escopo + +- Perfil de permissão por assessor (C141) e apresentação por perfil (C142). +- Notificação/feed ao ser marcado responsável. +- Auditoria de leituras da demanda. + +## Rabbit holes de produto + +- **"Responsável = assessor do município, simples."** Isso é exatamente o modelo de hoje, que o gate rejeitou. **Corte:** vínculo explícito; sugestões sim, herança automática não. +- **"Vou usar o histórico de quem criou."** `createdBy` existe, mas só o criador não cobre quem vai executar a demanda. **Corte:** campo próprio de responsáveis; criador vira um responsável, não o único. +- **"Vou esconder no cliente."** Esconder na UI não segura URL direta nem a API. **Corte:** regra no acesso de dados (fail-closed) — lista, URL e busca respeitam o mesmo where. + +## Questões em aberto (produto) + +Fechadas no gate. Assunções operacionais (sem pergunta nova): criador entra automaticamente como responsável; quem atualiza a demanda gerencia responsáveis; sugestões do campo = assessores do município da demanda; visível para = "Responsáveis · Candidato · Coordenador" (rótulo exibido no detalhe). _Assumidas — validar se contrariarem a mesa._ + +## Referências + +- Decisão do gate 2026-08-19 (resposta 1): responsáveis explícitos; assessor do município não-responsável não vê. +- Item irmão: `docs/plans/permissao-granular-assessores.md` (C141). +- Rascunho UI (gate): `docs/plans/demandas-responsaveis-ui-draft.html` + PNGs acima. +- Para abrir primeiro: `src/utilities/access/demands.ts`, `src/collections/CampaignDemand.ts`, `docs/plans/demandas-campanha.md`. +- `AGENTS.md` — convenção P3-D do escopo de assessor. diff --git a/docs/plans/permissao-granular-assessores-ui-draft-desktop.png b/docs/plans/permissao-granular-assessores-ui-draft-desktop.png new file mode 100644 index 00000000..b6e16b5d Binary files /dev/null and b/docs/plans/permissao-granular-assessores-ui-draft-desktop.png differ diff --git a/docs/plans/permissao-granular-assessores-ui-draft-detalhe.png b/docs/plans/permissao-granular-assessores-ui-draft-detalhe.png new file mode 100644 index 00000000..02d7f3f2 Binary files /dev/null and b/docs/plans/permissao-granular-assessores-ui-draft-detalhe.png differ diff --git a/docs/plans/permissao-granular-assessores-ui-draft-mobile.png b/docs/plans/permissao-granular-assessores-ui-draft-mobile.png new file mode 100644 index 00000000..4933490b Binary files /dev/null and b/docs/plans/permissao-granular-assessores-ui-draft-mobile.png differ diff --git a/docs/plans/permissao-granular-assessores-ui-draft.html b/docs/plans/permissao-granular-assessores-ui-draft.html new file mode 100644 index 00000000..390f92fd --- /dev/null +++ b/docs/plans/permissao-granular-assessores-ui-draft.html @@ -0,0 +1,223 @@ + + + + + + + UI draft — Perfis de permissão por assessor + + +
+

+ Coordenador/candidato define por assessor o que ele vê (Tudo | Carteira) e o que ele pode + editar (Tudo | Carteira | Somente leitura) — cenas: lista com coluna Permissão + editor, + mobile, detalhe do assessor. +

+ + +
+
+
+
+
+
+
+
Buscar assessor…
+
+ Novo assessor
+
+
+ +
+ +
+
+
Nome
+
E-mail
+
Celular
+
Municípios
+
Permissão
+
+
+
Nome do assessor
+
assessor@exemplo.org
+
(71) 90000-0000
+
+ Salvador (19) + Feira de Santana + +3 +
+
+ Carteira · Edita carteira +
+
+
+
Outra assessora
+
outra@exemplo.org
+
(71) 90000-0001
+
+ Camaçari
+
+
+ Tudo · Somente leitura +
+
+
+
Assessora de campo
+
campo@exemplo.org
+
(71) 90000-0002
+
+ Ilhéus + Itabuna +
+
+ Carteira · Edita carteira +
+ + +
+
Permissão da conta
+
Vale para todas as telas do /campanha.
+ +
+
Visão
+
+ Carteira — municípios que administra + ▾ +
+
Tudo: enxerga todos os municípios e lideranças.
+
+ +
+
Edição
+
+ Carteira — edita só o que administra + ▾ +
+
+ Somente leitura: nenhum controle de edição em lugar nenhum. +
+
+ +
+ Demandas seguem regra própria: só quem é responsável pela demanda (e candidato/coordenador) + a vê — mesmo com visão "Tudo". +
+ +
+
Cancelar
+
Salvar
+
+
+
+
+ +
+ Padrão de contas novas: Carteira · Edita carteira (comportamento atual). Alterações valem + na hora — ninguém precisa reenviar senha. +
+ +
+ + +
+
+
+
+
+ Novo
+
+
Buscar assessor…
+ +
+
+
Nome do assessor
+ Carteira · Edita +
+
assessor@exemplo.org · (71) 90000-0000
+
+ Salvador (19) + Feira de Santana + +3 +
+
+ +
+
+
Outra assessora
+ Tudo · Só leitura +
+
outra@exemplo.org · (71) 90000-0001
+
+ Camaçari +
+
+ +
+
+
Assessora de campo
+ Carteira · Edita +
+
campo@exemplo.org · (71) 90000-0002
+
+ Ilhéus + Itabuna +
+
+
+
+ + +
+
+
+
+
+
+
Nome do assessor
+
assessor@exemplo.org · (71) 90000-0000
+
+
+
Enviar link de redefinição de senha
+
+ +
+
+
Permissão da conta
+
+
Visão
+
+ Carteira — municípios que administra + ▾ +
+
+
+
Edição
+
+ Carteira — edita só o que administra + ▾ +
+
+
+ Demandas ficam sempre limitadas aos municípios de responsabilidade. Decisões de + coordenação (nível de envolvimento, contas, demandas escaladas) continuam restritas a + coordenador e candidato. +
+
+ +
+
Municípios administrados
+
+ Salvador (19) + Feira de Santana + Camaçari + Ilhéus + Itabuna + +8 +
+
Adicionar município…
+
+
+
+
+
+ + diff --git a/docs/plans/permissao-granular-assessores.md b/docs/plans/permissao-granular-assessores.md new file mode 100644 index 00000000..0187fa6c --- /dev/null +++ b/docs/plans/permissao-granular-assessores.md @@ -0,0 +1,101 @@ +# Perfis de permissão por assessor (visão × edição), configuráveis pelo coordenador/candidato + +Status: aguardando execução +Atualizado em: 2026-08-19 +Issue: #105 +Priority: P1 +Model: cursor-grok-4.5-high +Impeccable: B — encaixe em `/campanha/assessores` (lista + detalhe + novo) +Rascunho UI: docs/plans/permissao-granular-assessores-ui-draft.html +Appetite: ~2–3 dias eng; um modelo de permissão + configuração + enforcement fail-closed +Responsável: — + +## Intenção + +Hoje todo assessor tem exatamente um perfil: **vê e edita só os municípios da carteira**. No campo, a equipe descobriu que isso não cobre a mesa real: há assessor que precisa **ver tudo** (panorama, relatório, cobertura) sem poder **alterar nada**; há assessor que **vê tudo** mas só pode mexer **naquilo pelo que é responsável**; há assessor que só vê o que é seu — com ou sem edição. E **demandas** carregam custo e comprovantes (controle interno): só candidato, coordenador e as **pessoas responsáveis pela demanda** as veem — regra própria, detalhada no item irmão (C143). + +O coordenador/candidato precisa configurar isso **por conta**, na vertical `/campanha`, sem depender do Payload admin. + +## Persona e fluxo + +- **Persona / contexto:** Alex (Coordenador Geral) e o Candidato na mesa — montar e ajustar o time de assessores conforme o papel real de cada um; e o assessor, operando o `/campanha` dentro do que lhe foi liberado. +- **Job principal:** para cada assessor, definir **o que ele vê** e **o que ele pode editar**, em dois controles simples; e ter isso aplicado na hora, em todas as telas. +- **Fluxo desejado:** + 1. Alex abre `/campanha/assessores` e vê uma coluna "Permissão" por assessor (ex.: "Carteira · Edita carteira"). + 2. Toca no perfil de um assessor e escolhe **Visão** (Tudo | Carteira) e **Edição** (Tudo | Carteira | Somente leitura); a tela explica cada combinação e lembra que demandas seguem regra própria. + 3. Salva. O assessor entra e opera exatamente dentro do perfil — se "Somente leitura", não encontra nenhum controle de edição; se "Tudo", navega o estado inteiro (demandas fora, que seguem a regra de responsáveis). + 4. Conta nova nasce no padrão atual (Carteira · Carteira) — nada muda até alguém mexer. +- **Anti-goals de produto:** papel novo (só o assessor ganha perfis; liderança continua em lockdown e candidato/coordenador intocados); IAM tipo SaaS (grupos, herança, policy engine); permissão fina por coleção ("vê lideranças mas não atividades"); autoatendimento do próprio perfil. + +### Esboço de fluxo (B/C/D) + +```text +[assessores lista] → [coluna Permissão] → [editor: Visão × Edição + avisos] + → [salvar] → [perfil ativo imediatamente] +[assessor entra] → [telas renderizam e respondem dentro do perfil — fail-closed no servidor] +``` + +### Rascunho UI (B/C/D) + +![Rascunho UI — desktop (lista + editor)](permissao-granular-assessores-ui-draft-desktop.png) + +![Rascunho UI — mobile (cards)](permissao-granular-assessores-ui-draft-mobile.png) + +![Rascunho UI — detalhe do assessor](permissao-granular-assessores-ui-draft-detalhe.png) + +## Objetivo e aceite + +- O coordenador/candidato define, por assessor: **Visão** (Tudo | Carteira) e **Edição** (Tudo | Carteira | Somente leitura), nas superfícies de `/campanha/assessores` (lista, detalhe, novo). +- Contas novas e existentes mantêm o perfil atual por default — zero mudança de comportamento até configurarem. +- O assessor vê/edita **exatamente** o que o perfil permite, em todas as telas do `/campanha` e nas APIs — a checagem falha-fechada no servidor (nunca só ocultar botão no cliente). +- **Demandas:** ficam fora dos eixos — mesmo com Visão "Tudo", o assessor só vê demandas de que é responsável (regra explícita do item C143); Visão "Tudo" não abre demandas nem custo/comprovantes. +- Edição "Tudo" **não** libera escritas de coordenação: gerenciar contas, atribuir assessores a municípios, mover nível de envolvimento e decidir demandas escaladas seguem restritos a candidato/coordenador. +- Combinação incoerente (ex.: editar o que não vê) não é oferecida. +- **Apoiadores** (PII) continuam capados na carteira para todo staff abaixo de candidato/coordenador, mesmo com Visão "Tudo" _(decidido no gate)_. +- Configuração em três pontos: coluna + editor inline na lista, seção no detalhe e campos no formulário de novo assessor _(decidido no gate)_. Edit-where-you-see. +- Guardrails do repo intactos: liderança em lockdown, assimetria de votos (estimativas staff-only), postura LGPD fail-closed. + +## Dados (intenção) + +- **Vou apresentar dados?** Não — superfície de configuração de contas; sem KPI eleitoral. +- **Decisões desbloqueadas:** coordenador decide quem vê o quê e quem edita o quê, por pessoa. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** perfis na conta em `src/collections/CampaignUser.ts`; enforcement nos módulos de acesso `src/utilities/access/*` (o prologue `resolveActorScopedRead`/`resolveAccessibleIds` em `shared.ts` e os módulos por domínio — municípios, lideranças, pledges, demandas, atividades, organizações, dobradinhas, apoiadores); gates de escrita nas server actions `src/app/(campaign)/campanha/actions/*.ts`; UI em `src/components/campaign/advisor/` (`AdvisorsTable`, detalhe `[id]`, formulário novo) e helpers de papel client-safe em `src/lib/campaignRoles.ts`. +- **Precedente a olhar:** B19 (`gerenciar-assessores.md`) — a superfície e os gates de conta; a convenção P3-D do escopo de assessor (uma só grafia do fragmento `{ municipality(s): { in: ids } }`); C116/C116+ — células edit-in-place com estados read-only por papel. +- **Risco de acoplamento:** o escopo do assessor é central e compartilhado (mapa, quantis por escopo, listas, dossiê, Sollinha); qualquer mudança no "o que o assessor vê" propaga. Respeitar leader lockdown e o "não re-escrever o fragmento de escopo" da convenção. + +## Dependências + +- Nenhuma dura. **Guardrail:** a regra de demandas (C143) não depende deste item, e Visão "Tudo" nunca a contorna. C142 (superfícies respeitando o perfil) depende deste. + +## Fora de escopo + +- Perfis para `coordinator`/`candidate`/`leader` (congelados por política de produto). +- Demanda com "responsáveis" explícitos por demanda (vínculo por pessoa) — ver Questões; se confirmado, item sucessor. +- Permissão fina por coleção ou por campo além da regra de demandas. +- Autoatendimento/edição do próprio perfil. +- Histórico/auditoria de mudanças de perfil. + +## Rabbit holes de produto + +- **"Já que tem visão, vou adicionar um role novo."** Papel novo (`viewer`, `auditor`) recria o modelo de papéis e o seed de contas. **Corte:** perfis sobre o papel `advisor` existente — um assessor "visão Tudo · Somente leitura" É o leitor. +- **"Vou pedir permissão por coleção."** Cada campo novo vira matriz N×M e a tela vira IAM. **Corte:** dois eixos só; o que não couber nos eixos fica com a regra das demandas ou fora. +- **"Vou esconder botão no cliente e pronto."** Acesso de verdade mora no servidor; esconder botão é cosmético. **Corte:** enforcement no acesso de dados e nas actions primeiro; a apresentação é a entrega irmã (item seguinte). +- **"Visão Tudo abre as planilhas PII."** Apoiadores/custo de demandas são sensíveis (LGPD/controle interno). **Corte:** apoiadores capados na carteira (decidido); demandas seguem a regra de responsáveis (C143). + +## Decisões do gate (2026-08-19) + +- **Responsável por uma demanda = vínculo explícito por demanda** (opção B da rodada) — mesmo o assessor do município da demanda, se não estiver marcado como responsável, não vê. A regra vive no item irmão **C143**; este item apenas garante que Visão "Tudo" não a contorna. +- **Visão "Tudo" não abre superfícies sensíveis** (opção A) — apoiadores (PII) seguem capados na carteira; demandas seguem a regra de responsáveis (C143). +- **Edição "Tudo" não libera escritas de coordenação** (opção A). +- **Configuração na lista + detalhe + formulário de novo assessor** (opção A). + +## Referências + +- Pedido de produto 2026-08-19 (vertical `/campanha` — granularidade de acesso por conta); decisões do gate na seção acima. +- Item irmão: `docs/plans/demandas-responsaveis.md` (C143 — regra de responsáveis de demanda). +- Rascunho UI (gate): `docs/plans/permissao-granular-assessores-ui-draft.html` + PNGs acima. +- Para abrir primeiro: `src/utilities/access/shared.ts` (`resolveActorScopedRead`), `src/utilities/access/demands.ts` (regra atual de demandas = escopo de leitura), `src/components/campaign/advisor/AdvisorsTable.tsx`, `docs/plans/gerenciar-assessores.md` (B19). +- `AGENTS.md` — modelo de papéis de campanha, convenção P3-D do escopo de assessor. diff --git a/docs/plans/ui-respeita-perfil-permissao-ui-draft-demanda-leitura.png b/docs/plans/ui-respeita-perfil-permissao-ui-draft-demanda-leitura.png new file mode 100644 index 00000000..50e1a8cb Binary files /dev/null and b/docs/plans/ui-respeita-perfil-permissao-ui-draft-demanda-leitura.png differ diff --git a/docs/plans/ui-respeita-perfil-permissao-ui-draft-municipios-leitura.png b/docs/plans/ui-respeita-perfil-permissao-ui-draft-municipios-leitura.png new file mode 100644 index 00000000..386662b3 Binary files /dev/null and b/docs/plans/ui-respeita-perfil-permissao-ui-draft-municipios-leitura.png differ diff --git a/docs/plans/ui-respeita-perfil-permissao-ui-draft-municipios-visao-tudo.png b/docs/plans/ui-respeita-perfil-permissao-ui-draft-municipios-visao-tudo.png new file mode 100644 index 00000000..4b203706 Binary files /dev/null and b/docs/plans/ui-respeita-perfil-permissao-ui-draft-municipios-visao-tudo.png differ diff --git a/docs/plans/ui-respeita-perfil-permissao-ui-draft.html b/docs/plans/ui-respeita-perfil-permissao-ui-draft.html new file mode 100644 index 00000000..09a1d08e --- /dev/null +++ b/docs/plans/ui-respeita-perfil-permissao-ui-draft.html @@ -0,0 +1,185 @@ + + + + + + + UI draft — Interface respeita o perfil de permissão + + +
+

+ Depois do perfil de permissão (C141): as telas param de oferecer edição a quem não pode + editar e passam a renderizar o escopo completo para quem vê tudo — cenas: lista de municípios + em modo leitura, lista com visão total, detalhe de demanda somente leitura. +

+ + +
+
+
+
+
+
+ +
+ +
+
+
+
Município
+
Tendência
+
Nível
+
Classe
+
Cobertura
+
Últ. atualização
+
+
+
Salvador (19 zonas)
+
Favorável
+
N3
+
Reduto
+
82%
+
há 2 dias
+
+
+
Feira de Santana
+
Neutro
+
N2
+
Expansão
+
41%
+
há 5 dias
+
+
+
Ilhéus
+
Favorável
+
—
+
Manutenção
+
57%
+
há 1 dia
+
+
+
+ Mesma lista de sempre — mas sem autosave, sem chips editáveis, sem "Registrar atualização": + nenhum caminho de escrita visível. +
+
+
+ + +
+
+
+
+
+
+
Buscar município…
+
+ +
+
+
+
Município
+
Tendência
+
Nível
+
Classe
+
Cobertura
+
Últ. atualização
+
+
+
Salvador (19 zonas)
+
Favorável
+
N3
+
Reduto
+
82%
+
há 2 dias
+
+
+
Vitória da Conquista
+
Neutro
+
N1
+
Marginal
+
12%
+
há 9 dias
+
+
+
Barreiras
+
Favorável
+
N2
+
Expansão
+
38%
+
há 4 dias
+
+
+
Juazeiro
+
Desfavorável
+
N1
+
Sem base
+
9%
+
há 12 dias
+
+
+
+ Mesma mesa de trabalho de um coordenador (menos apoiadores fora da carteira e demandas de + que não é responsável) — ver regras no plano C141. +
+
+
+ + +
+
+
+
+
+ Material de campanha + Em aberto +
+
Cartazes para a caminhada do fim de semana
+
Ilhéus · liderança: Nome da liderança
+
+
+ +
+
+
Descrição
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor + incididunt ut labore et dolore magna aliqua. +
+
+
Custo estimado
+
R$ 1.200,00
+
+
+
Comprovantes
+
2 anexos
+
+
+ +
+
Histórico de status
+
+
+
+
+ Em aberto — criada por Assessora de campo · 12 ago +
+
+
+
+
+ Encaminhada — decidida por Coordenador Geral · 14 ago +
+
+
+
+ Sem botões de transição, sem "registrar pedido", sem edição — só leitura do andamento. +
+
+
+
+
+
+ + diff --git a/docs/plans/ui-respeita-perfil-permissao.md b/docs/plans/ui-respeita-perfil-permissao.md new file mode 100644 index 00000000..5fa3dc94 --- /dev/null +++ b/docs/plans/ui-respeita-perfil-permissao.md @@ -0,0 +1,88 @@ +# Interface respeita o perfil de permissão (assessor somente-leitura sem controles de edição; visão Tudo no escopo completo) + +Status: aguardando execução +Atualizado em: 2026-08-19 +Issue: #107 +Priority: P1 +Model: cursor-grok-4.5-medium +Impeccable: B — passada de apresentação sobre as superfícies staff do `/campanha` +Rascunho UI: docs/plans/ui-respeita-perfil-permissao-ui-draft.html +Appetite: ~1–2 dias eng; telas passam a refletir o perfil (sem 403s à vista, escopo coerente) +Responsável: — + +## Intenção + +O item irmão (perfis de permissão por assessor) entrega o modelo e o enforcement no servidor. Sem esta passada, um assessor "Somente leitura" ainda **vê** todos os botões, células autosave, FABs e sheets de edição — e cada toque morre com erro de permissão, o oposto do produto que a mesa espera. E um assessor que ganhou "Visão Tudo" precisa que listas, detalhes e mapa carreguem o estado inteiro de forma coerente (contagens, facetas, filtros), não meia-lista. + +## Persona e fluxo + +- **Persona / contexto:** o assessor com perfil restrito, operando o `/campanha` no celular e no desktop — não pode, não deve e não quer tentar editar; e o assessor de visão total, querendo a mesa de trabalho completa. +- **Job principal:** a interface diz a verdade sobre o perfil: quem não edita não encontra edição; quem vê tudo vê tudo. +- **Fluxo desejado:** + 1. Assessor "Carteira · Somente leitura" abre `/campanha/municipios`: células são leitura pura, sem chips editáveis, sem "Registrar atualização", sem FAB de ações — nenhum controle de escrita à vista, sem aviso: a tela simplesmente não oferece edição. + 2. Assessor "Tudo · Edita carteira" abre as mesmas listas: vê o estado inteiro (todos os municípios/lideranças) e edita apenas o que administra — o controle de edição aparece só onde a carteira alcança. + 3. Assessor "Carteira · Edita carteira": exatamente o comportamento de hoje (nada muda). +- **Anti-goals de produto:** bloquear por mensagem de erro em vez de ocultar/desabilitar; cinza-fantasma que confunde o que é editável; redesenho de superfícies que não precisam mudar. + +### Esboço de fluxo (B/C/D) + +```text +[login assessor] → [perfil da conta resolve o que renderizar] + → [visão: escopo completo ou carteira] × [edição: controles presentes ou ausentes] + → [nenhum caminho leva a 403; nenhum dado fora do escopo é oferecido] +``` + +### Rascunho UI (B/C/D) + +![Rascunho UI — lista de municípios em modo leitura](ui-respeita-perfil-permissao-ui-draft-municipios-leitura.png) + +![Rascunho UI — lista de municípios com visão Tudo](ui-respeita-perfil-permissao-ui-draft-municipios-visao-tudo.png) + +![Rascunho UI — detalhe de demanda em modo leitura](ui-respeita-perfil-permissao-ui-draft-demanda-leitura.png) + +## Objetivo e aceite + +- Assessor sem permissão de edição **não encontra nenhum controle de escrita** nas superfícies staff: células de autosave, chips removíveis, "Registrar atualização", FAB/ações rápidas, wizards, sheets e triggers de Popover — no desktop e no mobile. Sem aviso de modo leitura: a presença/ausência dos controles é a única linguagem _(decidido no gate: opção B)_. +- Assessor "Visão Tudo" navega listas, detalhes e mapa no escopo completo, com contagens, facetas e filtros coerentes com o que ele vê. +- Atalhos de escrita (ex.: busca global) seguem a mesma regra: destino de escrita some para quem não pode escrever; atalhos de navegação permanecem _(decidido no gate: opção A)_. +- Nada muda para coordenador/candidato/liderança e para o assessor "Carteira · Edita carteira". +- O enforcement de segurança não é relaxado em nenhum ponto: a apresentação acompanha o servidor, nunca o substitui. + +## Dados (intenção) + +- **Vou apresentar dados?** Não — passada de apresentação sobre superfícies existentes. +- **Decisões desbloqueadas:** nenhuma decisão de dado nova. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** componentes `src/components/campaign//*` — células edit-in-place e cascas compartilhadas (`CampaignCellEditOverlay`, `CampaignListSheetProvider`, colunas por papel), triggers de autosave por lista, FAB/ações rápidas, botões "Registrar atualização" em municípios/atividades, controles de status em demandas; predicados client-safe de perfil em `src/lib/campaignRoles.ts` (ou o helper do item irmão); dashboards/mapa (`MunicipalityMapPanel` e loaders escopados). +- **Precedente a olhar:** estados `readOnly` já existentes (`RelationChipCell`/`RelationOptionCell` com `readOnly`), a matriz por papel da célula de pessoas (C116: assessor edita só onde a carteira alcança, resto read-only), card mobile de municípios (B193). +- **Risco de acoplamento:** o mapa e as listas já leem "escopo do ator" — cuidado para não duplicar lógica de escopo no cliente; o fragmento de escopo continua vivendo uma vez só (convenção P3-D). + +## Dependências + +- **C141** (modelo + enforcement + configuração) — este item só faz sentido depois do perfil existir e valer no servidor. + +## Fora de escopo + +- Qualquer mudança no modelo de permissão ou no enforcement (é o item irmão). +- Redesenho de superfícies não relacionadas a permissão. +- Estado de leitura para liderança (lockdown já é outra superfície, intocada). + +## Rabbit holes de produto + +- **"Vou esconder tudo com um flag e rezar."** A passada precisa achar **cada** caminho de escrita real (autosave, sheets, wizards, links para formulários). **Corte:** varrer por superfície com a matriz de papéis, como a célula de pessoas já faz; o que não for achado agora aparece no aceite do item. +- **"Vou redesenhar a lista de municípios."** Tocar layout por tocar não é o pedido. **Corte:** manter layouts; mudar só presença/ausência de controles e o aviso de modo leitura. +- **"Cinza-fantasma em tudo."** Desabilitar tudo visualmente polui mais do que ajuda. **Corte:** controles de edição **ocultos** para leitura; aviso discreto no topo. + +## Decisões do gate (2026-08-19) + +- **Modo leitura sem aviso** (opção B) — controles ocultos; presença/ausência de edição é a única linguagem. +- **Atalhos de escrita seguem a regra** (opção A) — destino de escrita some para quem não pode escrever. + +## Referências + +- Item irmão: `docs/plans/permissao-granular-assessores.md` (C141) e `docs/plans/demandas-responsaveis.md` (C143 — a regra de demandas muda o que a demanda renderiza para quem não é responsável). +- Rascunho UI (gate): `docs/plans/ui-respeita-perfil-permissao-ui-draft.html` + PNGs acima. +- Para abrir primeiro: `src/components/campaign/shared/CampaignCellEditOverlay.tsx` (casca dos overlays de edição), `src/lib/campaignRoles.ts` (predicados por papel), a matriz por papel em `pessoas-*` (C116). +- `AGENTS.md` — convenção P3-D do escopo de assessor.