Commit graph

153 commits

Author SHA1 Message Date
Francisco Solla
6a3f61f968 ops(OPS53): etapa de deploy no CI para o homeserver (teqo-1313)
Job deploy em ci.yml (runs-on host na workstation) streama
scripts/deploy-homeserver.sh para o homeserver via SSH: build dos stages
runner+migrator com secrets do teqo-1313.env, push no registry local,
migrate pelo serviço de maintenance antes do rollout, up + smoke. Zero
secrets novos no Forgejo; HEAD guard + flock; rollback automático com
backup do compose; runbook docs/ops/teqo-1313-deploy.md; invariantes
unit do script (bash -n + estrutura).
2026-08-18 00:50:41 +00:00
Francisco Solla
e03ba1f83b ops(OPS51): migra o banco de produção do Neon para o Postgres do homeserver (teqo_1313)
All checks were successful
CI / static (push) Successful in 1m45s
CI / int (push) Successful in 2m2s
CI / build (push) Successful in 2m38s
CI / e2e (1) (push) Successful in 4m10s
CI / e2e (2) (push) Successful in 3m39s
CI / checks (push) Successful in 1s
Dump pg_dump -Fc do Neon no homeserver (/srv/hdd/backups/teqo-neon-pre-migracao/),
restore como a role teqo_1313 (o container já lia o banco preparado — sem mudança
de config). Neon intacto como rollback. Divergência da intenção (A/B validada como
B): destino = teqo_1313, não teqo_prod. Débito de media registrado (#10 → OPS52).
2026-08-17 22:41:18 +00:00
Francisco Solla
3cd0b4e0f5 style(worktree): prettier na ordem dos imports de node:fs
Some checks failed
CI / static (push) Successful in 2m10s
CI / int (push) Successful in 2m20s
CI / build (push) Successful in 3m7s
CI / e2e (2) (push) Has been cancelled
CI / e2e (1) (push) Has been cancelled
CI / checks (push) Has been cancelled
2026-08-17 19:32:40 -03:00
Francisco Solla
de8962457d fix(worktree): copia .opencode/secrets para o worktree provisionado
O opencode.json referencia .opencode/secrets/penpot-token via {file:...},
mas o arquivo é gitignored e git worktree não leva ignored files — o
launch do opencode no worktree morria com 'bad file reference'.
provision agora copia .opencode/secrets/* do worktree principal
(sem sobrescrever cópia manual).
2026-08-17 19:32:10 -03:00
Francisco Solla
f151376641 ops(OPS50): remove deploy Vercel do pipeline — produção é self-hosted no homeserver (jorgesolla1313.com.br); ci.yml vira verificador puro (sem deploy/requeue), apaga vercel-promote.yml, scripts/tests/vercel.json e secrets VERCEL_*
Some checks failed
Agent PR Ready + auto-merge / ready-automerge (pull_request) Has been skipped
CI (PR) / docs-guards (pull_request) Successful in 7s
CI (PR) / plans-only-closes (pull_request) Successful in 7s
CI (PR) / scope (pull_request) Successful in 32s
CI (PR) / lint (pull_request) Successful in 40s
CI (PR) / format (pull_request) Failing after 47s
CI (PR) / typecheck (pull_request) Successful in 31s
CI (PR) / knip (pull_request) Successful in 32s
CI (PR) / cycles (pull_request) Successful in 32s
CI (PR) / unit (pull_request) Successful in 46s
CI (PR) / int (pull_request) Has been skipped
CI (PR) / build (pull_request) Has been skipped
CI (PR) / e2e (1) (pull_request) Has been skipped
CI (PR) / e2e (2) (pull_request) Has been skipped
CI (PR) / checks (pull_request) Failing after 1s
2026-08-17 13:17:17 -03:00
Francisco Solla
02f68894c3 fix(ci OPS50): guards de banco aceitam o gateway da bridge do runner (RFC1918) — postgres do services: fica no IP do gateway, não em localhost
Some checks failed
Agent PR Ready + auto-merge / ready-automerge (pull_request) Has been skipped
CI (PR) / docs-guards (pull_request) Successful in 6s
CI (PR) / plans-only-closes (pull_request) Successful in 6s
CI (PR) / scope (pull_request) Successful in 31s
CI (PR) / lint (pull_request) Successful in 40s
CI (PR) / format (pull_request) Successful in 48s
CI (PR) / typecheck (pull_request) Successful in 31s
CI (PR) / knip (pull_request) Successful in 32s
CI (PR) / cycles (pull_request) Successful in 33s
CI (PR) / unit (pull_request) Successful in 46s
CI (PR) / build (pull_request) Has been skipped
CI (PR) / int (pull_request) Failing after 1m5s
CI (PR) / e2e (pull_request) Failing after 2m47s
CI (PR) / checks (pull_request) Failing after 1s
2026-08-17 03:46:16 -03:00
Francisco Solla
f20305759a OPS50: port CI e scripts de agentes do GitHub para o Forgejo
Workflows nativos em .forgejo/workflows/ (ci, ci-pr, agent-pool,
automerge, issue-transition, plan-issue, vercel-promote, archive),
removendo .github/workflows e .github/actions. Runner Forgejo v13 com
services Postgres por porta + DB_HOST via gateway do bridge. Libs de
agente sobre o novo cliente forgejo-api.mjs (zero dependências,
GITHUB_SERVER_URL/FORGEJO_API_URL), helpers de workflow plain-Node.
pnpm issue corrigido (await em função sync) e validado ao vivo. Testes:
forgejoApi.unit.spec.ts novo, pin do matrix do ci.yml atualizado.

Closes #1 (parte 1 — docs/issues/pool seguem na parte 2)
2026-08-16 23:32:20 -03:00
Francisco Solla
7ca0efc95c fix(ci): isola bundle e2e do servidor de desenvolvimento 2026-08-16 01:25:06 -03:00
Francisco Solla
7ddc281f22 feat(site): publica home da campanha Jorge Solla 1313 2026-08-16 00:49:24 -03:00
Francisco Solla
d6df8c6360
Merge pull request #741 from fsolla/C139-contatos-pagina-da-entidade-contact-lista-desktop-cards
C139 — Contatos — página da entidade Contact (lista desktop + cards mobile)
2026-08-13 19:27:17 +00:00
Francisco Solla
0b4d7913fe test(C139): suite e2e campaignContacts e remapeamento do manifest
Cobre a página /campanha/contatos: recorte por omnibox + WhatsApp na
linha, create row desktop (erro de validação mantém o valor digitado,
conflito de nome com mensagem segura, create válido com POST), gate de
staff (líder cai em meus-contatos) e os sheets mobile (create via FAB
com telefone, edit com conflito + ficha atômica). Nomes criados via UI
são letras-only: o runID hex vira [a-p] (bijection, 128 bits).

O manifest ganha a família própria campaignContacts (antes caía no
campaignHomeActions).
2026-08-13 15:16:34 -03:00
Francisco Solla
9471c8f0aa OPS44: changelog por entrega + guards de docs + merge por rebase 2026-08-13 17:55:22 +00:00
Francisco Solla
621364f41f feat(C139): página /campanha/contatos — lista desktop com células editáveis, criação e filtros 2026-08-13 14:29:11 -03:00
Francisco Solla
1daaaf9f4e feat(C139): domínio de contatos — URL state, loader com vínculos e invariante de nome
Fase 2 do plano aprovado. Três módulos em src/utilities/contacts/:
- contactListUrl: contrato de params (q|gender|state|city|ausencia|vinculo|sort|dir|page),
  canonicalize, hrefs de sort e where de fonte com 'phones.value' like (ILIKE verificado
  no Postgres local).
- contactListData: loader com UM find em contact (user threadado, overrideAccess false),
  vínculos (liderancas/dobradinhas/assessores/equipe) como facets sobre o conjunto
  legível, filtro/sort/paginação em memória, nulos no fim (precedente B15).
- contactNameInvariant: lock contact-name:{normalized} + prefilter ILIKE + veredito
  exato em memória; mensagem de conflito pt-BR.

38 testes unit novos; format + tsc limpos.
2026-08-13 14:05:24 -03:00
Francisco Solla
4626a2ea06 chore(ci): remove o migration-lock — deadlock de CI com PRs de schema paralelos (checks passa a ser o único required)
O check falhava quando >1 PR aberto tocava src/migrations/ + payload-types.ts,
deadlockando AMBOS os PRs (9 de 13 runs de CI falhos desde 11/08). A validação
real da cadeia de migrations já roda em todo PR e na main: pnpm migrate +
test:int (incl. campaignMigrationReconciliation). Pool mantém a serialização
de spawn de issues needs:migration via countOpenSchemaPrs.
2026-08-12 13:42:05 -03:00
Francisco Solla
5940c4c61e fix(OPS40): pnpm dev honra o PORT do .env.local — next dev -p via scripts/dev.mjs (Closes #682)
next dev resolve a porta antes de @next/env carregar env-files (commander
.env('PORT') no bin/next), então o PORT=3100+slot do provisionador de
worktree era ignorado e todo dev server subia em 3000. pnpm dev/devsafe
passam por scripts/dev.mjs: preflight do guard-dev-db inline, env com a
mesma precedência (real > .env.local > .env, override:false) e porta como
flag CLI -p (resolveDevPort/nextDevArgs em scripts/lib/cli.mjs,
unit-testados). Sem PORT → nenhum -p → default 3000 + allowRetry intactos.
2026-08-11 20:04:07 -03:00
Francisco Solla
631635ee89 chore(plan-issue): rascunho UI/UX do gate vira HTML+Tailwind commitado no repo (ad-hoc) 2026-08-11 19:14:21 -03:00
Francisco Solla
21b4b4d0c6 fix(gate): seleção e2e contendo apenas o spec setup vira none (setup é dev-only; OPS39) 2026-08-11 15:47:12 -03:00
Francisco Solla
aa8fe582c0 feat(B198): drawer mobile do Sollinha fecha ao navegar por link interno
O renderer de links do chat decide interno vs externo (B187/B188); a decisão
pura de fechamento mora no owner src/lib/ai/markdownLinks.ts
(shouldCloseDrawerOnLinkClick: interno && mobile && clique simples) e o
markdownComponents estatico virou useMemo no corpo do CampaignAIChat para
alcancar o contexto. Desktop inalterado; links externos/modos de nova aba
mantem o drawer da aba de origem; sessao e restore intactos (close persiste
open:false).

- unit: 12 testes da decisao pura
- e2e (modo CI, E2E_PROD=1): interno fecha + navega sem load + reload nao
  reabre; externo abre popup e mantem o drawer
- debito B199/#672 (depends #660): race de persistencia ao fechar mid-stream
2026-08-11 14:29:29 -03:00
Francisco Solla
6de8fad8f6 feat(C112): múltiplos telefones por pessoa — Contact.phones array (ordem = prioridade)
- Contact.phone (text único) → phones (array field Payload, subcampo value):
  fonte única; principal = phones[0]; beforeValidate normaliza, filtra vazios,
  rejeita inválido e duplicado DENTRO da ficha (C111 entre fichas preservado)
- migration add_contact_phones_array: backfill phone → phones[0] (gen_random_uuid)
  antes do drop da coluna + índice em value (hand-edit documentado; snapshot .json
  gerado mantém as colunas C99/C100 já existentes)
- primaryPhoneOf / phoneValuesOf / reorderWithPrimaryPhone em src/lib/phone.ts
  (ordem = prioridade; inline edit = seta o principal preservando o resto)
- findOrCreateContactByPhone aceita phones[] (dedupe pelo primário; reuse faz
  append dos faltantes; locks em todos os números digitados)
- sync conta→ficha (CampaignUser): phone da conta faz APPEND quando a ficha não
  tem (nunca reordena nem remove); tombstone LGPD substitui TODOS os telefones
- convite redemption: telefone digitado vira principal, demais preservados
- import CSV: preview sinaliza compartilhado também por número secundário;
  bulk insere contact_phones (JOIN nas leituras, uuid no insert)
- busca por telefone (apoiadores, pickers, combobox) casa qualquer número
- UI: PhonesFieldEditor compartilhado (repetível mascarado, remover, ↑/↓,
  modo inline com Salvar) nas 5 superfícies — liderança (form/ficha/lista),
  apoiador (form/ficha), dobradinha (ficha), assessor (ficha), wizard
- UI pública (petição/WhatsApp) intocada: zod e forms ficam com phone;
  as ações mapeiam phone → phones[0]
- testes: spec novo campaignMultiPhones (aceite completo), specs C111/C99
  atualizados, e2e wizard/apoiador ajustados
2026-08-11 10:47:02 -03:00
Francisco Solla
02a33f1bc0
Merge pull request #638 from fsolla/OPS35+-restaurar-pin-de-visibilidade-css-das-colunas-de-rede
test(OPS35+): restaurar pin de browser da visibilidade CSS das colunas de rede em Territórios
2026-08-11 01:23:44 +00:00
Francisco Solla
91ae6b5408 test(OPS35+): restaurar pin de browser da visibilidade CSS das colunas de rede em Territórios (Closes #616) 2026-08-10 21:28:52 -03:00
Francisco Solla
7c17d43723 fix(OPS37): db:start idempotente — não recria o container Postgres compartilhado (no-op quando saudável; --force-recreate explícito) 2026-08-10 20:40:36 -03:00
Francisco Solla
f460dac6cf
Merge pull request #623 from fsolla/OPS33-worktree-next-claima-deterministicamente-a-issue-e-abr
OPS33: worktree next claima deterministicamente a Issue (--issue N, reopen) e launch com /work-issue --issue N
2026-08-10 23:08:33 +00:00
Francisco Solla
f0f5b73f3f OPS33: worktree next claima deterministicamente a Issue (--issue N, reopen) e launch com /work-issue --issue N
Claim extraído para scripts/lib/agent-github.mjs (claimIssue/claimBriefLines/
claimQueueEntry/claimTargetVerdict), agent-claim.mjs vira CLI fino com mesma
saída; branch validada antes do claim (sem claim órfão); hint de falha
pós-claim; guard -B contra reset de commits de sessão; diretiva launch com
prompt citado + tokenização xargs no worktree.sh; --issue sem valor/posicional
morrem com motivo (sem misclaim); unit novos (directive com issueNumber,
claimQueueEntry, claimTargetVerdict); docs/textos (AGENTS.md, /worktree, skill
worktree-next-issue, AGENT-OPS, CHANGELOG).
2026-08-10 19:46:54 -03:00
Francisco Solla
1f31d1b628 test(OPS35): modo e2e full-stack sem browser (paradigma HTTP) + migração da família Territórios (Closes #600) 2026-08-10 19:30:29 -03:00
Francisco Solla
0047d2637c ops28(OPS28): worktrees rodam o seed mínimo no provisionamento — e2e local espelha a CI
- scripts/worktree.mjs: provision() aplica migrate + db:seed:minimal nos
  bancos dev e test (paridade com a CI, que roda o par antes do e2e);
  --no-migrate pula os dois (o seed depende do catálogo migrado); fallback
  sem Docker também migra+seeda o teqo/teqo_test compartilhado (com warning
  de sobrescrita dos pins).
- Guard de regressão tests/e2e/seedParity.setup.e2e.spec.ts no projeto setup:
  falha cedo com mensagem clara se o banco de teste não estiver seedado;
  evidência = users do seed (MINIMAL_CAMPAIGN_USERS), não os pins de priority
  — o cleanup dos fixtures e2e reseta priority por round-robin persistente.
- scripts/lib/test-affected-core.mjs: scripts/worktree.mjs em HIGH_RISK_EXACT.
- Docs: AGENTS.md, skill local-database, CHANGELOG-AGENTS.md, impl plan.

Closes #584
2026-08-10 16:11:27 -03:00
Francisco Solla
91a0aca5f0
Merge pull request #613 from fsolla/OPS34-ci-e2e-paralelizar-o-job-cadeia-serial-so-em-dev-shard
refactor(OPS34): fixes do /simplify — fallback e2e_shards, timeout webServer, pin anti-drift
2026-08-10 15:58:10 -03:00
Francisco Solla
4ae8f96242 refactor(OPS34): fixes do /simplify — fallback e2e_shards, timeout webServer CI-only, pin anti-drift, docs 2026-08-10 15:37:11 -03:00
Francisco Solla
97be0c28d6
Merge pull request #611 from fsolla/OPS34-ci-e2e-paralelizar-o-job-cadeia-serial-so-em-dev-shard
chore(OPS34): e2e CI em 2 shards e cadeia de projetos dev-only
2026-08-10 15:07:51 -03:00
Francisco Solla
f955c6a7fe chore(OPS34): e2e CI em 2 shards e cadeia de projetos dev-only (Closes #599) 2026-08-10 14:39:39 -03:00
Francisco Solla
9dd8022b6a feat(OPS31): worktree plan abre o opencode com /plan-issue já enviado 2026-08-10 14:36:27 -03:00
Francisco Solla
cc7dff88c4 feat(C100): lista unificada de pessoas em /campanha/pessoas
Merge por Contact (uma linha por pessoa física) de lideranças,
dobradinhas e staff, com capacidades como colunas; omnibox com
capacidade/município/apoio + filtros salvos (2º call site do B18 via
factory createSavedFilterStore); apagar pessoa com manifest de
confirmação e cascata transacional; mobile edge-to-edge (omnibox sem
bordas, cards com divisórias, salvar filtro no header). Sem migration.

Closes #495
2026-08-10 13:45:46 -03:00
Francisco Solla
6fbb71c7e7 chore(OPS22): mapeia o domínio do Sollinha no e2e-affected manifest (chat specs acordam com mudanças no chat) 2026-08-10 13:12:12 -03:00
Francisco Solla
4e5f9e738e OPS32: work-issue no paradigma de Issue já claimada + model-selection só-Cursor
- work-issue reescrita como fluxo próprio do humano: sem claim/verificações
  (contexto via $ARGUMENTS, 1 pergunta de fallback, validação gh issue view,
  nunca claim); plano de intenção do body da Issue (contrato extractPlanPath)
- desacoplada de agent-work-issue; Passos 4-6 extraídos para
  execution-pipeline.md compartilhado com deltas por ator
- model-selection volta ao cardápio único Cursor (remove model-local e o
  mapeamento canônico model:->DeepSeek)
- correlatos: claim brief (metadata consultiva + footer sem stage), pool
  prompt, command description, AGENT-OPS, plan-issue, rebase-on-main,
  CHANGELOG-AGENTS
2026-08-10 12:50:18 -03:00
Francisco Solla
da5dced89d style(OPS27): prettier no trabalho 2026-08-10 11:24:52 -03:00
Francisco Solla
06d34ed23b OPS27: worktree new — worktree neutro sem função pré-definida (work/<bag>) 2026-08-10 11:24:52 -03:00
Francisco Solla
da20ed6190 refactor(OPS26): simplify fixes do /simplify — marcador TEQO_ prefixado, helper printLaunchDirective, IFS pinado no launch, docs reconciliadas 2026-08-10 10:58:55 -03:00
Francisco Solla
344fe843df feat(OPS26): worktree next/plan no terminal abrem o opencode com presets (modelo deepseek-v4-flash, auto-approve, skill inicial) 2026-08-10 10:51:19 -03:00
Francisco Solla
152d0a1473 OPS24: worktree CLI default-go (--stay escape) + kill volta ao main
next/plan imprimem 'cd <dir>' na última linha por padrão; --stay suprime;
--go segue aceito como no-op. kill imprime 'cd <main>' como última linha
(depois do drop dos bancos) e recusa --stay. Superfícies: worktree.sh
aplica o cd por padrão; comando /worktree do opencode idem. Docs
(AGENTS.md, skills, CHANGELOG) atualizadas.
2026-08-10 10:21:08 -03:00
Francisco Solla
c2ddbf6006 refactor(D6): simplify — find endpoint-only no subscribe, sslmode verify-full, guards no check-push-chain 2026-08-10 00:01:46 -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
3838406a30
fix(worktree): define devUrl/testUrl antes do runMigrate em provision (#479)
provision() chamava runMigrate(dir, devUrl, ...) com variáveis nunca
definidas no escopo — 'devUrl is not defined' ao rodar pnpm worktree
next --go. Derivadas dos bancos do env (mesmo formato de
worktreeEnvFileContents).
2026-08-09 11:49:55 +00: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
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
Francisco Solla
c399b918c3 feat(worktree): comando plan — worktree dedicado ao /plan-issue
Novo subcomando `pnpm worktree plan [--go] [--no-migrate]` cria/reutiliza o
worktree de planejamento no branch fixo `plans/plan-issue`
(`PLAN_WORKTREE_BRANCH`), sem vínculo com a fila de claim: um `next` posterior
da próxima Issue nunca colide em branch nem em slot (slot derivado por hash do
branch, bumpado entre worktrees vivos). Mesmo provisionamento isolado do
`next` — porta 3100+slot, bancos teqo_wt<slot>/teqo_wt<slot>_test, migrations.

- scripts/worktree.mjs: cmdPlan + provision() com purpose/issue opcionais
- scripts/lib/worktree.mjs: constante PLAN_WORKTREE_BRANCH
- tests/unit/worktree.unit.spec.ts: derivação de slot do plano
- docs: .opencode/commands/worktree.md, shell, skills, AGENTS.md, changelog
2026-08-08 16:00:27 -03:00
Francisco Solla
bd06018bde B164: barra de navegação inferior no mobile para staff
Mobile bottom nav (staff only): 5 items (Início, Municípios, Atualizações,
Agenda, Mais) with Drawer overflow for secondary destinations. Leader and
desktop remain sidebar-only. FAB + scroll padding adjusted for safe-area.

Resolves #400
2026-08-08 12:57:05 -03:00
Francisco Solla
8125334401 feat(worktree): ambientes isolados por worktree — porta própria, bancos próprios, migrations no provision
pnpm worktree next [--go] [--no-migrate] agora provisiona um ambiente
determinístico por worktree: slot = parte numérica do código da Issue
(C15→15; hash sem dígitos; bump em colisão entre worktrees vivos), dev
server em 3100+slot, bancos teqo_wt<slot> / teqo_wt<slot>_test no
container compartilhado (-p teqo) com a cadeia de migrations aplicada;
escreve .env.local + .env.test.local (gitignored, marcador gerado; envs
manuais nunca sobrescritos) e copia PAYLOAD_SECRET/Blob/VAPID do main.
kill remove o worktree e dropa os bancos gerados (WITH FORCE, best-effort).

Suites leem .env.test.local depois de .env.test (vitest.setup /
playwright / db-doctor / gate-ci espelham o layering) e
assertTestDatabase aceita teqo_test ou teqo_<worktree>_test em localhost
só (fail-closed preservado). db:start/db:stop fixam -p teqo (um
container de qualquer diretório); max_connections 200→400. Sem Docker
(Cursor Cloud): degrada ao compartilhado com aviso.

Derivação pura em scripts/lib/worktree-env.mjs (unit-tested); fluxo
validado end-to-end: provision → migrate → 598/598 int no banco do
worktree → kill sem resíduo.
2026-08-08 11:33:07 -03:00
Francisco Solla
55178247c8
Merge pull request #409 from fsolla/C15-fullcalendar-em-campanha-agenda
feat(campanha): C15 — FullCalendar em /campanha/agenda
2026-08-07 04:56:52 -03:00
Francisco Solla
59983b33f7 feat(campanha): C15 — FullCalendar em /campanha/agenda
Issue #390 — entrada operacional staff com FullCalendar v7 route-local
(semana/mês/lista), filtros compartilháveis por município/deputado/tag,
criação pelo slot, detalhe por URL e remarcação drag/resize sob RBAC,
transação e lock por atividade.

- /campanha/atividades e giros permanecem como lista/fluxos legados
- Sem migration/collection nova; reutiliza activity de C14
- Fuso Bahia, range exclusivo, erro/revert, loading/empty testados
- Leader negado, advisor limitado pelo access atual
- E2E cobre filtros, drag, mobile 390x844 e slot prefill
- Int specs cobrem RBAC, concorrência e defense-in-depth

Impl: docs/plans/fullcalendar-agenda-campanha-impl.md
2026-08-07 04:37:36 -03:00