How leonardo-michelotti/observatorio-educacao-rs works
Purpose and entry points
This is an end-to-end local data product analyzing basic-education indicators for Santa Maria, Rio Grande do Sul, and Brazil. Its primary execution entry point is run_pipeline.py, which runs extraction, dbt transformation, chart creation, and static-page generation. Published entry points are public/index.html, public/arquitetura.html, and machine-readable freshness metadata in public/data-status.json.
Source ingestion and bronze boundary
Two ingestion paths deliberately isolate external data acquisition from analytical logic:
• Official INEP XLS/XLSX downloads for approval rates and age-grade distortion: ingestion/extract_inep.py, with source definitions and validation references in ingestion/inep_sources.json and ingestion/inep_reference_values.json.
• BigQuery/Base dos Dados extraction for IDEB and SAEB: ingestion/extract_bd.py.
• A snapshot restoration path supports refreshes without historical BigQuery queries: ingestion/load_ideb_snapshot.py.
Bronze outputs are Parquet plus provenance, separating raw source evidence from normalized analytics.
Transformation and analytical contract
DuckDB is the local analytical engine, with dbt implementing the silver/gold layers:
• Staging normalizes source-specific structures: dbt/models/staging/stg_ideb.sql and dbt/models/staging/stg_indicadores.sql.
• The mart exposes one tidy fact contract: dbt/models/marts/fct_indicadores.sql.
• The intended grain is indicator, geographic level, education stage, year, and value. Schema and semantic constraints are defined in dbt/models/marts/_marts.yml, with grain/range checks in dbt/tests/fct_indicadores_unique_grain.sql and dbt/tests/fct_indicadores_valid_ranges.sql.
This fact model is the sole intended boundary for downstream visualization and future indicators.
Product-generation layer
Visualization reads transformed DuckDB data rather than source files:
• viz/make_charts.py produces versioned PNG assets used by the README.
• viz/build_dashboard.py produces self-contained editorial analysis and architecture pages.
• Generated web artifacts are copied to public/index.html and public/arquitetura.html; working visual templates/artifacts live in viz/dashboard.html and viz/arquitetura.html.
The dashboard includes interactive charts, table alternatives, responsive behavior, and data-status publication.
Orchestration and update control
run_pipeline.py is the central control plane for a full reproducible build. It sequences ingestion, dbt build, chart generation, and page generation. Offline CI uses deterministic synthetic bronze data, while the manual official refresh workflow restores audited history and upserts the newest INEP year. This distinction prevents test fixtures from entering published outputs.
Runtime, infrastructure, and deployment
The main runtime is Python 3.12+ with dbt-duckdb, DuckDB, matplotlib, and BigQuery client access. BigQuery requires Google Cloud ADC and a billing project for IDEB/SAEB extraction. Static deployment uses Caddy in a container:
• Dockerfile
• Caddyfile
• railway.toml
Railway serves the generated static public/ directory over HTTPS; raw data and credentials are excluded from the deploy image.
Automation and quality gates
GitHub Actions separates responsibilities:
• .github/workflows/ci.yml rebuilds offline, runs dbt and Python tests, and validates desktop/mobile navigation and WCAG behavior through Playwright.
• .github/workflows/refresh-inep.yml performs real official-source refreshes, preserves provenance/artifacts, and opens update PRs.
• .github/workflows/deploy.yml deploys validated main-branch output to Railway.
Components 19
Ingestion
External acquisition and bronze evidence.
- INEP downloads · Approval-rate and age-grade-distortion source data.
- INEP extractor
ingestion/extract_inep.py - BigQuery / Base dos Dados · IDEB and SAEB extraction requires Google Cloud ADC and billing.
- IDEB & SAEB extractor
ingestion/extract_bd.py - IDEB snapshot restore · Restores audited history without historical BigQuery queries.
ingestion/load_ideb_snapshot.py - Bronze Parquet + provenance · Separates source evidence from normalized analytics.
Analytics
DuckDB and dbt analytical contract.
- Local DuckDB
- Staging models · Normalizes IDEB and indicator source structures.
dbt/models/staging/stg_ideb.sql - Indicators fact · Sole downstream contract at indicator, geography, stage, year, and value grain.
dbt/models/marts/fct_indicadores.sql - Mart constraints · Enforces fact grain and valid indicator ranges.
dbt/models/marts/_marts.yml
Product generation
Static analysis and visual outputs.
- Versioned chart assets · Creates README chart assets from transformed DuckDB data.
viz/make_charts.py - Dashboard page builder · Builds self-contained editorial dashboard and architecture pages.
viz/build_dashboard.py - Published static site · Dashboard, architecture page, and freshness metadata.
public/index.html
Automation & deploy
Validated refresh and publication workflows.
- Offline CI · Uses deterministic synthetic bronze data and validates tests, navigation, and WCAG behavior.
.github/workflows/ci.yml - Official refresh · Refreshes INEP data, preserves provenance, and opens update PRs.
.github/workflows/refresh-inep.yml - Railway deployment · Deploys validated main-branch static output.
.github/workflows/deploy.yml - Caddy static server · Serves public artifacts over HTTPS; raw data and credentials are excluded.
Caddyfile - Railway
railway.toml
Other components
- Full pipeline · Reproducibly sequences ingestion, transforms, charts, and pages.
run_pipeline.py
Connections 23
- Full pipeline → INEP extractor: runs
- Full pipeline → IDEB & SAEB extractor: runs
- Full pipeline → Local DuckDB: builds
- Full pipeline → Versioned chart assets: runs
- Full pipeline → Dashboard page builder: runs
- INEP downloads → INEP extractor: downloads
- BigQuery / Base dos Dados → IDEB & SAEB extractor: queries
- INEP extractor → Bronze Parquet + provenance: writes
- IDEB & SAEB extractor → Bronze Parquet + provenance: writes
- IDEB snapshot restore → Bronze Parquet + provenance: restores
- Bronze Parquet + provenance → Staging models: normalizes
- Staging models → Indicators fact: models
- Indicators fact → Local DuckDB: materialized in
- Mart constraints → Indicators fact: validates
- Local DuckDB → Versioned chart assets: reads
- Local DuckDB → Dashboard page builder: reads
- Dashboard page builder → Published static site: publishes pages
- Offline CI → Full pipeline: offline rebuild
- Official refresh → IDEB snapshot restore: restores history
- Official refresh → INEP extractor: refreshes
- Railway deployment → Published static site: deploys
- Published static site → Caddy static server: served by
- Caddy static server → Railway: hosted on