Economic indicators dashboard built with FastAPI + DuckDB + ECharts, serving 11 interactive sections with data from 9 official statistical sources.
- οΏ½οΈ Documentation Map β Quick navigation guide for all resources
- οΏ½π Full Documentation Index β Central guide to all project docs
- Contribution guide:
CONTRIBUTING.md - Formal source registry:
SOURCES.md - Design resources:
docs/design/β design inspiration notes and open-source implementations (no copyrighted book files) - AI agent guidelines:
copilot-instructions.md
DocumentaΓ§Γ£o complementar em portuguΓͺs estΓ‘ disponΓvel em docs/ e em notas de projeto como SETUP_NOTES.md. O README principal mantΓ©m-se em inglΓͺs para o pΓΊblico open-source internacional.
prumo/
βββ app/ # FastAPI application
β βββ main.py # App entrypoint, CORS, static mount, healthcheck
β βββ config.py # Environment variables and paths
β βββ database.py # Thread-safe DuckDB connection pool
β βββ constants/ # Static data (catalog, events, country lists)
β β βββ catalog.py # CATALOG β 9 sources, ~380 indicators
β β βββ events.py # CHART_EVENTS, BRIEFING/SUMMARY indicator lists
β β βββ countries.py # COMPARE_COUNTRIES, COMPARE_DATASETS
β β βββ mappings.py # USED_IN, FRED_SERIES, WB_CODES, SOURCE_META
β βββ routes/
β β βββ api.py # /api/* endpoints (thin handlers β services)
β β βββ pages.py # GET / β serves dashboard via Jinja2
β βββ services/ # Business logic, one module per section
β βββ helpers.py # Shared: YoY, trend, sparkline, period utils
β βββ resumo.py # Resumo KPIs
β βββ industria.py # Industrial production (IPI)
β βββ energia.py # Energy (REN, E-REDES, DGEG)
β βββ emprego.py # Employment (IEFP, INE)
β βββ macro.py # Macro indicators (GDP, inflation, trade)
β βββ ficha.py # Data sheet / DB stats
β βββ fosso.py # EU convergence gap
β βββ produtividade.py # Productivity metrics
β βββ analysis.py # Automated trend analysis
β βββ explorador.py # Data explorer catalog
β βββ series.py # Generic time series queries + country compare
β βββ briefing.py # Auto-generated briefing + summary
βββ templates/
β βββ dashboard.html # SPA shell (Jinja2, hash router, ECharts)
βββ static/
β βββ css/
β β βββ swd-theme.css # Storytelling with Data theme
β β βββ sections.css # Section-specific styles
β βββ js/
β βββ app.js # Hash router + lazy section loading
β βββ api.js # Fetch wrappers with 5-min cache
β βββ swd-charts.js # SWD chart factory (ECharts)
β βββ sections/ # 11 section initializers (one per tab)
βββ collectors/ # Data source clients (CLI tools)
β βββ ine.py # INE β Instituto Nacional de EstatΓstica
β βββ eurostat.py # Eurostat
β βββ fred.py # FRED β Federal Reserve Economic Data
β βββ oecd.py # OECD
β βββ bportugal.py # Banco de Portugal
β βββ ren.py # REN β Rede EnergΓ©tica Nacional
β βββ eredes.py # E-REDES β electricity distribution
β βββ dgeg_fuel_api.py # DGEG β fuel prices
β βββ worldbank.py # World Bank
βββ stats_lib/ # Shared data layer for collectors
βββ scripts/
β βββ cae-collect # Main collection orchestrator
β βββ cae-v4-backfill.py # Historical data backfill
βββ analise-content.html # Pre-rendered analysis content
βββ analise-metadata.json # Analysis metadata
βββ requirements.txt # Python dependencies
βββ Dockerfile # Python 3.12 + uvicorn
| Source | Provider | Data |
|---|---|---|
| INE | Instituto Nacional de EstatΓstica | Industrial production, employment, GDP, trade |
| Eurostat | European Commission | Cross-country comparisons (manufacturing, GDP, unemployment) |
| FRED | Federal Reserve Bank of St. Louis | US interest rates, global benchmarks |
| OECD | Organisation for Economic Co-operation | Composite leading indicators, productivity |
| BdP | Banco de Portugal | Monetary/financial indicators |
| REN | Rede EnergΓ©tica Nacional | Electricity consumption/production |
| E-REDES | Electricity distribution | Grid distribution data |
| DGEG | DirecΓ§Γ£o-Geral de Energia e Geologia | Fuel prices |
| World Bank | World Bank Group | Long-term development indicators |
For provider URLs, cadence and terms/caveats notes, see SOURCES.md.
| Section | Route | API | Description |
|---|---|---|---|
| Resumo | #resumo |
/api/resumo |
Overview KPIs with sparklines and trends |
| IndΓΊstria | #industria |
/api/industria |
Industrial Production Index (IPI) by sector |
| Europa | #europa |
/api/europa |
PT vs EU country comparisons |
| Energia | #energia |
/api/energia |
Energy consumption and production |
| Emprego | #emprego |
/api/emprego |
Employment, unemployment, job offers |
| Macro | #macro |
/api/macro |
GDP, inflation, trade balance |
| AnΓ‘lise | #analise |
/api/analysis |
Automated trend analysis |
| Fosso | #fosso |
/api/fosso |
EU convergence gap |
| Produtividade | #produtividade |
/api/produtividade |
Labour productivity metrics |
| Explorador | #explorador |
/api/explorador |
Data explorer (all indicators) |
| Ficha TΓ©cnica | #ficha |
/api/ficha |
Data sheet, DB stats, sources |
All endpoints are under /api/ and return JSON.
| Endpoint | Method | Parameters | Description |
|---|---|---|---|
/api/resumo |
GET | β | Summary KPIs |
/api/industria |
GET | period (int, default 5) |
IPI sectors data |
/api/europa |
GET | dataset, countries, months, indicator, source, since |
Country comparison |
/api/energia |
GET | β | Energy data |
/api/emprego |
GET | β | Employment data |
/api/macro |
GET | β | Macro indicators |
/api/ficha |
GET | β | DB stats and source metadata |
/api/fosso |
GET | β | EU convergence gap |
/api/produtividade |
GET | β | Productivity metrics |
/api/analysis |
GET | β | Automated trend analysis |
/api/explorador |
GET | β | Full indicator catalog |
/api/briefing |
GET | β | Auto-generated briefing |
/api/summary |
GET | β | Executive summary |
/api/series |
GET | source, indicator, from, to |
Raw time series query |
/api/compare |
GET | dataset, countries, months, indicator, source, since |
Country comparison (alias for europa) |
/api/data |
GET | β | Full dataset dump |
/api/kpis |
GET | β | Latest value per indicator |
/api/catalog |
GET | β | CATALOG enriched with DB stats |
/api/events |
GET | β | Historical event markers |
/healthz |
GET | β | Health check |
/docs |
GET | β | Swagger UI (auto-generated) |
| Variable | Default | Description |
|---|---|---|
CAE_DB_PATH |
/data/cae-data.duckdb |
Path to main DuckDB database |
CAE_PORT |
8080 |
Server port |
CAE_BASE_PATH |
"" |
URL base path (for subpath serving) |
SKILLS_DIR |
/home/node/.openclaw/workspace/skills/cae-reports |
Path to OpenClaw skills directory |
TZ |
β | Timezone (from compose) |
For machine-specific setup, use a local folder at stacks/web/images/prumo/server-env/.
server-env/is intentionally ignored by git and must never be committed.- Keep all local-only links/files inside
server-env/(for example symlinks to root-level resources such as.bash_aliases,.env, and selected folders undermd/). - Preferred pattern is symlink-based references from
server-env/so local server context is available without changing tracked deployment/configuration files.
Example local setup:
mkdir -p stacks/web/images/prumo/server-env
ln -s ../../../../../.bash_aliases stacks/web/images/prumo/server-env/bash_aliases
ln -s ../../../../../.env stacks/web/images/prumo/server-env/env
ln -s ../../../../../md stacks/web/images/prumo/server-env/mdThis workflow is local-only and does not change compose behavior or deployment semantics.
On its first run, the container will automatically initialize the /data volume with default configuration (site.json) and ideology defaults if they don't already exist. The DuckDB database is not included in the image; if one is not mounted, the system will place a README-DB.txt indicating that data needs to be populated via the collection scripts or mounted externally. This ensures safe, idempotent bootstrapping without overwriting existing data.
The dashboard runs as a Docker container behind Traefik reverse proxy.
Prumo is now split into two compose layers under stacks/web/compose/:
prumo.base.yml: portable/OSS app defaults (build, runtime env, healthcheck).prumo.yml: server override (Traefik routes, proxy cert chain, server networks, bind mounts used on this host).
The stack loader in stacks/web/compose.yml includes base first and override second so current server behavior remains unchanged while keeping a reusable base.
dc-jarbas-up cae-dashboard- Primary:
https://cae.joao.dateβ direct access - Subpath:
https://joao.date/dadosβ served under subpath with Traefik StripPrefix
The subpath route uses Traefik's StripPrefix middleware which sets X-Forwarded-Prefix: /dados. The app reads this header to inject the correct BASE_PATH into the template, so all static asset and API URLs resolve correctly.
docker exec cae-dashboard ./scripts/cae-collect- Single worker: Uvicorn runs with
--workers 1because DuckDB connections are not thread-safe. FastAPI's thread pool handles concurrent requests via per-thread connection reuse. - No auth: Dashboard is public (
chain-no-auth@filemiddleware in Traefik). - SPA routing: The frontend uses hash-based routing (
#section). All navigation is client-side; the server only serves the single HTML shell. - Chart library: ECharts 5.5.0 (CDN) with a custom SWD (Storytelling with Data) theme.
- Caching:
api.jscaches API responses in memory for 5 minutes to reduce DB load during tab switching. - Database: DuckDB in read-only mode. Data is collected externally by the
cae-collectscript and written to the database separately.