diff --git a/docs/plans/barra-navegacao-inferior-mobile-ajustes.md b/docs/plans/barra-navegacao-inferior-mobile-ajustes.md new file mode 100644 index 00000000..4c13b2b6 --- /dev/null +++ b/docs/plans/barra-navegacao-inferior-mobile-ajustes.md @@ -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) diff --git a/docs/plans/feed-atualizacoes-campanha-threads.md b/docs/plans/feed-atualizacoes-campanha-threads.md index ec6f9f20..73858f7a 100644 --- a/docs/plans/feed-atualizacoes-campanha-threads.md +++ b/docs/plans/feed-atualizacoes-campanha-threads.md @@ -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