diff --git a/docs/arquitetura/fluxo-de-dados.md b/docs/arquitetura/fluxo-de-dados.md
index 9dbe9a5..8ce29a8 100644
--- a/docs/arquitetura/fluxo-de-dados.md
+++ b/docs/arquitetura/fluxo-de-dados.md
@@ -1,48 +1,53 @@
# Fluxo de Dados
-## Pipeline Diário
+## Pipeline
-O pipeline de dados é executado diariamente às **4AM UTC** (1AM Brasília) via GitHub Actions.
+O pipeline de dados é composto por dois estágios independentes:
+
+1. **Scraping** (repo `scraper`): Via Airflow DAGs, a cada 15 minutos
+2. **Enrichment** (repo `data-platform`): Via GitHub Actions, diário às 4AM UTC
### Diagrama de Sequência Completo
```mermaid
sequenceDiagram
- participant GH as GitHub Actions
- participant SC as Scraper Container
+ participant AF as Airflow DAGs
+ participant API as Scraper API (Cloud Run)
participant GOV as Sites gov.br
participant EBC as Sites EBC
participant PG as PostgreSQL
+ participant GH as GitHub Actions
participant CF as Cogfy API
participant EMB as Embeddings API
participant TS as Typesense
- participant AF as Airflow (6AM UTC)
+ participant AF2 as Airflow (6AM UTC)
participant HF as HuggingFace
rect rgb(227, 242, 253)
- Note over GH,SC: ETAPA 1: Scraping gov.br
- GH->>SC: Trigger main-workflow (4AM UTC)
- SC->>GOV: Requisições HTTP (160+ sites)
- GOV-->>SC: HTML das páginas
- SC->>SC: Parse HTML → Markdown
- SC->>SC: Gera unique_id (MD5)
- SC->>PG: postgres.insert(new_articles)
+ Note over AF,API: ETAPA 1: Scraping (a cada 15min, via Airflow)
+ AF->>API: POST /scrape/agencies
+ API->>GOV: Requisições HTTP (~155 sites)
+ GOV-->>API: HTML das páginas
+ API->>API: Parse HTML → Markdown
+ API->>API: Gera unique_id (MD5)
+ API->>PG: postgres.insert(new_articles)
end
rect rgb(255, 243, 224)
- Note over SC,EBC: ETAPA 2: Scraping EBC
- SC->>EBC: Requisições HTTP (sites EBC)
- EBC-->>SC: HTML das páginas
- SC->>SC: Parse especializado EBC
- SC->>PG: postgres.insert(ebc_articles, allow_update=True)
+ Note over AF,EBC: ETAPA 2: Scraping EBC (a cada 15min)
+ AF->>API: POST /scrape/ebc
+ API->>EBC: Requisições HTTP (sites EBC)
+ EBC-->>API: HTML das páginas
+ API->>API: Parse especializado EBC
+ API->>PG: postgres.insert(ebc_articles, allow_update=True)
end
rect rgb(255, 253, 231)
- Note over SC,CF: ETAPA 3: Upload para Cogfy
- SC->>PG: get_news(date_range)
- PG-->>SC: Registros
- SC->>CF: POST /records (batch 1000)
- CF-->>SC: IDs dos registros
+ Note over GH,CF: ETAPA 3: Upload para Cogfy (diário 4AM UTC)
+ GH->>PG: get_news(date_range)
+ PG-->>GH: Registros
+ GH->>CF: POST /records (batch 1000)
+ CF-->>GH: IDs dos registros
end
rect rgb(232, 245, 233)
@@ -53,37 +58,36 @@ sequenceDiagram
end
rect rgb(252, 228, 236)
- Note over SC,PG: ETAPA 5: Enriquecimento
- SC->>CF: GET /records (busca por unique_id)
- CF-->>SC: themes + summary
- SC->>SC: Mapeia códigos → labels
- SC->>SC: Calcula most_specific_theme
- SC->>PG: postgres.update(enriched_data)
+ Note over GH,PG: ETAPA 5: Enriquecimento
+ GH->>CF: GET /records (busca por unique_id)
+ CF-->>GH: themes + summary
+ GH->>GH: Mapeia códigos → labels
+ GH->>GH: Calcula most_specific_theme
+ GH->>PG: postgres.update(enriched_data)
end
rect rgb(255, 248, 225)
- Note over SC,EMB: ETAPA 6: Embeddings
- SC->>PG: get_news_without_embeddings()
- PG-->>SC: Notícias sem vetores
- SC->>EMB: POST /embed (batch 100)
- EMB-->>SC: Vetores 768-dim
- SC->>PG: postgres.update(embeddings)
+ Note over GH,EMB: ETAPA 6: Embeddings
+ GH->>PG: get_news_without_embeddings()
+ PG-->>GH: Notícias sem vetores
+ GH->>EMB: POST /embed (batch 100)
+ EMB-->>GH: Vetores 768-dim
+ GH->>PG: postgres.update(embeddings)
end
rect rgb(243, 229, 245)
Note over TS,PG: ETAPA 7: Indexação Typesense
- GH->>TS: Trigger typesense-sync
- TS->>PG: iter_news_for_typesense()
- PG-->>TS: Batches de 5000
- TS->>TS: Upsert documentos
+ GH->>PG: iter_news_for_typesense()
+ PG-->>GH: Batches de 5000
+ GH->>TS: Upsert documentos
end
rect rgb(225, 245, 254)
- Note over AF,HF: ETAPA 8: Sync HuggingFace
- AF->>PG: Query novos registros
- PG-->>AF: Registros do dia anterior
- AF->>AF: Cria parquet shard
- AF->>HF: Upload shard
+ Note over AF2,HF: ETAPA 8: Sync HuggingFace
+ AF2->>PG: Query novos registros
+ PG-->>AF2: Registros do dia anterior
+ AF2->>AF2: Cria parquet shard
+ AF2->>HF: Upload shard
end
```
@@ -91,41 +95,21 @@ sequenceDiagram
### Etapa 1: Scraping gov.br
-**Workflow**: `main-workflow.yaml` → job `scraper`
+**Repo**: `scraper` — via Airflow DAGs (a cada 15 min)
-```bash
-data-platform scrape --start-date YYYY-MM-DD --end-date YYYY-MM-DD
-```
+- ~158 DAGs dinâmicas chamam `POST /scrape/agencies` na Scraper API (Cloud Run)
+- Cada agência é raspada independentemente
+- Parse HTML → Markdown, gera `unique_id = MD5(agency + published_at + title)`
+- Insert direto no PostgreSQL
-**Processo**:
-
-1. Carrega URLs de `src/data_platform/scrapers/site_urls.yaml` (~160+ URLs)
-2. Para cada URL, instancia `WebScraper`
-3. Navega por páginas com paginação (`?b_start:int=N`)
-4. Extrai campos: title, date, url, image, category, tags
-5. Faz fetch do conteúdo completo de cada notícia
-6. Converte HTML → Markdown com `markdownify`
-7. Gera `unique_id = MD5(agency + published_at + title)`
-8. Insere no PostgreSQL via `PostgresManager.insert()`
-
-**Retry Logic**:
-```python
-@retry(tries=5, delay=2, backoff=3, jitter=(1,3))
-def fetch_page(url): ...
-```
+→ Veja [Módulo Scraper](../modulos/scraper.md) para detalhes.
### Etapa 2: Scraping EBC
-**Workflow**: `main-workflow.yaml` → job `ebc-scraper`
-
-```bash
-data-platform scrape-ebc --start-date YYYY-MM-DD --end-date YYYY-MM-DD --allow-update
-```
-
-**Diferenças**:
+**Repo**: `scraper` — via Airflow DAG `scrape_ebc`
+- DAG chama `POST /scrape/ebc` na Scraper API
- Scraper especializado (`EBCWebScraper`)
-- Estrutura HTML diferente dos sites gov.br
- `allow_update=True` permite sobrescrever registros existentes
### Etapa 3: Upload para Cogfy
@@ -303,15 +287,12 @@ data-platform sync-typesense --start-date YYYY-MM-DD
## Execução Manual
-### Scraping de período específico
+### Enrichment de período específico
```bash
-# Via CLI
-data-platform scrape --start-date 2024-01-01 --end-date 2024-01-31
-
-# Via GitHub Actions
-gh workflow run main-workflow.yaml \
- -f start-date=2024-01-01 \
- -f end-date=2024-01-31
+# Via GitHub Actions (enrichment pipeline)
+gh workflow run main-workflow.yaml -R destaquesgovbr/data-platform \
+ -f start_date=2024-01-01 \
+ -f end_date=2024-01-31
```
### Enriquecimento manual
diff --git a/docs/modulos/data-platform.md b/docs/modulos/data-platform.md
index 7d9d277..36bf60c 100644
--- a/docs/modulos/data-platform.md
+++ b/docs/modulos/data-platform.md
@@ -7,9 +7,8 @@ Repositório centralizado para toda a infraestrutura de dados do DestaquesGovBr.
## Visão Geral
-O **data-platform** unifica toda a lógica de dados que anteriormente estava distribuída em múltiplos repositórios (`scraper`, `typesense`). Ele é responsável por:
+O **data-platform** é responsável por enriquecimento, embeddings e armazenamento de dados do DestaquesGovBr. A coleta (scraping) é feita pelo repo standalone [scraper](https://github.com/destaquesgovbr/scraper).
-- **Coleta**: Scrapers para gov.br e EBC
- **Armazenamento**: Gerenciamento do PostgreSQL (fonte de verdade) e HuggingFace (distribuição)
- **Enriquecimento**: Integração com Cogfy para classificação temática e sumários
- **Embeddings**: Geração de vetores para busca semântica
@@ -19,9 +18,9 @@ O **data-platform** unifica toda a lógica de dados que anteriormente estava dis
```mermaid
graph TB
- subgraph "Coleta"
- S1[Scraper Gov.br]
- S2[Scraper EBC]
+ subgraph "Coleta (repo scraper)"
+ S[Scraper API
Cloud Run]
+ DAG_S[DAGs Airflow
~158 agências + EBC]
end
subgraph "Armazenamento"
@@ -29,17 +28,17 @@ graph TB
HF[(HuggingFace
Dados Abertos)]
end
- subgraph "Processamento"
+ subgraph "Processamento (data-platform)"
COG[Cogfy
Enriquecimento]
EMB[Embeddings API
Vetores 768-dim]
end
- subgraph "Indexação"
+ subgraph "Indexação (data-platform)"
TS[Typesense
Busca]
end
- S1 --> PG
- S2 --> PG
+ DAG_S -->|HTTP POST| S
+ S -->|INSERT| PG
PG --> COG
COG --> PG
PG --> EMB
@@ -56,10 +55,7 @@ data-platform/
│ ├── managers/ # Gerenciadores de storage
│ │ ├── postgres_manager.py # Acesso ao PostgreSQL
│ │ ├── dataset_manager.py # Acesso ao HuggingFace
-│ │ └── storage_adapter.py # Abstração dual-write
-│ ├── scrapers/ # Scrapers de notícias
-│ │ ├── scrape_manager.py # Gov.br
-│ │ └── ebc_scrape_manager.py
+│ │ └── storage_adapter.py
│ ├── cogfy/ # Integração Cogfy
│ │ ├── cogfy_manager.py
│ │ ├── upload_manager.py
@@ -69,8 +65,9 @@ data-platform/
│ │ ├── collection.py
│ │ └── indexer.py
│ ├── jobs/ # Jobs de processamento
+│ │ ├── enrichment/
+│ │ ├── embeddings/
│ │ ├── typesense/sync_job.py
-│ │ ├── embeddings/embedding_generator.py
│ │ └── hf_sync/
│ ├── models/ # Modelos Pydantic
│ │ └── news.py
@@ -84,16 +81,6 @@ data-platform/
## CLI - Comandos Disponíveis
-### Scraping
-
-```bash
-# Raspar sites gov.br
-data-platform scrape --start-date 2025-01-01 --end-date 2025-01-31
-
-# Raspar sites EBC (Agência Brasil, TV Brasil)
-data-platform scrape-ebc --start-date 2025-01-01
-```
-
### Enriquecimento
```bash
@@ -134,43 +121,6 @@ data-platform typesense-delete --confirm
data-platform sync-hf --start-date 2025-01-01
```
-## Storage Adapter
-
-O **StorageAdapter** é a camada de abstração que permite transição gradual entre backends de armazenamento.
-
-### Modos de Operação
-
-| Modo | Descrição |
-|------|-----------|
-| `POSTGRES` | Escreve apenas no PostgreSQL |
-| `HUGGINGFACE` | Escreve apenas no HuggingFace (legado) |
-| `DUAL_WRITE` | Escreve em ambos para transição segura |
-
-### Configuração
-
-```bash
-# Variáveis de ambiente
-STORAGE_BACKEND=postgres # postgres | huggingface | dual_write
-STORAGE_READ_FROM=postgres # De onde ler os dados
-```
-
-### Uso no Código
-
-```python
-from data_platform.managers.storage_adapter import StorageAdapter, StorageBackend
-
-adapter = StorageAdapter(
- backend=StorageBackend.DUAL_WRITE,
- read_from=StorageBackend.POSTGRES
-)
-
-# Insert transparente - escreve em ambos
-inserted = adapter.insert(news_list, allow_update=False)
-
-# Read - sempre do backend configurado em read_from
-news = adapter.get(filters={"agency_key": "mec"}, limit=100)
-```
-
## PostgresManager
Gerenciador de acesso ao PostgreSQL com connection pooling e cache.
@@ -226,17 +176,13 @@ COGFY_COLLECTION_ID=xxx
# Embeddings
EMBEDDINGS_API_URL=https://embeddings-api-xxx.run.app
EMBEDDINGS_API_KEY=xxx
-
-# Storage
-STORAGE_BACKEND=postgres
-STORAGE_READ_FROM=postgres
```
## Workflows GitHub Actions
| Workflow | Trigger | Descrição |
|----------|---------|-----------|
-| `main-workflow.yaml` | Diário (4AM UTC) | Pipeline completo: scrape → enrich → embed → sync |
+| `main-workflow.yaml` | Diário (4AM UTC) | Pipeline de enrichment: upload-cogfy → enrich → embed → sync |
| `typesense-maintenance-sync.yaml` | Diário (10AM UTC) | Sync incremental Typesense |
| `composer-deploy-dags.yaml` | Push | Deploy de DAGs no Airflow |
diff --git a/docs/modulos/scraper.md b/docs/modulos/scraper.md
index cffeff3..5c21b4f 100644
--- a/docs/modulos/scraper.md
+++ b/docs/modulos/scraper.md
@@ -1,54 +1,152 @@
-# Módulo: Scraper (Arquivado)
+# Módulo: Scraper
-!!! warning "Módulo Migrado"
- Este módulo foi migrado para o repositório **data-platform**.
- O repositório `scraper` foi arquivado.
-
- **Novo repositório**: [github.com/destaquesgovbr/data-platform](https://github.com/destaquesgovbr/data-platform)
+!!! info "Repositório"
+ **GitHub**: [destaquesgovbr/scraper](https://github.com/destaquesgovbr/scraper)
---
-## Documentação Atualizada
+## Visão Geral
+
+O **scraper** é um repositório standalone que coleta notícias de ~155 agências governamentais (gov.br) e da EBC (Agência Brasil, TV Brasil, etc.).
+
+A coleta é orquestrada por **DAGs Airflow** (Cloud Composer) que chamam uma **API FastAPI** hospedada no Cloud Run. Os dados são inseridos diretamente no PostgreSQL (insert-only).
+
+```
+DAGs Airflow (a cada 15min)
+ → HTTP POST para Cloud Run API
+ → Scraper faz fetch do site gov.br
+ → Parse HTML → Markdown
+ → INSERT no PostgreSQL
+```
+
+## Arquitetura
+
+```mermaid
+graph TB
+ subgraph "Cloud Composer"
+ DAG1[~158 DAGs scrape_agency]
+ DAG2[scrape_ebc]
+ end
+
+ subgraph "Cloud Run"
+ API[Scraper API
FastAPI]
+ end
+
+ subgraph "Armazenamento"
+ PG[(PostgreSQL
Cloud SQL)]
+ end
+
+ subgraph "Sites"
+ GOV[~155 sites gov.br]
+ EBC[Sites EBC]
+ end
+
+ DAG1 -->|HTTP POST| API
+ DAG2 -->|HTTP POST| API
+ API --> GOV
+ API --> EBC
+ API -->|INSERT| PG
+```
+
+## Estrutura do Repositório
+
+```
+scraper/
+├── src/govbr_scraper/
+│ ├── api.py # FastAPI (Cloud Run)
+│ ├── scrapers/
+│ │ ├── webscraper.py # Scraper gov.br
+│ │ ├── scrape_manager.py # Coordenador gov.br
+│ │ ├── ebc_webscraper.py # Scraper EBC
+│ │ ├── ebc_scrape_manager.py # Coordenador EBC
+│ │ └── config/
+│ │ └── site_urls.yaml # URLs por agência
+│ ├── storage/
+│ │ ├── storage_adapter.py
+│ │ └── postgres_manager.py
+│ └── models/
+│ └── news.py # Modelos Pydantic
+├── dags/ # DAGs Airflow
+│ ├── scrape_agencies.py # ~158 DAGs dinâmicas
+│ ├── scrape_ebc.py # 1 DAG EBC
+│ └── config/
+│ └── site_urls.yaml
+├── docker/Dockerfile
+└── .github/workflows/
+ ├── scraper-api-deploy.yaml
+ ├── composer-deploy-dags.yaml
+ └── tests.yaml
+```
+
+## API Endpoints
+
+A API roda no Cloud Run e é chamada pelas DAGs Airflow.
+
+| Método | Endpoint | Descrição |
+|--------|----------|-----------|
+| `POST` | `/scrape/agencies` | Raspa sites gov.br (aceita lista de agências, datas) |
+| `POST` | `/scrape/ebc` | Raspa sites EBC |
+| `GET` | `/health` | Health check |
+
+### Request: `/scrape/agencies`
+
+```json
+{
+ "start_date": "2025-01-01",
+ "end_date": "2025-01-02",
+ "agencies": ["mec", "mds"],
+ "allow_update": false,
+ "sequential": true
+}
+```
-A funcionalidade de scraping agora faz parte do repositório unificado `data-platform`. Consulte:
+## DAGs Airflow
-- **[Data Platform](data-platform.md)** - Visão geral do repositório unificado
-- **[Fluxo de Dados](../arquitetura/fluxo-de-dados.md)** - Pipeline completo de coleta e enriquecimento
-- **[PostgreSQL](../arquitetura/postgresql.md)** - Banco de dados central (fonte de verdade)
+| DAG | Quantidade | Schedule | Descrição |
+|-----|-----------|----------|-----------|
+| `scrape_{agency_key}` | ~158 | A cada 15min | 1 DAG por agência gov.br |
+| `scrape_ebc` | 1 | A cada 15min | Sites EBC |
-## Principais Mudanças
+Cada DAG:
-| Antes (scraper) | Agora (data-platform) |
-|-----------------|----------------------|
-| Repositório separado | Repositório unificado |
-| HuggingFace como fonte de verdade | PostgreSQL como fonte de verdade |
-| `python src/main.py scrape` | `data-platform scrape` |
-| DatasetManager (HF) | PostgresManager + StorageAdapter |
+- Chama a API no Cloud Run via HTTP POST
+- Retry: 2x com backoff de 5min
+- Timeout: 15min por execução
-## CLI Atual
+→ Veja [Airflow DAGs](../workflows/airflow-dags.md) para detalhes de deploy e configuração.
+
+## Variáveis de Ambiente
```bash
-# Raspagem de sites gov.br
-data-platform scrape --start-date YYYY-MM-DD --end-date YYYY-MM-DD
+DATABASE_URL=postgresql://... # PostgreSQL connection string
+STORAGE_BACKEND=postgres # Sempre postgres
+LOG_LEVEL=INFO # Loguru level
+```
+
+## Deploy
+
+| Componente | Destino | Workflow |
+|-----------|---------|----------|
+| **API** | Cloud Run | `scraper-api-deploy.yaml` |
+| **DAGs** | Cloud Composer (`{bucket}/scraper/`) | `composer-deploy-dags.yaml` |
-# Raspagem de sites EBC
-data-platform scrape-ebc --start-date YYYY-MM-DD --end-date YYYY-MM-DD
+→ Veja [Docker Builds](../workflows/docker-builds.md) para detalhes de build da imagem.
+
+## Desenvolvimento Local
+
+```bash
+# Instalar dependências
+poetry install
-# Upload para Cogfy (enriquecimento)
-data-platform upload-cogfy --start-date YYYY-MM-DD --end-date YYYY-MM-DD
+# Rodar testes
+poetry run pytest
-# Buscar enriquecimento do Cogfy
-data-platform enrich --start-date YYYY-MM-DD --end-date YYYY-MM-DD
+# Rodar API localmente
+poetry run uvicorn govbr_scraper.api:app --reload
```
-## Arquivos Principais (Novo Local)
+## Links Relacionados
-| Componente | Localização |
-|------------|-------------|
-| WebScraper | `src/data_platform/scrapers/webscraper.py` |
-| EBCWebScraper | `src/data_platform/scrapers/ebc_webscraper.py` |
-| ScrapeManager | `src/data_platform/scrapers/scrape_manager.py` |
-| PostgresManager | `src/data_platform/managers/postgres_manager.py` |
-| StorageAdapter | `src/data_platform/managers/storage_adapter.py` |
-| site_urls.yaml | `src/data_platform/scrapers/site_urls.yaml` |
-| agencies.yaml | `src/data_platform/scrapers/agencies.yaml` |
+- **[Data Platform](data-platform.md)** — Enriquecimento, embeddings e indexação (pipeline pós-scraping)
+- **[Pipeline de Dados](../workflows/scraper-pipeline.md)** — Visão completa do pipeline scraping + enrichment
+- **[PostgreSQL](../arquitetura/postgresql.md)** — Banco de dados central
diff --git a/docs/onboarding/setup-backend.md b/docs/onboarding/setup-backend.md
index bf36295..f11b950 100644
--- a/docs/onboarding/setup-backend.md
+++ b/docs/onboarding/setup-backend.md
@@ -170,23 +170,11 @@ python -c "from src.data_platform.managers.postgres_manager import PostgresManag
---
-## 6. Executar o Scraper Localmente
+## 6. Scraper (Repo Separado)
-### Scraping de um período específico
-
-```bash
-# Raspar notícias dos últimos 7 dias
-data-platform scrape --start-date $(date -v-7d +%Y-%m-%d) --end-date $(date +%Y-%m-%d)
-
-# Raspar período específico
-data-platform scrape --start-date 2024-12-01 --end-date 2024-12-03
-```
-
-### Scraping EBC
-
-```bash
-data-platform scrape-ebc --start-date 2024-12-01 --end-date 2024-12-03 --allow-update
-```
+!!! note "Scraper Standalone"
+ O scraping agora é feito pelo repositório separado [destaquesgovbr/scraper](https://github.com/destaquesgovbr/scraper), via API FastAPI + DAGs Airflow.
+ Veja [Módulo Scraper](../modulos/scraper.md) para setup local.
---
@@ -296,12 +284,6 @@ docker run --env-file .env data-platform data-platform --help
# Ver ajuda
data-platform --help
-# Scraping gov.br
-data-platform scrape --start-date YYYY-MM-DD --end-date YYYY-MM-DD
-
-# Scraping EBC
-data-platform scrape-ebc --start-date YYYY-MM-DD --end-date YYYY-MM-DD --allow-update
-
# Upload para Cogfy
data-platform upload-cogfy --start-date YYYY-MM-DD --end-date YYYY-MM-DD
diff --git a/docs/workflows/airflow-dags.md b/docs/workflows/airflow-dags.md
index 64206c2..9e13781 100644
--- a/docs/workflows/airflow-dags.md
+++ b/docs/workflows/airflow-dags.md
@@ -1,6 +1,6 @@
# Airflow DAGs (Cloud Composer)
-O projeto utiliza **Cloud Composer 3** (Apache Airflow gerenciado) para orquestração de pipelines de dados, especialmente a sincronização entre PostgreSQL e HuggingFace.
+O projeto utiliza **Cloud Composer 3** (Apache Airflow gerenciado) para orquestração de pipelines de dados: scraping de notícias (repo `scraper`) e sincronização entre PostgreSQL e HuggingFace (repo `data-platform`).
!!! info "Cloud Composer"
**Ambiente**: `destaquesgovbr-composer`
@@ -18,11 +18,16 @@ graph TB
TRIGGER[Triggerer]
end
- subgraph "DAGs"
+ subgraph "DAGs (data-platform)"
DAG1[sync_postgres_to_huggingface]
DAG2[test_postgres_connection]
end
+ subgraph "DAGs (scraper)"
+ DAG3[~158x scrape_agency]
+ DAG4[scrape_ebc]
+ end
+
subgraph "Recursos GCP"
PG[(PostgreSQL
Cloud SQL)]
SM[Secret Manager]
@@ -37,13 +42,66 @@ graph TB
SCHED --> WORKER
WORKER --> DAG1
WORKER --> DAG2
+ WORKER --> DAG3
+ WORKER --> DAG4
DAG1 --> PG
DAG1 --> HF
+ DAG3 -->|HTTP POST| CR[Cloud Run
Scraper API]
+ DAG4 -->|HTTP POST| CR
+ CR --> PG
SM --> WORKER
```
+## Organização de DAGs no Bucket
+
+O Composer armazena DAGs de múltiplos repos em subdiretórios do mesmo bucket:
+
+```
+gs://{COMPOSER_BUCKET}/dags/
+├── data-platform/ # DAGs do repo data-platform
+│ ├── sync_postgres_to_huggingface.py
+│ └── test_postgres_connection.py
+└── scraper/ # DAGs do repo scraper
+ ├── scrape_agencies.py # ~158 DAGs dinâmicas
+ ├── scrape_ebc.py
+ └── config/
+ └── site_urls.yaml
+```
+
+Cada repo tem seu próprio workflow `composer-deploy-dags.yaml` que faz `gsutil rsync` para seu subdiretório.
+
## DAGs Disponíveis
+### DAGs do Scraper (repo `scraper`)
+
+#### `scrape_{agency_key}` (~158 DAGs dinâmicas)
+
+Cada agência gov.br gera uma DAG de scraping independente.
+
+| Configuração | Valor |
+|--------------|-------|
+| **Schedule** | `*/15 * * * *` (a cada 15 min) |
+| **Catchup** | Desabilitado |
+| **Retries** | 2 (com backoff de 5 min) |
+| **Timeout** | 15 min |
+
+Cada DAG faz HTTP POST para a Scraper API no Cloud Run (`POST /scrape/agencies` com a agência específica).
+
+#### `scrape_ebc`
+
+DAG para scraping dos sites EBC (Agência Brasil, TV Brasil).
+
+| Configuração | Valor |
+|--------------|-------|
+| **Schedule** | `*/15 * * * *` (a cada 15 min) |
+| **Retries** | 2 (com backoff de 5 min) |
+
+Faz HTTP POST para `POST /scrape/ebc` no Cloud Run.
+
+→ Veja [Módulo Scraper](../modulos/scraper.md) para detalhes da API e do repo.
+
+### DAGs do Data Platform (repo `data-platform`)
+
### `sync_postgres_to_huggingface`
Sincroniza notícias do PostgreSQL para o HuggingFace diariamente.
@@ -172,7 +230,7 @@ apache-airflow-providers-postgres>=5.10.2
apache-airflow-providers-google>=10.14.0
sqlalchemy>=1.4.52
requests>=2.31.0
-pandas>=2.0.0
+pyyaml>=6.0
```
### Environment Variables
@@ -219,22 +277,16 @@ As connections são gerenciadas via **Secret Manager**:
### Via GitHub Actions
-O workflow `composer-deploy-dags.yaml` faz deploy automático em push:
-
-```yaml
-# .github/workflows/composer-deploy-dags.yaml
-on:
- push:
- paths:
- - 'src/data_platform/dags/**'
-
-jobs:
- deploy:
- steps:
- - name: Upload DAGs to GCS
- run: |
- gsutil -m cp -r src/data_platform/dags/* \
- gs://${{ env.COMPOSER_BUCKET }}/dags/
+Cada repo tem seu próprio workflow `composer-deploy-dags.yaml` que sincroniza para o subdiretório correspondente:
+
+**Repo `data-platform`**:
+```bash
+gsutil -m rsync -r -d src/data_platform/dags/ gs://{BUCKET}/dags/data-platform/
+```
+
+**Repo `scraper`**:
+```bash
+gsutil -m rsync -r -d dags/ gs://{BUCKET}/dags/scraper/
```
### Manual via gcloud
@@ -245,8 +297,11 @@ BUCKET=$(gcloud composer environments describe destaquesgovbr-composer \
--location us-central1 \
--format="value(config.dagGcsPrefix)")
-# Upload das DAGs
-gsutil -m cp -r src/data_platform/dags/* $BUCKET/
+# Upload das DAGs do data-platform
+gsutil -m rsync -r -d src/data_platform/dags/ $BUCKET/data-platform/
+
+# Upload das DAGs do scraper
+gsutil -m rsync -r -d dags/ $BUCKET/scraper/
```
## Monitoramento
diff --git a/docs/workflows/docker-builds.md b/docs/workflows/docker-builds.md
index 687a213..3b15582 100644
--- a/docs/workflows/docker-builds.md
+++ b/docs/workflows/docker-builds.md
@@ -8,14 +8,15 @@ O projeto usa Docker para containerização de dois serviços principais:
| Serviço | Imagem | Registry |
| ------- | --------- | ------------------------- |
-| Scraper | `scraper` | GitHub Container Registry |
+| Scraper API | `scraper` | GCP Artifact Registry |
| Portal | `portal` | GCP Artifact Registry |
```mermaid
flowchart LR
- subgraph "Scraper"
- A[Push tag] --> B[Build]
- B --> C[GHCR]
+ subgraph "Scraper API"
+ A[Push main] --> B[Build]
+ B --> F1[Artifact Registry]
+ F1 --> G1[Cloud Run]
end
subgraph "Portal"
@@ -27,114 +28,42 @@ flowchart LR
---
-## Build do Scraper
+## Build do Scraper API
-**Arquivo**: `scraper/.github/workflows/docker-build.yaml`
+**Arquivo**: `scraper/.github/workflows/scraper-api-deploy.yaml`
-### Trigger
+O workflow faz build da imagem Docker e deploy automático no Cloud Run em push para `main`.
-```yaml
-on:
- push:
- tags:
- - "v*" # Apenas tags de versão
- workflow_dispatch: # Manual
-```
-
-### Workflow
+### Trigger
```yaml
-name: Build Docker Image
-
on:
push:
- tags:
- - "v*"
+ branches: [main]
+ paths:
+ - 'src/**'
+ - 'docker/**'
+ - 'pyproject.toml'
workflow_dispatch:
-
-jobs:
- build:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Login to GHCR
- uses: docker/login-action@v3
- with:
- registry: ghcr.io
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Extract metadata
- id: meta
- uses: docker/metadata-action@v5
- with:
- images: ghcr.io/${{ github.repository }}
- tags: |
- type=semver,pattern={{version}}
- type=semver,pattern={{major}}.{{minor}}
- type=raw,value=latest
-
- - name: Build and push
- uses: docker/build-push-action@v5
- with:
- context: .
- push: true
- tags: ${{ steps.meta.outputs.tags }}
- labels: ${{ steps.meta.outputs.labels }}
```
-### Dockerfile do Scraper
+### Pipeline
-```dockerfile
-FROM python:3.12-slim
-
-WORKDIR /app
-
-# Instalar dependências do sistema
-RUN apt-get update && apt-get install -y \
- git \
- && rm -rf /var/lib/apt/lists/*
-
-# Instalar Poetry
-RUN pip install poetry
+1. Build da imagem Docker
+2. Push para GCP Artifact Registry
+3. Deploy no Cloud Run (`destaquesgovbr-scraper-api`)
-# Copiar arquivos de dependência
-COPY pyproject.toml poetry.lock ./
-
-# Instalar dependências
-RUN poetry config virtualenvs.create false \
- && poetry install --no-dev --no-interaction --no-ansi
-
-# Copiar código
-COPY src/ ./src/
-
-# Comando padrão
-CMD ["python", "src/main.py", "--help"]
-```
+### Dockerfile
-### Tags geradas
-
-Para tag `v1.2.3`:
-
-- `ghcr.io/destaquesgovbr/scraper:1.2.3`
-- `ghcr.io/destaquesgovbr/scraper:1.2`
-- `ghcr.io/destaquesgovbr/scraper:latest`
+Localizado em `scraper/docker/Dockerfile`.
### Execução
```bash
-# Via tag (dispara automático)
-git tag v1.2.3
-git push origin v1.2.3
+# Deploy automático em push para main
# Manual
-gh workflow run docker-build.yaml
+gh workflow run scraper-api-deploy.yaml -R destaquesgovbr/scraper
```
---
@@ -212,27 +141,6 @@ CMD ["node", "server.js"]
---
-## GitHub Container Registry (GHCR)
-
-### Autenticação
-
-```bash
-# Login via CLI
-echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
-```
-
-### Pull de imagem
-
-```bash
-docker pull ghcr.io/destaquesgovbr/scraper:latest
-```
-
-### Permissões
-
-O workflow usa `GITHUB_TOKEN` automático com permissão `packages: write`.
-
----
-
## GCP Artifact Registry
### Autenticação
@@ -252,16 +160,16 @@ docker push us-east1-docker.pkg.dev/PROJECT_ID/destaquesgovbr/portal:TAG
## Build Local
-### Scraper
+### Scraper API
```bash
cd scraper
# Build
-docker build -t scraper .
+docker build -f docker/Dockerfile -t scraper-api .
# Executar
-docker run --env-file .env scraper python src/main.py --help
+docker run --env-file .env -p 8080:8080 scraper-api
```
### Portal
diff --git a/docs/workflows/scraper-pipeline.md b/docs/workflows/scraper-pipeline.md
index 2deaea7..c9832b4 100644
--- a/docs/workflows/scraper-pipeline.md
+++ b/docs/workflows/scraper-pipeline.md
@@ -1,234 +1,101 @@
-# Workflow: Pipeline do Scraper
+# Workflow: Pipeline de Coleta e Enriquecimento
-> Pipeline diário de coleta e enriquecimento de notícias.
-
-**Arquivo**: `data-platform/.github/workflows/main-workflow.yaml`
+> Pipeline completo de coleta de notícias (scraper) e enriquecimento (data-platform).
## Visão Geral
-O pipeline é executado diariamente às **4AM UTC** (1AM Brasília) e consiste em 7 jobs sequenciais:
+O pipeline é dividido em dois estágios independentes, em repositórios separados:
+
+1. **Scraping** (repo `scraper`): Via Airflow DAGs, a cada 15 minutos
+2. **Enrichment** (repo `data-platform`): Via GitHub Actions, diário às 4AM UTC
```mermaid
flowchart LR
- A[scraper] --> B[ebc-scraper]
- B --> C[upload-to-cogfy]
- C --> D[wait-cogfy]
- D --> E[enrich-themes]
- E --> F[generate-embeddings]
- F --> G[sync-typesense]
-```
-
----
-
-## Trigger
-
-```yaml
-on:
- schedule:
- - cron: '0 4 * * *' # 4AM UTC diário
- workflow_dispatch: # Manual
- inputs:
- start-date:
- description: 'Data inicial (YYYY-MM-DD)'
- required: false
- end-date:
- description: 'Data final (YYYY-MM-DD)'
- required: false
-```
-
-### Execução automática
-
-- **Horário**: 4AM UTC (1AM Brasília)
-- **Frequência**: Diária
-- **Dias cobertos**: Últimos 3 dias (para capturar atualizações)
-
-### Execução manual
-
-Via GitHub Actions UI ou CLI:
-
-```bash
-# Últimos 3 dias (padrão)
-gh workflow run main-workflow.yaml
-
-# Período específico
-gh workflow run main-workflow.yaml \
- -f start-date=2024-12-01 \
- -f end-date=2024-12-03
+ subgraph "Scraping (Airflow, a cada 15min)"
+ DAG[~158 DAGs] -->|HTTP POST| API[Scraper API
Cloud Run]
+ API --> PG[(PostgreSQL)]
+ end
+
+ subgraph "Enrichment (GitHub Actions, diário)"
+ UC[upload-cogfy] --> W[wait-cogfy]
+ W --> EN[enrich-themes]
+ EN --> EMB[generate-embeddings]
+ EMB --> TS[sync-typesense]
+ end
+
+ PG -.->|lê dados novos| UC
```
---
-## Jobs Detalhados
+## Estágio 1: Scraping (Airflow)
-### Job 1: `scraper`
+**Repositório**: [destaquesgovbr/scraper](https://github.com/destaquesgovbr/scraper)
-Raspa notícias dos sites gov.br e insere no PostgreSQL.
+### Como funciona
-```yaml
-scraper:
- runs-on: ubuntu-latest
- container:
- image: ghcr.io/destaquesgovbr/data-platform:latest
- steps:
- - name: Scrape gov.br sites
- run: |
- data-platform scrape \
- --start-date ${{ inputs.start-date || steps.dates.outputs.start }} \
- --end-date ${{ inputs.end-date || steps.dates.outputs.end }}
- env:
- POSTGRES_HOST: ${{ secrets.POSTGRES_HOST }}
- POSTGRES_DB: ${{ secrets.POSTGRES_DB }}
- POSTGRES_USER: ${{ secrets.POSTGRES_USER }}
- POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
-```
-
-**Duração**: ~30-60 minutos (dependendo do período)
+- ~158 DAGs dinâmicas (1 por agência gov.br) + 1 DAG EBC
+- Cada DAG roda a cada **15 minutos**
+- A DAG faz HTTP POST para a Scraper API no Cloud Run
+- A API raspa o site, parseia HTML → Markdown, e insere no PostgreSQL
-### Job 2: `ebc-scraper`
+### DAGs
-Raspa notícias dos sites EBC (Agência Brasil, etc).
-
-```yaml
-ebc-scraper:
- needs: scraper
- runs-on: ubuntu-latest
- container:
- image: ghcr.io/destaquesgovbr/data-platform:latest
- steps:
- - name: Scrape EBC sites
- run: |
- data-platform scrape-ebc \
- --start-date ${{ inputs.start-date || steps.dates.outputs.start }} \
- --end-date ${{ inputs.end-date || steps.dates.outputs.end }} \
- --allow-update
- env:
- POSTGRES_HOST: ${{ secrets.POSTGRES_HOST }}
- POSTGRES_DB: ${{ secrets.POSTGRES_DB }}
- POSTGRES_USER: ${{ secrets.POSTGRES_USER }}
- POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
-```
+| DAG | Schedule | Descrição |
+|-----|----------|-----------|
+| `scrape_{agency_key}` (~158) | `*/15 * * * *` | Raspa 1 agência gov.br |
+| `scrape_ebc` | `*/15 * * * *` | Raspa sites EBC |
-**Duração**: ~10-20 minutos
-
-### Job 3: `upload-to-cogfy`
-
-Envia notícias do PostgreSQL para classificação no Cogfy.
-
-```yaml
-upload-to-cogfy:
- needs: ebc-scraper
- runs-on: ubuntu-latest
- container:
- image: ghcr.io/destaquesgovbr/data-platform:latest
- steps:
- - name: Upload to Cogfy
- run: |
- data-platform upload-cogfy \
- --start-date ${{ inputs.start-date || steps.dates.outputs.start }} \
- --end-date ${{ inputs.end-date || steps.dates.outputs.end }}
- env:
- POSTGRES_HOST: ${{ secrets.POSTGRES_HOST }}
- POSTGRES_DB: ${{ secrets.POSTGRES_DB }}
- POSTGRES_USER: ${{ secrets.POSTGRES_USER }}
- POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
- COGFY_API_KEY: ${{ secrets.COGFY_API_KEY }}
- COGFY_COLLECTION_ID: ${{ secrets.COGFY_COLLECTION_ID }}
-```
+### API Endpoints
-**Duração**: ~5-10 minutos
+| Método | Endpoint | Descrição |
+|--------|----------|-----------|
+| `POST` | `/scrape/agencies` | Raspa sites gov.br |
+| `POST` | `/scrape/ebc` | Raspa sites EBC |
+| `GET` | `/health` | Health check |
-### Job 4: `wait-cogfy`
+### Deploy
-Aguarda processamento no Cogfy.
+| Componente | Destino | Workflow |
+|-----------|---------|----------|
+| API | Cloud Run | `scraper-api-deploy.yaml` |
+| DAGs | Composer bucket `{bucket}/scraper/` | `composer-deploy-dags.yaml` |
-```yaml
-wait-cogfy:
- needs: upload-to-cogfy
- runs-on: ubuntu-latest
- steps:
- - name: Wait for Cogfy processing
- run: sleep 1200 # 20 minutos
-```
-
-**Duração**: 20 minutos (fixo)
-
-### Job 5: `enrich-themes`
-
-Busca resultados do Cogfy e atualiza PostgreSQL.
+---
-```yaml
-enrich-themes:
- needs: wait-cogfy
- runs-on: ubuntu-latest
- container:
- image: ghcr.io/destaquesgovbr/data-platform:latest
- steps:
- - name: Enrich with themes
- run: |
- data-platform enrich \
- --start-date ${{ inputs.start-date || steps.dates.outputs.start }} \
- --end-date ${{ inputs.end-date || steps.dates.outputs.end }}
- env:
- POSTGRES_HOST: ${{ secrets.POSTGRES_HOST }}
- POSTGRES_DB: ${{ secrets.POSTGRES_DB }}
- POSTGRES_USER: ${{ secrets.POSTGRES_USER }}
- POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
- COGFY_API_KEY: ${{ secrets.COGFY_API_KEY }}
- COGFY_COLLECTION_ID: ${{ secrets.COGFY_COLLECTION_ID }}
-```
+## Estágio 2: Enrichment Pipeline (GitHub Actions)
-**Duração**: ~10-20 minutos
+**Repositório**: [destaquesgovbr/data-platform](https://github.com/destaquesgovbr/data-platform)
-### Job 6: `generate-embeddings`
+**Arquivo**: `data-platform/.github/workflows/main-workflow.yaml`
-Gera embeddings para notícias sem vetores.
+### Trigger
```yaml
-generate-embeddings:
- needs: enrich-themes
- runs-on: ubuntu-latest
- container:
- image: ghcr.io/destaquesgovbr/data-platform:latest
- steps:
- - name: Generate embeddings
- run: |
- data-platform generate-embeddings \
- --start-date ${{ inputs.start-date || steps.dates.outputs.start }}
- env:
- POSTGRES_HOST: ${{ secrets.POSTGRES_HOST }}
- POSTGRES_DB: ${{ secrets.POSTGRES_DB }}
- POSTGRES_USER: ${{ secrets.POSTGRES_USER }}
- POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
- EMBEDDINGS_API_URL: ${{ secrets.EMBEDDINGS_API_URL }}
+on:
+ schedule:
+ - cron: '0 4 * * *' # 4AM UTC diário
+ workflow_dispatch:
+ inputs:
+ start_date:
+ description: 'Start date (YYYY-MM-DD)'
+ end_date:
+ description: 'End date (YYYY-MM-DD)'
+ cogfy_wait_minutes:
+ description: 'Minutes to wait for Cogfy (default: 20)'
```
-**Duração**: ~10-15 minutos
+### Jobs
-### Job 7: `sync-typesense`
+| # | Job | Descrição | Duração |
+|---|-----|-----------|---------|
+| 1 | `upload-to-cogfy` | Envia notícias novas para classificação no Cogfy | ~5-10 min |
+| 2 | `wait-cogfy` | Aguarda processamento no Cogfy | 20 min (fixo) |
+| 3 | `enrich-themes` | Busca temas e sumários do Cogfy, atualiza PostgreSQL | ~10-20 min |
+| 4 | `generate-embeddings` | Gera vetores 768-dim via Embeddings API (Cloud Run) | ~10-15 min |
+| 5 | `sync-typesense` | Sincroniza dados enriquecidos para o Typesense | ~5-10 min |
-Sincroniza dados do PostgreSQL para o Typesense.
-
-```yaml
-sync-typesense:
- needs: generate-embeddings
- runs-on: ubuntu-latest
- container:
- image: ghcr.io/destaquesgovbr/data-platform:latest
- steps:
- - name: Sync to Typesense
- run: |
- data-platform sync-typesense \
- --start-date ${{ inputs.start-date || steps.dates.outputs.start }}
- env:
- POSTGRES_HOST: ${{ secrets.POSTGRES_HOST }}
- POSTGRES_DB: ${{ secrets.POSTGRES_DB }}
- POSTGRES_USER: ${{ secrets.POSTGRES_USER }}
- POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
- TYPESENSE_HOST: ${{ secrets.TYPESENSE_HOST }}
- TYPESENSE_API_KEY: ${{ secrets.TYPESENSE_API_KEY }}
-```
-
-**Duração**: ~5-10 minutos
+**Duração total**: ~50-75 minutos
---
@@ -236,54 +103,49 @@ sync-typesense:
```mermaid
sequenceDiagram
- participant GH as GitHub Actions
- participant DP as Data Platform Container
- participant GOV as Sites gov.br
- participant EBC as Sites EBC
+ participant AF as Airflow DAGs
+ participant API as Scraper API (Cloud Run)
+ participant GOV as Sites gov.br / EBC
participant PG as PostgreSQL
+ participant GH as GitHub Actions
participant CF as Cogfy
participant EMB as Embeddings API
participant TS as Typesense
- Note over GH: 4AM UTC - Trigger
+ Note over AF: A cada 15 min
- GH->>DP: Job: scraper
- DP->>GOV: Fetch ~160+ sites
- GOV-->>DP: HTML pages
- DP->>DP: Parse → Markdown
- DP->>PG: Insert articles
+ AF->>API: POST /scrape/agencies
+ API->>GOV: Fetch sites
+ GOV-->>API: HTML pages
+ API->>API: Parse → Markdown
+ API->>PG: INSERT articles
- GH->>DP: Job: ebc-scraper
- DP->>EBC: Fetch EBC sites
- EBC-->>DP: HTML pages
- DP->>PG: Insert/Update articles
+ Note over GH: 4AM UTC - Trigger diário
- GH->>DP: Job: upload-to-cogfy
- DP->>PG: Load articles
- DP->>CF: POST records (batch)
+ GH->>PG: Load new articles
+ GH->>CF: POST records (batch)
Note over GH: Wait 20 min
- GH->>DP: Job: enrich-themes
- DP->>CF: GET processed records
- CF-->>DP: Themes + Summary
- DP->>PG: Update with enrichment
+ GH->>CF: GET processed records
+ CF-->>GH: Themes + Summary
+ GH->>PG: UPDATE with enrichment
- GH->>DP: Job: generate-embeddings
- DP->>PG: Get news without embeddings
- DP->>EMB: POST texts (batch)
- EMB-->>DP: Vectors 768-dim
- DP->>PG: Update with embeddings
+ GH->>PG: Get news without embeddings
+ GH->>EMB: POST texts (batch)
+ EMB-->>GH: Vectors 768-dim
+ GH->>PG: UPDATE with embeddings
- GH->>DP: Job: sync-typesense
- DP->>PG: Get news for indexing
- DP->>TS: Upsert documents
+ GH->>PG: Get news for indexing
+ GH->>TS: Upsert documents
```
---
## Secrets Necessárias
+### Repo `data-platform` (enrichment)
+
| Secret | Descrição | Usado em |
|--------|-----------|----------|
| `POSTGRES_HOST` | Host do Cloud SQL | Todos os jobs |
@@ -296,112 +158,41 @@ sequenceDiagram
| `TYPESENSE_HOST` | Host do Typesense | sync-typesense |
| `TYPESENSE_API_KEY` | API Key do Typesense | sync-typesense |
-### Configurar secrets
+### Repo `scraper`
-```bash
-# Via GitHub CLI
-gh secret set POSTGRES_HOST --body "10.x.x.x"
-gh secret set POSTGRES_DB --body "destaquesgovbr"
-gh secret set POSTGRES_USER --body "admin"
-gh secret set POSTGRES_PASSWORD --body "xxxxx"
-gh secret set COGFY_API_KEY --body "sk-xxxxx"
-gh secret set COGFY_COLLECTION_ID --body "uuid-xxxxx"
-gh secret set EMBEDDINGS_API_URL --body "https://embeddings-xxx.run.app"
-gh secret set TYPESENSE_HOST --body "10.x.x.x"
-gh secret set TYPESENSE_API_KEY --body "xxxxx"
-```
+| Secret | Descrição |
+|--------|-----------|
+| `DATABASE_URL` | Connection string PostgreSQL |
+| GCP SA credentials | Para deploy no Cloud Run e Composer |
---
## Monitoramento
-### Ver status do workflow
+### Scraping (Airflow)
```bash
-# Listar execuções recentes
-gh run list --workflow=main-workflow.yaml
-
-# Ver detalhes de uma execução
-gh run view
-
-# Ver logs
-gh run view --log
+# Acessar Web UI do Airflow
+gcloud composer environments describe destaquesgovbr-composer \
+ --location us-central1 \
+ --format="value(config.airflowUri)"
```
-### Via interface GitHub
-
-1. Acessar repositório no GitHub
-2. Aba "Actions"
-3. Selecionar "main-workflow"
-4. Ver execuções e logs
-
----
-
-## Tratamento de Erros
-
-### Falha em scraping
-
-- Jobs posteriores **não executam** (dependência)
-- Artigos com erro são **skipados** (não bloqueia)
-- Logs detalhados disponíveis
-
-### Falha em upload Cogfy
-
-- Retry automático (3 tentativas)
-- Enriquecimento não executa
-- Dados ficam sem classificação até próxima execução
-
-### Falha em embeddings
-
-- Notícias sem embeddings são marcadas
-- Próxima execução tenta novamente
-
-### Falha em sync Typesense
-
-- Portal continua funcionando com dados antigos
-- Próxima execução tenta novamente
-
----
-
-## Execução Manual (Dispatch)
-
-### Para período específico
+### Enrichment (GitHub Actions)
```bash
-gh workflow run main-workflow.yaml \
- -f start-date=2024-01-01 \
- -f end-date=2024-01-31
-```
-
-### Para reprocessar
+# Listar execuções recentes
+gh run list --workflow=main-workflow.yaml -R destaquesgovbr/data-platform
-```bash
-# Reprocessar últimos 7 dias
-gh workflow run main-workflow.yaml \
- -f start-date=$(date -v-7d +%Y-%m-%d) \
- -f end-date=$(date +%Y-%m-%d)
+# Ver detalhes de uma execução
+gh run view -R destaquesgovbr/data-platform
```
---
-## Duração Total
-
-| Job | Duração Típica |
-|-----|----------------|
-| scraper | 30-60 min |
-| ebc-scraper | 10-20 min |
-| upload-to-cogfy | 5-10 min |
-| wait-cogfy | 20 min (fixo) |
-| enrich-themes | 10-20 min |
-| generate-embeddings | 10-15 min |
-| sync-typesense | 5-10 min |
-| **Total** | **~90-155 min** |
-
----
-
## Sync HuggingFace (Separado)
-O sync para o HuggingFace é feito via DAG no Cloud Composer, não faz parte deste workflow.
+O sync para o HuggingFace é feito via DAG no Cloud Composer (repo `data-platform`), não faz parte dos pipelines acima.
→ Veja [Airflow DAGs](./airflow-dags.md) para detalhes.
@@ -409,8 +200,8 @@ O sync para o HuggingFace é feito via DAG no Cloud Composer, não faz parte des
## Links Relacionados
-- [Data Platform](../modulos/data-platform.md) - Repositório unificado
+- [Módulo Scraper](../modulos/scraper.md) - Detalhes do scraper standalone
+- [Data Platform](../modulos/data-platform.md) - Repositório de enrichment
- [PostgreSQL](../arquitetura/postgresql.md) - Fonte de verdade
-- [Fluxo de Dados](../arquitetura/fluxo-de-dados.md) - Visão geral do pipeline
-- [Integração Cogfy](../modulos/cogfy-integracao.md) - Classificação LLM
-- [Docker Builds](./docker-builds.md) - Build da imagem
+- [Airflow DAGs](./airflow-dags.md) - DAGs de sync e scraping
+- [Docker Builds](./docker-builds.md) - Build das imagens