Merge pull request #394 from fsolla/plans/c14-c16-agenda

docs: plans C14–C16 agenda (FullCalendar + sync)
This commit is contained in:
Francisco Solla 2026-08-06 03:05:15 +00:00 committed by GitHub
commit 343ccdcf93
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 259 additions and 0 deletions

View file

@ -0,0 +1,82 @@
# C15 — FullCalendar em `/campanha/agenda`
Status: blocked (plano ainda não em main)
Atualizado em: 2026-08-06
Issue: #390
Priority: P1
Model: composer-2.5
Model-local: deepseek-v4-flash-high
Impeccable: D — superfície nova: agenda semanal/mensal no lugar da grade de cards como vista primária
Canvas UI: `/home/fsolla/.cursor/projects/home-fsolla-cursor-worktrees-teqo-jr8x/canvases/plan-c15-ui-draft.canvas.tsx`
Appetite: ~1,5–2 dias eng; um outcome verificável — staff opera a semana em calendário em Teqo
Responsável: —
## Intenção
Com o modelo enxuto (C14), a maior alavanca de adoção é **ver e mexer o tempo como no Google Calendar**, dentro de Teqo — sem sync ainda. FullCalendar (MIT: week/month/list + interaction) na rota `/campanha/agenda`, com filtros que a mesa já entende (município, deputado presente, tags) — os mesmos filtros que a C16 transforma em link de import.
## Persona e fluxo
- **Persona / contexto:** coordenador na semana do candidato; assessor no recorte de municípios; quem só precisa _ver_ usa filtros (ex.: deputado presente).
- **Job principal:** enxergar a semana filtrada, criar no slot, abrir compromisso; remarcar presença do deputado só se for coordenador/candidato.
- **Fluxo desejado:** Agenda → semana → aplica filtros (tags / município / deputado presente) → cria no vazio / abre evento / arrasta (se permitido) → detalhe operacional quando precisar.
- **Anti-goals de produto:** N calendários tipo Google Resources; sync nesta fatia; assessor remarcar agenda do deputado.
### Esboço de fluxo (D)
```text
[/campanha/agenda] → filtros → semana → criar / abrir / arrastar (se permitido)
```
## Objetivo e aceite
- Staff abre `/campanha/agenda`: vista **semana** default; mês e lista disponíveis.
- Filtros de produto: pelo menos **município**, **deputado presente**, **tags** (e combinação). A vista reflete o filtro ativo.
- Slot vazio → criar com horário pré-preenchido (fluxo C14); município obrigatório.
- Clique no evento → detalhe/painel; drag/resize só quando o ator pode editar aquele compromisso (presença do deputado = só coordenador/candidato).
- Nav “Agenda” → `/campanha/agenda`; rotas antigas de atividades não quebram o hábito (redirect/equivalência — implementação).
- Leader lockdown; sem Google/link de import nesta fatia (C16).
## Dados (intenção)
- **Vou apresentar dados?** Não analítico — calendário operacional.
- **Decisões desbloqueadas:** “o que cabe nesta semana (neste filtro)?” / “posso remarcar?”
- **Forma:** FullCalendar; escopo de leitura do ator.
## Direção no codebase (hipótese)
- **Áreas prováveis:** rota `…/agenda`, componentes de activity/agenda, nav, actions de horário com gate de `deputyPresent`.
- **Precedente a olhar:** `/campanha/atividades`, E13 giros, B138; FullCalendar React MIT plugins.
- **Risco de acoplamento:** client bundle; access; filtros reutilizáveis pela C16.
## Dependências
- Dura: **C14**.
## Fora de escopo
- Link de import / sync Google → **C16** (consome os mesmos filtros).
- Premium resources, recorrência, papéis novos.
- Redesign do compositor de giros.
## Rabbit holes de produto
- **“Sync já.”** **Corte:** C16.
- **“Resources por assessor.”** **Corte:** filtros.
- **“Assessor arrasta evento do deputado.”** **Corte:** política C14.
## Questões em aberto (produto)
- **Calendário vs lista:** **Opções:** A) calendário default + lista modo | B) só calendário. **Recomendação:** **A**. _(assumido — validar)_
- **Filtros persistidos na URL?** **Opções:** A) sim (compartilhável / base do link C16) | B) só estado local. **Recomendação:** **A** — alinha com “link de import do filtro” na C16. _(assumido — validar)_
## Decisões travadas (gate)
- Remarcar `deputyPresent`: só coordenador/candidato.
- Filtros de agenda incluem município, deputado presente, tags (insumo da C16).
## Referências
- GitHub Issue [#390](https://github.com/fsolla/teqo/issues/390)
- Canvas UI (gate): [`plan-c15-ui-draft.canvas.tsx`](/home/fsolla/.cursor/projects/home-fsolla-cursor-worktrees-teqo-jr8x/canvases/plan-c15-ui-draft.canvas.tsx)
- Plano C14 · https://fullcalendar.io · C3/C13/E13

View file

@ -0,0 +1,92 @@
# C14 — Remodelar atividades para a agenda (calendário)
Status: blocked (plano ainda não em main)
Atualizado em: 2026-08-06
Issue: #389
Priority: P1
Model: cursor-grok-4.5-medium
Model-local: deepseek-v4-high
Impeccable: C — simplifica o formulário/detalhe de atividade e o vocabulário da vertical (pré-requisito da UI de calendário)
Canvas UI: `/home/fsolla/.cursor/projects/home-fsolla-cursor-worktrees-teqo-jr8x/canvases/plan-c14-ui-draft.canvas.tsx`
Appetite: ~1,5–2 dias eng; um outcome verificável — criar/editar atividade no modelo enxuto, pronto para calendário
Responsável: —
## Intenção
A equipe vive em Google Calendar; em Teqo a atividade ainda é um formulário operacional denso (tipo fixo `kind`, rascunho/planejado, origem, prazo, vários relacionamentos). Isso atrasa a adoção e força o “ligar pro candidato pra mexer no calendário”. Antes de colocar FullCalendar na tela, o modelo precisa **parecer compromisso de agenda**: tempo + lugar + quem participa + **`tags`** (ex-`kind`) — sem taxonomia rígida que a mesa não usa.
## Persona e fluxo
- **Persona / contexto:** coordenador ou assessor montando a semana sob pressão; celular ou mesa; não quer “cadastrar plano de ação”.
- **Job principal:** registrar ou ajustar um compromisso (com ou sem presença do deputado) em poucos campos, no vocabulário de calendário.
- **Fluxo desejado:** abre criar/editar → título, início/fim, município, flag “deputado presente”, tags livres, omnibox de associados (assessor / liderança / organização) → salva como `confirmado`; status só o ciclo útil (confirmado / realizado / cancelado).
- **Anti-goals de produto:** segundo cadastro de pessoa; enum rígido de tipo; campos de inteligência que a mesa não preenche; sync Google nesta fatia.
### Esboço de fluxo (C)
```text
[criar/editar] → tempo + município + tags + associados (omnibox)
→ (opcional) deputado presente
→ salvo como compromisso na agenda
```
## Objetivo e aceite
- Removidos do modelo/fluxo de produto: `origin`, `deadline`, status `rascunho`/`planejado`.
- No modelo, o campo **`kind` passa a se chamar `tags`**: deixa de ser enum fixo de tipo; vira tags livres (a mesa classifica e filtra como quiser — comício, imprensa, etc.).
- Status enxuto: `confirmado | realizado | cancelado`; compromisso novo nasce `confirmado` com `startAt` obrigatório.
- Associados (assessor, liderança, organização) numa **única** omnibox (multi-seleção mista).
- Continua: um município por atividade; staff-only (leader lockdown); `deputyPresent` acionável.
- **Remarcar / editar horário de compromisso com `deputyPresent`:** só **coordenador** e **candidato** nesta leva (assessor cria/edita o resto no seu escopo; mais papéis depois).
- Lista/detalhe/actions da vertical continuam usáveis após o remodel (C15 traz o calendário).
- Critério de campo: marcar compromisso novo em tempo comparable a um evento no Google Calendar (~menos de um minuto nos essenciais).
## Dados (intenção)
- **Vou apresentar dados?** Não — remodel de cadastro/fluxo.
- **Decisões desbloqueadas:** N/A nesta fatia (desbloqueia filtros/tags na C15/C16).
- **Forma:** adiada.
## Direção no codebase (hipótese)
- **Áreas prováveis:** vertical de atividades (forms, filtros), `src/components/campaign/activity/`, `src/lib/schemas/activity.ts`, actions, access (`deputyPresent` write gate), consumidores de `origin`/`kind`/`deadline` (E13, dossiê, triggers) — `kind` → `tags`; `origin`/`deadline` saem.
- **Precedente a olhar:** C3/C13; C12 (`origin` — **aceite explícito de remover** para simplificar); B138 omnibox; padrões de tag/filtro em outras verticais.
- **Risco de acoplamento:** leader lockdown; não inventar pessoa fora de `Contact`/relações; E13 e filtros que liam `kind` passam a `tags`.
## Dependências
- Nenhuma dura. Soft: C3/C13/C12/E13 entregues (este item **simplifica** inclusive cortando `origin` do C12).
## Fora de escopo
- FullCalendar / `/campanha/agenda` → **C15**.
- Sync / link de import → **C16**.
- Recorrência; novos papéis além de coordenador/candidato para presença do deputado.
- Redesign do compositor de giros (só não quebrar sem destino).
## Rabbit holes de produto
- **“Unificar atividade e giro.”** **Corte:** C14 só enxuga o átomo.
- **“Omnibox busca município/demanda/mídia.”** **Corte:** só associados; município campo próprio.
- **“Taxonomia oficial de tags.”** **Corte:** campo se chama `tags`; valores livres; a mesa inventa; filtro é o valor.
- **“Manter origin ‘só um pouco’.”** **Corte:** removido — produto pediu simplificar.
## Questões em aberto (produto)
- **Tags: livres digitáveis vs catálogo sugerido?** **Opções:** A) só livres | B) livres + sugestões das já usadas | C) catálogo admin fechado. **Recomendação:** **B** (livre + autocomplete do que já existe) — filtro sem burocracia. _(assumido — validar na implementação)_
- **Campo `responsible` (Contact) e tarefas/feed/resultado?** **Opções:** A) manter no detalhe | B) absorver na omnibox. **Recomendação:** **A**. _(assumido — validar)_
- **Dados históricos de `kind`/`origin`?** **Opções:** A) descartar | B) migrar valor antigo de `kind` para `tags`. **Recomendação:** **B** quando houver valor legível; `origin` some. _(assumido — executor decide o barato seguro)_
## Decisões travadas (gate)
- Remover `origin` (aceite: série J-B/C12 deixa de existir nesta dimensão).
- No modelo: renomear **`kind` → `tags`** (tags livres para filtro, não enum de tipo).
- Remarcar presença do deputado: só coordenador e candidato (por enquanto).
- Status: `confirmado | realizado | cancelado`; sem rascunho/planejado; sem `deadline` no compromisso.
## Referências
- GitHub Issue [#389](https://github.com/fsolla/teqo/issues/389)
- Canvas UI (gate): [`plan-c14-ui-draft.canvas.tsx`](/home/fsolla/.cursor/projects/home-fsolla-cursor-worktrees-teqo-jr8x/canvases/plan-c14-ui-draft.canvas.tsx)
- `docs/plans/eventos-agenda-mobilizacao.md` (C3), `renomear-plano-acao-para-atividade.md` (C13), `registro-fundacao.md` (C12), `planejador-de-giros.md` (E13)
- `src/collections/Activity.ts`, `src/lib/schemas/activity.ts`, `src/components/campaign/activity/`

View file

@ -0,0 +1,85 @@
# C16 — Sync por filtro + link de import (Google Calendar)
Status: blocked (plano ainda não em main)
Atualizado em: 2026-08-06
Issue: #392
Priority: P2
Model: cursor-grok-4.5-medium
Model-local: deepseek-v4-high
Impeccable: B — encaixe na agenda: filtro ativo → sync / link de import
Canvas UI: `/home/fsolla/.cursor/projects/home-fsolla-cursor-worktrees-teqo-jr8x/canvases/plan-c16-ui-draft.canvas.tsx`
Appetite: ~1,5–2 dias eng; um outcome verificável — com um filtro da agenda, a pessoa obtém um link de import e o Google Calendar passa a refletir esse recorte
Responsável: —
## Intenção
Quem ainda vive no Google não precisa de “um espelho mágico de tudo”: precisa do **recorte certo** (só deputado presente, só um município, só certas tags, combinação). Em Teqo a pessoa aplica o filtro na agenda e **gera um link de import** desse filtro para colar no Google Calendar (Assinar URL / importar). Teqo continua SoT; o Google consome o recorte. Assim comunicação e o candidato escolhem o que acompanhar sem ligar pedindo atualização.
## Persona e fluxo
- **Persona / contexto:** coordenador monta o filtro “deputado presente”; comunicação importa esse link no GCal da equipe; assessor pode querer só seus municípios (no escopo que já vê).
- **Job principal:** transformar o filtro atual da agenda num calendário assinável no Google.
- **Fluxo desejado:** na agenda (C15) aplica filtros → “Link de import” / sincronizar este filtro → copia URL → cola no Google Calendar → cria/edita/cancela em Teqo atualizam o feed desse recorte.
- **Anti-goals de produto:** sync bidirecional; obrigar OAuth de N contas pessoais; um único espelho sem filtro; Teqo como escravo do Google.
### Esboço de fluxo (B)
```text
[filtros na agenda] → gerar link de import deste filtro → Google assina a URL
→ mudanças em Teqo (no recorte) aparecem no GCal
```
## Objetivo e aceite
- A partir dos filtros da agenda (município, deputado presente, tags, combinação), o usuário autorizado gera um **link de import** daquele recorte.
- O link é usável no Google Calendar como calendário por URL (feed do recorte); quem importa vê os compromissos que passam no filtro.
- Alterações em Teqo no conjunto filtrado refletem no feed (criar / remarcar / cancelar no recorte).
- Teqo permanece SoT: falha ou atraso no consumidor não corrompe dados locais.
- Escopo de leitura do link respeita access (não vaza municípios fora do ator que criou/autorizou o link — fail-closed).
- Leader lockdown; sem Google → Teqo.
## Dados (intenção)
- **Vou apresentar dados?** Não analítico.
- **Decisões desbloqueadas:** “este recorte da agenda está no meu Google?”
- **Forma:** adiada (UI: ação na barra de filtros + estado do link).
## Direção no codebase (hipótese)
- **Áreas prováveis:** agenda C15 (barra de filtros), endpoint/feed assinável do recorte, token/HMAC ou secret de feed (precedente de tokens de campanha), sem PII extra além do necessário no evento (título + município).
- **Precedente a olhar:** filtros C15/C14 tags; padrões de token HMAC em campanha; Google “From URL”.
- **Risco de acoplamento:** URL secreta = capacidade de leitura do recorte — rotação/revogação; não expor telefone de liderança no feed.
## Dependências
- Dura: **C15** (filtros + agenda). Soft: **C14** (tags).
## Fora de escopo
- Sync bidirecional / import contínuo Google → Teqo.
- OAuth push obrigatório para um único GCal canônico (o link de import cobre o job; push OAuth só se o link não bastar — fora desta fatia).
- Papéis novos; N conexões OAuth por assessor.
## Rabbit holes de produto
- **“Push OAuth + ICS + webhooks.”** **Corte:** link de import do filtro é o outcome.
- **“Feed público sem segredo.”** **Corte:** fail-closed; link com credencial revogável.
- **“Um link global sem filtro.”** **Corte:** o valor é o recorte.
## Questões em aberto (produto)
- **Quem gera/revoga links?** **Opções:** A) só coordenador/candidato | B) qualquer staff no próprio escopo. **Recomendação:** **B** para o próprio escopo (assessor gera link dos municípios que já vê); coordenador para recortes amplos. _(assumido — validar)_
- **Evento no feed:** **Opções:** A) título + município | B) título só | C) + tags. **Recomendação:** **A** (+ tags no título/descrição curta se ajudar o filtro mental); sem lista de lideranças. _(assumido — validar)_
- **Cancelados no feed?** **Opções:** A) somem | B) constam como cancelados. **Recomendação:** **A** (some do calendário importado). _(assumido — validar)_
## Decisões travadas (gate)
- Sync **de acordo com o filtro** (município, deputado presente, tags, etc.).
- Entrega = **link de import** do filtro (não espelho único fixo “só deputado”).
- Direção Teqo → consumidor (Google); sem bidirecional.
## Referências
- GitHub Issue [#392](https://github.com/fsolla/teqo/issues/392)
- Canvas UI (gate): [`plan-c16-ui-draft.canvas.tsx`](/home/fsolla/.cursor/projects/home-fsolla-cursor-worktrees-teqo-jr8x/canvases/plan-c16-ui-draft.canvas.tsx)
- Planos C14 / C15