π Economic Indicators Dashboard - Bazel Polyglot TutorialΒΆ
A comprehensive Bazel-based polyglot application that demonstrates building and orchestrating Go, Python, and React services in a single repository. This project fetches real economic data from the FRED API, serves it through a REST API, and visualizes it in a modern web dashboard.
π― What This Project DemonstratesΒΆ
This is a teaching repository that shows:
- β Polyglot builds with Bazel (Go + Python + React)
- β Incremental compilation and caching
- β Hermetic testing without network dependencies
- β Modern toolchain integration (rules_go, rules_python, npm/vite)
- β CI/CD with GitHub Actions and Bazel caching
- β Real-world architecture patterns (data fetcher β API β UI)
ποΈ ArchitectureΒΆ
βββββββββββββββ ββββββββββββββββ βββββββββββββββ
β Go Fetch β writes β SQLite DB β reads β Python API β
β Service βββββββββββ (econ.db) βββββββββββ (FastAPI) β
βββββββββββββββ ββββββββββββββββ βββββββββββββββ
β
β HTTP
β
βββββββββββββββ
β React UI β
β (Vite) β
βββββββββββββββ
ComponentsΒΆ
go_fetch/- Go service that fetches economic indicators from FRED API- Fetches 14 FRED series covering 10 high-ROI macro indicators with 30-year baseline
- Stores data in SQLite database (
store_sqlite.go) - FRED API client (
fred.go) - Rich metadata and categorization (
metadata.go) - Comprehensive data dictionary (
indicators.md) - Includes mock HTTP tests (
fred_test.go) -
Bazel build config:
BUILD.bazel -
py_api/- Python FastAPI REST service - Reads from SQLite database (
db.py) - Computes MoM/YoY deltas (
handlers.py) - FastAPI server (
main.py) - Exposes normalized JSON endpoints
- Includes fixture-based tests (
test_api.py) -
Bazel build config:
BUILD.bazel -
web_ui/- React + TypeScript + Vite frontend - Dashboard view with indicator cards (
App.tsx) - Chart component (
LineChart.tsx) - Detailed series view with charts
- Responsive design
- Bazel build config:
BUILD.bazel
π Live DemoΒΆ
The Economic Indicators Dashboard is deployed live on GitHub Pages:
- Automatic updates: Data refreshes daily at 12:00 UTC via GitHub Actions
- Static hosting: Fully client-side React app with pre-generated JSON data
- Zero backend: No API servers required - all data served as static files
- Free hosting: Powered by GitHub Pages and GitHub Actions
How it WorksΒΆ
- GitHub Actions workflow runs daily (schedule) or manually (workflow_dispatch)
- Bazel builds the Go fetch service and fetches latest FRED data
- JSON export generates static data files (
summary.json,series-*.json) - React build creates optimized production bundle with data files
- GitHub Pages serves the static site
See .github/workflows/update-dashboard.yaml for the complete workflow.
π Quick StartΒΆ
PrerequisitesΒΆ
-
Install Bazel (6.4.0 or later)
-
Get a FRED API Key (free)
- Sign up at: https://fred.stlouisfed.org/docs/api/api_key.html
- Set environment variable:
Running the DashboardΒΆ
Option 1: Run All Components (Recommended)ΒΆ
This will: 1. Fetch latest economic data from FRED 2. Start the Python API server on http://localhost:8000 3. Show instructions for starting the web UI
Then in another terminal:
Open http://localhost:3000 in your browser π
π View Live Dashboard
Once running, access the dashboard at:
- Dashboard UI: http://localhost:3000 - Interactive charts and indicators
- API Server: http://localhost:8000 - REST API
- API Docs: http://localhost:8000/docs - Swagger/OpenAPI documentation
Option 2: Run Components IndividuallyΒΆ
# 1. Fetch data
bazel run //go_fetch:refresh
# 2. Start API (in one terminal)
bazel run //py_api:server
# 3. Start UI (in another terminal)
cd web_ui && npm install && npm run dev
π§ͺ TestingΒΆ
All tests use fixtures and mocks - no network access required!
# Run all tests
bazel test //...
# Run specific tests
bazel test //go_fetch:fred_test
bazel test //py_api:api_test
# View test output
bazel test //... --test_output=all
ποΈ BuildingΒΆ
# Build everything
bazel build //...
# Build specific targets
bazel build //go_fetch:refresh
bazel build //py_api:server
bazel build //web_ui:build
# Query the build graph
bazel query //...
bazel query 'deps(//py_api:server)'
π Available IndicatorsΒΆ
The dashboard tracks 10 core high-ROI macroeconomic indicators (14 FRED series total) with 30-year baseline coverage:
Core IndicatorsΒΆ
| # | Indicator | FRED Codes | Category | Coverage |
|---|---|---|---|---|
| 1οΈβ£ | Real GDP | GDPC1 |
Growth | 1947β |
| 2οΈβ£ | CPI (Inflation) | CPIAUCSL, CPILFESL |
Inflation | 1947β |
| 3οΈβ£ | Unemployment Rate | UNRATE |
Labor Market | 1948β |
| 4οΈβ£ | Fed Funds Rate | FEDFUNDS |
Monetary Policy | 1954β |
| 5οΈβ£ | Treasury Yield Curve | T10Y2Y, DGS10, DGS2 |
Yield Curve | 1976β |
| 6οΈβ£ | M2 Money Supply | M2SL |
Liquidity | 1959β |
| 7οΈβ£ | Brent Crude Oil | POILBREUSDM |
Commodities | 1987β |
| 8οΈβ£ | Manufacturing | MANEMP |
Manufacturing | 1939β |
| 9οΈβ£ | Consumer Sentiment | UMCSENT |
Sentiment | 1978β |
| π | Global Trade | IMPCH, EXPCH |
Trade | 1947β |
Coverage: All indicators have data back to 1990 or earlier β
Detailed Specifications: See go_fetch/indicators.md for complete data dictionary
Economic CategoriesΒΆ
Indicators are organized by economic domain:
- Growth: Real GDP
- Inflation: Headline CPI, Core CPI
- Labor Market: Unemployment Rate
- Monetary Policy: Federal Funds Rate
- Yield Curve: 10Y-2Y Spread, Treasury Yields
- Liquidity: M2 Money Supply
- Commodities: Oil Prices (also relevant for inflation analysis)
- Manufacturing: Employment
- Sentiment: Consumer Confidence
- Trade: Real Imports/Exports
π API EndpointsΒΆ
GET /api/healthΒΆ
Health check and service status
GET /api/econ/summaryΒΆ
Summary of all indicators with latest values and deltas
GET /api/econ/series?code=<CODE>&range=<RANGE>ΒΆ
Time series data for a specific indicator
- code: Series code (e.g., CPIAUCSL)
- range: Time range - 1y, 5y, or max (default)
GET /api/econ/metaΒΆ
Metadata about all available series
API documentation: http://localhost:8000/docs
π§± Bazel ConceptsΒΆ
MODULE.bazelΒΆ
This file defines external dependencies using Bzlmod (Bazel's modern dependency system):
- rules_go - Go toolchain and build rules
- rules_python - Python toolchain and pip integration
- aspect_rules_js - Modern JavaScript/Node.js support
BUILD.bazel FilesΒΆ
Each component has a BUILD.bazel file that defines:
- Binaries (go_binary, py_binary) - Executable programs
- Libraries (go_library, py_library) - Reusable code
- Tests (go_test, py_test) - Test targets
Example from go_fetch/BUILD.bazel:
Targets and LabelsΒΆ
Targets are referenced with labels: //package:target
- //go_fetch:refresh - Go binary in go_fetch package
- //py_api:server - Python server binary
- //... - All targets in the repository
π Incremental BuildsΒΆ
Bazel only rebuilds what changed. Try this:
# First build (downloads deps, compiles everything)
bazel build //...
# Edit go_fetch/main.go
# Only Go targets rebuild!
bazel build //...
# Edit py_api/handlers.py
# Only Python targets rebuild!
bazel build //...
π Deploy Your Own DashboardΒΆ
Want to deploy your own version on GitHub Pages? Here's how:
Step 1: Fork the RepositoryΒΆ
Fork bazel-tutorial to your GitHub account.
Step 2: Create a Personal Access Token (PAT)ΒΆ
The workflow needs a PAT to bypass branch protection rules when committing data updates.
- Go to: https://github.com/settings/tokens/new
- Configure the token:
- Note:
bazel-tutorial-workflow(or any descriptive name) - Expiration: Choose desired expiration (recommend 90 days or longer)
- Select scopes:
- β
repo(Full control of private repositories) - β
workflow(Update GitHub Action workflows)
- β
- Click Generate token
- Copy the token (you won't see it again!)
Step 3: Configure GitHub SecretsΒΆ
- Go to your fork's Settings β Secrets and variables β Actions
- Add two repository secrets:
First secret:
- Name: FRED_API_KEY
- Value: Your FRED API key (get one free here)
Second secret:
- Name: WORKFLOW_PAT
- Value: The Personal Access Token you created above
Step 4: Enable GitHub PagesΒΆ
- Go to Settings β Pages
- Under Source, select GitHub Actions
- The workflow will automatically deploy your dashboard
Step 5: Trigger the WorkflowΒΆ
- Go to Actions tab
- Select Update Economic Dashboard workflow
- Click Run workflow β Run workflow
Within a few minutes, your dashboard will be live at:
Customization OptionsΒΆ
Change update frequency: Edit .github/workflows/update-dashboard.yaml:
Add more indicators: Edit go_fetch/main.go:
defaultSeries = []string{
"CPIAUCSL",
"UNRATE",
"GDPC1", // Add GDP
"DEXUSEU", // Add EUR/USD exchange rate
}
Customize UI: Edit web_ui/src/App.tsx and web_ui/src/App.css
π How to ExtendΒΆ
Adding a New Economic IndicatorΒΆ
-
Update
go_fetch/main.go- Add series code todefaultSeries -
Refresh data
-
Indicator automatically appears in UI - No frontend changes needed!
Adding Go DependenciesΒΆ
-
Add to
go_fetch/go.mod: -
Run:
Adding Python DependenciesΒΆ
-
Add to
py_api/requirements.txt: -
Update
MODULE.bazelpip.parse section -
Rebuild:
π TroubleshootingΒΆ
"Database not found"ΒΆ
Solution: Run the data fetcher first:
"FRED_API_KEY not set"ΒΆ
Solution: Get a free API key and set it:
"Build is slow"ΒΆ
Solution: First build downloads all dependencies. Subsequent builds are fast due to caching.
"Tests failing"ΒΆ
Solution: Tests are hermetic and don't need network/API keys. If failing, check:
"Web UI not loading"ΒΆ
Solution: Ensure API server is running:
π Repository StructureΒΆ
bazel-tutorial/
βββ MODULE.bazel # Bazel dependencies (Bzlmod)
βββ .bazelrc # Bazel configuration
βββ .bazelversion # Pin Bazel version
βββ run_all.sh # Convenience script to start all services
β
βββ go_fetch/ # Go data fetcher service
β βββ main.go # CLI entry point
β βββ fred.go # FRED API client
β βββ store_sqlite.go # SQLite storage
β βββ fred_test.go # Tests with mocks
β βββ go.mod # Go dependencies
β βββ BUILD.bazel # Bazel build config
β
βββ py_api/ # Python FastAPI service
β βββ main.py # FastAPI server
β βββ handlers.py # API endpoints
β βββ db.py # Database layer
β βββ test_api.py # Tests with fixtures
β βββ requirements.txt # Python dependencies
β βββ BUILD.bazel # Bazel build config
β
βββ web_ui/ # React frontend
β βββ src/
β β βββ App.tsx # Main app component
β β βββ components/
β β β βββ IndicatorCard.tsx
β β β βββ LineChart.tsx
β β βββ main.tsx
β βββ package.json # npm dependencies
β βββ vite.config.ts # Vite configuration
β βββ BUILD.bazel # Bazel build config
β
βββ data/ # SQLite database (gitignored)
β βββ econ.db # Created by go_fetch
β
βββ .github/workflows/
βββ ci.yaml # CI/CD pipeline
π ConfigurationΒΆ
Environment VariablesΒΆ
FRED_API_KEY- Required for data fetchingECON_DB_PATH- Database path (default:./data/econ.db)PORT- API server port (default:8000)
FilesΒΆ
.env- Local environment variables (create yourself, not committed).bazelrc- Bazel configuration (caching, output options)
π’ CI/CDΒΆ
The project includes GitHub Actions workflow (.github/workflows/ci.yaml) that:
- β Sets up Bazel and caches dependencies
- β
Builds all targets (
bazel build //...) - β
Runs all tests (
bazel test //...) - β Uses Bazel cache for fast builds
Bazel's hermetic builds ensure CI runs are deterministic and cacheable.
π§ Why Bazel for Polyglot Repos?ΒΆ
Benefits Demonstrated in This ProjectΒΆ
- Single Build System
- One tool for Go, Python, and JavaScript
-
Consistent commands across languages
-
Incremental Builds
- Only rebuild what changed
-
Shared cache across projects
-
Hermetic Testing
- Tests don't depend on network or system state
-
Use mocks and fixtures
-
Explicit Dependencies
- Clear dependency graph
-
No hidden dependencies
-
Scalability
- Works for small projects (this) and massive monorepos (Google)
- Parallel builds and tests
π Learning ResourcesΒΆ
BazelΒΆ
RulesΒΆ
Economic DataΒΆ
π€ ContributingΒΆ
This is a tutorial project. Contributions welcome!
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure
bazel test //...passes - Submit a pull request
π LicenseΒΆ
MIT License - See LICENSE file for details
π AcknowledgmentsΒΆ
- FRED - Federal Reserve Economic Data
- Bazel - Google's build system
- FastAPI - Modern Python web framework
- React - UI library
- Vite - Fast build tool
Happy Building! π
For questions or issues, please open a GitHub issue.