add docker; update readme

This commit is contained in:
Joey Eamigh 2026-02-11 22:44:04 -05:00
parent 79850a61be
commit dd75b2fdce
No known key found for this signature in database
GPG Key ID: CE8C05DFFC53C9CB
5 changed files with 242 additions and 14 deletions

11
.dockerignore Normal file
View File

@ -0,0 +1,11 @@
node_modules
.next
.git
.gitignore
.env
.env.*
pgdata
*.md
docker-compose.yml
.prettierrc.js
eslint.config.js

View File

@ -2,14 +2,6 @@
This project builds a real-time interactive dashboard showing how AI datacenter buildout is driving regional electricity demand and energy prices across the US. Read `SPEC.md` in full before starting any work — it contains the business case, technical architecture, database schema, and implementation phases. Understanding *why* this dashboard exists (not just *what* it does) will make your code better.
## Rules (NON-NEGOTIABLE)
- You will NOT create a github repository, push code, or deploy ANYTHING.
- You will NOT publish the code anywhere.
- You will NOT make this code public in any way.
This is the local development portion only. No deployment. No public repos. No exceptions.
## Read the Spec
Before writing a single line of code, read `SPEC.md` cover to cover. Every agent on this project — orchestrator, builder, reviewer, tester — should understand:

25
Dockerfile Normal file
View File

@ -0,0 +1,25 @@
FROM oven/bun:1 AS deps
WORKDIR /app
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile
FROM node:22 AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Prisma client + TypedSQL must be pre-generated locally (needs live DB for --sql).
# src/generated/ is gitignored but included in Docker context from local dev.
ENV DATABASE_URL="postgresql://placeholder:placeholder@localhost:5432/placeholder"
RUN npx next build
FROM node:22-slim AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV HOSTNAME=0.0.0.0
ENV PORT=3000
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
EXPOSE 3000
CMD ["node", "server.js"]

211
README.md
View File

@ -1,15 +1,214 @@
# bonus4
# Energy & AI: The Datacenter Power Crunch
To install dependencies:
A real-time interactive dashboard that visualizes how AI datacenter buildout is driving regional electricity demand and energy prices across the United States.
**Live URL**: [https://energy.busi488.claiborne.soy](https://energy.busi488.claiborne.soy)
## Purpose & Functionality
AI datacenters are reshaping US energy markets. Training a single frontier model can consume as much electricity as a small town uses in a year, and every major tech company is building GPU clusters at unprecedented scale. This dashboard makes that impact visible.
The dashboard pulls real-time electricity pricing, demand, generation mix, and commodity data from the EIA and FRED APIs, overlays it on a map of US grid regions with 100+ datacenter locations, and lets users explore the relationship between AI infrastructure buildout and energy market dynamics.
**Key features:**
- **Interactive map** with datacenter locations, grid region overlays, and power plant positions (Google Maps with AdvancedMarker)
- **Real-time price ticker** showing current electricity prices across all major ISO/RTO regions
- **Price, demand, and generation charts** with hourly/daily/weekly granularity and time range selection
- **Datacenter impact analysis** showing price correlation in regions with heavy AI buildout vs. those without
- **GPU cost calculator** that translates electricity prices into per-GPU-hour operating costs
- **Grid stress gauges** showing how close regions are to capacity limits
- **Automated data ingestion** that refreshes every 30 minutes from government APIs
## Target Audience
**Energy investors** evaluating utility stocks and commodity positions who need to see where datacenter load is concentrating and how it's affecting regional prices. Today they stitch together spreadsheets from a dozen sources; this dashboard gives them a single view.
**Utility analysts** planning generation and transmission investments who need to understand where demand growth is coming from and which regions are approaching capacity constraints.
**Datacenter site selectors** choosing where to build next who need real-time visibility into regional electricity prices, grid capacity, and existing datacenter density.
**Business strategists** assessing the infrastructure costs underlying AI who need to understand the energy economics behind GPU compute.
These users currently rely on static reports, scattered government data portals, and expensive terminal subscriptions. This dashboard provides a free, unified, real-time view of the AI-energy nexus.
## Sales Pitch & Monetization
This dashboard generates value for anyone making infrastructure or investment decisions at the intersection of AI and energy. The data it unifies is publicly available but scattered across dozens of sources with inconsistent formats and no geospatial context. The value is in the integration.
**Monetization model:** Freemium SaaS.
- **Free tier**: Full dashboard with real-time data, map, charts, and the GPU cost calculator
- **Premium tier** ($49/mo): Predictive analytics (price forecasting), custom region comparisons, CSV/API data export, email alerting for price spike events
- **Enterprise tier** (custom): Embeddable widgets for trading desks and analyst reports, white-label options, dedicated support
The addressable market includes energy trading desks, utility planning departments, datacenter REITs, and infrastructure-focused hedge funds, all of whom currently spend significant analyst time on exactly this kind of cross-referencing.
## Tech Stack
| Layer | Technology | Why |
| ------------- | ----------------------------------- | ----------------------------------------------------------------------------- |
| Framework | Next.js 16 (App Router, Turbopack) | Server Components, `"use cache"` directive, Partial Prerendering |
| Styling | Tailwind CSS 4 + shadcn/ui | Dark theme, consistent component library with built-in chart wrappers |
| Maps | @vis.gl/react-google-maps | Google's official React library with AdvancedMarker support |
| Database | PostgreSQL 18 + PostGIS 3.6 | Geospatial queries (ST_DWithin, spatial joins) for datacenter/region analysis |
| ORM | Prisma 7 with TypedSQL | Type-safe CRUD + typed wrappers for raw PostGIS SQL queries |
| Charts | Recharts via shadcn/ui | Consistent theming, responsive, works with Server Components |
| Serialization | superjson | Preserves Date, BigInt, Map, Set across server-client boundary |
| Runtime | Bun (dev) / Node.js 22 (production) | Bun for fast local dev; Node.js for stable production runtime |
| Validation | Zod | Every external API response is schema-validated before ingestion |
| Container | Docker (standalone Next.js) | Multi-stage build, ~440MB production image |
## Data Sources
| Source | Data | Update Frequency |
| ---------------------------------------- | -------------------------------------------------------------------------- | ------------------------ |
| [EIA API](https://www.eia.gov/opendata/) | Regional electricity prices, demand, generation mix | Hourly |
| [FRED API](https://fred.stlouisfed.org/) | Natural gas (Henry Hub), WTI crude, coal spot prices | Daily |
| Curated seed data | 100+ datacenter locations, grid region boundaries (GeoJSON), AI milestones | Static (seeded at setup) |
Data ingestion runs automatically every 30 minutes via the Next.js instrumentation hook.
## Installation & Setup
### Prerequisites
- [Bun](https://bun.sh/) (latest)
- [Docker](https://docs.docker.com/get-docker/) and Docker Compose
- API keys for: [EIA](https://www.eia.gov/opendata/register.php), [FRED](https://fred.stlouisfed.org/docs/api/api_key.html), [Google Maps](https://console.cloud.google.com/)
### 1. Clone and install dependencies
```bash
git clone https://git.claiborne.soy/joey/busi488-energy-dashboard.git
cd busi488-energy-dashboard
bun install
```
To run:
### 2. Set up environment variables
```bash
bun run
Create a `.env` file in the project root:
```env
# Google Maps
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY="your-google-maps-api-key"
NEXT_PUBLIC_GOOGLE_MAP_ID="your-map-id"
GOOGLE_MAPS_STYLE_NAME="your-style-name"
GOOGLE_MAPS_STYLE_ID="your-style-id"
# Data APIs
EIA_API_KEY="your-eia-api-key"
FRED_API_KEY="your-fred-api-key"
# Database
DATABASE_URL="postgresql://energy:energydash2026@localhost:5433/energy_dashboard"
POSTGRES_PASSWORD="energydash2026"
# Ingestion auth
INGEST_SECRET="any-random-hex-string"
```
This project was created using `bun init` in bun v1.3.8. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
### 3. Start the database
```bash
docker compose up -d
```
This starts PostgreSQL 18 with PostGIS 3.6 on port 5433.
### 4. Run migrations and seed data
```bash
bunx prisma migrate deploy
bunx prisma db seed
```
This creates the schema (grid regions, datacenters, price tables) and loads seed data (datacenter locations, grid region boundaries, AI milestones).
### 5. Generate Prisma client and TypedSQL
```bash
bunx prisma generate --sql
```
This generates typed TypeScript wrappers for both the Prisma ORM client and all PostGIS SQL queries in `prisma/sql/`.
### 6. Start the development server
```bash
bun run dev
```
The dashboard is now running at [http://localhost:3000](http://localhost:3000). Data ingestion starts automatically after 10 seconds.
## Docker Deployment
The app is containerized as a standalone Next.js image for production deployment.
### Build and push
```bash
# Prisma TypedSQL must be generated locally first (requires live database)
bunx prisma generate --sql
# Build the production image
docker build -t registry.claiborne.soy/busi488energy:latest .
# Push to the internal registry
docker push registry.claiborne.soy/busi488energy:latest
```
### Database migration to production
```bash
# Dump the local database (schema + data)
docker compose exec db pg_dump -U energy -Fc energy_dashboard > energy_dashboard.dump
# Port-forward to the production PostGIS instance
kubectl port-forward -n database svc/postgis 5434:5432 &
# Restore to production
pg_restore -h localhost -p 5434 -U busi488energy -d busi488energy \
--no-owner --no-privileges energy_dashboard.dump
```
### Infrastructure
The production deployment runs on Kubernetes (k3s) with Terraform-managed infrastructure:
- **PostGIS 18** in the `database` namespace (`postgis.database.svc.cluster.local:5432`)
- **Next.js standalone** in the `random` namespace, served behind Traefik ingress with automatic TLS via cert-manager
- **Keel** watches the internal registry and auto-deploys new image pushes
## Project Structure
```
bonus4/
├── prisma/
│ ├── schema.prisma # Database schema (PostGIS models)
│ ├── migrations/ # SQL migration files
│ ├── seed.ts # Seed data loader
│ └── sql/ # TypedSQL queries (PostGIS spatial joins, aggregations)
├── src/
│ ├── app/ # Next.js App Router pages
│ │ ├── page.tsx # Dashboard home (ticker, metrics, charts)
│ │ ├── map/ # Interactive map with datacenters + grid regions
│ │ ├── trends/ # Price correlation and DC impact analysis
│ │ ├── demand/ # Regional demand charts
│ │ ├── generation/ # Generation mix breakdown
│ │ └── api/ingest/ # Data ingestion endpoints (EIA, FRED)
│ ├── actions/ # Server Actions (typed server-to-client boundary)
│ ├── components/
│ │ ├── charts/ # Price, demand, generation, correlation charts
│ │ ├── map/ # Google Maps with datacenter markers + controls
│ │ ├── dashboard/ # Ticker tape, GPU calculator, grid stress gauges
│ │ └── layout/ # Navigation, footer, data freshness indicator
│ └── lib/
│ ├── api/ # EIA and FRED API clients with Zod schemas
│ ├── schemas/ # Zod validation schemas for external data
│ ├── db.ts # Prisma client singleton
│ └── superjson.ts # Serialization utilities
├── docker-compose.yml # Local PostGIS database
├── Dockerfile # Multi-stage production build
└── next.config.ts # Next.js config (standalone output, cache policies)
```

View File

@ -1,6 +1,7 @@
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
output: 'standalone',
typedRoutes: true,
cacheComponents: true,
cacheLife: {