docs(plans): B171 barra inferior mobile (folga + rótulos) e C89 página Atualizações (feed + filtro + criar)

This commit is contained in:
Francisco Solla 2026-08-08 18:01:29 -03:00
parent 8b2bc51aa5
commit bef68678ff
2 changed files with 118 additions and 46 deletions

View file

@ -0,0 +1,74 @@
# B171 — Barra inferior mobile: folga no topo + rótulos sem sobreposição
Status: rascunho
Atualizado em: 2026-08-08
Issue: #443
Priority: P1
Model: composer-2.5
Model-local: deepseek-v4-flash-high
Impeccable: C — encaixe no chrome que todo staff vê no mobile (barra inferior)
Canvas UI: `/home/fsolla/.cursor/projects/home-fsolla-cursor-worktrees-teqo-41rz/canvases/plan-b171-ui-draft.canvas.tsx`
Appetite: ~0,5 dia eng; um outcome verificável — a barra lê sem fricção no celular
Responsável: —
## Intenção
A barra inferior mobile de **B164** chegou funcional, mas com dois defeitos de leitura: os botões **encostam no limite superior da barra** (sem respiro antes da borda) e os **rótulos se sobrepõem** em telas estreitas — "Atualizações" é longo demais para a fonte atual. É polimento estético do chrome principal do staff no celular, nada funcional.
## Persona e fluxo
- **Persona / contexto:** coordenador/assessor no celular; barra fixa é o primeiro e último que ele toca.
- **Job principal:** ler os 5 destinos de relance, sem esforço, e tocar com o polegar.
- **Fluxo desejado:** a barra respira em relação à própria borda superior e cada rótulo é legível, sem colidir com o vizinho — em qualquer largura de viewport mobile.
- **Anti-goals de produto:** redesenhar a barra; mudar ordem/itens; mexer em desktop/tablet (sidebar segue igual); encolher a área de toque.
### Esboço de fluxo (C)
```text
[mobile staff, qualquer rota (app)]
→ barra: itens com folga no topo; rótulos menores e sem sobreposição
→ mesmo comportamento de toque/navegação de B164
```
## Objetivo e aceite
- Há um pequeno espaçamento entre o conteúdo dos itens e a borda superior da barra (sem o item "colado" no limite).
- Os rótulos dos 5 botões **não se sobrepõem** em viewport mobile; a fonte dos rótulos é menor que a atual.
- Área de toque e estado ativo continuam equivalentes (não ~encolher~ o alvo que o polega tenta acertar).
- Sem regressão: leader lockdown e desktop/tablet intactos (mudança restrita ao chrome da barra inferior).
## Dados (intenção)
- **Vou apresentar dados?** Não — polimento visual de chrome, sem número novo para exibir.
- **Forma:** N/A.
## Direção no codebase (hipótese)
- **Áreas prováveis:** componente da barra inferior (shell `(app)`) — onde `getCampaignBottomNav` alimenta os itens; apenas ajuste de espaçamento/estilo dos itens e rótulos.
- **Precedente a olhar:** `barra-navegacao-inferior-mobile-impl.md` (B164); chrome de labels em outras barras mobile.
- **Risco de acoplamento:** FAB/thumb-zone acima da barra (folga não deve empurrar conteúdo); safe-area inferior; não mexer em desktop.
## Dependências
- **B164** (a barra é o entregável dele — sucessor direto; não editar o plano já entregue).
## Fora de escopo
- Redesign da barra, novos itens, ordem ou ícones.
- Mudanças de desktop/tablet/sidebar.
- Comportamento de navegação (inalterado).
## Rabbit holes de produto
- **"Já que tá aqui, redesenha a barra."** Dois jobs. **Corte:** só folga + legibilidade dos rótulos; resto é outro item.
- **"Menor é melhor em tudo."** Fonte menor demais quebra acessibilidade. **Corte:** legibilidade mínima em viewport estreito, sem encolher abaixo do padrão de UI.
## Questões em aberto (produto)
- Nenhuma pendente — o pedido é específico (folga no topo + fonte menor nos rótulos).
## Referências
- Sucessor do plano B164: [barra-navegacao-inferior-mobile.md](barra-navegacao-inferior-mobile.md)
- Canvas UI (gate): [`plan-b171-ui-draft.canvas.tsx`](/home/fsolla/.cursor/projects/home-fsolla-cursor-worktrees-teqo-41rz/canvases/plan-b171-ui-draft.canvas.tsx)
- `src/components/campaign/shell/nav.ts` · `CampaignBottomNav` (direção hipotética)

View file

@ -1,97 +1,95 @@
# C89 — Feed da campanha de atualizações (cada update = thread)
# C89 — Página Atualizações: feed de cards + filtro + criar (modal / bottom sheet)
Status: ready
Atualizado em: 2026-08-06
Atualizado em: 2026-08-08
Issue: #401
Priority: P1
Model: cursor-grok-4.5-medium
Model-local: deepseek-v4-high
Impeccable: D — superfície nova: feed campanha-wide + interação por fio
Impeccable: D — superfície nova: feed campanha-wide + criação in-place (modal ↔ bottom sheet)
Canvas UI: `/home/fsolla/.cursor/projects/home-fsolla-cursor-worktrees-teqo-41rz/canvases/plan-c89-ui-draft.canvas.tsx`
Appetite: ~1,5–2 dias eng; um outcome verificável — staff acompanha e discute o que aconteceu na carteira num só lugar
Appetite: ~1,5–2 dias eng; um outcome verificável — staff acompanha o que aconteceu na carteira num só lugar e registra novo fato sem sair da página
Responsável: —
## Intenção
A mesa precisa de um **feed da campanha** — não só o histórico dentro de um município — para ver o que está acontecendo, comentar e deliberar. Cada **atualização** vira um **fio (thread)**: o fato registrado é o post; a conversa (e, com C88, responsável / resolvido) vive ali. O slot **Atualizações** da barra mobile (**B164**) aponta para esta superfície; desktop também a alcança pela nav.
A barra mobile (**B164**) já aponta **Atualizações** para `/campanha/atualizacoes` — hoje um placeholder honesto ("em breve"). Este item entrega a **página de verdade**: um **feed de cards de atualização**, mais recentes no topo, com um **filtro combinado** (mesmo padrão da lista de Municípios) e um **botão "+"** à direita do filtro que abre a criação de uma nova atualização — **modal em desktop, bottom sheet no mobile**. A discussão em fios por atualização é camada futura (**C88**), **não** bloqueia esta página.
## Persona e fluxo
- **Persona / contexto:** coordenador varrendo a carteira no celular ou na mesa; assessor no recorte dos municípios que administra; pressão entre campo e WhatsApp.
- **Job principal:** ver o que aconteceu recentemente, entrar no fio de uma atualização, participar da discussão (e fechar quando couber).
- **Persona / contexto:** coordenador / assessor varrendo a carteira no celular ou na mesa; assessor vê só os municípios que administra.
- **Job principal:** ver o que aconteceu recentemente (e registrar um fato novo) sem entrar em cada município.
- **Fluxo desejado:**
1. Abre **Atualizações** (barra mobile ou nav) → feed cronológico das atualizações da **carteira do ator** (assessor = só seus municípios; unrestricted = amplo).
2. Cada card = uma atualização (texto, polaridade/urgente quando C87 existir, município, idade).
3. Toca o card → o update abre como **thread**: corpo imutável do fato + comentários em sequência (+ responsável / resolvido quando **C88** estiver disponível).
4. Comenta / atribui / marca resolvido conforme o poder do papel (regras de C88); volta ao feed.
- **Anti-goals de produto:** segundo tracker estilo Jira; chat em tempo real; feed público / liderança; misturar Demandas/Atividades; spreadsheet de KPIs; twin do modelo de atualização fora de C87/C88.
1. Abre **Atualizações** → feed cronológico da carteira do ator (mais recentes no topo).
2. Usa o **combobox de filtro** acima do feed para estreitar por **município, polaridade, urgente, quem criou** ou **busca por texto** — um combobox só, no padrão omnibox das listas.
3. Toca **"+"** ao lado do filtro → **modal** (desktop) / **bottom sheet** (mobile) → preenche texto + polaridade (+ urgente) → confirma → volta ao feed com o novo card no topo.
- **Anti-goals de produto:** tracker estilo Jira; thread/comentário/deliberação nesta fatia (→ **C88**); scroll infinito/KPI; feed público/liderança; misturar Demandas/Atividades; segundo modelo de atualização.
### Esboço de fluxo (D)
```text
[Atualizações]
→ feed (carteira)
→ toca update
→ thread: fato + comentários (+ responsável / resolvido)
→ volta ao feed
→ feed (carteira, mais recentes no topo)
→ filtro combobox acima do feed
→ "+" → modal (desktop) / bottom sheet (mobile) → nova atualização
→ novo card no topo
```
## Objetivo e aceite
- Existe destino de produto **Atualizações** (rota de feed) usável por staff no escopo da carteira.
- Feed lista atualizações recentes com identidade do município e sinal de estado do fio (ex.: aberta / resolvida — quando C88 existir).
- Abrir um item mostra a atualização como **thread** interativa (comentar no fio); o corpo do fato permanece o registro original (imutável na intenção — alinhado a C88).
- Deliberação (responsável, resolvido, reabrir) **reusa** a intenção de **C88** — não inventa um segundo protocolo de ticket neste item.
- Leader lockdown: liderança **não** vê o feed nem os fios staff.
- Slot da barra **B164** e entrada de nav apontam para este destino (quando ambos existirem).
- **Atualizações** deixa de ser placeholder: rota de feed usável por staff no escopo da carteira, cards mais recentes primeiro.
- Card mostra o essencial do fato: **avatar de quem criou** (canto superior esquerdo), texto, polaridade, urgente, autor, identidade do município e data.
- **Filtro combobox** acima do feed, mesmo padrão do filtro da lista de Municípios (`/campanha/municipios`); cobre **município, polaridade, urgente, quem criou e busca por texto**.
- Botão **"+"** à direita do filtro abre a **criação de nova atualização**: modal em desktop e **bottom drawer/sheet no mobile**; confirmação insere no feed sem recarregar a página à toa.
- Criar segue as regras existentes de acesso (staff; assessor só nos municípios que administra) e o formulário/registro atual unificado.
- **Leader lockdown** intacto: liderança não vê o feed nem cria atualização.
- Thread/comentário/deliberação ficam para **C88** — esta página não inventa um segundo protocolo.
## Dados (intenção)
- **Vou apresentar dados?** Sim, superfície neste item (feed operacional, não KPI estadual).
- **Decisões desbloqueadas:**
- Coordenação/assessor: “o que aconteceu na carteira desde ontem?”
- No fio: “o que falta / quem resolve / podemos fechar?” (com C88)
- **Forma:** adiada — restrição: leitura relativa à carteira do ator; sem % estadual absoluto.
- Coordenação/assessor: "o que aconteceu na carteira desde ontem?"
- Registrar: "anotei o fato do dia" (mesmo formulário unificado já vivo).
- **Forma:** adiada ao plano de implementação — restrição: leitura relativa à carteira do ator; sem % estadual absoluto.
## Direção no codebase (hipótese)
- **Áreas prováveis:** rota `/campanha/atualizacoes` (ou equivalente), componentes de feed/thread no domínio de atualização de município, nav (`nav.ts` + slot B164), loaders no escopo do ator; actions de comentário/deliberação alinhadas a C88.
- **Precedente a olhar:** feed de atualizações no detalhe do município; C87 / C88; notificações `municipality_update`; B164.
- **Risco de acoplamento:** access por município; não criar pessoa fora de `campaignUser`/`Contact`; serialização com migrations de C87/C88.
- **Áreas prováveis:** rota `/campanha/atualizacoes` (substitui o placeholder), componentes de feed e de criação de atualização no domínio do município, filtro/omnibox no padrão das listas, preview de bottom sheet já usado na área; loaders escopados ao papel do ator.
- **Precedente a olhar:** feed de atualizações do detalhe do município; formulário unificado de atualização já existente; filtro combobox/omnibox de Municípios (B127/B128/B120); avatar de usuário da campanha (foto ou iniciais); bottom sheet (B112/B109); dashboard "últimas atualizações de campo".
- **Risco de acoplamento:** access por município (assessor = carteira); não criar pessoa fora de `campaignUser`/`Contact`; não duplicar o registro de atualização — reusar o fluxo de criação existente; serialização com trabalho de C87/C88 se tocar schema.
## Dependências
- **Dura:** **C87** (modelo unificado de atualização) — o feed consome esse registro.
- **Dura:** **C88** (fio / responsável / resolvido) — a interação completa do thread; sem C88 o feed ainda pode listar e abrir o fato, mas deliberação fica incompleta — preferir shipar C89 **depois** de C88 ou degradar honestamente (só leitura + “comentários em breve”) se o gate pedir paralelismo com B164.
- Soft: **B164** (slot na barra); C15 irrelevante.
- Soft: **C87** (modelo unificado já vivo no card/formulário — sem dura).
- Soft: **C88** (thread/discussão futura sobre os mesmos cards — não bloqueia esta página).
- Soft: **B164** (slot da barra já aponta para a rota — esta página substitui o placeholder).
## Fora de escopo
- Thread, comentário, responsável e "resolvido" por atualização → **C88** (depois; sobre os mesmos cards).
- Chrome da barra inferior / página Mais → **B164**.
- Remodel do formulário de registro (polaridade / urgente) → **C87**.
- Definir de novo as regras de quem atribui/resolve → já em **C88** (não reabrir aqui).
- Mentions @, anexos rich, reações, SLA, kanban.
- Participação de liderança/apoiador.
- Sync externo / WhatsApp.
- Redesign do formulário de registro (já unificado em **C87**).
- Analytics, scroll infinito, kanban, mentions/reações, feed público ou de liderança.
## Rabbit holes de produto
- **"Feed + barra no mesmo item."** Estoura appetite e mistura chrome com domínio. **Corte:** B164 vs C89.
- **"Vira rede social da campanha."** Curtidas, stories. **Corte:** fato + fio de trabalho.
- **"Filtros infinitos / analytics no feed."** **Corte:** cronológico da carteira; filtros só se couberem no appetite (município / abertas) sem virar BI.
- **"Comentário edita o fato."** **Corte:** corpo imutável; fio à parte (C88).
- **"Feed + thread no mesmo item."** Estoura appetite e acopla à deliberação (C88). **Corte:** só feed + filtro + criar; fio fica com C88.
- **"Filtrar por tudo."** Combobox vira BI. **Corte:** as dimensões pedidas (município, polaridade, urgente, quem criou, texto) são o teto — sem analytics, _saved filters_ nem cruzamento adicional.
- **"Botão + = formulário novo e diferente."** Segundo registro. **Corte:** reusar o fluxo/formulário unificado existente.
- **"Card clica e abre thread que não existe."** Expectativa furada. **Corte:** card lê o fato; interação de fio quando C88.
## Questões em aberto (produto)
- Nenhuma pendente — gate 2026-08-06 confirmou o lote com as recomendações:
1. **Ordem:** C87 → C88 → C89 (feed completo com thread); B164 pode âncora/empty antes.
2. **Desktop:** item “Atualizações” também na nav staff (mesmo destino).
3. **Criar no feed:** não nesta fatia — só caminhos existentes (município / wizard).
- **Filtro do feed** — _resolvido (gate 2026-08-08):_ inclui **município, polaridade, urgente, quem criou e busca por texto** num único combobox (padrão omnibox, sugestões agrupadas).
- **Município ao criar:** obrigatório, com prefill do município do filtro ativo — _confirmado (gate 2026-08-08)._
- **Clique no card:** só leitura em v1 (sem thread, sem navegar) — _confirmado (gate 2026-08-08)._ Discussão vem com **C88**.
- **Avatar do autor:** no canto superior esquerdo do card (foto ou iniciais, como o restante da área) — _pedido no gate 2026-08-08._
## Referências
- GitHub Issue: [#401](https://github.com/fsolla/teqo/issues/401)
- Canvas UI (gate): [`plan-c89-ui-draft.canvas.tsx`](/home/fsolla/.cursor/projects/home-fsolla-cursor-worktrees-teqo-41rz/canvases/plan-c89-ui-draft.canvas.tsx)
- Irmão chrome: [barra-navegacao-inferior-mobile.md](barra-navegacao-inferior-mobile.md) (**B164**)
- Depende: C87 [#396](https://github.com/fsolla/teqo/issues/396), C88 [#397](https://github.com/fsolla/teqo/issues/397)
- Planos: [atualizacao-unificada-polaridade-urgente.md](atualizacao-unificada-polaridade-urgente.md), [deliberacao-atualizacao-responsavel-thread.md](deliberacao-atualizacao-responsavel-thread.md)
- Camadas futuras: [deliberacao-atualizacao-responsavel-thread.md](deliberacao-atualizacao-responsavel-thread.md) (**C88**), [atualizacao-unificada-polaridade-urgente.md](atualizacao-unificada-polaridade-urgente.md) (**C87**)
- Precedentes: filtro combobox de Municípios (B127/B128/B120), bottom sheet (B112/B109), `MunicipalityUpdateFeed`/form unificado