From 32a62d3bb3f23ab861ac42179783fbf7c40c1766 Mon Sep 17 00:00:00 2001 From: nitai Date: Thu, 26 Feb 2026 18:25:42 -0300 Subject: [PATCH 1/2] feat: add Blog section with MkDocs Material blog plugin - Enable built-in blog plugin with excerpt separator - Add first post: "6 dias, 36 PRs, 3 repos novos" - Add author profile (nitai) with GitHub avatar - Add custom CSS to limit blog post width (45em) - Add Blog entry to navigation Co-Authored-By: Claude Opus 4.6 --- docs/blog/.authors.yml | 5 + docs/blog/index.md | 1 + .../posts/2026-02-26-desmembrando-monolito.md | 249 ++++++++++++++++++ docs/stylesheets/blog.css | 3 + mkdocs.yml | 7 + 5 files changed, 265 insertions(+) create mode 100644 docs/blog/.authors.yml create mode 100644 docs/blog/index.md create mode 100644 docs/blog/posts/2026-02-26-desmembrando-monolito.md create mode 100644 docs/stylesheets/blog.css diff --git a/docs/blog/.authors.yml b/docs/blog/.authors.yml new file mode 100644 index 0000000..1b928ec --- /dev/null +++ b/docs/blog/.authors.yml @@ -0,0 +1,5 @@ +authors: + nitai: + name: Nitai + description: Tech Lead + avatar: https://github.com/nitaibezerra.png diff --git a/docs/blog/index.md b/docs/blog/index.md new file mode 100644 index 0000000..05761ac --- /dev/null +++ b/docs/blog/index.md @@ -0,0 +1 @@ +# Blog diff --git a/docs/blog/posts/2026-02-26-desmembrando-monolito.md b/docs/blog/posts/2026-02-26-desmembrando-monolito.md new file mode 100644 index 0000000..77fda7f --- /dev/null +++ b/docs/blog/posts/2026-02-26-desmembrando-monolito.md @@ -0,0 +1,249 @@ +--- +date: 2026-02-26 +authors: + - nitai +categories: + - Arquitetura + - Airflow + - Refatoração +title: "6 dias, 36 PRs, 3 repos novos: desmembrando o monolito data-platform" +hide: + - toc +--- + +# 6 dias, 36 PRs, 3 repos novos: desmembrando o monolito data-platform + +Em 6 dias, refatoramos a plataforma de dados do DGB de um monolito para uma arquitetura de repos por domínio, ao mesmo tempo em que concluímos o servidor ActivityPub e ganhamos capacidade de federação. Foram **36 PRs mergeados** em **9 repos** e **3 repos novos** criados. De quebra, fechamos 4 issues que já estavam mapeadas no backlog e avançamos parcialmente outras 5. + + + +## As duas linhas de trabalho + +Essas evoluções aconteceram em dois trilhos paralelos que convergem na mesma visão: cada componente da plataforma vive no seu repo, deploya suas próprias DAGs no Airflow, e é independente para evoluir. + +### Trilho 1: Scraper para Airflow (e além) + +### Trilho 2: Servidor ActivityPub + Federação + +--- + +## Trilho 1 -- Do monolito ao ecossistema de repos + +### Dia 1 (23/fev, domingo): Scraper no Airflow + +Tudo começou com a issue [`data-platform#57`](https://github.com/destaquesgovbr/data-platform/issues/57) -- "Migrar Scraper para Airflow com DAG por Órgão". O scraping de ~158 agências gov.br rodava via GitHub Actions, sequencial, 1x/dia. O plano ([`_plan/MIGRAR-SCRAPER-AIRFLOW.md`](https://github.com/destaquesgovbr/data-platform/blob/main/_plan/MIGRAR-SCRAPER-AIRFLOW.md)) desenhava DAGs dinâmicas, uma por agência, com schedule de 15 minutos. + +**PRs**: +- [`data-platform#76`](https://github.com/destaquesgovbr/data-platform/pull/76) -- feat(dags): migrar scraper para Airflow com DAG por órgão +- [`data-platform#77`](https://github.com/destaquesgovbr/data-platform/pull/77) -- fix: corrigir formato requirements.txt e deploy source via plugins/ +- [`data-platform#78`](https://github.com/destaquesgovbr/data-platform/pull/78) -- fix: corrigir ordem dos args do gsutil rsync +- [`data-platform#79`](https://github.com/destaquesgovbr/data-platform/pull/79) -- fix: adicionar loguru e scipy ao requirements.txt + +A sequência de fixes conta a história real: deploy no Composer e um, dois, três ajustes até funcionar. Composer é implacável -- cada `requirements.txt` leva 10-20 min para instalar. Cada fix, mais 10-20 min de espera. + +### Ainda Dia 1: A revelação -- Cloud Run API + +Enquanto esperava o Composer, veio a percepção: instalar o scraper inteiro como dependência do Composer é frágil. O plano [`_plan/SCRAPER-CLOUD-RUN-API.md`](https://github.com/destaquesgovbr/data-platform/blob/main/_plan/SCRAPER-CLOUD-RUN-API.md) redesenhou a arquitetura: + +``` +Airflow DAG (leve) Cloud Run (scraper-api) ++------------------+ HTTP POST +----------------------+ +| scrape_mec |-------------->| POST /scrape/agencies | +| (httpx + IAM) | Bearer IAM | ScrapeManager.run() | ++------------------+ | -> PostgreSQL | + +----------------------+ +``` + +DAGs viram simples chamadas HTTP. Workers do Airflow ficam leves. Scraper roda em container isolado com scale-to-zero. + +**PRs**: +- [`data-platform#80`](https://github.com/destaquesgovbr/data-platform/pull/80) -- feat: scraper API no Cloud Run + DAGs leves via HTTP +- [`infra#78`](https://github.com/destaquesgovbr/infra/pull/78) -- feat: add Terraform para Scraper API Cloud Run + +### Dia 2 (24/fev, segunda): Nasce o repo `scraper` + +Com a API funcionando, o próximo passo natural era extrair tudo para um repo próprio. O plano [`_plan/EXTRAIR-SCRAPER-REPO.md`](https://github.com/destaquesgovbr/data-platform/blob/main/_plan/EXTRAIR-SCRAPER-REPO.md) mapeou a cirurgia completa. + +**Novo repo**: [`destaquesgovbr/scraper`](https://github.com/destaquesgovbr/scraper) -- criado em 24/fev + +Para fazer o deploy de DAGs de múltiplos repos no mesmo Composer, cada repo precisa usar um subdiretório próprio no bucket GCS. Isso exigiu mudanças coordenadas: + +**PRs de infraestrutura do deploy**: +- [`infra#82`](https://github.com/destaquesgovbr/infra/pull/82) -- Add WI binding para repo scraper +- [`data-platform#81`](https://github.com/destaquesgovbr/data-platform/pull/81) -- Deploy DAGs para subdiretório `data-platform/` +- [`data-platform#82`](https://github.com/destaquesgovbr/data-platform/pull/82) -- Remove scraper code (extracted to standalone repo) +- [`scraper#1`](https://github.com/destaquesgovbr/scraper/pull/1) -- docs: CLAUDE.md completo do scraper +- [`infra#80`](https://github.com/destaquesgovbr/infra/pull/80) -- feat: increase concurrency scraper-api +- [`infra#83`](https://github.com/destaquesgovbr/infra/pull/83) -- Remove unused pandas do Composer +- [`data-platform#83`](https://github.com/destaquesgovbr/data-platform/pull/83) -- Remove unused requirements.txt step + +### Dia 3 (25/fev, terça): Reusable workflows + data-publishing + +O padrão "cada repo deploya suas DAGs" precisava de DRY. Em vez de copiar o workflow de deploy em cada repo, criamos um **reusable workflow** centralizado. + +**PR fundacional**: +- [`reusable-workflows#3`](https://github.com/destaquesgovbr/reusable-workflows/pull/3) -- feat: add reusable workflow for Composer DAG deployment + +Todos os repos migram para chamar esse workflow com 2-3 parâmetros. E então rolamos a adoção: + +- [`data-platform#85`](https://github.com/destaquesgovbr/data-platform/pull/85) -- refactor: use reusable workflow +- [`scraper#2`](https://github.com/destaquesgovbr/scraper/pull/2) + [`scraper#3`](https://github.com/destaquesgovbr/scraper/pull/3) -- refactor: use reusable workflow + fix permissions + +Último desmembramento do dia: o plano [`_plan/PLAN-data-publishing-migration.md`](https://github.com/destaquesgovbr/data-platform/blob/main/_plan/PLAN-data-publishing-migration.md) extraiu a DAG de sync PostgreSQL -> HuggingFace para um repo próprio. Isso resolveu de forma elegante a issue [`data-platform#28`](https://github.com/destaquesgovbr/data-platform/issues/28) -- "Executar sync HuggingFace em ambiente isolado (evitar PyPI no Composer)" -- que pedia KubernetesPodOperator, mas ganhou uma solução melhor: repo dedicado com plugins no Composer. + +**Novo repo**: [`destaquesgovbr/data-publishing`](https://github.com/destaquesgovbr/data-publishing) -- criado em 25/fev + +**PRs de finalização**: +- [`infra#85`](https://github.com/destaquesgovbr/infra/pull/85) -- Authorize data-publishing repo in WIF +- [`data-platform#86`](https://github.com/destaquesgovbr/data-platform/pull/86) -- chore: remove test_postgres_connection DAG +- [`data-platform#87`](https://github.com/destaquesgovbr/data-platform/pull/87) -- Remove HuggingFace sync DAG (migrated to data-publishing) +- [`docs#31`](https://github.com/destaquesgovbr/docs/pull/31) -- docs: update site após extração do scraper + +### Ainda Dia 3: Codificando o padrão -- skill `/criar-dag` + +Com 3 repos já seguindo o mesmo padrão de DAGs (scraper, data-publishing, activitypub-server), ficou claro que tínhamos uma convenção madura. Em vez de deixar esse conhecimento implícito, codificamos tudo numa **skill do Claude Code**: + +- [`data-platform#88`](https://github.com/destaquesgovbr/data-platform/pull/88) -- feat: add /criar-dag skill for Airflow DAG creation + +A skill `/criar-dag` é um guia de ~470 linhas que inclui: referência completa da arquitetura Airflow do projeto (connections, schema PostgreSQL, pipeline de dados), templates para módulos plugin + DAG + workflow de deploy + testes, e passo-a-passo de setup na infra (WIF, connections, Secret Manager). Agora, quando precisarmos de uma nova DAG em qualquer repo, basta invocar `/criar-dag` no Claude Code e o padrão se replica sozinho. + +Isso fecha um ciclo interessante: começamos a semana criando DAGs manualmente, terminamos codificando o padrão para que DAGs futuras nasçam prontas. + +--- + +## Trilho 2 -- ActivityPub: de servidor a pipeline federado + +### Contexto + +O repo [`activitypub-server`](https://github.com/destaquesgovbr/activitypub-server) (criado em 13/fev) implementa o protocolo ActivityPub para que as notícias do DGB possam ser seguidas via Mastodon e qualquer servidor do Fediverso. O servidor já existia, mas faltava a integração com o pipeline de dados. + +### Dia 2 (24-25/fev): Federation DAG + Deploy + +A pergunta era: como o servidor ActivityPub sabe que existem notícias novas para publicar? A resposta: uma DAG no Airflow que consulta o PostgreSQL, enfileira artigos novos com payload completo, e dispara a publicação. + +**PRs (em sequência rápida)**: +- [`infra#79`](https://github.com/destaquesgovbr/infra/pull/79) -- fix: remove reserved PORT env var dos Cloud Run services +- [`infra#81`](https://github.com/destaquesgovbr/infra/pull/81) -- Fix federation DATABASE_URL parsing and connectivity +- [`infra#84`](https://github.com/destaquesgovbr/infra/pull/84) -- Add Airflow secrets for federation database +- [`activitypub-server#1`](https://github.com/destaquesgovbr/activitypub-server/pull/1) -- **Phase 6: news_payload in queue + federation DAG** + +A Phase 6 é o PR central: adiciona coluna `news_payload JSONB` na fila de publicação, a DAG `federation_publish` que roda a cada 10 min, e conecta tudo. + +### Dia 3 (25/fev): Ajustes de produção + +Com a DAG rodando, vieram os ajustes finos de quem monitora produção: +- [`activitypub-server#2`](https://github.com/destaquesgovbr/activitypub-server/pull/2) -- fix(dag): batch loop + configurable watermark +- [`activitypub-server#3`](https://github.com/destaquesgovbr/activitypub-server/pull/3) -- fix(dag): max_active_runs=1 +- [`activitypub-server#5`](https://github.com/destaquesgovbr/activitypub-server/pull/5) -- perf(dag): batch INSERT + reduce log verbosity +- [`activitypub-server#6`](https://github.com/destaquesgovbr/activitypub-server/pull/6) -- refactor: use reusable workflow for DAG deployment +- [`activitypub-server#7`](https://github.com/destaquesgovbr/activitypub-server/pull/7) -- feat: local Airflow dev environment com Astro CLI +- [`activitypub-server#8`](https://github.com/destaquesgovbr/activitypub-server/pull/8) -- Remove publish queue limit + +A sequência batch loop -> max_active_runs -> batch INSERT mostra o ciclo clássico: deploy, observar, otimizar. + +Note que o `activitypub-server#7` (Astro CLI) avança a issue [`data-platform#42`](https://github.com/destaquesgovbr/data-platform/issues/42) -- "Criar Ambiente Airflow Local com Astro CLI". O padrão está pronto para ser replicado nos demais repos. + +--- + +## Trilho paralelo: Organização do projeto + +Em paralelo, o repo [`project`](https://github.com/destaquesgovbr/project) ganhou sua primeira PR: +- [`project#1`](https://github.com/destaquesgovbr/project/pull/1) -- Add /enviar-telegram skill + +O repo `project` centraliza skills do Claude Code para gestão do backlog: daily standup, sprint status, refinement, mover issues, enviar relatórios para Telegram. É a "sala de controle" do projeto. + +Também no portal: +- [`portal#80`](https://github.com/destaquesgovbr/portal/pull/80) -- docs: documentação de API e arquitetura dos feeds RSS/Atom/JSON + +--- + +## O antes e depois + +### Antes (20/fev) + +``` +data-platform/ (monolito) + scrapers/ -- scraping gov.br + api.py -- FastAPI do scraper + dags/ -- TODAS as DAGs + scrape_*.py + sync_hf.py + managers/ -- storage, dataset + cogfy/ -- enriquecimento + typesense/ -- busca +``` + +### Depois (26/fev) + +``` +scraper/ -- Scraping gov.br (API + DAGs) +data-publishing/ -- Sync PG -> HuggingFace (DAG + plugins) +activitypub-server/ -- Federação ActivityPub (server + DAG) +data-platform/ -- Enriquecimento, Typesense, Cogfy (core pipeline) +reusable-workflows/ -- CI/CD compartilhado (novo workflow DAG deploy) +infra/ -- Terraform, IAM, WIF (3 novos bindings) +``` + +Cada repo: +- Tem seu próprio CLAUDE.md +- Deploya suas próprias DAGs num subdiretório do Composer +- Usa o reusable workflow para deploy +- Tem autonomia de release + +--- + +## Issues resolvidas pelo caminho + +Uma surpresa positiva: ao revisar o backlog, descobrimos que várias issues já mapeadas foram resolvidas (total ou parcialmente) como efeito colateral das refatorações. + +### Fechadas (implementação completa) + +| Issue | Título | Como foi resolvida | +|-------|--------|-------------------| +| [`data-platform#57`](https://github.com/destaquesgovbr/data-platform/issues/57) | Migrar Scraper para Airflow com DAG por Órgão | Implementação direta -- PRs #76-#82 + extração para repo `scraper` | +| [`data-platform#28`](https://github.com/destaquesgovbr/data-platform/issues/28) | Executar sync HF em ambiente isolado | Resolvida por caminho diferente: extração para `data-publishing` com plugins | +| [`data-platform#22`](https://github.com/destaquesgovbr/data-platform/issues/22) | Criar DAG para exportar dataset HuggingFace | Já existia, refatorada e migrada para `data-publishing` | +| [`docs#30`](https://github.com/destaquesgovbr/docs/issues/30) | Criar Repositório data-science | Repo criado em 13/fev com 14 issues de pesquisa | + +### Avançadas (progresso parcial) + +| Issue | Título | Progresso | O que falta | +|-------|--------|-----------|-------------| +| [`data-platform#42`](https://github.com/destaquesgovbr/data-platform/issues/42) | Astro CLI para dev local | ~70% | Replicar padrão do activitypub-server nos outros repos | +| [`data-platform#45`](https://github.com/destaquesgovbr/data-platform/issues/45) | Remover código morto HF | ~50% | Revisar StorageAdapter e limpar dual-write residual | +| [`data-platform#73`](https://github.com/destaquesgovbr/data-platform/issues/73) | Monitoramento de falhas do scraper | ~30% | Alertas automáticos (Airflow já dá visibilidade por DAG) | +| [`docs#15`](https://github.com/destaquesgovbr/docs/issues/15) | Documentar DAG sync HF | ~40% | Atualizar docs site com nova arquitetura | +| [`data-platform#64`](https://github.com/destaquesgovbr/data-platform/issues/64) | Campo `active` para agências | Habilitada | Airflow permite pausar DAGs, campo YAML seria bônus | + +--- + +## Números + +| Métrica | Valor | +|---------|-------| +| PRs mergeados | 36 | +| Repos tocados | 9 (data-platform, infra, scraper, activitypub-server, data-publishing, reusable-workflows, portal, docs, project) | +| Repos novos | 3 (scraper, data-publishing, data-science) | +| Issues fechadas | 4 | +| Issues avançadas | 5 | +| Planos escritos | 4 (migrar-airflow, cloud-run-api, extrair-scraper, data-publishing) | +| Skills criadas | 2 (/enviar-telegram, /criar-dag) | +| Dias | 6 | + +--- + +## Lições + +1. **Planejar antes de codar** -- Cada refatoração teve um `_plan/*.md` com arquitetura alvo, sequência de migração, e critérios de verificação. Isso evitou retrabalho e deu visibilidade. + +2. **Migrar sem downtime** -- A sequência sempre foi: criar novo -> validar -> pausar antigo -> remover. Nunca quebramos o pipeline em produção. + +3. **Reusable workflows são multiplicadores** -- Um workflow parametrizado no `reusable-workflows` economiza meia hora de config em cada repo novo. + +4. **Composer é lento, Cloud Run é ágil** -- Mover execução pesada para Cloud Run e manter DAGs leves (só HTTP) foi a decisão de arquitetura mais impactante da semana. + +5. **O ciclo deploy-observar-otimizar é inevitável** -- Os PRs #2 a #8 do activitypub-server mostram que nenhum plano sobrevive ao primeiro contato com produção. E tá tudo bem. + +6. **Codificar padrões, não só usar** -- Quando um padrão se repete 3 vezes, vale transformar em skill ou template. A `/criar-dag` nasceu assim: depois de criar DAGs em 3 repos, codificamos o padrão para que o próximo dev (ou o Claude Code) replique automaticamente. + +7. **Refatorar revela issues resolvidas** -- Das 4 issues que fechamos, nenhuma foi atacada diretamente. Todas foram resolvidas como efeito colateral de decisões arquiteturais. Isso reforça que boa arquitetura resolve problemas que você nem estava olhando. diff --git a/docs/stylesheets/blog.css b/docs/stylesheets/blog.css new file mode 100644 index 0000000..6496c13 --- /dev/null +++ b/docs/stylesheets/blog.css @@ -0,0 +1,3 @@ +.md-content--post .md-content__inner { + max-width: 45em; +} diff --git a/mkdocs.yml b/mkdocs.yml index 6729f1c..22ec06d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -5,6 +5,9 @@ repo_url: https://github.com/destaquesgovbr/docs repo_name: destaquesgovbr/docs docs_dir: docs +extra_css: + - stylesheets/blog.css + theme: name: material language: pt-BR @@ -25,6 +28,9 @@ theme: plugins: - search: lang: pt + - blog: + blog_dir: blog + post_excerpt_separator: "" markdown_extensions: - admonition @@ -99,6 +105,7 @@ nav: - Setup Dev VM: onboarding/setup-devvm.md - Primeiro PR: onboarding/primeiro-pr.md - Troubleshooting: onboarding/troubleshooting.md + - Blog: blog/index.md - Sobre: - Contribuir: CONTRIBUTING.md - Engenharia de Prompt: plano/PLANO_IMPLEMENTACAO.md From d3bd548242d0e14f9d1f3c4d1133dd385cf3e35c Mon Sep 17 00:00:00 2001 From: nitai Date: Thu, 26 Feb 2026 19:33:43 -0300 Subject: [PATCH 2/2] feat(blog): rewrite blog post with emojis, Mermaid diagrams and improved narrative Rewrites the monolith decomposition blog post with: - Mermaid diagrams for architecture (flowchart + block diagrams) - Emojis throughout headings, transitions and highlights - Improved storytelling flow and context section for external readers - Fix title slug (remove emoji from front matter title) Co-Authored-By: Claude Opus 4.6 --- .../posts/2026-02-26-desmembrando-monolito.md | 259 ++++++++---------- 1 file changed, 107 insertions(+), 152 deletions(-) diff --git a/docs/blog/posts/2026-02-26-desmembrando-monolito.md b/docs/blog/posts/2026-02-26-desmembrando-monolito.md index 77fda7f..9c7dd59 100644 --- a/docs/blog/posts/2026-02-26-desmembrando-monolito.md +++ b/docs/blog/posts/2026-02-26-desmembrando-monolito.md @@ -11,239 +11,194 @@ hide: - toc --- -# 6 dias, 36 PRs, 3 repos novos: desmembrando o monolito data-platform +# 🏗️ 6 dias, 36 PRs, 3 repos novos: desmembrando o monolito data-platform -Em 6 dias, refatoramos a plataforma de dados do DGB de um monolito para uma arquitetura de repos por domínio, ao mesmo tempo em que concluímos o servidor ActivityPub e ganhamos capacidade de federação. Foram **36 PRs mergeados** em **9 repos** e **3 repos novos** criados. De quebra, fechamos 4 issues que já estavam mapeadas no backlog e avançamos parcialmente outras 5. +Na quinta passada, o data-platform era um monolito: scrapers, DAGs, sync de datasets e integração com LLM — tudo num repo só 😅. Hoje, uma semana depois, cada domínio vive no seu repo, deploya suas próprias DAGs e tem autonomia de release. Pelo caminho, o servidor ActivityPub ganhou pipeline de publicação e entramos no Fediverso 🌐. Foram **36 PRs mergeados** em **9 repos**, **3 repos novos** criados, **4 issues fechadas** e **5 avançadas** — tudo sem parar o pipeline em produção. -## As duas linhas de trabalho - -Essas evoluções aconteceram em dois trilhos paralelos que convergem na mesma visão: cada componente da plataforma vive no seu repo, deploya suas próprias DAGs no Airflow, e é independente para evoluir. - -### Trilho 1: Scraper para Airflow (e além) - -### Trilho 2: Servidor ActivityPub + Federação +Este post conta essa história: as decisões, os erros, as esperas de 20 minutos ⏳ e o momento em que percebemos que estávamos codificando um padrão novo. --- -## Trilho 1 -- Do monolito ao ecossistema de repos +## 🗺️ Contexto: o que é o DGB -### Dia 1 (23/fev, domingo): Scraper no Airflow +O [Destaques Gov BR](https://github.com/destaquesgovbr) agrega notícias de ~158 órgãos do governo federal. Um scraper coleta as publicações, um pipeline enriquece via LLM (classificação temática, embeddings), e um portal público exibe tudo com busca semântica. A infraestrutura roda na GCP: Cloud SQL (PostgreSQL), Cloud Composer (Airflow), Cloud Run e Typesense. -Tudo começou com a issue [`data-platform#57`](https://github.com/destaquesgovbr/data-platform/issues/57) -- "Migrar Scraper para Airflow com DAG por Órgão". O scraping de ~158 agências gov.br rodava via GitHub Actions, sequencial, 1x/dia. O plano ([`_plan/MIGRAR-SCRAPER-AIRFLOW.md`](https://github.com/destaquesgovbr/data-platform/blob/main/_plan/MIGRAR-SCRAPER-AIRFLOW.md)) desenhava DAGs dinâmicas, uma por agência, com schedule de 15 minutos. +Até a semana passada, quase toda essa lógica vivia em um único repositório: `data-platform`. 👀 -**PRs**: -- [`data-platform#76`](https://github.com/destaquesgovbr/data-platform/pull/76) -- feat(dags): migrar scraper para Airflow com DAG por órgão -- [`data-platform#77`](https://github.com/destaquesgovbr/data-platform/pull/77) -- fix: corrigir formato requirements.txt e deploy source via plugins/ -- [`data-platform#78`](https://github.com/destaquesgovbr/data-platform/pull/78) -- fix: corrigir ordem dos args do gsutil rsync -- [`data-platform#79`](https://github.com/destaquesgovbr/data-platform/pull/79) -- fix: adicionar loguru e scipy ao requirements.txt +--- -A sequência de fixes conta a história real: deploy no Composer e um, dois, três ajustes até funcionar. Composer é implacável -- cada `requirements.txt` leva 10-20 min para instalar. Cada fix, mais 10-20 min de espera. +## ☀️ Domingo: scraper no Airflow (e a frustração que mudou a arquitetura) -### Ainda Dia 1: A revelação -- Cloud Run API +Tudo começou com a issue [`data-platform#57`](https://github.com/destaquesgovbr/data-platform/issues/57) — "Migrar Scraper para Airflow com DAG por Órgão". O scraping rodava via GitHub Actions, sequencial, uma vez por dia. O plano ([`MIGRAR-SCRAPER-AIRFLOW.md`](https://github.com/destaquesgovbr/data-platform/blob/main/_plan/MIGRAR-SCRAPER-AIRFLOW.md)) desenhava DAGs dinâmicas, uma por agência, com schedule de 15 minutos. -Enquanto esperava o Composer, veio a percepção: instalar o scraper inteiro como dependência do Composer é frágil. O plano [`_plan/SCRAPER-CLOUD-RUN-API.md`](https://github.com/destaquesgovbr/data-platform/blob/main/_plan/SCRAPER-CLOUD-RUN-API.md) redesenhou a arquitetura: +Os primeiros PRs foram direto ao ponto: [`data-platform#76`](https://github.com/destaquesgovbr/data-platform/pull/76) migrou o scraper para o Airflow. E aí começaram os fixes — [`#77`](https://github.com/destaquesgovbr/data-platform/pull/77), [`#78`](https://github.com/destaquesgovbr/data-platform/pull/78), [`#79`](https://github.com/destaquesgovbr/data-platform/pull/79) — cada um corrigindo algo que só aparece em produção: formato do `requirements.txt`, ordem dos argumentos do `gsutil rsync`, dependências faltando 🤦. O Composer é implacável: cada atualização de requirements leva 10-20 minutos. Deploy, esperar, descobrir o erro, fix, esperar de novo. -``` -Airflow DAG (leve) Cloud Run (scraper-api) -+------------------+ HTTP POST +----------------------+ -| scrape_mec |-------------->| POST /scrape/agencies | -| (httpx + IAM) | Bearer IAM | ScrapeManager.run() | -+------------------+ | -> PostgreSQL | - +----------------------+ -``` +Foi justamente nessas esperas de 20 minutos que veio a percepção mais importante da semana 💡: **instalar o scraper inteiro como dependência do Composer é frágil**. O Composer deveria orquestrar, não executar. O plano [`SCRAPER-CLOUD-RUN-API.md`](https://github.com/destaquesgovbr/data-platform/blob/main/_plan/SCRAPER-CLOUD-RUN-API.md) redesenhou tudo: -DAGs viram simples chamadas HTTP. Workers do Airflow ficam leves. Scraper roda em container isolado com scale-to-zero. +```mermaid +flowchart LR + subgraph Composer["☁️ Cloud Composer (Airflow)"] + DAG["🔄 DAG scrape_mec\n2 linhas de HTTP"] + end + subgraph CloudRun["🐳 Cloud Run (scraper-api)"] + API["POST /scrape/agencies\nScrapeManager.run()\n→ PostgreSQL"] + end + DAG -->|"HTTP POST\nBearer IAM 🔐"| API +``` -**PRs**: -- [`data-platform#80`](https://github.com/destaquesgovbr/data-platform/pull/80) -- feat: scraper API no Cloud Run + DAGs leves via HTTP -- [`infra#78`](https://github.com/destaquesgovbr/infra/pull/78) -- feat: add Terraform para Scraper API Cloud Run +DAGs viram chamadas HTTP de duas linhas. Workers do Airflow ficam leves. Scraper roda em container isolado com scale-to-zero 🎯. Um PR no data-platform ([`#80`](https://github.com/destaquesgovbr/data-platform/pull/80)) e outro no infra ([`infra#78`](https://github.com/destaquesgovbr/infra/pull/78)) para o Terraform, e a nova arquitetura estava rodando. -### Dia 2 (24/fev, segunda): Nasce o repo `scraper` +--- -Com a API funcionando, o próximo passo natural era extrair tudo para um repo próprio. O plano [`_plan/EXTRAIR-SCRAPER-REPO.md`](https://github.com/destaquesgovbr/data-platform/blob/main/_plan/EXTRAIR-SCRAPER-REPO.md) mapeou a cirurgia completa. +## 📦 Segunda: nasce o repo `scraper` -**Novo repo**: [`destaquesgovbr/scraper`](https://github.com/destaquesgovbr/scraper) -- criado em 24/fev +Com a API funcionando no Cloud Run, o scraper já não pertencia ao data-platform. O plano [`EXTRAIR-SCRAPER-REPO.md`](https://github.com/destaquesgovbr/data-platform/blob/main/_plan/EXTRAIR-SCRAPER-REPO.md) mapeou a cirurgia: novo repo, Workload Identity Federation, deploy de DAGs em subdiretório separado no bucket GCS do Composer. -Para fazer o deploy de DAGs de múltiplos repos no mesmo Composer, cada repo precisa usar um subdiretório próprio no bucket GCS. Isso exigiu mudanças coordenadas: +🆕 **Novo repo**: [`destaquesgovbr/scraper`](https://github.com/destaquesgovbr/scraper) -**PRs de infraestrutura do deploy**: -- [`infra#82`](https://github.com/destaquesgovbr/infra/pull/82) -- Add WI binding para repo scraper -- [`data-platform#81`](https://github.com/destaquesgovbr/data-platform/pull/81) -- Deploy DAGs para subdiretório `data-platform/` -- [`data-platform#82`](https://github.com/destaquesgovbr/data-platform/pull/82) -- Remove scraper code (extracted to standalone repo) -- [`scraper#1`](https://github.com/destaquesgovbr/scraper/pull/1) -- docs: CLAUDE.md completo do scraper -- [`infra#80`](https://github.com/destaquesgovbr/infra/pull/80) -- feat: increase concurrency scraper-api -- [`infra#83`](https://github.com/destaquesgovbr/infra/pull/83) -- Remove unused pandas do Composer -- [`data-platform#83`](https://github.com/destaquesgovbr/data-platform/pull/83) -- Remove unused requirements.txt step +A extração exigiu mudanças coordenadas em três repos simultâneos. No infra: WIF binding ([`infra#82`](https://github.com/destaquesgovbr/infra/pull/82)), ajuste de concorrência ([`infra#80`](https://github.com/destaquesgovbr/infra/pull/80)), remoção do pandas do Composer ([`infra#83`](https://github.com/destaquesgovbr/infra/pull/83)). No data-platform: migrar DAGs para subdiretório ([`#81`](https://github.com/destaquesgovbr/data-platform/pull/81)), remover código extraído ([`#82`](https://github.com/destaquesgovbr/data-platform/pull/82)), limpar step de requirements ([`#83`](https://github.com/destaquesgovbr/data-platform/pull/83)). No scraper: CLAUDE.md documentando tudo ([`scraper#1`](https://github.com/destaquesgovbr/scraper/pull/1)). -### Dia 3 (25/fev, terça): Reusable workflows + data-publishing +O padrão ficou claro: **cada repo deploya suas DAGs num subdiretório próprio do Composer via `gsutil rsync`**. O data-platform usa `data-platform/`, o scraper usa `scraper/`. Simples, mas precisava funcionar com Workload Identity Federation, permissões GCS e GitHub Actions — tudo coordenado 🤝. -O padrão "cada repo deploya suas DAGs" precisava de DRY. Em vez de copiar o workflow de deploy em cada repo, criamos um **reusable workflow** centralizado. +--- -**PR fundacional**: -- [`reusable-workflows#3`](https://github.com/destaquesgovbr/reusable-workflows/pull/3) -- feat: add reusable workflow for Composer DAG deployment +## 🔧 Terça: reusable workflows, data-publishing e o padrão que virou skill -Todos os repos migram para chamar esse workflow com 2-3 parâmetros. E então rolamos a adoção: +### ♻️ DRY no deploy -- [`data-platform#85`](https://github.com/destaquesgovbr/data-platform/pull/85) -- refactor: use reusable workflow -- [`scraper#2`](https://github.com/destaquesgovbr/scraper/pull/2) + [`scraper#3`](https://github.com/destaquesgovbr/scraper/pull/3) -- refactor: use reusable workflow + fix permissions +Com dois repos deployando DAGs no mesmo bucket, copiar o workflow de deploy era questão de tempo. Antes de ter um terceiro, criamos o reusable workflow ([`reusable-workflows#3`](https://github.com/destaquesgovbr/reusable-workflows/pull/3)): qualquer repo chama com 2-3 parâmetros e ganha deploy no Composer. A adoção foi imediata — [`data-platform#85`](https://github.com/destaquesgovbr/data-platform/pull/85), [`scraper#2`](https://github.com/destaquesgovbr/scraper/pull/2) e [`scraper#3`](https://github.com/destaquesgovbr/scraper/pull/3) migraram no mesmo dia. -Último desmembramento do dia: o plano [`_plan/PLAN-data-publishing-migration.md`](https://github.com/destaquesgovbr/data-platform/blob/main/_plan/PLAN-data-publishing-migration.md) extraiu a DAG de sync PostgreSQL -> HuggingFace para um repo próprio. Isso resolveu de forma elegante a issue [`data-platform#28`](https://github.com/destaquesgovbr/data-platform/issues/28) -- "Executar sync HuggingFace em ambiente isolado (evitar PyPI no Composer)" -- que pedia KubernetesPodOperator, mas ganhou uma solução melhor: repo dedicado com plugins no Composer. +### 📤 Segundo desmembramento: data-publishing -**Novo repo**: [`destaquesgovbr/data-publishing`](https://github.com/destaquesgovbr/data-publishing) -- criado em 25/fev +O plano [`PLAN-data-publishing-migration.md`](https://github.com/destaquesgovbr/data-platform/blob/main/_plan/PLAN-data-publishing-migration.md) extraiu a DAG de sync PostgreSQL → HuggingFace para um repo próprio. Isso resolveu, por um caminho inesperado, a issue [`data-platform#28`](https://github.com/destaquesgovbr/data-platform/issues/28) — que pedia KubernetesPodOperator para isolar dependências pesadas. A solução acabou sendo mais elegante: repo dedicado com plugins no Composer, sem Kubernetes ✨. -**PRs de finalização**: -- [`infra#85`](https://github.com/destaquesgovbr/infra/pull/85) -- Authorize data-publishing repo in WIF -- [`data-platform#86`](https://github.com/destaquesgovbr/data-platform/pull/86) -- chore: remove test_postgres_connection DAG -- [`data-platform#87`](https://github.com/destaquesgovbr/data-platform/pull/87) -- Remove HuggingFace sync DAG (migrated to data-publishing) -- [`docs#31`](https://github.com/destaquesgovbr/docs/pull/31) -- docs: update site após extração do scraper +🆕 **Novo repo**: [`destaquesgovbr/data-publishing`](https://github.com/destaquesgovbr/data-publishing) -### Ainda Dia 3: Codificando o padrão -- skill `/criar-dag` +Os PRs de finalização limparam o data-platform: remoção da DAG de teste ([`#86`](https://github.com/destaquesgovbr/data-platform/pull/86)), remoção do sync HuggingFace ([`#87`](https://github.com/destaquesgovbr/data-platform/pull/87)), WIF no infra ([`infra#85`](https://github.com/destaquesgovbr/infra/pull/85)), e atualização da documentação ([`docs#31`](https://github.com/destaquesgovbr/docs/pull/31)). -Com 3 repos já seguindo o mesmo padrão de DAGs (scraper, data-publishing, activitypub-server), ficou claro que tínhamos uma convenção madura. Em vez de deixar esse conhecimento implícito, codificamos tudo numa **skill do Claude Code**: +### 🧠 O momento meta: codificando o padrão -- [`data-platform#88`](https://github.com/destaquesgovbr/data-platform/pull/88) -- feat: add /criar-dag skill for Airflow DAG creation +Com três repos seguindo o mesmo padrão de DAGs (scraper, data-publishing, activitypub-server), ficou claro que tínhamos uma convenção madura. Em vez de deixar esse conhecimento implícito, codificamos tudo numa **skill do Claude Code** 🤖: -A skill `/criar-dag` é um guia de ~470 linhas que inclui: referência completa da arquitetura Airflow do projeto (connections, schema PostgreSQL, pipeline de dados), templates para módulos plugin + DAG + workflow de deploy + testes, e passo-a-passo de setup na infra (WIF, connections, Secret Manager). Agora, quando precisarmos de uma nova DAG em qualquer repo, basta invocar `/criar-dag` no Claude Code e o padrão se replica sozinho. +[`data-platform#88`](https://github.com/destaquesgovbr/data-platform/pull/88) — `/criar-dag`, um guia de ~470 linhas que inclui: referência completa da arquitetura Airflow do projeto (connections, schema PostgreSQL, pipeline de dados), templates para plugin + DAG + workflow + testes, e passo-a-passo de setup na infra. -Isso fecha um ciclo interessante: começamos a semana criando DAGs manualmente, terminamos codificando o padrão para que DAGs futuras nasçam prontas. +Começamos a semana criando DAGs manualmente. Terminamos codificando o padrão para que DAGs futuras nasçam prontas 🚀. --- -## Trilho 2 -- ActivityPub: de servidor a pipeline federado - -### Contexto - -O repo [`activitypub-server`](https://github.com/destaquesgovbr/activitypub-server) (criado em 13/fev) implementa o protocolo ActivityPub para que as notícias do DGB possam ser seguidas via Mastodon e qualquer servidor do Fediverso. O servidor já existia, mas faltava a integração com o pipeline de dados. +## 🌐 O outro trilho: ActivityPub e o Fediverso -### Dia 2 (24-25/fev): Federation DAG + Deploy +Em paralelo à decomposição do monolito, o [`activitypub-server`](https://github.com/destaquesgovbr/activitypub-server) (criado em 13/fev) ganhava sua peça final: a integração com o pipeline de dados. O servidor já existia, mas como ele saberia que existem notícias novas? 🤔 -A pergunta era: como o servidor ActivityPub sabe que existem notícias novas para publicar? A resposta: uma DAG no Airflow que consulta o PostgreSQL, enfileira artigos novos com payload completo, e dispara a publicação. +A resposta: uma DAG no Airflow. O PR central ([`activitypub-server#1`](https://github.com/destaquesgovbr/activitypub-server/pull/1) — Phase 6) adicionou coluna `news_payload JSONB` na fila de publicação e a DAG `federation_publish` que roda a cada 10 minutos. No infra, três PRs prepararam o terreno: remoção da variável PORT reservada ([`infra#79`](https://github.com/destaquesgovbr/infra/pull/79)), fix de conectividade ([`infra#81`](https://github.com/destaquesgovbr/infra/pull/81)) e secrets para o banco ([`infra#84`](https://github.com/destaquesgovbr/infra/pull/84)). -**PRs (em sequência rápida)**: -- [`infra#79`](https://github.com/destaquesgovbr/infra/pull/79) -- fix: remove reserved PORT env var dos Cloud Run services -- [`infra#81`](https://github.com/destaquesgovbr/infra/pull/81) -- Fix federation DATABASE_URL parsing and connectivity -- [`infra#84`](https://github.com/destaquesgovbr/infra/pull/84) -- Add Airflow secrets for federation database -- [`activitypub-server#1`](https://github.com/destaquesgovbr/activitypub-server/pull/1) -- **Phase 6: news_payload in queue + federation DAG** +Com a DAG em produção, veio o ciclo clássico de observar e otimizar 🔁. Em 24 horas, seis PRs de ajuste: batch loop ([`#2`](https://github.com/destaquesgovbr/activitypub-server/pull/2)), max_active_runs=1 ([`#3`](https://github.com/destaquesgovbr/activitypub-server/pull/3)), batch INSERT ([`#5`](https://github.com/destaquesgovbr/activitypub-server/pull/5)), migração para reusable workflow ([`#6`](https://github.com/destaquesgovbr/activitypub-server/pull/6)), ambiente local com Astro CLI ([`#7`](https://github.com/destaquesgovbr/activitypub-server/pull/7)) e remoção do limite de fila ([`#8`](https://github.com/destaquesgovbr/activitypub-server/pull/8)). A sequência batch loop → max_active_runs → batch INSERT é o tipo de história que nenhum plano prevê — e tá tudo bem 😄. -A Phase 6 é o PR central: adiciona coluna `news_payload JSONB` na fila de publicação, a DAG `federation_publish` que roda a cada 10 min, e conecta tudo. - -### Dia 3 (25/fev): Ajustes de produção - -Com a DAG rodando, vieram os ajustes finos de quem monitora produção: -- [`activitypub-server#2`](https://github.com/destaquesgovbr/activitypub-server/pull/2) -- fix(dag): batch loop + configurable watermark -- [`activitypub-server#3`](https://github.com/destaquesgovbr/activitypub-server/pull/3) -- fix(dag): max_active_runs=1 -- [`activitypub-server#5`](https://github.com/destaquesgovbr/activitypub-server/pull/5) -- perf(dag): batch INSERT + reduce log verbosity -- [`activitypub-server#6`](https://github.com/destaquesgovbr/activitypub-server/pull/6) -- refactor: use reusable workflow for DAG deployment -- [`activitypub-server#7`](https://github.com/destaquesgovbr/activitypub-server/pull/7) -- feat: local Airflow dev environment com Astro CLI -- [`activitypub-server#8`](https://github.com/destaquesgovbr/activitypub-server/pull/8) -- Remove publish queue limit - -A sequência batch loop -> max_active_runs -> batch INSERT mostra o ciclo clássico: deploy, observar, otimizar. - -Note que o `activitypub-server#7` (Astro CLI) avança a issue [`data-platform#42`](https://github.com/destaquesgovbr/data-platform/issues/42) -- "Criar Ambiente Airflow Local com Astro CLI". O padrão está pronto para ser replicado nos demais repos. +O Astro CLI ([`#7`](https://github.com/destaquesgovbr/activitypub-server/pull/7)) merece nota: avança a issue [`data-platform#42`](https://github.com/destaquesgovbr/data-platform/issues/42) e cria o padrão de ambiente Airflow local que será replicado nos outros repos. --- -## Trilho paralelo: Organização do projeto - -Em paralelo, o repo [`project`](https://github.com/destaquesgovbr/project) ganhou sua primeira PR: -- [`project#1`](https://github.com/destaquesgovbr/project/pull/1) -- Add /enviar-telegram skill +## 🎮 Organizando a sala de controle -O repo `project` centraliza skills do Claude Code para gestão do backlog: daily standup, sprint status, refinement, mover issues, enviar relatórios para Telegram. É a "sala de controle" do projeto. +Enquanto os repos de dados eram decompostos, o repo [`project`](https://github.com/destaquesgovbr/project) ganhava forma como sala de controle do DGB. A skill `/enviar-telegram` ([`project#1`](https://github.com/destaquesgovbr/project/pull/1)) foi a primeira a chegar — permite enviar resumos de sprint, daily e backlog direto para o canal da equipe no Telegram 📲. -Também no portal: -- [`portal#80`](https://github.com/destaquesgovbr/portal/pull/80) -- docs: documentação de API e arquitetura dos feeds RSS/Atom/JSON +E no portal, a documentação dos feeds RSS/Atom/JSON ([`portal#80`](https://github.com/destaquesgovbr/portal/pull/80)) finalizou uma peça que faltava para consumidores externos da API. --- -## O antes e depois +## 🔀 O antes e depois ### Antes (20/fev) -``` -data-platform/ (monolito) - scrapers/ -- scraping gov.br - api.py -- FastAPI do scraper - dags/ -- TODAS as DAGs - scrape_*.py - sync_hf.py - managers/ -- storage, dataset - cogfy/ -- enriquecimento - typesense/ -- busca +```mermaid +block-beta + columns 1 + block:monolito["📦 data-platform (monolito)"] + columns 3 + scrapers["🕷️ scrapers/"] + api["⚡ api.py"] + dags["📋 dags/ (TODAS)"] + managers["💾 managers/"] + cogfy["🤖 cogfy/"] + typesense["🔍 typesense/"] + end ``` ### Depois (26/fev) -``` -scraper/ -- Scraping gov.br (API + DAGs) -data-publishing/ -- Sync PG -> HuggingFace (DAG + plugins) -activitypub-server/ -- Federação ActivityPub (server + DAG) -data-platform/ -- Enriquecimento, Typesense, Cogfy (core pipeline) -reusable-workflows/ -- CI/CD compartilhado (novo workflow DAG deploy) -infra/ -- Terraform, IAM, WIF (3 novos bindings) +```mermaid +block-beta + columns 3 + scraper["🕷️ scraper\nCloud Run API + DAGs"]:1 + publishing["📤 data-publishing\nSync PG → HuggingFace"]:1 + activitypub["🌐 activitypub-server\nFederação + DAG"]:1 + platform["⚙️ data-platform\nCore: Cogfy, Typesense"]:1 + workflows["♻️ reusable-workflows\nCI/CD compartilhado"]:1 + infra["🏗️ infra\nTerraform, IAM, WIF"]:1 ``` -Cada repo: -- Tem seu próprio CLAUDE.md -- Deploya suas próprias DAGs num subdiretório do Composer -- Usa o reusable workflow para deploy -- Tem autonomia de release +Cada repo tem seu próprio `CLAUDE.md`, deploya suas DAGs num subdiretório do Composer, usa o reusable workflow e tem autonomia completa de release ✅. --- -## Issues resolvidas pelo caminho +## ✅ Issues resolvidas pelo caminho -Uma surpresa positiva: ao revisar o backlog, descobrimos que várias issues já mapeadas foram resolvidas (total ou parcialmente) como efeito colateral das refatorações. +Uma surpresa positiva da semana: ao revisar o backlog, descobrimos que várias issues mapeadas foram resolvidas como efeito colateral das refatorações — nenhuma atacada diretamente 🎯. -### Fechadas (implementação completa) +### 🟢 Fechadas | Issue | Título | Como foi resolvida | |-------|--------|-------------------| -| [`data-platform#57`](https://github.com/destaquesgovbr/data-platform/issues/57) | Migrar Scraper para Airflow com DAG por Órgão | Implementação direta -- PRs #76-#82 + extração para repo `scraper` | -| [`data-platform#28`](https://github.com/destaquesgovbr/data-platform/issues/28) | Executar sync HF em ambiente isolado | Resolvida por caminho diferente: extração para `data-publishing` com plugins | -| [`data-platform#22`](https://github.com/destaquesgovbr/data-platform/issues/22) | Criar DAG para exportar dataset HuggingFace | Já existia, refatorada e migrada para `data-publishing` | -| [`docs#30`](https://github.com/destaquesgovbr/docs/issues/30) | Criar Repositório data-science | Repo criado em 13/fev com 14 issues de pesquisa | +| [`data-platform#57`](https://github.com/destaquesgovbr/data-platform/issues/57) | Migrar Scraper para Airflow | Implementação direta → extração para repo `scraper` | +| [`data-platform#28`](https://github.com/destaquesgovbr/data-platform/issues/28) | Sync HF em ambiente isolado | Extração para `data-publishing` com plugins (sem K8s!) | +| [`data-platform#22`](https://github.com/destaquesgovbr/data-platform/issues/22) | DAG de exportação HuggingFace | Refatorada e migrada para `data-publishing` | +| [`docs#30`](https://github.com/destaquesgovbr/docs/issues/30) | Criar repo data-science | Repo criado em 13/fev com 14 issues de pesquisa | -### Avançadas (progresso parcial) +### 🟡 Avançadas -| Issue | Título | Progresso | O que falta | -|-------|--------|-----------|-------------| -| [`data-platform#42`](https://github.com/destaquesgovbr/data-platform/issues/42) | Astro CLI para dev local | ~70% | Replicar padrão do activitypub-server nos outros repos | -| [`data-platform#45`](https://github.com/destaquesgovbr/data-platform/issues/45) | Remover código morto HF | ~50% | Revisar StorageAdapter e limpar dual-write residual | -| [`data-platform#73`](https://github.com/destaquesgovbr/data-platform/issues/73) | Monitoramento de falhas do scraper | ~30% | Alertas automáticos (Airflow já dá visibilidade por DAG) | -| [`docs#15`](https://github.com/destaquesgovbr/docs/issues/15) | Documentar DAG sync HF | ~40% | Atualizar docs site com nova arquitetura | -| [`data-platform#64`](https://github.com/destaquesgovbr/data-platform/issues/64) | Campo `active` para agências | Habilitada | Airflow permite pausar DAGs, campo YAML seria bônus | +| Issue | Título | Progresso | +|-------|--------|-----------| +| [`data-platform#42`](https://github.com/destaquesgovbr/data-platform/issues/42) | Astro CLI para dev local | ~70% — padrão pronto no activitypub-server, falta replicar | +| [`data-platform#45`](https://github.com/destaquesgovbr/data-platform/issues/45) | Remover código morto HF | ~50% — falta limpar StorageAdapter | +| [`data-platform#73`](https://github.com/destaquesgovbr/data-platform/issues/73) | Monitoramento do scraper | ~30% — Airflow dá visibilidade por DAG, faltam alertas | +| [`docs#15`](https://github.com/destaquesgovbr/docs/issues/15) | Documentar DAG sync HF | ~40% — atualizar docs com nova arquitetura | +| [`data-platform#64`](https://github.com/destaquesgovbr/data-platform/issues/64) | Campo `active` para agências | Habilitada via pause/unpause de DAGs no Airflow | --- -## Números +## 📊 Números | Métrica | Valor | |---------|-------| -| PRs mergeados | 36 | -| Repos tocados | 9 (data-platform, infra, scraper, activitypub-server, data-publishing, reusable-workflows, portal, docs, project) | -| Repos novos | 3 (scraper, data-publishing, data-science) | -| Issues fechadas | 4 | -| Issues avançadas | 5 | -| Planos escritos | 4 (migrar-airflow, cloud-run-api, extrair-scraper, data-publishing) | -| Skills criadas | 2 (/enviar-telegram, /criar-dag) | -| Dias | 6 | +| 🔀 PRs mergeados | 36 | +| 📁 Repos tocados | 9 | +| 🆕 Repos novos | 3 (scraper, data-publishing, data-science) | +| ✅ Issues fechadas | 4 | +| 🟡 Issues avançadas | 5 | +| 📝 Planos escritos | 4 | +| 🤖 Skills criadas | 2 (/enviar-telegram, /criar-dag) | +| 📅 Dias | 6 | --- -## Lições +## 💡 Lições + +**1. 📋 Planejar antes de codar.** Cada refatoração teve um `_plan/*.md` com arquitetura alvo, sequência de migração e critérios de verificação. Nenhum plano sobreviveu intacto ao contato com produção, mas todos evitaram decisões erradas que custariam horas. -1. **Planejar antes de codar** -- Cada refatoração teve um `_plan/*.md` com arquitetura alvo, sequência de migração, e critérios de verificação. Isso evitou retrabalho e deu visibilidade. +**2. 🔄 Migrar sem downtime é uma sequência, não um evento.** Criar novo → validar → pausar antigo → remover. Sempre nessa ordem. Nunca quebramos o pipeline em produção. -2. **Migrar sem downtime** -- A sequência sempre foi: criar novo -> validar -> pausar antigo -> remover. Nunca quebramos o pipeline em produção. +**3. ♻️ Reusable workflows são multiplicadores.** Um workflow parametrizado economiza meia hora de configuração em cada repo novo. Com três repos adotando em uma semana, já se pagou. -3. **Reusable workflows são multiplicadores** -- Um workflow parametrizado no `reusable-workflows` economiza meia hora de config em cada repo novo. +**4. 🎯 Orquestrar, não executar.** Mover execução pesada para Cloud Run e manter DAGs leves (duas linhas de HTTP) foi a decisão de arquitetura mais impactante. Nasceu da frustração com o Composer — às vezes a melhor ideia vem enquanto você espera ⏳. -4. **Composer é lento, Cloud Run é ágil** -- Mover execução pesada para Cloud Run e manter DAGs leves (só HTTP) foi a decisão de arquitetura mais impactante da semana. +**5. 🔁 O ciclo deploy-observar-otimizar é inevitável.** Os PRs #2 a #8 do activitypub-server são a prova: nenhum design prevê tudo. O importante é que o ciclo seja rápido. -5. **O ciclo deploy-observar-otimizar é inevitável** -- Os PRs #2 a #8 do activitypub-server mostram que nenhum plano sobrevive ao primeiro contato com produção. E tá tudo bem. +**6. 🤖 Codificar padrões, não só usar.** Quando um padrão se repete três vezes, vale transformar em skill ou template. A `/criar-dag` nasceu depois de criarmos DAGs em três repos — agora o próximo dev (ou o Claude Code) replica o padrão sozinho. -6. **Codificar padrões, não só usar** -- Quando um padrão se repete 3 vezes, vale transformar em skill ou template. A `/criar-dag` nasceu assim: depois de criar DAGs em 3 repos, codificamos o padrão para que o próximo dev (ou o Claude Code) replique automaticamente. +**7. 🏛️ Boa arquitetura resolve problemas que você nem estava olhando.** Das quatro issues fechadas, nenhuma foi atacada diretamente. Todas caíram como efeito colateral de decisões arquiteturais. Isso diz algo sobre o valor de refatorar com intenção. + +--- -7. **Refatorar revela issues resolvidas** -- Das 4 issues que fechamos, nenhuma foi atacada diretamente. Todas foram resolvidas como efeito colateral de decisões arquiteturais. Isso reforça que boa arquitetura resolve problemas que você nem estava olhando. +*Todos os PRs, issues e planos estão linkados ao longo do texto. O código é aberto — explore à vontade 🙌*