Commit graph

878 commits

Author SHA1 Message Date
Francisco Solla
32b6929ddb
Merge pull request #563 from fsolla/plans/plan-issue-21
docs(OPS22): plano — CI main e2e da agenda mobile vermelho desde o B188 (deploy bloqueado)
2026-08-10 08:05:29 -03:00
Francisco Solla
f54552bc7f docs(OPS22): plano — CI main e2e da agenda mobile vermelho desde o B188 (deploy bloqueado) 2026-08-10 08:00:51 -03:00
Francisco Solla
f073fc48c9 style(OPS21): prettier-format impl plan 2026-08-10 07:52:16 -03:00
Francisco Solla
e54ed44fd7 docs(OPS21): REVALIDATE_SECRET na Vercel production — runbook /api/revalidate restaurado 2026-08-10 07:49:17 -03:00
Francisco Solla
733b019f2b
Merge pull request #560 from fsolla/B190-sollinha-municipios-sem-dobradinha-dobradinhas-orfas-co
B190 — Sollinha: municípios sem dobradinha + dobradinhas órfãs (cobertura de parcerias)
2026-08-10 07:35:01 -03:00
Francisco Solla
7bdd7f91b1
Merge pull request #559 from fsolla/B187-sollinha-links-com-aparencia-de-link-nas-respostas
B187 — Sollinha: links com aparência de link nas respostas
2026-08-10 07:34:36 -03:00
Francisco Solla
c4591eedaa
Merge pull request #558 from fsolla/B185-sollinha-liderancas-pendentes-de-abordagem-assessores-r
docs(D8): plano — restaurar entradas B183/C102 perdidas do CHANGELOG
2026-08-10 07:25:00 -03:00
Francisco Solla
4373599192 feat(B190): Sollinha — cobertura de parcerias (municípios sem dobradinha + dobradinhas órfãs)
Nova tool getPartnershipCoverage com dois modos: municípios do escopo sem
nenhuma dobradinha vinculada (Salvador agrupada por cidade, drill-down por
ZE) e dobradinhas órfãs (sem município vinculado no registro inteiro, via
bypass agregado-only do helper B34). Gate fail-closed para leader; região
tolerante a acento; critério declarado na resposta. buildCampaignLinks ganha
o filtro stateDeputies sem_dobradinha na lista de municípios (URL B176).

Closes #527
2026-08-10 07:24:15 -03:00
Francisco Solla
3be112a42e docs(D8): plano — restaurar entradas B183/C102 perdidas do CHANGELOG (merge do C104) 2026-08-10 07:23:23 -03:00
Francisco Solla
807b8fde61 style(B187): format (prettier) 2026-08-10 07:21:25 -03:00
Francisco Solla
1016668265 feat(B187): links com aparência de link nas respostas do Sollinha
Estilo de links no markdown do chat (primária + sublinhado + hover/foco),
externos abrem em aba nova; compõe com o next/link interno do B188.
Sem migration; e2e + unit cobrem a superfície.
2026-08-10 07:20:44 -03:00
Francisco Solla
1937688fc5
Merge pull request #555 from fsolla/C106-atualizacoes-mobile-feed-sem-moldura-omnibox-sticky-sem
C106 — Atualizações mobile: feed sem moldura (omnibox sticky sem label, criar no header, cards edge-to-edge)
2026-08-10 04:31:17 -03:00
Francisco Solla
74ccce432d
Merge pull request #554 from fsolla/B191-sollinha-acoes-rapidas-de-abertura-no-chat-chips-de-per
feat(B191): chips de pergunta de abertura no chat Sollinha
2026-08-10 04:15:38 -03:00
Francisco Solla
40f38eeb8c feat(C106): cards do feed edge-to-edge com linha + empty state (padrão B184/C107 compartilhado)
- Adota o mecanismo canônico que o irmão B184/C107 estabeleceu em main
  (campaignListOmniboxFormClassName + campaignMobileHeaderIconClassName):
  a hipótese original de CSS de página virava twin — rebase resolveu
  mantendo a versão do irmão em CampaignUpdatesFilters.
- C106 entrega o que o irmão não cobriu: cards edge-to-edge (-mx-4,
  border-b last:border-b-0, padrão exato de MunicipalityListMobileCards),
  neutralização do leak do @layer base ul (my-0 list-none [&>li]:mt-0) e
  copy única do empty state.
- E2E campaignUpdatesMobile: label oculta, form sticky, icon abre o bottom
  sheet, cards edge-to-edge, empty state, regressão desktop.
- Impl plan + changelog atualizados com a decisão revisada.
2026-08-10 04:12:33 -03:00
Francisco Solla
7eaa65ce03 feat(C106): atualizações mobile sem moldura — omnibox sticky, criar no header, cards edge-to-edge
- CSS de página (padrão C101): .campaign-updates-filter-strip sticky sob a
  top bar com linha separadora, :has() zera o padding-top do scroll container
- Chassis B127 ganha o hook estável data-slot=campaign-omnibox-field (sem
  mudança de comportamento)
- 'Nova atualização' vira icon no header via SetCampaignHeaderAction (slot
  C94/C95), gate de resolução 100% CSS (md:hidden); mesmo modal C89
- Cards edge-to-edge (-mx-4) sem borda, divisor de linha; corrigido o leak do
  @layer base editorial (ul my-6 ml-6 [&>li]:mt-2) que afetava a única lista
  campaign em <ul>
- Empty state com copy única descrevendo a ação
- E2E campaignUpdatesMobile (mobile + regressão desktop); impl plan + changelog
2026-08-10 04:12:23 -03:00
Francisco Solla
04951f6772 feat(B191): chips de pergunta de abertura no chat Sollinha (curados por papel e viewport)
- src/lib/sollinhaOpeningQuestions.ts: catálogo puro de chips de abertura
  (staff: 4 perguntas ancoradas nas tools atuais; leader: conjunto seguro
  sem tool eleitoral — fail-closed B180)
- ChatChipGroup: primitivo presentacional reutilizável (slot compartilhado
  com o B192)
- role do usuário flui do layout server pelo shell até o context do chat
- slot acima do input renderiza só com conversa vazia (messages 0 + ready);
  tocar envia via sendMessage e os chips somem no primeiro envio
- unit tests do catálogo + e2e (staff desktop 4 / mobile 3 / leader seguro)
2026-08-10 03:49:08 -03:00
fsolla
437b5f0c2f test(C103): mobile agenda e2e clica o slot diretamente (C104 all-day lane mudou o grid) 2026-08-10 03:34:33 -03:00
Francisco Solla
acd522f035 feat(C103): agenda mobile — formulário de criação usável (sheet do topo, sem labels, salvar fixo, seletor em bottom sheet) 2026-08-10 03:34:33 -03:00
Francisco Solla
3ca200e7b0
Merge pull request #549 from fsolla/B184-municipios-mobile-lista-sem-moldura-omnibox-sticky-x-de
B184 — Municípios mobile: lista sem moldura (omnibox sticky, X de limpar no input, salvar filtro no header, cards edge-to-edge)
2026-08-10 03:30:25 -03:00
Francisco Solla
d60fe3867a
Merge pull request #552 from fsolla/C107-atualizacoes-mobile-sheet-de-criacao-usavel-altura-auto
C107 — Atualizações mobile: sheet de criação usável (altura auto até o topo, form sem labels com divisórias, placeholders, polaridade em toggle, checks à direita)
2026-08-10 03:29:43 -03:00
Francisco Solla
fab834fc95 docs(B184): changelog entry (re-added after second rebase conflict) 2026-08-10 03:12:02 -03:00
Francisco Solla
426d14bbb2 docs(B184): agenda exception (C101 strip) after rebase 2026-08-10 03:11:43 -03:00
Francisco Solla
324e1c3c51 feat(B184): omnibox mobile sem moldura como padrão das listas (sticky no form, X de limpar no input, salvar filtro no header, cards edge-to-edge)
- Chassis CampaignListOmnibox (B127): abaixo de md a label some (input carrega
  aria-label), o campo perde borda/sombra (md: restaura), o form do filtro vira
  barra sticky com linha separadora (sticky no form porque não escapa do
  containing block — a coluna do input dentro do wrapper curto não grudava),
  o texto Limpar vira X circular dentro do input (chips OU busca; slot sempre
  renderizado com invisible; hit target 44px; live region de limpeza), botão
  texto Limpar desktop-only. Padrão para as 11 listas via
  campaignListOmniboxFormClassName.
- Municípios: Salvar filtro vira icon no header mobile (C94/C95 slot,
  presentation='icon', nome de rename = contrato 2.5.3); cards edge-to-edge
  com separador de linha (border-b last:border-b-0, -mx-4, gate md:).
- Atualizações: Nova atualização vai para o header mobile (único trailing
  mobile-visible que grudaria na barra).
- campaignMobileHeaderIconClassName compartilhada (3º consumidor).
- E2E mobile novo (390x844) com pins: foco/aria-expanded após limpar, salvar
  -> renomear no header, cards, desktop invertido.
- D7 registrado no caminho: sticky dos headers da tabela desktop morto.
2026-08-10 03:11:43 -03:00
Francisco Solla
7cf820f51b fix(B185): revisão /simplify — escopo efetivo de assessor, chips sem vazamento, DRY e convenções
- Município/território real fora do portfólio devolve lista vazia escopada (antes
  erro 'não reconhecido') + escopoRestrito: true declarado na resposta
- Chips de município fora do acesso omitidos (nunca id pelado)
- uniqueRelationshipIds canônico no lugar do uniqueIDs local
- Chaves do input zod em inglês (scope/filter/mode); Salvador sem round-trip
- Pledge query restrita a lideranças engajado + dica quando truncado + prompt
2026-08-10 03:07:13 -03:00
Francisco Solla
c3f10cce23 feat(C108): sino de notificações — abrir marca tudo como lido, painel limpo, modal central no desktop
openCampaignNotifications (lista + marca em 1 round trip) substitui
listCampaignNotifications + markAllCampaignNotificationsRead; markAllNotificationsRead
extraída (owner-scoped, idempotente, cap 200) com int test; bell vira Dialog
desktop / Drawer mobile (par C94), sem título/rodapé/botões, skeleton de
loading, safe-area, focus-visible, role=alert; readAt sai do contrato do item;
P4-D ledger atualizado (batch sem transação agora no hot path, self-healing).
2026-08-10 02:56:20 -03:00
Francisco Solla
07464b8810
Merge pull request #548 from fsolla/B188-sollinha-contexto-da-conversa-persiste-na-sessao-da-jan
B188 — Sollinha: contexto da conversa persiste na sessão da janela/tab
2026-08-10 02:53:54 -03:00
Francisco Solla
03a2f57d03 feat(B185): tool do Sollinha para lideranças pendentes de abordagem + assessores responsáveis
getPendingLeaderships: escopo por território/cidade(Salvador=19ZE)/município com
folding de acento, critério de pendência declarado (status A abordar/Em disputa
ou Engajado sem votePledge no escopo; negativo excluído na query), filtro
sem_assessor (C3), modo municipios_sem_lideranca (C4), nomes de assessores via
query própria, gate staff fail-closed (leader deny antes de qualquer query).
Sem migration/Consent/UI; unit tests 14 novos; allowlist P3-D justificada.
2026-08-10 02:27:04 -03:00
Francisco Solla
1b92c3a305 docs(B193): remove dependência C109 — defect descartado como não-reproduzível em main 2026-08-10 02:07:50 -03:00
Francisco Solla
4fd39cc21c
Merge pull request #544 from fsolla/plans/plan-issue-19
docs(B193): plano de intenção — card de município mobile denso
2026-08-10 01:50:34 -03:00
Francisco Solla
01621e28ab docs(B193): plano de intenção — card de município mobile denso (edit-where-you-see + última atualização expandível) 2026-08-10 01:42:48 -03:00
Francisco Solla
c8e009b47a
Merge pull request #537 from fsolla/C104-agenda-compromisso-todo-o-dia-na-criacao-rapida-so-data
C104 — Compromisso 'Todo o dia' na criação rápida da agenda (só datas, multi-dia)
2026-08-10 01:37:56 -03:00
Francisco Solla
5380154dca fix(B188): simplify — settle não reabre chat fechado no reload desktop; prune com cabeça de pergunta; node fora do Link; mock SSE v7 no B167
- P1: B167 settle forçava open=true no load desktop mesmo com sessão restaurada
  open:false (storage auto-curava para true); restore agora vence quando existe
- prune: cabeça assistant quebra convertToModelMessages; drop até ancorar em user
- MarkdownLink: node do react-markdown não vaza para <Link>/<a>
- isUIMessage: parts com shape inválido falham-closed no restore
- B167 mock: chunk legado {"type":"text"} falha schema v7 (status preso em erro);
  agora usa start/text-start/text-delta/text-end/finish
2026-08-10 01:34:53 -03:00
Francisco Solla
9c1d4839b2
Merge pull request #539 from fsolla/agent/C101-ux-agenda-mobile-affordance-do-hoje-no-titulo-navegacao
C101-ux — Agenda mobile: navegação por teclado + affordance do tap no título
2026-08-10 01:17:05 -03:00
Francisco Solla
ca1dbb80f7 feat(B188): contexto da conversa do Sollinha persiste na sessão da janela/tab
- sessionStorage por aba: mensagens + estado aberto, restaurados no reload;
  escrita só em estado settle (nunca mid-stream); guardrail 50 msgs / 256 KB
- links internos (/campanha…) do markdown navegam via next/link (sem reload)
- e2e novo + ajuste do B167 (visita mobile nova agora loga em viewport mobile)
2026-08-10 01:13:25 -03:00
Francisco Solla
d52d001613 style(C104): format (prettier) 2026-08-10 01:13:12 -03:00
Francisco Solla
ea700e3113 feat(C104): compromisso 'Todo o dia' na criação rápida da agenda (só datas, multi-dia) 2026-08-10 01:13:12 -03:00
Francisco Solla
4e920ee064 feat(C107): sheet de criação de atualização usável no mobile — altura auto até o topo, form sem labels com divisórias full-bleed, placeholders, polaridade em toggle, checks à direita
- MunicipalityUpdateFields ganha layout 'labeled'|'list'; polaridade vira ToggleGroup Ruim|Neutra|Boa nas duas resoluções (mesmo dado, hidden input)
- layout 'list': labels sr-only, textarea sem borda, divisórias divide-y full-bleed, Urgente/Sinalizar adversário como linha tocável com check à direita
- StrictCombobox: prop placeholder (backward-compatible)
- Sheet do feed: max-h-dvh (teto no topo, rola por dentro), título sr-only, form lista com placeholders descritivos; desktop preservado
- Quick-edit B42 herda o visual no sheet mobile via layout
- unit/e2e atualizados para o toggle (radio)
2026-08-10 01:11:24 -03:00
Francisco Solla
8c79eddf96
Merge pull request #536 from fsolla/C105-agenda-tags-para-agrupar-compromissos-filtro-por-tag-na
feat(C105): tags na agenda — sheet, rótulo no evento e prefill do Mais detalhes
2026-08-10 00:58:56 -03:00
Francisco Solla
f3c41d3382 feat(C101-ux): agenda mobile — navegação por teclado (região focável) + affordance do tap no título
- useAgendaKeyboardNavigation: ArrowLeft/Right → prev/next no mobile
  (FullCalendar v7 não tem setas no grid — verificado no bundle); skips
  para modificadores/dialog/menu/inputs; restore de foco na região
- Região de teclado mobile-only: tabIndex/role/aria-label gateados por
  isMobile (desktop mantém a toolbar e sua árvore a11y intacta)
- onTitleClick ganha icon?: LucideIcon (glyph da página, aria-hidden);
  agenda passa RotateCcw como affordance do 'voltar para hoje'
- E2E: teste de teclado (dia e mês), glyph no título, hardening do swipe
  CDP (pacing 25ms — burst era classificado como flick pelo Chromium e
  disparava back-nav ~35% das runs)
- Unit: 14 testes do hook/pura + 4 do renderer do glyph; impl plan
  docs/plans/c101-ux-pos-critique-impl.md (aprovado pelo humano)

Closes #512
2026-08-10 00:53:19 -03:00
Francisco Solla
a4d7b88375
Merge pull request #535 from fsolla/D6-push-no-dispositivo-funcionando-de-ponta-a-ponta-notifica
fix(D6): push no device ponta a ponta — SW dinâmico, subscribe idempotente, check-push-chain
2026-08-10 00:27:47 -03:00
Francisco Solla
cd41b44de4 feat(C105): tags no sheet da agenda + rótulo no evento + prefill no "Mais detalhes"
O filtro por tag na omnibox já existia (C94); o C105 completa a superfície da
agenda: campo de tags no overlay de criação inline (chips, sugestões das tags
já usadas), rótulo leve #tag no evento do calendário (oculto no mês/mobile) e
tags via prefill do "Mais detalhes" (params repetidos, parse fail-closed).

- ActivityTagInput extraído do ActivityForm (compartilhado, aria-label novo)
- "Mais detalhes" espelha estado vivo (horários editados + tags)
- popover do sheet com max-h --radix-popper-available-height (shift-before-flip
  do Radix clipava os campos do topo em viewports baixos)
- submit lê tags do estado espelho (fonte única), 4 KB cap p/ responsáveisJson
- limites mantidos 20/80 (C14), sem migration/access/Consent

Impl: docs/plans/agenda-tags-eventos-impl.md (aprovado no gate humano)
2026-08-10 00:21:20 -03:00
Francisco Solla
944cb6bac1 docs(B191,B192): planos de intenção — ações rápidas de abertura no chat Sollinha (chips no estado vazio) e follow-ups na própria resposta (bloco no prompt, extraído pela UI, slot acima do input) 2026-08-10 00:08:45 -03:00
Francisco Solla
f4873b8b3f fix(D6): push no device ponta a ponta — SW dinâmico, subscribe idempotente, check-push-chain
- /campanha/sw.js force-dynamic: buildId VERCEL_DEPLOYMENT_ID em runtime
  (deploys CLI --prebuilt não têm envs de build; prod servia campanha-dev)
- subscribeCampaignPush find-before-create (endpoint UNIQUE — 2º toque
  estourava com erro falso)
- scripts/check-push-chain.mjs + pnpm db:check:push-chain (read-only,
  veredito por elo: SW/envs/consent/inscrições/eventos)
- VAPID envs adicionadas no Vercel production (ops)
- impl plan + CHANGELOG-AGENTS
2026-08-09 23:41:00 -03:00
Francisco Solla
7576a3489e docs(B185,B186,B189,B190): formatação prettier dos planos 2026-08-09 23:37:04 -03:00
Francisco Solla
1e9693410b docs(B185,B186,B187,B188,B189,B190): planos de intenção — Sollinha gestão (lideranças pendentes, prioridades do momento, cobertura de atualização e de dobradinhas) + links com aparência de link + contexto por sessão da janela 2026-08-09 23:34:57 -03:00
Francisco Solla
7fedf45cd7 docs(C108,D6): planos de intenção — sino de notificações (ler ao abrir + modal desktop) e push no device em produção 2026-08-09 23:10:52 -03:00
Francisco Solla
8896dcb952
Merge pull request #520 from fsolla/plans/plan-issue-16
docs: plano C107 — atualizações mobile sheet de criação usável
2026-08-09 22:56:03 -03:00
Francisco Solla
28c7ef8b2b docs(C107): plano de intenção — atualizações mobile sheet de criação usável (altura auto até o topo, form sem labels com divisórias, placeholders, polaridade em toggle, checks à direita) 2026-08-09 22:52:31 -03:00
Francisco Solla
a7dce2c716
Merge pull request #516 from fsolla/C101-agenda-mobile-calendario-com-cara-de-app-nativo-context
C101 — Agenda mobile: calendário com cara de app nativo (contexto no header, navegação por arrasto, filtro sticky, dia na hora atual)
2026-08-09 22:43:12 -03:00
Francisco Solla
8ee500c3d7
Merge pull request #518 from fsolla/plans/plan-issue-15
docs(plans): C106 — atualizações mobile sem moldura (feed, omnibox sticky, criar no header)
2026-08-09 22:39:00 -03:00
Francisco Solla
505b2f8c85 docs(C106): plano de intenção — atualizações mobile sem moldura (omnibox sticky sem label, criar no header, cards edge-to-edge) 2026-08-09 22:35:30 -03:00
Francisco Solla
c6f13fc6a7 docs(B184): plano de intenção — municípios mobile sem moldura (omnibox sticky, X no input, salvar no header) 2026-08-09 22:28:04 -03:00
Francisco Solla
51fb715ec7 feat(C101): agenda mobile com cara de app nativo — contexto no header, swipe, filtro sticky, dia na hora atual
- toolbar do FullCalendar some no mobile; título do header mostra o período
  ("9 Agosto", "3–9 Agosto", "Agosto", "Agenda") e tap volta ao hoje
- navegação por arrasto horizontal (useAgendaSwipeNavigation): limiar 48px,
  claim 12px com preventDefault, touchcancel sintético contra o long-press
  do FC, dateClick do dia suprimido (C91/C15 intactos)
- filtro vira strip edge-to-edge sem rótulo, sticky sob a barra do app
  (containing block via :has no padding do scroll container)
- visão de dia com scroll interno (height fixa), 08:00 na abertura,
  cabeçalho do dia fixo, scroll preservado ao trocar de dia
- desktop inalterado; impl plan + plano pós-critique (C101-ux)
2026-08-09 22:09:47 -03:00
Francisco Solla
cde4d4107b docs(C99): registra defers com gatilho e explicitamente fora do impl plan (triage pós-merge) 2026-08-09 22:06:38 -03:00
Francisco Solla
457aad5a21
Merge pull request #510 from fsolla/C102-mobile-sem-botao-sheet-de-sidebar-navegacao-pela-barra-
C102 — Mobile: sem botão/sheet de sidebar — navegação pela barra inferior + Mais
2026-08-09 19:56:07 -03:00
Francisco Solla
f0dff330bd feat(C102): sem hamburger/sheet de sidebar no mobile staff — navegação pela barra + Mais
No mobile (<768px) staff perde o botão de abrir sidebar na top bar
(CampaignMobileTopBar role-gated via useCampaignPageChromeRole +
isStaffCampaignRole; leader mantém) e o sheet de navegação deixa de
montar (CampaignSidebar early-return quando isMobile && staff).
Filtros salvos de Municípios (B18) migram para o drawer Mais
(MunicipalityNavSavedFilters variant 'overflow', mesma store,
apagar/desfazer/sucessão de foco; drawer ganha overflow-y-auto).

Correção de bug pré-existente (D4): o Toaster vivia dentro do wrapper
[contain:layout_paint] do painel da AI, que vira containing block para
position:fixed e stacking context próprio — toasts com ação (ex.
Desfazer) ficavam inalcançáveis sob os portais z-50 de drawer/sheet.
Movido para o root layout (campaign).

Testes: unit top bar (staff sem trigger / leader com trigger) + e2e
(staff sem trigger/dialog, leader com sheet, B18 no drawer completo).
2026-08-09 19:13:43 -03:00
Francisco Solla
27daa1339e feat(C99): toda conta campaignUser aponta para uma ficha Contact; lideranças ganham assessores responsáveis 2026-08-09 19:12:35 -03:00
Francisco Solla
7af76b9f68
Merge pull request #509 from fsolla/B183-pwa-ios-foco-em-inputs-aplica-auto-zoom-que-nao-volta-f
fix(campanha): impede auto-zoom do iOS em inputs do PWA (B183)
2026-08-09 19:10:58 -03:00
Francisco Solla
12d339cf7f
Merge pull request #508 from fsolla/B182-pwa-ios-tela-ampliada-e-com-as-bordas-cortadas-desde-o-
fix(B182): PWA iOS — heal do zoom preso do visual viewport no standalone
2026-08-09 19:04:49 -03:00
Francisco Solla
e835108324 fix(campanha): impede auto-zoom do iOS em inputs do PWA (B183)
Regra CSS única em styles.css — @media (pointer: coarse) and (hover: none)
+ [data-theme='campaign'] :is(input, select, textarea, [contenteditable]) a
16px (limiar do Safari iOS). Cobre omnibox B127, Command search, native-select
e textareas em qualquer orientação do iPhone; desktop intocado.

E2E campaignIosInputZoom: emulação iPhone 13 pina 16px na omnibox de
/campanha/municipios; control desktop pina 14px.

Closes #501
2026-08-09 18:54:33 -03:00
Francisco Solla
dff940681d fix(B182): PWA iOS — heal do zoom preso do visual viewport no standalone
Motor client-side (standalone-iOS only, no-op em aba/desktop):
heal imediato no install + launch/bfcache/resume/pós-teclado/resize,
scrollTo(0,0) + re-measure nudge, retry ≤3×250ms por episódio,
pinça preservada (janela renovada por gesture*/touch ≥2), debug
global para verificação em aparelho, fallback maximum-scale off.

40 testes unit (jsdom) pinam detecção, guards, retry e teardown.
2026-08-09 18:50:00 -03:00
Francisco Solla
df842ae246
Merge pull request #507 from fsolla/plans/plan-issue-13
plan(C103/C104/C105): agenda mobile — form de criação usável, todo o dia, tags
2026-08-09 18:37:21 -03:00
Francisco Solla
fc8cecb427 plan(C103/C104/C105): agenda mobile — form de criação usável, todo o dia, tags (planos de intenção) 2026-08-09 18:35:33 -03:00
Francisco Solla
44f4f3b96a
Merge pull request #503 from fsolla/plans/plan-issue-12
plan(B182/B183): status dos planos → ready
2026-08-09 18:10:48 -03:00
Francisco Solla
1f0bcdb2df plan(B182/B183): promote status → ready (planos em main) 2026-08-09 18:09:10 -03:00
Francisco Solla
e938a0e0d2
Merge pull request #502 from fsolla/plans/plan-issue-12
plan(B182/B183): PWA iOS — zoom preso no viewport + auto-zoom de inputs (planos de intenção)
2026-08-09 18:08:38 -03:00
Francisco Solla
a6f15bc81d plan(B182/B183): PWA iOS — zoom preso no viewport + auto-zoom de inputs (planos de intenção) 2026-08-09 18:06:22 -03:00
Francisco Solla
3b652dd7d9 plan(C101/C102): agenda mobile nativa + sem sidebar mobile (planos de intenção) 2026-08-09 17:49:44 -03:00
Francisco Solla
3f7f0cc552
Merge pull request #496 from fsolla/plans/plan-issue-10
plan(C99/C100): identidade de pessoas via Contact + lista unificada
2026-08-09 17:21:13 -03:00
Francisco Solla
79885a715d plan(C99/C100): identidade de pessoas via Contact + lista unificada de pessoas (planos de intenção) 2026-08-09 17:19:32 -03:00
Francisco Solla
65ed945b27 feat(C98): verify calendar import link generation end-to-end (env fix + e2e)
Production feed generation failed with a generic message because
NEXT_PUBLIC_SITE_URL was missing on Vercel production: buildFeedUrl calls
getCampaignInviteBaseURL(), which throws in NODE_ENV=production without the
env (intentional fail-closed), so the action catch returned 'Não foi
possível criar o feed de calendário.' and nothing was created. The local
real-flow verification (login -> agenda without filters -> header icon ->
name -> generate -> link /campanha/agenda/ical/<secret> -> iCal 200 with
the activity) proved C92/C93 work; the divergence was the environment.
Configured NEXT_PUBLIC_SITE_URL=https://pt.jorgesolla.com.br in Production
(+ checked Preview) and redeployed.

New e2e campaignAgendaFeed pins the real flow: desktop (header -> dialog
-> generate -> link responds iCal with the fixture activity) and mobile
(FAB -> sheet -> generate). The e2e fixture now owns calendarFeed rows
(createdBy NOT NULL made the campaignUser cleanup transaction abort).

AGENTS.md deploy checklist notes NEXT_PUBLIC_SITE_URL as mandatory in
Production.

Closes #483
2026-08-09 16:20:59 -03:00
Francisco Solla
fdedfa9ad4 feat(C97): seletor shadcn de dia+horário 24h no popover de criação rápida da agenda
Troca o datetime-local nativo (AM/PM no idioma do browser, horário pouco
confiável) por ActivityDateTimeField: trigger com rótulo civil
dd/mm/aaaa às hh:mm + popover com Calendar (react-day-picker 9.7,
timeZone America/Bahia, locale pt-BR) e selects Hora 00-23 / Minuto
em passos de 15. Contrato de valor e submit inalterados; prefill do
slot mantido. Novo ui/Calendar.tsx (variante radix-nova), helpers
puros em campaignTime.ts. Sem migration. Closes #482 (PR).
2026-08-09 15:13:15 -03:00
Francisco Solla
ff53e15e7e feat(B180): gate fail-closed de leader nas tools eleitorais legadas do Sollinha (getTopDeputies/getMunicipalityVotes)
ElectionDataGate compartilhado (3 call sites) + refactor da B177 para o helper.
2026-08-09 14:54:31 -03:00
Francisco Solla
07b4509e42 feat(campaign): Tendência migra para Ações ao colapsar a coluna (B172)
Em /campanha/municipios (staff), abaixo de 60rem do container a coluna
Tendência some inteira (hidden @min-60:table-cell no th+td, invertendo a
decisão B158 'container query nunca duplica' só para Tendência) e o mesmo
editor monta como ícone compacto na coluna Ações, ao lado do de atualização;
acima de 60rem volta o badge completo e Ações é gated fechado quando nada
está oculto manualmente. Ações torna-se sempre montada para staff e pinada
por ocultação manual no B17. Uma instância visível do editor por linha por
faixa (dual-render CSS-gated, sem JS/resize). Sem migration. Closes #446.
2026-08-09 13:36:04 -03:00
Francisco Solla
d05e299f26 style(C95): formata impl plan (prettier) 2026-08-09 12:35:29 -03:00
Francisco Solla
dff3a9e8b1 feat(C95): seletor de modo de visualização no header do app (agenda)
- view=week|day|month|list no contrato URL da agenda (canônico, fail-closed)
- seletor compacto 'Semana ▾' no header desktop e mobile (slot C94/C95)
- FullCalendar headerToolbar sem os 4 botões de modo; escolha vence resize
- effect normaliza a vista também quando a URL perde o param (sem vista órfã)
- useNarrowMeasured(breakpoint) em hooks/use-mobile (settle de hidratação)
- e2e reescrito no seletor + persistência + escolha-vence-resize + estabilização
  dos waits de slot (grid lazy do FullCalendar substitui gridcells no load)
2026-08-09 12:34:04 -03:00
Francisco Solla
6cf29b3810
Merge pull request #486 from fsolla/B179-sollinha-persona-no-genero-masculino-prompt-referencias
B179 — Sollinha: persona no gênero masculino (prompt + referências .md)
2026-08-09 10:22:35 -03:00
Francisco Solla
f1a8332835
Merge pull request #487 from fsolla/B178-salvador-cidade-agregada-no-campanha-pagina-virtual-lin
feat(B178): Salvador como cidade no /campanha — página virtual, linha comum na lista e busca, sem dupla contagem
2026-08-09 10:21:16 -03:00
Francisco Solla
6760b99942 feat(B179): Sollinha persona no gênero masculino (prompt + placeholder + docs) 2026-08-09 10:07:21 -03:00
Francisco Solla
de66fe3e3f feat(B178): Salvador como cidade no /campanha — página virtual, linha comum na lista e busca, sem dupla contagem 2026-08-09 10:07:05 -03:00
Francisco Solla
d5d1d0c30e chore(B181): remove o aviso de janela vazia da agenda
Sem bloco 'Nenhum compromisso nesta janela e neste filtro' nem botão
'Criar atividade' acima do calendário: a criação segue pelo slot click
(C91), botão dos filtros e FAB. buildActivityCreateHref permanece com
2 consumidores. Teste unitário de regressão + impl plan + changelog.
2026-08-09 09:34:25 -03:00
Francisco Solla
76915b9410
Merge pull request #473 from fsolla/C93-gerar-link-de-import-sem-filtros-agenda-do-escopo
feat(C93): allow generating calendar import link without filters
2026-08-09 09:16:39 -03:00
Francisco Solla
69b7094b1d
Merge pull request #484 from fsolla/plans/plan-issue-6
plan(C98): link de import da agenda sem filtros + geração garantida
2026-08-09 09:13:57 -03:00
Francisco Solla
5ab636018f docs(C97): plano de intenção — seletor shadcn de dia+horário no popover de criação rápida da agenda 2026-08-09 09:11:46 -03:00
Francisco Solla
a6cede2ad7 plan(C98): link de import da agenda sem filtros + geração garantida 2026-08-09 09:11:39 -03:00
Francisco Solla
77ffc22128 docs(plans): B181 — remover aviso de janela vazia na agenda (plano de intenção) 2026-08-09 09:08:12 -03:00
Francisco Solla
2ba7a88531 feat(C93): allow generating calendar import link without filters
The 'Link de import' button was disabled whenever no agenda filter was
active, forcing a filter to subscribe to the full campaign agenda. The
server already supported the empty-filter case (filterMunicipality empty
= entire creator scope via buildFeedWhere/resolveFeedCreatorAccess), so
this unlocks the button and drops the now-dead state/hasFilters props.
The dialog copy is neutralized ('recorte' -> 'agenda') to cover both the
filtered and filterless shapes.

Int tests pin the content acceptance: coordinator filterless feed covers
all municipalities; advisor filterless feed is scoped to the administered
portfolio (nothing out-of-scope leaks); an advisor with no assigned
municipality serves an empty feed (fail-closed). A new component test
asserts the button is enabled with zero filters and the create flow works.

Closes #437
2026-08-09 09:02:06 -03:00
Francisco Solla
1dae9d3823 style(C94): formata changelog (prettier) 2026-08-09 05:09:48 -03:00
Francisco Solla
a195dd6851 docs(C94): nota de estabilização do e2e no impl plan 2026-08-09 04:36:02 -03:00
Francisco Solla
b8ee59f0f6 style(C94): formata (prettier) 2026-08-09 04:36:02 -03:00
Francisco Solla
340407c758 docs(C94): débitos deferidos com gatilho no impl plan 2026-08-09 04:36:02 -03:00
Francisco Solla
d4aceccf3f docs(C94): registra desfecho do /simplify no impl plan 2026-08-09 04:36:02 -03:00
Francisco Solla
ad39602d04 feat(C94): toolbar omnibox + e2e agenda hardening + changelog 2026-08-09 04:36:02 -03:00
Francisco Solla
e0530a3a90 feat(C94): agenda omnibox + feed no header/FAB 2026-08-09 04:35:39 -03:00
Francisco Solla
331ba1b374 style(B176): formata (prettier) 2026-08-09 03:22:47 -03:00
Francisco Solla
14bbee6e00 feat(B176): filtrar municípios por Dobradinha/Liderança/Partido + coluna Dobradinhas ao assessor
Omnibox de /campanha/municipios ganha as dimensões Dobradinha (nome do
contato), Liderança (nome do contato) e Partido (sigla), com recortes
"Sem dobradinha"/"Sem liderança"/"Sem partido" no precedente de
"Sem nível". Params aditivos stateDeputy/leadership/party na URL
congelada; buildMunicipalityListWhere ganha catálogo request-scoped
fail-closed (municipalityRelationSets) que vira as leituras reversa e
cruzada em where — sem migration, paginação nativa mantida; facets
estendidas e o mapa compartilha o catálogo. Coluna Dobradinhas liberada
ao staff (servidor já scoped B37/B157; só o gate de UI mudou).
Extrato do par sentinela+exists:false em campaignListUrl (5 call sites).
2026-08-09 03:19:54 -03:00
Francisco Solla
5be317318d
chore(ai-chat): Sollinha volta para a DeepSeek direta (api.deepseek.com) (#476)
O cache-hit do DeepSeek-V4-Flash custa $0.0028/M contra $0.018/M na
Deep Infra (~6,4x mais barato), e a Sollinha tem prefixo estável
(system prompt + tools + historico), entao o custo efetivo cai. Mesmo
modelo (deepseek-v4-flash), mesmas tools. @ai-sdk/deepseek pinado em
3.0.19 para ficar na ferroviaria provider 4.0.4 / provider-utils
5.0.18 do ai@7.0.47 (o ^ flutuaria a 3.0.26 e duplicaria 4.0.7).

STT (B173) permanece na Deep Infra: whisper-large-v3 a $0.00045/min
de audio e o mais barato verificado (Groq $0.0019, OpenAI $0.006).
.env.example documenta as duas chaves: DEEPSEEK_API_KEY (LLM) e
DEEPINFRA_API_KEY (STT).
2026-08-09 06:11:00 +00:00
Francisco Solla
5a7f3bbb8a
Merge pull request #475 from fsolla/B177-sollinha-responder-em-quais-cidades-x-foi-o-deputado-ma
feat(B177): Sollinha responde em quais cidades X foi o deputado mais votado (rank competitivo reverso, flexível)
2026-08-09 02:46:17 -03:00
Francisco Solla
234c69ceef
Merge pull request #468 from fsolla/C96-feed-ical-interseptar-escopo-do-criador-no-read-defesa-e
fix(C96): intersect creator scope in calendar feed read (+ tests)
2026-08-09 02:35:56 -03:00
Francisco Solla
cef946ad7d feat(B177): Sollinha responde em quais cidades X foi o deputado mais votado (rank competitivo reverso, flexível) 2026-08-09 02:35:53 -03:00
Francisco Solla
7785c1088c fix(worktree): provisiona PLAYWRIGHT_BASE_URL no .env.test.local — e2e usa porta do slot (OPS20)
O .env.test.local (que o playwright.config.ts lê) passa a carregar
PLAYWRIGHT_BASE_URL na porta do slot (3100+slot); antes só o .env.local
(que o config não lê) o tinha, então dois test:e2e em worktrees paralelos
subiam dev servers na porta 3000. Causa-raiz tratada: os dois blocos env
inline do provision viraram um builder puro único (worktreeEnvFileContents
em scripts/lib/worktree-env.mjs) que deriva NEXT_PUBLIC_SITE_URL +
PLAYWRIGHT_BASE_URL do mesmo devPort para ambos os arquivos — paridade
estrutural, drift impossível + unit tests de paridade. playwright.config.ts
intocado (a variável certa já existia).
2026-08-09 02:19:26 -03:00
Francisco Solla
177803a54a
Merge pull request #470 from fsolla/B173-sollinha-consulta-por-voz-no-chat
B173 — Sollinha: consulta por voz no chat
2026-08-09 02:16:53 -03:00
Francisco Solla
9f997aa232
Merge pull request #471 from fsolla/B175-repintar-a-lista-de-territorios-no-padrao-da-lista-de-m
B175 — Repintar a lista de Territórios no padrão da lista de Municípios
2026-08-09 01:58:06 -03:00
Francisco Solla
4668c018bf feat(B173): consulta por voz no chat da Sollinha (STT → rascunho)
Adiciona entrada por voz ao chat: botão de mic no InputGroup grava no
browser (getUserMedia + MediaRecorder), envia o clip multipart para a nova
rota POST /campanha/api/ai-transcribe (auth cookie + rate limit no mesmo
balde + same-origin) e injeta a transcrição como rascunho editável — o
envio segue o fluxo normal do chat. O áudio nunca é persistido.

STT via Deep Infra whisper-large-v3 (DEEPINFRA_API_KEY, mesma do B174);
a costura de rede vive em utilities/ai/deepInfraTranscribe.ts; a máquina
de captura em useMicTranscript. Falha de permissão/provedor degrada a
mensagem em pt-BR sem quebrar o chat por texto.

Closes #448
2026-08-09 01:47:03 -03:00
Francisco Solla
fe81358fe3 B170 — spec do contrato do colapso de chips + shift único do load SSR deferido documentado
F1: RelationChipCell ganha spec unitário (relationChipCellCollapse) que pina o
colapso medido pelo layout real (16 chips → slice de 3 linhas = 12), expande
pelo 'Ver mais…' e recolhe pelo 'Ver menos', com getBoundingClientRect stubado
por índice — a lacuna que o B169 deixou (specs com measureOverflow:false ou
1 chip) não tinha regressão do comportamento de colapso após a mudança de timing.

F2: medição PerformanceObserver no worktree confirma o resíduo pré-hidratação
do B169 sem regressão material: load SSR→hidratação com shifts únicos
[0.139, 0.043, 0.257] (fontes do shell, nenhuma célula de chips) e ordenação
client-side com zero shifts novos; eliminá-lo exigiria estimativa de largura
(rejeitada) ou mudança de layout/regra (anti-goal) → defer documentado.

Sem migration, dados, access ou mudança visual.
2026-08-09 01:36:59 -03:00
Francisco Solla
fd1f6b267b docs(plans): C96 — registra triage de débitos no impl plan (defer S1/S2 + descartes) 2026-08-09 01:26:45 -03:00
Francisco Solla
c9f42bfc70
Merge pull request #465 from fsolla/B174-sollinha-no-deep-infra-llm-mesma-api-e-chave-dos-agente
B174 — Sollinha no Deep Infra (LLM) — mesma API e chave dos agentes
2026-08-09 01:20:34 -03:00
Francisco Solla
01ffb86c8d
Merge pull request #466 from fsolla/plans/plan-issue-8
docs(plans): OPS20 — isola porta do e2e por worktree
2026-08-09 01:06:47 -03:00
Francisco Solla
47f30d1bb1 docs(plans): OPS20 — isola porta do e2e por worktree (PLAYWRIGHT_BASE_URL no .env.test.local) 2026-08-09 01:03:18 -03:00
Francisco Solla
8a8d6631aa docs(plans): remover placeholder literal de classe Tailwind do impl plan B175 2026-08-09 00:56:01 -03:00
Francisco Solla
071a2eb32f
Merge pull request #463 from fsolla/plans/plan-issue-7
docs(plans): B177–B179 — planos de intenção da família Sollinha
2026-08-09 00:55:34 -03:00
Francisco Solla
5b342146d5 fix(C96): intersect creator scope in calendar feed read
buildFeedWhere trusted filterMunicipality without intersecting the
creator's current municipality scope when accessibleMunicipalityIds is
non-null (advisor). An advisor removed from a municipality after creating
a pinned feed kept serving its activities. Now the read re-derives the
creator's scope on every request (fail-closed, aligned with C16) and
intersects it into the where clause via the canonical
advisorMunicipalityScopeWhere fragment.

Int tests cover: advisor in-scope lists, advisor removed stops serving,
coordinator (unrestricted) unchanged. No migration (config/consulta only).
2026-08-09 00:55:11 -03:00
Francisco Solla
74fb12723b docs(plans): B177–B179 — planos de intenção da família Sollinha (cidades mais votadas · Salvador cidade · gênero masculino) 2026-08-09 00:52:42 -03:00
Francisco Solla
0c7adad44b
Merge pull request #459 from fsolla/plans/plan-issue-5
docs(plans): B176 — filtrar municípios por Dobradinha/Liderança/Partido + coluna Dobradinhas ao Assessor
2026-08-09 00:43:12 -03:00
Francisco Solla
175483e7b0 docs(plans): B176 — filtrar municípios por Dobradinha/Liderança/Partido na omnibox + coluna Dobradinhas ao Assessor 2026-08-09 00:38:58 -03:00
Francisco Solla
9d827fbd0d style(docs): formato prettier no impl plan B174 2026-08-09 00:06:12 -03:00
Francisco Solla
3a8506ad06 chore(ai-chat): Sollinha via Deep Infra — mesma API e chave dos agentes
Troca o provider da Sollinha de @ai-sdk/deepseek (api.deepseek.com) para
@ai-sdk/deepinfra (API OpenAI-compatível da Deep Infra), mantendo o mesmo
modelo deepseek-ai/DeepSeek-V4-Flash e as mesmas tools. Uma chave só
(DEEPINFRA_API_KEY), a mesma dos agentes; rollback = git revert.

Closes #449
2026-08-09 00:06:12 -03:00
Francisco Solla
e3f6d3f5eb
Merge pull request #457 from fsolla/C89-pagina-atualizacoes-feed-de-cards-filtro-criar-modal-bot
C89 — Página Atualizações: feed de cards + filtro + criar (modal / bottom sheet)
2026-08-09 00:05:05 -03:00
Francisco Solla
e75bb1c2f3 feat(campaignTerritories): repintar a lista de Territórios no padrão da lista de Municípios (B175)
- Colunas responsivas ao painel via @container/territory-list (P0→P3), sem scroll horizontal
- Contagem de municípios no nome ("Irecê (20)"); % e votos absorvidos na célula 2022 (hover = válidos)
- Célula 2026 no detalhe de Municípios (valor central + %, faixa de cenários no hover, leitura)
- Colunas de rede só leitura: Assessor, Liderança, Dobradinha (para todo o staff)
- Cobertura oculta por padrão no seletor; labels curtos (2022/2026/Captura/Cobertura)
- loadTerritoryOverview devolve { rows, references }; rollup puro com soma por cenário, hasEstimate e uniões de rede
2026-08-08 23:58:54 -03:00
Francisco Solla
c9134becd1
Merge pull request #456 from fsolla/C92-link-de-import-corrigir-criacao-do-feed
fix(C92): corrige criação do link de import da agenda (feed)
2026-08-08 23:39:43 -03:00
Francisco Solla
29ed733190 fix(C92): calendar feed creation stripped by admin-only system fields
createCalendarFeedLinkRecord failed with `overrideAccess:false` +
`user: campaignUser` because Payload stripped the required
`secretSlug`/`createdBy` fields (create access was admin-only) -> 400
behind the generic message; revokeCalendarFeedRecord silently no-opped
(revokedAt update access also admin-only).

- canCreateCalendarFeed now enforces advisor filterMunicipality scope
  on data (canCreateSupporter precedent) + canSetCalendarFeedSecret /
  canSetCalendarFeedRevocation permit staff to mint the secret on create
  and mark a feed revoked; secret read stays `() => false` and update
  admin-only.
- CalendarFeed stamps createdBy via stampCampaignCreatedBy; secret
  create + revokedAt update use the new staff field accesses.
- Action refactored to `*Record` (payload, actor) cores + thin wrappers;
  assertFilterMunicipalityInScope (tour precedent); console.error keeps
  the real error on the server while the friendly message stays.
- 10 int tests for create/scope/revoke/leader/secret; fixture tracks
  calendarFeed cleanup.

Closes #436
2026-08-08 23:13:30 -03:00
Francisco Solla
5a51d60c9e style(C89): formata (prettier) 2026-08-08 23:11:05 -03:00
Francisco Solla
8d96263554 docs(plans): C89 — registra triage de débitos no impl plan (defer S1 + descartes) 2026-08-08 23:07:23 -03:00
Francisco Solla
7343f15053 feat(C89): página Atualizações — feed de cards + filtro omnibox + criar (modal/bottom sheet)
Substitui o placeholder B164 por um feed operacional da carteira (staff):
- Cards com avatar do autor, polaridade/urgente/adversário, município e data
- Filtro omnibox (município via dotted-path, polaridade, urgente, autor, busca)
  no padrão das listas (URL canônica + adapter puro)
- Criação in-place: modal desktop / bottom sheet mobile, reusando o registro
  unificado (C87) com prefill do município do filtro ativo
- Leader lockdown intacto (gate staff + canReadMunicipalityUpdate fail-closed)
- parseMunicipalityUpdateFormData único para os 3 forms de atualização
- Loader cruzando a carteira sem cláusula de município (access por ator)
- Int/unit specs (19 unit + 5 int) + convenções

Fix real: o modal de criação não pode ser filho React do <form> de filtros —
React 19 não liga progressive enhancement em action-form aninhado.
2026-08-08 23:07:23 -03:00
Francisco Solla
0a073c8e61
Merge pull request #454 from fsolla/B171-barra-inferior-mobile-folga-no-topo-rotulos-sem-sobrepo
fix(campaign): barra inferior mobile — folga no topo e rótulos sem sobreposição
2026-08-08 19:15:59 -03:00
Francisco Solla
5a3ff06b9f docs(plans): B171 — gatilho deferido do /simplify no impl plan 2026-08-08 18:46:10 -03:00
Francisco Solla
f3d2f46a58 test(campaign): reforça e2e da barra inferior mobile após /simplify
- pina paddingTop >= 10px (pt-2.5) e cobre viewport 320px — o aceite da
  intenção promete rótulos legíveis em qualquer largura mobile.
2026-08-08 18:45:42 -03:00
Francisco Solla
2ba0cebf6f
Merge pull request #452 from fsolla/C91-criar-evento-inline-no-calendario-da-agenda-estilo-googl
C91: criar evento inline no calendário da agenda (estilo Google Calendar)
2026-08-08 18:45:27 -03:00
Francisco Solla
ecb1af695a
Merge pull request #453 from fsolla/plans/plan-issue-3
docs(plans): B175 — repintar lista de Territórios (padrão Municípios)
2026-08-08 18:40:27 -03:00
Francisco Solla
330aa2aa62 docs(plans): B175 — repintar a lista de Territórios no padrão da lista de Municípios 2026-08-08 18:38:47 -03:00
Francisco Solla
a1a0e3701d
Merge pull request #434 from fsolla/B167-migrar-o-chat-sollinha-entre-painel-e-drawer-ao-redimen
B167 — Migrar o chat Sollinha entre painel e drawer ao redimensionar
2026-08-08 18:38:24 -03:00
Francisco Solla
eb94a81ebc fix(campaign): barra inferior mobile — folga no topo e rótulos sem sobreposição
B171 #443
- CampaignBottomNav: pt-2.5 no nav (respiro da borda superior) e rótulos
  text-[10px] nowrap com gap-1 — sem encolher a área de toque.
- e2e: assert paddingTop >= 8px, rótulos < 12px e sem sobreposição horizontal.
2026-08-08 18:37:12 -03:00
Francisco Solla
77673147ca feat(C91): cria evento inline no calendário da agenda (popover/drawer no slot clicado) 2026-08-08 18:27:25 -03:00
Francisco Solla
5b59e07143
Merge pull request #450 from fsolla/plans/plan-issue-1
docs(plans): B173-B174 — Sollinha: consulta por voz + LLM movido para a Deep Infra
2026-08-08 18:22:55 -03:00
Francisco Solla
343f9f0fae docs(plans): B173-B174 — Sollinha: consulta por voz no chat + LLM movido para a Deep Infra 2026-08-08 18:20:51 -03:00
Francisco Solla
77498c83c1
Merge pull request #447 from fsolla/plans/plan-issue-2
docs(plans): B172 — tendência colapsa para a coluna Ações na lista de municípios
2026-08-08 18:12:13 -03:00
Francisco Solla
89445d17fb docs(plans): B172 — tendência colapsa para a coluna Ações na lista de municípios
Sucessor/refino do B158: onde a coluna Tendência colapsaria para ícone no
próprio lugar, esconder a coluna inteira e mostrar o editor como ícone em
Ações, ao lado do ícone de atualização. Uma instância por linha (invariante
B158). Related #446.
2026-08-08 18:09:33 -03:00
Francisco Solla
9b6fa2763c
Merge pull request #445 from fsolla/plans/plan-issue
docs(plans): mark B171 plan ready
2026-08-08 18:06:53 -03:00
Francisco Solla
a097252af7 docs(plans): B171 status ready após promote 2026-08-08 18:05:30 -03:00
Francisco Solla
031521b4f5
Merge pull request #442 from fsolla/B169-estabilizar-a-lista-de-dobradinhas-parar-o-flicker-de-l
B169 — Estabilizar a lista de Dobradinhas (parar o flicker de linhas/colunas)
2026-08-08 18:04:19 -03:00
Francisco Solla
63e5ea1c51
Merge pull request #444 from fsolla/plans/plan-issue
docs(plans): B171 barra inferior mobile + C89 página Atualizações
2026-08-08 18:04:17 -03:00
Francisco Solla
bef68678ff docs(plans): B171 barra inferior mobile (folga + rótulos) e C89 página Atualizações (feed + filtro + criar) 2026-08-08 18:01:29 -03:00
Francisco Solla
3d55d5760f B169 — estabilizar a lista de Dobradinhas: medir overflow de chips antes da paint (useLayoutEffect)
O ciclo medir→recolher de RelationChipCell rodava em useEffect (pós-pintura),
fazendo cada remount (navegação RSC, paginação, ordenação, filtro) pintar o
clamp max-h-18 e só então colapsar para o slice de 3 linhas — uma onda de
LayoutShift por célula (tabela 1122→682px). Mudar os 3 effects de
medição/invalidação para useLayoutEffect faz a primeira pintura já chegar na
altura final (medido: tabela estável, zero LayoutShift nas navegações).

Documenta o resíduo do load SSR (paint pré-hidratação) e registra follow-up
B170 (#441) para o spec do contrato de colapso + avaliação do shift único.
2026-08-08 17:53:20 -03:00
Francisco Solla
0e38d19d42 feat(B167): migra o chat Sollinha entre painel e drawer ao redimensionar
- Converse (useChat) lifts to the provider: survives desktop panel <-> mobile
  drawer swaps, internal /campanha navigation and resize (new tab still resets).
- Chat Panel/Separator always mounted (RRP panel-count change forces a full
  navigation); footprint hidden via elementRef + .b167-ai-chat-hidden
  (display:none !important), avoiding RRP's imperative collapse/expand races.
- Single 'open' flag drives both surfaces (open && viewport); reconciled with
  the panel at desktop settle and on user drag-collapse (gated by isUserInteraction).
- Mobile Drawer extracted to CampaignAIDrawer; FAB/setOpen unified; focus moves
  into the chat on the mobile->desktop swap.
- e2e campaignAiChatResize: desktop->mobile, mobile->desktop, closed stays
  closed, fresh mobile visit closed, navigation survival, new tab resets.
- Impl plan: docs/plans/migrar-chat-painel-drawer-resize-impl.md

Closes #416
2026-08-08 17:52:02 -03:00
Francisco Solla
09d44c1b9d
Merge pull request #435 from fsolla/C90-remodelar-responsaveis-da-atividade-campo-unico-polimorf
C90 — remodela responsáveis da Atividade (campo único polimórfico)
2026-08-08 17:25:02 -03:00
Francisco Solla
d48cb9ed91
Merge pull request #440 from fsolla/plans/c92-c95-agenda-header-feed
docs(plans): C92–C95 — agenda: feed link, sem-filtros, combobox e header do app
2026-08-08 17:23:19 -03:00
Francisco Solla
0d5bf274ff docs(plans): C92-C95 — agenda: corrigir feed link, sem-filtros, combobox e header do app 2026-08-08 17:20:48 -03:00
Francisco Solla
63642483a4 feat(C90): remodela responsáveis da Atividade em campo único polimórfico
Um campo responsible (staff campaignUser · leadership · stateDeputy) multi-valor
substitui responsible/Contact + advisors + leadership; assessor mantém acesso via
notação-objeto equals no access; nova migração esquema+dados (advisors/leadership
→ responsible); busca q da lista título-only; notificação notifica staff do campo.
Closes #426
2026-08-08 17:10:48 -03:00
Francisco Solla
8b2bc51aa5
Merge pull request #433 from fsolla/plans/plan-issue
worktree: plan cria um worktree diferente por invocação (paralelismo /plan-issue)
2026-08-08 16:52:26 -03:00
Francisco Solla
6c8c466b40 fix(worktree): plan cria um worktree diferente por invocação (paralelismo /plan-issue)
Cada 'pnpm worktree plan' agora deriva um branch próprio: plans/plan-issue-<bag>
quando um bag é passado (sufixo -2/-3 em colisão) ou o próximo sequencial
plans/plan-issue-<n> quando não. O prefixo minúsculo plans/… nunca colide com o
branch <Code>-<slug> de 'next'. planBranchName (scripts/lib/worktree.mjs)
unit-testado; docs e shell/command atualizados.
2026-08-08 16:40:05 -03:00