121 lines
7.8 KiB
Markdown
121 lines
7.8 KiB
Markdown
# 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.
|
|
|
|
## 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 <url> # 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
|