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

Next.js 16 (App Router, Server Components, Turbopack, React Compiler)
React 19
TypeScript 5

Styling & Visualization

Tailwind CSS 3
@tailwindcss/forms
shadcn/ui
Radix primitives
Custom dark theme
D3 (SVG choropleth)
Plotly.js
Mapbox GL (planned/proxied)

State, Services, Infra

React context (DistrictDataProvider)
Zustand 5 (available for richer stores)
R Plumber analytics service (external)
Node-based ETL worker stub (BullMQ planned)
Dockerfiles for web/R/worker
nginx reverse proxy
GitHub Actions CI
pnpm workspaces
ESLint 9
Vitest 2

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.

pnpm install

Run

pnpm --filter @fluxcast/web dev # http://localhost:3000
pnpm --filter @fluxcast/web build
pnpm --filter @fluxcast/web start # after build
# Optional worker stub
pnpm --filter @fluxcast/etl-worker dev

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

Replace synthetic energy with analytics output from the R service + database.
Flesh out ETL worker (BullMQ jobs) for ingest/retraining; automate schedules.
Add regression tests for scenario simulator logic and /api/districts route.
Integrate WebSocket streams for near real-time nowcasts and live updates.
Expand visual regression testing (maps/charts).
Improve accessibility and keyboard navigation across controls and tables.
Add model monitoring (versioning, accuracy over time, drift signals).

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.