From 8d16b8a0cb2cf6f0075b5d49deef2bffc7ffefab Mon Sep 17 00:00:00 2001 From: Francisco Solla Date: Sun, 16 Aug 2026 21:54:25 -0300 Subject: [PATCH] =?UTF-8?q?plan(OPS50-52):=20planos=20de=20inten=C3=A7?= =?UTF-8?q?=C3=A3o=20=E2=80=94=20CI=20Forgejo,=20DB=20Neon=E2=86=92homeser?= =?UTF-8?q?ver,=20Blob=E2=86=92Garage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related #1 #2 #3 --- docs/plans/ops50-ci-github-para-forgejo.md | 76 +++++++++++++++++++++ docs/plans/ops51-db-neon-para-homeserver.md | 73 ++++++++++++++++++++ docs/plans/ops52-blob-vercel-para-garage.md | 75 ++++++++++++++++++++ 3 files changed, 224 insertions(+) create mode 100644 docs/plans/ops50-ci-github-para-forgejo.md create mode 100644 docs/plans/ops51-db-neon-para-homeserver.md create mode 100644 docs/plans/ops52-blob-vercel-para-garage.md diff --git a/docs/plans/ops50-ci-github-para-forgejo.md b/docs/plans/ops50-ci-github-para-forgejo.md new file mode 100644 index 00000000..d60d3b3c --- /dev/null +++ b/docs/plans/ops50-ci-github-para-forgejo.md @@ -0,0 +1,76 @@ +# Migrar o CI e o paradigma de agentes do GitHub para o Forgejo + +Status: registrado +Atualizado em: 2026-08-16 +Issue: #1 +Priority: P1 +Model: cursor-grok-4.5-medium +Impeccable: A — N/A +Rascunho UI: N/A — sem UI +Appetite: ~2–3 dias eng; um outcome verificável +Responsável: — + +## Intenção + +O repo já vive no Forgejo (`git.solla.dev`) e o runner da workstation já executa os +workflows — mas por fallback: os YAMLs continuam em `.github/workflows/`, os scripts +`agent-*` falam `gh`→github.com, 59 arquivos de skills/rules descrevem fluxos GitHub, +os docs canônicos pinam GitHub Issues, e o repo GitHub existe defasado. Metade do +paradigma funciona por sorte (Forgejo lê `.github/workflows`), metade está quebrada +(`gh` ausente, tracker canônico apontando para um repo que não recebe push). +Queremos **zero dependência do GitHub**: CI, Issues, PRs, pool e docs rodando +nativamente no Forgejo. + +## Persona e fluxo + +- **Persona / contexto:** o dev (humano) e os agentes (pool, `work-issue`, claims) — mesa/casa, fluxo diário de entregas. +- **Job principal:** operar o repo de ponta a ponta no Forgejo, como hoje se fazia no GitHub. +- **Fluxo desejado:** push → CI verde no Forgejo Actions; register/claim/ready/status das Issues no Forgejo; PRs no Forgejo com auto-merge; pool supervisor rodando no Forgejo; docs e skills descrevendo o Forgejo. +- **Anti-goals de produto:** manter um meio-termo (tracker em um lugar, CI em outro) que exija dois contextos mentais; republicar o remote GitHub (isso re-dispara os builds Git da Vercel). + +## Objetivo e aceite + +- Workflows movidos para `.forgejo/workflows/` e verdes no Forgejo Actions (sem fallback do caminho `.github/`). +- Scripts `agent-*` operando contra o Forgejo (Issues/PRs/labels/Actions) — register/claim/ready/status/pool funcionais. +- Skills, rules e docs canônicos (`AGENTS.md`, `docs/AGENT-OPS.md`, `docs/roadmap.md`) descrevendo o Forgejo como fonte única. +- Secrets de CI existentes no Forgejo Actions; branch protection configurado no Forgejo. +- As Issues deste lote (OPS50/51/52) são as primeiras registradas no tracker Forgejo. +- Guardrails de produto: o deploy de produção (Vercel, até o cutover de hospedagem) continua gated pelo CI; o runner não é re-registrado sem necessidade (já operacional); nenhum push volta a acionar builds Git da Vercel. + +## Dados (intenção) + +- **Vou apresentar dados?** Não +- **Decisões desbloqueadas:** nenhuma de produto — é trabalho de infra/processo. +- **Forma:** N/A + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** `.github/workflows/*.yml` (8 arquivos, hoje lidos por fallback) → `.forgejo/workflows/`; `scripts/lib/agent-github.mjs` (coração `gh`) + `scripts/agent-*.mjs` + `scripts/lib/agent-pool-*.mjs`; `.agents/skills/**` e `.agents/rules/**` (referências a `gh pr`, github.com, "GitHub Issues" — 59 arquivos); `AGENTS.md`, `docs/AGENT-OPS.md`, `docs/roadmap.md`. +- **Precedente a olhar:** runner Forgejo já executando (workstation-runner v0.2.11, labels `host`/`ubuntu-latest`/`ubuntu-20.04`); MCP Forgejo autenticado no opencode; `docs/plans/agent-pool-orchestrator.md` (pool). +- **Risco de acoplamento:** o pool (Cursor Cloud) depende do tracker — a migração não pode deixar a fila invisível no meio do caminho; os workflows de merge (`agent-pr-ready-automerge`, `issue-done-on-main-merge`, `plan-issue-ready-on-main-merge`) chamam `gh` e precisam de equivalente Forgejo na mesma entrega. + +## Dependências + +- Nenhuma (fundação das outras duas deste lote; OPS51/OPS52 a declaram como `depends` suave) + +## Fora de escopo + +- Cutover de hospedagem (Vercel → homeserver, DNS pt.jorgesolla.com.br) — é infra §7.5–7.6, manual, outro lote. +- Migrar o **histórico** de Issues do GitHub para o Forgejo — o passado fica como arquivo; só o tracker daqui para frente é Forgejo. +- Substituir Vercel/Neon/Blob — OPS51/OPS52. + +## Rabbit holes de produto + +- **Migrar tudo (histórico, releases, wiki).** Se alguém "só completar": semanas de porte de dados sem valor. **Corte neste item:** tracker novo no Forgejo; GitHub congela como arquivo. +- **Suportar os dois trackers por um período.** Meio-termo que duplica bookkeeping e quebra a fila do pool. **Corte neste item:** uma fonte só (Forgejo), com o pool portado na mesma entrega. + +## Questões em aberto (produto) + +- **Como o agente conversa com o Forgejo?** **Opções:** A) `gh` apontado para `git.solla.dev` via `GH_HOST` | B) API nativa via scripts Node (padrão das libs existentes). **Recomendação:** B — consistente com o pool que já usa PATs, e `gh` não existe nas máquinas de trabalho. +- **O repo GitHub fica como espelho read-only ou morre?** **Opções:** A) arquivar | B) manter espelho. **Recomendação:** A — espelho convida push acidental e re-dispara Vercel. _(assumido — validar)_ + +## Referências + +- Runner verificado 2026-08-16: `workstation-runner` online em git.solla.dev, agent-pool.yml verde a cada 10 min +- infra-solla: `STATE.md`, `plano-implementacao.md` §7.4 (pipeline Forgejo→Runner→registry→homeserver) +- `docs/AGENT-OPS.md` (paradigma de claim/PR/merge), `scripts/lib/agent-github.mjs` diff --git a/docs/plans/ops51-db-neon-para-homeserver.md b/docs/plans/ops51-db-neon-para-homeserver.md new file mode 100644 index 00000000..3d4cda61 --- /dev/null +++ b/docs/plans/ops51-db-neon-para-homeserver.md @@ -0,0 +1,73 @@ +# Migrar o banco de produção do Neon para o Postgres do homeserver + +Status: registrado +Atualizado em: 2026-08-16 +Issue: #2 +Priority: P1 +Model: cursor-grok-4.5-high +Impeccable: A — N/A +Rascunho UI: N/A — sem UI +Appetite: ~1–2 dias eng; um outcome verificável +Responsável: — + +## Intenção + +O banco de produção (pt.jorgesolla.com.br) vive no Neon. O homeserver já roda +Postgres 17 com o banco `teqo_1313` (cadeia completa de migrations aplicada, mas +**sem** conteúdo/PII de produção) e o container `teqo-1313` saudável. Falta a parte +cara: mover os dados reais — contatos, assinaturas, apoiadores, campanha — para +casa, com LGPD fail-closed e rollback documentado (o Neon continua vivo até o +cutover de hospedagem, que é outro lote). + +## Persona e fluxo + +- **Persona / contexto:** o dev (humano) conduzindo a migração; a equipe de campanha usando `/campanha` sem perceber a troca. +- **Job principal:** o banco de prod viver no homeserver, com os mesmos dados e sem queda perceptível. +- **Fluxo desejado:** dump seguro do Neon feito no homeserver (nunca em máquina de trabalho) → restore num banco de destino dedicado → deploy apontando para ele → smoke completo (login, WebAuthn, convites, revalidate) → Neon congelado como rollback. +- **Anti-goals de produto:** despejar PII em disco de máquina de trabalho; misturar o conteúdo de produção com o banco do site 1313 (que tem vida própria); cortar o Neon antes de provar o rollback. + +## Objetivo e aceite + +- Dump completo do Neon restaurado no homeserver, com PII íntegra e sem cópias intermediárias fora do homeserver. +- O deploy (container no homeserver) lê o banco local; `/campanha` funciona de ponta a ponta (login, WebAuthn, convites, revalidate). +- Rollback documentado e testável: o Neon permanece operacional e o caminho de volta é re-apontar o `DATABASE_URL`. +- Guardrails de produto: nenhum dado de produção toca bancos de dev/test (`teqo`, `teqo_test`, worktrees); o processo é fail-closed — qualquer passo que falhe deixa o Neon como fonte viva. + +## Dados (intenção) + +- **Vou apresentar dados?** Não +- **Decisões desbloqueadas:** nenhuma de produto — migração de infra. +- **Forma:** N/A + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** env do deploy (DATABASE_URL no compose do homeserver, `~/stack/`); migração em si é operação (pg_dump/restore), não código; `pnpm migrate` + `pnpm db:seed:minimal` já provados no `teqo_1313`. +- **Precedente a olhar:** infra-solla `plano-implementacao.md` §7.3 (backup Neon → `teqo_prod_pre_migracao` no homeserver); `local-database` skill (guards que provam a higiene local); nota de "Mandatory production blocker" no AGENTS.md (LGPD/PII). +- **Risco de acoplamento:** a media (Vercel Blob) continua sendo servida de fora até o OPS52 — os posts restaurados devem continuar renderizando capas; o container teqo-1313 (site 1313) é outro banco e não deve ser tocado. + +## Dependências + +- OPS50 (suave — o pipeline Forgejo→homeserver precisa existir para o deploy do novo apontamento) + +## Fora de escopo + +- Cutover de DNS/hospedagem de pt.jorgesolla.com.br (infra §7.5–7.6, manual). +- Migração da media (Vercel Blob → Garage) — OPS52. +- Excluir/cancelar a conta Neon — só depois do cutover estável. +- Replicação contínua Neon→casa — dump + janela basta para este appetite. + +## Rabbit holes de produto + +- **Sincronização contínua / zero-downtime.** Para este appetite, janela de manutenção com dump é suficiente; replicação em tempo real triplica o risco sem pedido. **Corte neste item:** dump + smoke + rollback. +- **Unificar com o banco do 1313.** Sites diferentes, conteúdos diferentes, rollbacks diferentes. **Corte neste item:** banco de destino dedicado para a produção. + +## Questões em aberto (produto) + +- **Banco de destino: novo (`teqo_prod`) ou reusar `teqo_1313`?** **Opções:** A) novo banco dedicado | B) reusar o existente. **Recomendação:** A — o `teqo_1313` serve o site da campanha 1313 (vida própria); misturar complica rollback e privacidade. _(assumido — validar)_ +- **Janela de manutenção?** **Opções:** A) congelar escrita durante o dump | B) dump com leitura consistente em produção aberta. **Recomendação:** A para simplicidade (apetite pequeno; campanha interna tolera minutos de leitura na janela). _(assumido — validar)_ + +## Referências + +- infra-solla: `STATE.md` (homeserver: postgres 17, DBs `forgejo`/`teqo_1313`), `plano-implementacao.md` §7.3 +- `AGENTS.md` — regras de banco local/PII e guardas (`db:start`, `guard-dev-db`) +- Container `teqo-1313` (imagem `teqo-1313:21b3c00d`) já no homeserver diff --git a/docs/plans/ops52-blob-vercel-para-garage.md b/docs/plans/ops52-blob-vercel-para-garage.md new file mode 100644 index 00000000..7efde27b --- /dev/null +++ b/docs/plans/ops52-blob-vercel-para-garage.md @@ -0,0 +1,75 @@ +# Migrar a media de produção do Vercel Blob para o Garage S3 + +Status: registrado +Atualizado em: 2026-08-16 +Issue: #3 +Priority: P2 +Model: cursor-grok-4.5-medium +Impeccable: A — N/A +Rascunho UI: N/A — sem UI +Appetite: ~1–2 dias eng; um outcome verificável +Responsável: — + +## Intenção + +A media (capas de posts, fotos de atividades) vive no Vercel Blob via plugin +`vercelBlobStorage` com token `BLOB_READ_WRITE_TOKEN` — inclusive no seed de posts, +que usa `@vercel/blob` direto contra uma store compartilhada entre ambientes. O +homeserver já roda o **Garage S3** (3900/3903). Queremos uploads e serving vindos +de casa, com os objetos existentes migrados e um contrato de URL pública que não +quebre o que já foi publicado. + +## Persona e fluxo + +- **Persona / contexto:** o dev (humano) migrando; o editor do admin subindo capas; o visitante do site vendo os posts antigos sem imagem quebrada. +- **Job principal:** media de produção inteiramente no Garage, sem dependência do Vercel Blob. +- **Fluxo desejado:** novo upload vai pro Garage → post antigo continua servindo a mesma imagem → seed de posts re-roda escrevendo no Garage → o site renderiza tudo sem referenciar o Blob. +- **Anti-goals de produto:** quebrar URLs públicas já publicadas (posts indexados, emails enviados); manter dois storages vivos para sempre; upload silencioso quando o token/credencial falta. + +## Objetivo e aceite + +- Storage da collection `media` aponta para o Garage S3; novos uploads não tocam o Vercel Blob. +- Objetos existentes migrados do Blob para o Garage; posts antigos seguem servindo imagens (contrato de URL pública estável ou migração de URLs + redirect). +- `pnpm db:seed:posts` escreve no Garage (e a re-execução do seed continua idempotente). +- Aceite de falha: sem credencial de storage, o upload falha com erro claro (fail-closed), nunca grava em lugar errado nem some. +- Guardrails de produto: a store não é mais compartilhada entre ambientes sem querer — cada ambiente aponta para o bucket certo. + +## Dados (intenção) + +- **Vou apresentar dados?** Não +- **Decisões desbloqueadas:** nenhuma de produto — migração de infra. +- **Forma:** N/A + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** `src/payload.config.ts` (plugin `vercelBlobStorage` → storage S3-compatível para `media`); `scripts/seed-posts.mjs` (usa `@vercel/blob` direto: `put`/`del` de capas); env (`BLOB_READ_WRITE_TOKEN` em `.env.example`); referências a URLs de media em docs/richText. +- **Precedente a olhar:** Garage S3 rodando no homeserver (acessível por LAN/tailnet/túnel); Payload suporta storage S3-compatível (padrão de plugin); infra-solla `plano-implementacao.md` §7.1 (S3→Garage já previsto no branch standalone). +- **Risco de acoplamento:** o contrato de URL pública (domínio das imagens) está embutido em conteúdo já publicado — a migração precisa preservar ou redirecionar; o seed compartilha a store entre ambientes hoje, então o divisor de ambientes precisa ser explícito. + +## Dependências + +- OPS50 (suave — pipeline/deploy Forgejo para empurrar a troca) +- OPS51 (soft — a media referenciada pelos posts restaurados deve continuar resolvível durante a migração do banco) + +## Fora de escopo + +- Excluir a conta/objects do Vercel Blob — só após cutover estável. +- Migrar outros storages (não há) ou o Vercel Analytics. +- Cutover de DNS/hospedagem — infra §7.5–7.6. +- E-mail (Stalwart/Brevo) — outro item do §7.1. + +## Rabbit holes de produto + +- **Reescrever URLs de media no banco em massa.** Frágil e destrutivo se não houver redirect. **Corte neste item:** priorizar contrato de URL estável (mesmo caminho público, outro backend) e reescrever só se o executor provar que é seguro. +- **CDN/otimização de imagens própria.** Fora do apetite; hoje o Blob serve direto. **Corte neste item:** serving simples via túnel/rota existente. + +## Questões em aberto (produto) + +- **Como servir a media publicamente a partir do Garage?** **Opções:** A) rota pública dedicada via Cloudflare (ex.: media.) apontando para o Garage | B) a própria app serve/re-encaminha. **Recomendação:** A — separa tráfego de mídia do container e mantém URLs limpas. _(assumido — validar)_ +- **Manter o domínio antigo do Blob como redirect durante a transição?** **Opções:** A) sim, por N dias | B) não. **Recomendação:** A enquanto o Blob existir — posts/emails antigos continuam funcionando. _(assumido — validar)_ + +## Referências + +- `src/payload.config.ts` (plugin `vercelBlobStorage`, collection `media`) +- `scripts/seed-posts.mjs` (uso direto de `@vercel/blob`, capas determinísticas) +- infra-solla: `STATE.md` (Garage em 3900/3903, rota `garage.solla.dev`) -- 2.45.2