plan(OPS50-52): planos de intenção — CI Forgejo, DB Neon→homeserver, Blob→Garage #4
3 changed files with 224 additions and 0 deletions
76
docs/plans/ops50-ci-github-para-forgejo.md
Normal file
76
docs/plans/ops50-ci-github-para-forgejo.md
Normal file
|
|
@ -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`
|
||||
73
docs/plans/ops51-db-neon-para-homeserver.md
Normal file
73
docs/plans/ops51-db-neon-para-homeserver.md
Normal file
|
|
@ -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
|
||||
75
docs/plans/ops52-blob-vercel-para-garage.md
Normal file
75
docs/plans/ops52-blob-vercel-para-garage.md
Normal file
|
|
@ -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.<domínio>) 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`)
|
||||
Loading…
Reference in a new issue