A multi-country energy-market intelligence terminal for understanding what is happening in power markets, why it is happening, what may happen next, and what an operator should care about. The app combines day-ahead prices, weather, market-regime detection, data-quality gates, infrastructure intelligence, forecasting, flexibility optimization, trading simulation, AI-style explanations, and reports behind a Next.js dashboard served by a FastAPI backend.
Status: Product MVP / portfolio project. Denmark (DK1/DK2) runs on live-capable data from Energi Data Service and Open-Meteo. Germany, ERCOT, Japan, and broader Europe are represented through seeded/demo datasets until their production-grade adapters are connected. Pages label stale or fallback data clearly so demos do not pretend sample data is live market truth.
- Full-stack energy analytics with a typed frontend/backend contract.
- Real ingestion jobs for Denmark prices and weather, with run logs and data quality checks.
- Decision workflows that turn price, weather, and risk signals into operator recommendations.
- A GIS-style infrastructure map where assets and zones answer: what is this, what is happening here, and what should the operator care about?
- Reliability practice: health checks, stale-source detection, repair commands, Docker Compose, GitHub Actions examples, and Supabase practice activity notes.
- Architecture at a glance
- Quick start (local)
- Project layout
- Modules
- API summary
- Data sources
- Documentation index
- Testing
- Troubleshooting
Full detail: docs/architecture.md.
Prerequisites: Python 3.11+, Node.js 20+, and (optionally) PostgreSQL. Without PostgreSQL you can run entirely on SQLite.
cd backend
python -m venv .venv
# Windows: .venv\Scripts\activate
# macOS/Linux: source .venv/bin/activate
pip install -r requirements.txt
# Point at a database. For a zero-setup local run, use SQLite:
# PowerShell: $env:DATABASE_URL="sqlite:///./local.db"
# bash: export DATABASE_URL="sqlite:///./local.db"
# Or copy .env.example to .env and edit DATABASE_URL for PostgreSQL.
cp .env.example .env
# Create tables:
python -c "from app.db.init_db import init_db; init_db()"
# (optional) seed sample prices for DE/US/JP zones:
python -m scripts.seed_sample_data --days 14
# Run the API:
uvicorn app.main:app --reload --port 8000API docs live at http://localhost:8000/docs.
cd frontend
npm install
cp .env.local.example .env.local # NEXT_PUBLIC_API_BASE_URL=http://localhost:8000/api/v1
npm run devOpen http://localhost:3000 → you land on the login page, then the dashboard.
cd backend && source .venv/bin/activate # or the Windows equivalent
python ../pipelines/jobs/ingest_market_prices.py
python ../pipelines/jobs/ingest_weather.pySee the Operations Manual if anything fails.
make install # install backend + frontend deps
make seed # create tables + seed sample data
make dev # run backend and frontend together
make test # backend pytest + frontend buildenergy-intelligence-terminal/
├── backend/ FastAPI app, services, models, tests
│ └── app/
│ ├── api/v1/ HTTP endpoints (one file per module)
│ ├── services/ business logic (forecast, screener, ...)
│ ├── repositories/ DB access
│ ├── models/ SQLAlchemy ORM tables
│ ├── schemas/ Pydantic request/response contracts
│ └── core/ config + country/zone registry
├── frontend/ Next.js 16 (App Router) dashboard
│ ├── app/dashboard/ one folder per module page
│ ├── components/ shared UI (ZoneSelect, cards, layout)
│ ├── hooks/ data-fetching hooks (useApi, ...)
│ ├── lib/ api client, constants, sample GIS
│ └── types/ TypeScript mirrors of backend schemas
├── pipelines/ ingestion jobs, source clients, normalizers, configs
├── cloud/ per-provider deployment notes (Vercel, Railway, ...)
├── docs/ all documentation (see index below)
├── ml/ (reserved) model training scripts
├── docker-compose.yml local Postgres + backend + frontend
└── Makefile dev shortcuts
| Module | Route | Backed by |
|---|---|---|
| Market Cockpit | /dashboard/market-cockpit |
market overview + prices + risk |
| Power Prices | /dashboard/power-prices |
prices, forecast |
| Weather Intelligence | /dashboard/weather |
weather |
| Screener | /dashboard/screener |
screener |
| Flexibility Optimizer | /dashboard/flexibility |
flexibility |
| Trading Simulator | /dashboard/simulator |
simulator |
| Risk Monitor | /dashboard/risk |
risk |
| AI Advisor | /dashboard/advisor |
advisor |
| Reports | /dashboard/reports |
reports |
| Infrastructure Map | /dashboard/infrastructure-map |
gis, infrastructure_assets |
| Gas & Carbon | /dashboard/gas-carbon |
gas/carbon economics |
| Derivatives | /dashboard/derivatives |
forward curve analytics |
Base URL: http://localhost:8000/api/v1
| Method | Path | Purpose |
|---|---|---|
| GET | /health |
liveness |
| GET | /market/overview |
KPIs + regime + recommendation |
| GET | /market/countries |
country/zone registry |
| GET | /prices/day-ahead |
stored hourly prices |
| GET | /forecast/day-ahead |
forecast + regime + backtest metrics |
| GET | /weather/forecast |
stored weather |
| GET | /screener/opportunities |
cheap/expensive hours, risk flags |
| GET | /flexibility/schedule |
battery/EV/load schedule + savings |
| GET | /simulator/backtest |
storage strategy P&L |
| GET | /risk/status |
SAFE/WARN/CRITICAL gate |
| GET | /risk/data-quality |
per-check data-quality report |
| POST | /advisor/ask |
question → data-grounded answer |
| GET | /advisor/suggested-questions |
starter prompts |
| GET | /reports/daily |
daily market report (markdown) |
| GET | /reports/weekly-savings |
weekly savings report |
Full request/response detail: docs/api.md.
| Area | Source | Access |
|---|---|---|
| Denmark power prices | Energi Data Service | Free/open |
| Weather | Open-Meteo | Free (non-commercial) |
| Germany/Europe | ENTSO-E | Free registration (adapter pending) |
| US / Japan | ISO/RTO & JEPX | sample data (adapters pending) |
Details: docs/data_sources.md.
| Doc | What it covers |
|---|---|
| architecture.md | System design, data flow, module map |
| api.md | Every endpoint, params, and example payloads |
| database_schema.md | Tables, columns, constraints |
| data_sources.md | External feeds and licensing |
| deployment.md | Cloud deployment (Vercel + Railway + Neon/Supabase) |
| cloud_architecture.md | Cloud topology and env vars |
| multi_country_design.md | Zone registry, live vs sample |
| gis_architecture.md | Infrastructure-map data model |
| ui_design.md | Layout, theming, component conventions |
| roadmap.md | 24-week plan and what's next |
| OPERATIONS_MANUAL.md | Run/fix guide — start here when something breaks |
| STALE_LIVE_SOURCE_RUNBOOK.md | Why stale/live-source warnings happen and how to repair them |
| SUPABASE_PRACTICE_ACTIVITY_SETUP.md | Practice-only heartbeat and scheduled ingestion setup |
| GO_TO_MARKET.md | Positioning, ICP, pricing, launch plan |
cd backend && pytest # API contract tests (SQLite, no network)
cd frontend && npm run build # type-check + production buildThe single source of truth for "it broke, now what" is the Operations Manual. It covers backend won't start, DB connection errors, empty charts, CORS, ingestion failures, and deployment issues, each with a symptom → cause → fix table.