FluxCast Urban
Real-time city energy intelligence dashboard
A Next.js 16 + TypeScript dashboard that visualizes district-level energy demand, climate signals, and uncertainty-aware forecasts to help planners and sustainability teams make better grid decisions.
Overview
What it delivers
High-contrast, map-first dashboard with district metrics, scenario toggles, and forecast ranges to support energy planning decisions.
Self-contained: GeoJSON served internally; no external API dependency for the current dataset.
Ops & Reliability
Small API surface (/api/districts), cached in memory; nginx reverse proxy prepared for TLS and routing.
CI via GitHub Actions for lint/test/build with pnpm caching; release workflow for tagged builds.
Features
Real-time and forecasted demand views with district metrics, synthetic energy TWh values, and uncertainty-aware ranges.
Interactive choropleth map (GeoJSON + D3) with hover tooltips, camera reset, lock/unlock, and high-contrast dark styling.
District explorer tables for districts, scenarios, and models with shared styling and dark theme.
Scenario simulation panel to explore what-if demand multipliers across districts and compare synthetic outcomes.
Model/analytics views surfacing capacity and distribution summaries for validation and planning.
Shared UI kit via packages/ui for consistent buttons, tables, toolbars, and empty states.
GeoBoundaries-backed dataset served via internal API route, keeping the app self-contained.
Tech Stack
Framework & Language
Styling & Visualization
State, Services, Infra
Architecture
Next.js web app (App Router) renders overview, districts, scenarios, models; Server Components hydrate charts/maps.
API route GET /api/districts reads public/data/lka_districts.geojson once, caches in memory, and serves to the DistrictDataProvider.
DistrictDataProvider enriches features with synthetic energy values; visualization components consume the cached dataset.
ETL worker stub planned for ingest/retraining via BullMQ; external R Plumber service envisioned for analytics.
Flow: Browser → Next.js web → /api/districts (cached GeoJSON) → map/tables; planned: web + worker → analytics service + DB.
Getting Started
Prerequisites & Install
Node.js 20.9+, pnpm 9.x, Git, modern browser.
Run
If a dev server crashes, remove apps/web/.next/dev/lock before restarting.
Configuration
Env: copy apps/web/.env.example → apps/web/.env.local; optionally set NEXT_PUBLIC_API_BASE_URL when reverse proxied (defaults to same origin).
Key config files:
- configs/app.yaml — service ports, feature flags, and app config.
- configs/logging.yaml — JSON logging formats and log levels.
- configs/secrets.example.yaml — template for production secrets.
- infra/nginx/nginx.conf — reverse proxy, TLS termination, routing.
Scripts
- pnpm dev
Run the web dashboard in dev mode (@fluxcast/web).
- pnpm build
Build the web app for production.
- pnpm lint
Run ESLint across the web app.
- make install
pnpm install
- make web
pnpm --filter @fluxcast/web dev
- make web-build
pnpm --filter @fluxcast/web build
- make worker
pnpm --filter @fluxcast/etl-worker dev
Testing & linting (web): pnpm --filter @fluxcast/web test, pnpm --filter @fluxcast/web lint.
API / Modules
- GET /api/districts — serves cached Sri Lanka ADM2 GeoJSON from public/data/lka_districts.geojson.
- Response: FeatureCollection with GeoBoundaries metadata; client enriches with synthetic energy_twh values.
- Caching: file read once, cached in memory; on error returns 500 with { error }.
- Frontend consumers: DistrictDataProvider (apps/web/stores/district-data.tsx), LoadHeatmap, DistrictsExplorer, ScenarioPanel, CapacityTable.
Data & Migrations
- db/migrations: SQL migrations for future DB use; db/seed for districts/meters/holidays.
- data/schemas: dataset contracts and metadata for inputs/outputs.
- models/registry: registry metadata (versions, metrics, artifact URIs); not model binaries.
- tools/scripts: run_migrations.sh, load_sample_data.sh, validate_data.py, smoke_tests.sh.
Testing
- Vitest 2.x for utilities and data transforms (energy assignment, formatting helpers).
- Integration tests for /api/districts to confirm GeoJSON serving.
- Manual/visual checks for the D3 choropleth, scenario tables, and layouts.
- Planned: regression tests for scenario simulator and districts route.
CI/CD
- .github/workflows/ci.yml — lint, type-check, test, build with pnpm cache.
- .github/workflows/release.yml — tagged release builds and artifacts.
- .github/workflows/security.yml — composition analysis and security checks.
- Deploy: pnpm --filter @fluxcast/web build/start on VM; Vercel recommended (Node 20+); nginx proxy in infra/nginx/nginx.conf.
- Post-deploy checks: GET /api/districts returns 200 + FeatureCollection; Overview/Districts/Scenarios render with synthetic energy values.
Performance & Security
- GeoJSON served once then cached; small API surface (/api/districts only).
- Next.js 16 with Server Components + Turbopack for faster loads and dev builds.
- No external API keys needed for current dataset; secrets modeled via configs/secrets.example.yaml.
- nginx proxy prepared for TLS; future: add rate limiting and stricter headers.
- KPIs: forecast MAE/MAPE by district, nowcast freshness, dashboard TTI < 2s on broadband.
Roadmap
Contributing
- Feature branches and conventional commits (feat:, fix:, docs:, chore:); keep PRs small with screenshots/JSON samples.
- TypeScript strictness per packages/tsconfig; Tailwind v3; prefer borders/rings over heavy shadows.
- Review checklist: type-check, lint, build locally; document API changes in docs/api.md; add new env vars to apps/web/.env.example.
License & Credits
License: MIT (LICENSE in repo root).
Credits: GeoBoundaries Sri Lanka ADM2 dataset (CC BY 4.0); Plotly.js, D3.js, Mapbox GL JS (planned/proxied); Tailwind CSS, shadcn/ui, Radix UI; R Plumber ecosystem; Node/TypeScript tooling powering build/test/CI.