# Bonus Assignment 4 — Energy & AI Dashboard 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: - **The business case**: AI datacenters are reshaping US energy markets. This isn't a toy dashboard — it's a tool for people making billion-dollar infrastructure decisions. - **The user**: Energy investors, utility analysts, datacenter site selectors. They need real-time visibility, not static reports. - **The real-time candy**: The ticker tape, pulsing markers, GPU cost calculator, grid stress gauges — these are what make the dashboard feel alive. They're not afterthoughts. Code that understands its purpose is better code. A developer who knows *why* the GPU cost calculator exists will make better implementation decisions than one who's just following a component spec. ## Code Standards ### Type Safety is Non-Negotiable This project is end-to-end type-safe. Every boundary is validated: - **External APIs** (EIA, FRED): Zod schemas validate every response. Never trust untyped JSON. - **Database**: Prisma generates types for standard CRUD. TypedSQL generates typed wrappers for PostGIS queries. - **Server → Client**: Server Actions and Server Components pass typed props. No `any` leaking across the boundary. - **Serialization**: Use `superjson` for all server-to-client data passing. React's default serialization silently converts `Date` objects to strings, `Map` to `{}`, `Set` to `{}`, etc. — but TypeScript still thinks they're the original type. This is a silent type lie. `superjson` preserves `Date`, `BigInt`, `Map`, `Set`, `RegExp`, `undefined`, and other types across the wire. Wrap Server Action returns and component props through superjson serialize/deserialize. This is especially critical for this project — almost every data point has a timestamp. - **No `any`**. No `as unknown as X`. No `@ts-ignore`. No `// @ts-expect-error`. If you can't type it, you don't understand it well enough yet. ### Write Clean Code - **Meaningful names.** `getRegionPriceHeatmap`, not `getData`. `datacenterMarkerPulseAnimation`, not `anim1`. - **Small functions.** If a function does more than one thing, split it. - **Co-locate related code.** A component's types, helpers, and styles should live near the component. - **No dead code.** Don't comment things out "for later." Delete it. Git has history. - **Handle errors at the boundaries.** Zod parse failures, API timeouts, database connection errors — handle them where they occur, with meaningful messages. Don't let errors propagate silently. - **Follow existing patterns.** Before creating something new, check if there's already a pattern in the codebase for it. Consistency matters more than personal preference. ### Styling - **Dark theme only.** Every component should look great on a dark background. - **Tailwind 4 only.** No inline styles. No CSS modules. Use Tailwind utility classes and shadcn/ui component variants. - **shadcn/ui first.** Before building a custom component, check if shadcn/ui has one. Use their chart components (Recharts wrappers) for all data visualization. - **Responsive.** Everything should work on desktop and tablet at minimum. ### Timestamps & Timezones - **Store everything in UTC.** All `TIMESTAMPTZ` columns, all in-memory dates, all API responses — UTC. - **Display in market-local time.** ERCOT → Central, PJM → Eastern, CAISO → Pacific. Convert only at the render layer. - **Use `formatMarketTime(utcDate, regionCode)`** — a shared utility in `src/lib/utils.ts` for consistent display. ### Performance - **Server Components by default.** Only use `"use client"` when you need interactivity (maps, charts, forms, animations). - **Cache aggressively.** Use Next.js 16's `"use cache"` directive for data that doesn't change every request. - **Don't fetch in loops.** Batch database queries. Use PostGIS spatial joins instead of N+1 queries. - **Lazy load heavy components.** Google Maps, Recharts — use `next/dynamic` with `ssr: false` where appropriate. ### Testing - **No unit tests.** They devolve into testing constants and mocking everything. Useless. - **Integration tests only.** Test the real pipeline: API → Zod → Postgres → query → typed result. Against the real database. - **E2E smoke tests.** Every page renders, map loads, charts display data, no console errors. - **The minimum bar** for any task: `bunx tsc --noEmit` passes, `bun run lint` passes, the page renders with real data. ## Tech Stack & Constraints | Concern | Choice | Notes | |---------|--------|-------| | **Package manager** | `bun` | Not npm, not yarn, not pnpm. Always `bun`. | | **Python** | `uv` | If any Python is needed, always use `uv`. | | **Framework** | Next.js 16 | App Router. Turbopack. `"use cache"` directive. | | **Styling** | Tailwind CSS 4 | CSS-first config. | | **Components** | shadcn/ui | Latest, with `tw-animate-css`. | | **Maps** | `@vis.gl/react-google-maps` | Google's recommended React library. Use `AdvancedMarker`. | | **Database** | PostgreSQL 18 + PostGIS 3.5 | Docker Compose. **Port 5433** (5432 is taken). | | **ORM** | Prisma 7.x with TypedSQL | `.sql` files in `prisma/sql/` for geo queries. | | **Charts** | Recharts via shadcn/ui chart components | Consistent theming out of the box. | | **Serialization** | `superjson` | Preserves `Date`, `BigInt`, `Map`, `Set` across server→client. Required for all Server Actions and temporal data. | | **Animations** | `framer-motion` | For number transitions, pulse effects, etc. | | **Toasts** | `sonner` | For price spike notifications. | ### Existing Files (Do NOT Overwrite) These config files are already in the project root with the user's preferred settings: - `.prettierrc.js` — Prettier configuration - `eslint.config.js` — ESLint configuration - `tsconfig.json` — TypeScript configuration - `.env` — API keys (Google Maps key, Google Maps Map ID, EIA, FRED). **Never log, commit, or expose these.** When scaffolding the Next.js project, you must integrate with these existing configs, not replace them. Install whatever dependencies they require. ### Version Discipline Use the latest stable versions of everything. There have been recent JS CVEs — do not pin to old versions out of habit. When installing a package, let bun resolve the latest. If a specific version is required for compatibility, document why. ## Browser Automation Use `agent-browser` for visual verification. Run `agent-browser --help` for all commands. ``` agent-browser connect 9222 # Connect to chromium agent-browser open # Navigate to page agent-browser snapshot -i # Get interactive elements with refs agent-browser click @e1 # Click element agent-browser fill @e2 "text" # Fill input ``` Always re-snapshot after page changes to get fresh element refs. ## Project Structure See `SPEC.md` for the full directory tree. Key landmarks: - `prisma/schema.prisma` — Database schema (Prisma + PostGIS) - `prisma/sql/` — TypedSQL query files for geospatial operations - `prisma/seed.ts` — Seed data (datacenter locations, grid boundaries, AI milestones) - `src/app/` — Next.js App Router pages - `src/components/` — React components (ui/, map/, charts/, dashboard/, layout/) - `src/lib/api/` — EIA and FRED API clients with Zod schemas - `src/actions/` — Server Actions (typed server-to-client boundary) - `docker-compose.yml` — PostgreSQL 18 + PostGIS 3.5