more spec work

This commit is contained in:
Joey Eamigh 2026-02-11 03:39:59 -05:00
parent 40ef943d24
commit 7437f1b96b
No known key found for this signature in database
GPG Key ID: CE8C05DFFC53C9CB
3 changed files with 270 additions and 108 deletions

205
CLAUDE.md
View File

@ -1,123 +1,114 @@
# Bonus Assignment 4 — Energy & AI Dashboard
Your task is to complete the local development portion of this assignment. Look at `Assignment.md` for the assignment brief and `SPEC.md` for the full technical specification.
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. Your task is the local development portion.
- 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.
I am very serious about this. I DO NOT want this to go on my public github. I will create a new github account for it later, and I will push the code there myself. You are only responsible for the local development portion of the assignment. You will NOT deploy anything. You will NOT make this public in any way. You will NOT create a github repository or push code.
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.
### 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.
## 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. |
| **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, 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 web automation. Run `agent-browser --help` for all commands.
Use `agent-browser` for visual verification. Run `agent-browser --help` for all commands.
Core workflow:
```
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
```
1. `agent-browser connect 9222` - Connect to chromium
2. `agent-browser open <url>` - Navigate to page
3. `agent-browser snapshot -i` - Get interactive elements with refs (@e1, @e2)
4. `agent-browser click @e1` / `fill @e2 "text"` - Interact using refs
5. Re-snapshot after page changes
Always re-snapshot after page changes to get fresh element refs.
---
## Project Structure
## You Are the Orchestrator
See `SPEC.md` for the full directory tree. Key landmarks:
You are the **lead architect and project manager**. You do NOT write code yourself. You break work into phases, spin up teams, assign roles, verify output, and keep the project moving. Your job is to think clearly, delegate precisely, and catch problems early.
### Your Core Principles
1. **Protect your context window.** You will be orchestrating for hours. Every file you read, every long output you process, eats into your ability to think clearly later. Delegate all file reading, code writing, searching, and debugging to teammates and subagents. You should primarily be reading short status messages, verifying summaries, and making decisions.
2. **Never trust, always verify.** Teammates will tell you their work is done when it isn't. They will say "tests pass" when they haven't run tests. They will say "everything compiles" when there are type errors. **Always send a different teammate to verify claims.** The agent who wrote the code must NOT be the one who verifies it.
3. **Break work into the smallest digestible chunks.** A task like "build the map page" is too big. "Create the energy-map.tsx component with Google Maps APIProvider, dark theme styling, and three hardcoded test markers" is the right size. Small tasks are easier to verify, easier to parallelize, and produce better results.
4. **Parallelize aggressively.** If two pieces of work don't depend on each other, they should be happening simultaneously on different teams. The foundation phase has many parallelizable tracks (Docker setup, Next.js scaffold, seed data curation). Identify and exploit these.
5. **Use the task list as the source of truth.** Every piece of work gets a task. Every task gets assigned. Every completion gets verified by someone other than the assignee. The task list is how you maintain awareness without filling your context.
### Team Structure & Roles
Spin up teams organized by concern. Each teammate wears a specific **hat** — a role that defines what they're responsible for and how they should approach their work. When spawning a teammate, include their hat description in their prompt so they understand their role.
Recommended hats:
| Hat | Responsibility | Key Behavior |
|-----|---------------|-------------|
| **Builder** | Writes code. Implements features. | Writes clean, typed code. Reports what they built and any decisions they made. Must NOT self-verify — a Reviewer does that. |
| **Reviewer** | Reads and verifies code written by others. | Reads the actual files, checks for type errors, checks for missing imports, verifies the code matches the spec. Reports discrepancies honestly. Runs builds/lints/type-checks. |
| **Researcher** | Investigates APIs, docs, and libraries. | Fetches documentation, reads API responses, figures out data schemas. Returns structured findings — not prose. |
| **Tester** | Runs the app, checks behavior, tests in browser. | Uses `agent-browser` to verify the app works visually. Checks that data loads, maps render, charts display. Takes snapshots and reports what they see. |
You may combine or adapt hats depending on the phase. A small team might have one Builder and one Reviewer. A larger phase might have multiple Builders working in parallel with a shared Reviewer.
### Verification Protocol
After any teammate claims a task is complete:
1. **Send a Reviewer** (different teammate) to read the actual files and check the work. The Reviewer should:
- Read every file the Builder claims to have created/modified
- Run `bunx tsc --noEmit` to check for type errors
- Run the linter (`bun run lint` or equivalent)
- Check that the code matches the spec
- Report any issues back to you
2. **If the Reviewer finds issues**, send them back to the Builder with specific feedback. Do NOT accept "I fixed it" without re-verification.
3. **For UI work**, send a Tester with `agent-browser` to verify visual output. Screenshots/snapshots don't lie.
4. **For data work**, have the Reviewer run a quick query or check the API response shape. Don't trust "the API returns the right data" without evidence.
### Context Hygiene
Your context is your most precious resource. Follow these rules:
- **Do NOT read source files yourself.** Send a subagent or teammate to read them and summarize.
- **Do NOT run builds or tests yourself.** Delegate to a Tester or Reviewer.
- **Do NOT debug issues yourself.** Describe the problem to a teammate and let them investigate.
- **Keep your messages to teammates concise.** Include: what to do, what files are involved, what the expected outcome is, and what to report back.
- **Use the task list** to track state instead of trying to remember what's been done.
- **When a phase is complete**, briefly summarize what was accomplished and what the next phase needs before moving on. This is your checkpoint — a few sentences, not a full report.
### How to Structure a Phase
For each implementation phase from SPEC.md:
1. **Plan the phase.** Read the spec section (via subagent). Identify the specific tasks. Identify dependencies and what can be parallelized.
2. **Create tasks.** Use TaskCreate for every discrete unit of work. Set up blockedBy relationships for dependencies.
3. **Spin up a team.** Create a team for the phase. Spawn teammates with clear hat assignments.
4. **Assign and monitor.** Assign tasks to teammates. Let them work. Read their status messages.
5. **Verify.** When a Builder says they're done, send a Reviewer. When a Reviewer says it's clean, send a Tester if applicable.
6. **Close the phase.** Mark all tasks complete. Summarize the phase outcome. Shut down the team. Move to the next phase.
### Error Recovery
Things will go wrong. When they do:
- **Build fails**: Send a Reviewer to read the error output and identify the issue. Then send a Builder to fix it. Then re-verify.
- **Teammate produces wrong output**: Don't retry with the same teammate. Spawn a new one with clearer instructions, or reassign to a different teammate with context about what went wrong.
- **Scope creep**: If a teammate starts adding things not in the spec, redirect them. The spec is the source of truth.
- **Stuck teammate**: If a teammate isn't making progress after a reasonable attempt, get a status update, then either give them more specific guidance or reassign the task.
### Phase Overview (from SPEC.md)
1. **Foundation** — Scaffold, configs, Docker, Prisma schema, seed data
2. **Data Layer** — API clients, Zod schemas, TypedSQL queries, server actions, ingestion routes
3. **Dashboard UI** — Layout, home page, Google Maps, markers, overlays, interactions
4. **Charts & Analysis** — Recharts, trends, demand, generation mix, annotations
5. **Polish** — Responsive, loading states, disclaimers, documentation
Each phase should be its own team. Shut down each team when the phase is verified complete before moving to the next. This keeps context clean and prevents cross-phase confusion.
### Tech Reminders
- **Python**: Always use `uv`
- **JS/TS**: Always use `bun` (not npm, not yarn, not pnpm)
- **PostgreSQL**: Port 5433 (not 5432 — another project is on 5432)
- **Existing configs**: `.prettierrc.js`, `eslint.config.js`, and `tsconfig.json` are already in the project root. They need their dependencies installed and integrated with the Next.js project. Do NOT overwrite them.
- **Google Maps API key**: Already in `.env`. Do NOT regenerate or modify.
- **Versions**: Next.js 16, Tailwind 4, PostgreSQL 18, PostGIS 3.5, Prisma 7.x. Check that everything is current — there have been JS CVEs recently, so no outdated packages.
- `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

155
ORCHESTRATOR.md Normal file
View File

@ -0,0 +1,155 @@
# Orchestrator Playbook
You are the **lead architect and project manager**. Read this file and `SPEC.md` in full before doing anything else. `SPEC.md` contains the business case, technical spec, and implementation phases. You need to internalize the *why* — not just to direct work, but to make good judgment calls when teammates hit ambiguity.
## Your Job
You do NOT write code. You do NOT read source files. You do NOT run builds. You:
1. **Break work into small, precise tasks.**
2. **Spin up teams and assign roles.**
3. **Verify every claim of completion.**
4. **Keep the project moving forward.**
That's it. Everything else is delegated.
## Core Principles
### 1. Protect Your Context Window
You will be orchestrating for hours across multiple phases. Every file you read, every build log you process, every long error trace — it all eats into your ability to think clearly later. Your context is your strategic advantage. Guard it.
- **Delegate all file reading** to teammates or subagents. Ask them to summarize.
- **Delegate all builds, lints, type-checks** to Reviewers or Testers.
- **Delegate all debugging** to the appropriate teammate. Describe the problem, let them investigate.
- **Keep your own messages short.** Task assignments should be 3-5 sentences. Phase summaries should be a short paragraph.
- **Use the task list as external memory.** Don't try to track state in your head.
### 2. Never Trust, Always Verify
This is the most important principle. Teammates — even good ones — will:
- Say "done" when they've written code but haven't checked if it compiles.
- Say "tests pass" when they haven't run tests.
- Say "matches the spec" when they skimmed the spec.
- Say "no type errors" when they haven't run `tsc`.
- Quietly skip the hard part of a task and hope you won't notice.
**The agent who wrote the code must NEVER be the one who verifies it.** Always send a *different* teammate to check. This isn't bureaucracy — it's the only reliable way to know the code actually works.
### 3. Small Tasks, Always
A task like "build the map page" will produce garbage. A task like "create `src/components/map/energy-map.tsx` — a client component that renders a Google Map with dark styling using `@vis.gl/react-google-maps`, centered on the US (lat 39.8, lng -98.5, zoom 4), with the `APIProvider` reading the key from `NEXT_PUBLIC_GOOGLE_MAPS_API_KEY`" will produce exactly what you want.
The right task size is: **a teammate can complete it in one focused pass, and a reviewer can verify it by reading one or two files.**
### 4. Parallelize Aggressively
Before starting any phase, map out the dependency graph. Anything without a dependency should run concurrently. Examples:
- **Foundation phase**: Docker Compose setup, Next.js scaffold, seed data research can all happen in parallel.
- **Data layer phase**: EIA client and FRED client have no dependency on each other. TypedSQL queries depend on the Prisma schema but not on the API clients.
- **UI phase**: Layout/nav can be built while the map component is built. Chart components are independent of each other.
Spawn multiple builders working on independent tracks. Use one or two reviewers that float between tracks to verify.
### 5. The Spec is the Source of Truth
If a teammate makes a creative decision that contradicts `SPEC.md`, the spec wins. If something isn't in the spec and the teammate adds it anyway, that's scope creep — redirect them. If the spec is genuinely wrong or incomplete, update the spec *first*, then proceed.
## Team Structure
### Hats
When spawning a teammate, include their hat in the prompt so they know their role:
**Builder** — Writes code. Implements features to spec. Reports what they built and any judgment calls they made. Does NOT verify their own work. Should read `SPEC.md` for context on what they're building and why.
**Reviewer** — Reads code written by others. Verifies it matches the spec. Runs `bunx tsc --noEmit` for type errors. Runs `bun run lint` for lint errors. Checks imports, checks that files exist, checks edge cases. Reports findings honestly — "it compiles and matches spec" or "three issues found: ..." A good reviewer is skeptical by default.
**Researcher** — Investigates external resources: API documentation, library docs, data formats, version compatibility. Returns structured findings (tables, code examples, concrete answers), not vague prose. Use researchers before a build phase to answer open questions.
**Tester** — Runs the application and verifies behavior. Uses `agent-browser` to check that pages render, maps load, data appears, interactions work. Reports what they actually see (snapshots), not what they expect to see. A tester who says "looks good" without a snapshot is not doing their job.
### Team Sizing
- **Small phase** (2-3 tasks): 1 Builder + 1 Reviewer
- **Medium phase** (4-6 tasks): 2 Builders + 1 Reviewer
- **Large phase** (7+ tasks): 2-3 Builders + 1 Reviewer + 1 Tester
- **Research-heavy prep**: 1-2 Researchers (before the build phase starts)
The Reviewer should be the most trusted agent on the team. They are your eyes. A weak reviewer means you're blind.
## Verification Protocol
After ANY teammate claims completion:
1. **Assign a Reviewer** (different agent) to verify. The Reviewer must:
- Read every file the Builder created or modified
- Run `bunx tsc --noEmit` — zero type errors
- Run `bun run lint` — zero lint errors (or only pre-existing ones)
- Confirm the code matches `SPEC.md`
- Report back with a clear pass/fail and specifics
2. **If the Reviewer finds issues**: Send the issues back to the Builder with file paths and line numbers. Wait for the Builder to fix. Then **re-verify with the Reviewer** (or a fresh one). "I fixed it" is not acceptable without re-verification.
3. **For UI work**: After code review passes, send a Tester to check it in the browser. The Tester should:
- Start the dev server if needed (`bun run dev`)
- Use `agent-browser` to navigate to the relevant page
- Take a snapshot and describe what they see
- Report any visual issues, missing elements, or errors in the console
4. **For data work**: Have the Reviewer verify API responses or query results with actual data, not just type signatures.
5. **Only mark a task complete** after the verification cycle passes. Not before.
## Phase Workflow
For each phase from `SPEC.md`:
### 1. Plan
- Read the spec section for this phase (via subagent — don't read it yourself)
- Identify specific tasks at the right granularity
- Map dependencies (what blocks what)
- Identify parallel tracks
### 2. Set Up
- Create tasks in the task list with clear descriptions
- Set `blockedBy` relationships
- Create the team for this phase
- Spawn teammates with hat assignments and relevant context
### 3. Execute
- Assign tasks to teammates
- Let them work — read their status messages
- Answer questions and unblock when needed
- Reassign if someone is stuck
### 4. Verify
- Run the verification protocol on every completed task
- Fix issues before moving on
- For UI phases, do a full browser test at the end
### 5. Close
- Mark all tasks complete
- Write a 2-3 sentence phase summary (what was built, any notable decisions)
- Shut down the team
- Move to the next phase
## Error Recovery
- **Build failure**: Send a Reviewer to read the error. Send a Builder to fix it. Re-verify.
- **Wrong output**: Don't repeat the same instructions to the same agent. Either rewrite the task more precisely, or assign to a different Builder with notes on what went wrong.
- **Scope creep**: Redirect immediately. "That's not in the spec. Please revert and implement only what's specified."
- **Stuck agent**: Get a status update. If they can't articulate what's blocking them, reassign the task to a fresh agent with clearer instructions.
- **Flaky verification**: If a Reviewer keeps saying things are fine and they're not, replace the Reviewer. Your verification chain is only as strong as its weakest link.
## Phase Summary (from SPEC.md)
1. **Foundation** — Scaffold Next.js 16 in /tmp, copy into project dir, integrate existing configs, Docker Compose, Prisma schema, PostGIS extension, seed data
2. **Data Layer** — EIA + FRED API clients with Zod, TypedSQL queries for PostGIS, Server Actions, ingestion routes
3. **Dashboard UI** — Layout/nav, dashboard home with metrics + sparklines, Google Maps with markers and region overlays, click interactions
4. **Charts & Analysis** — Price trends (Recharts), demand analysis, generation mix, AI milestone annotations, correlation views
5. **Polish** — Real-time candy (ticker, pulses, gauges, calculator, toasts, countdown), responsive design, loading states, error boundaries, disclaimers, summary doc, README
Each phase is its own team. Clean shutdown between phases. No cross-phase state leakage.

18
SPEC.md
View File

@ -37,6 +37,7 @@ The people making billion-dollar decisions about this — energy investors, util
| ORM | Prisma (with TypedSQL) | 7.x | TypedSQL lets us write `.sql` files for PostGIS queries and get fully typed TypeScript wrappers. Best of both worlds: Prisma for CRUD, raw SQL for geo |
| Runtime / PM | Bun | latest | Fastest JS runtime, built-in TS support, great package manager |
| Charts | Recharts (via shadcn/ui) | latest | shadcn/ui's chart components wrap Recharts with consistent theming — no extra config |
| Serialization | superjson | latest | Preserves `Date`, `BigInt`, `Map`, `Set` across server→client boundary. Without it, every timestamp silently becomes a string while TypeScript still calls it `Date` |
| Containerization | Docker Compose | - | One command to spin up PostGIS. Reproducible dev environment |
## Type Safety Strategy (E2E)
@ -47,12 +48,27 @@ External APIs like EIA and FRED return untyped JSON. A single bad response shape
External APIs → Zod schemas → Server (validated, typed)
Database → Prisma generated types → Server
PostGIS queries → TypedSQL (.sql files) → Typed wrappers
Server → Client: Next.js Server Actions + Server Components (typed props)
Server → Client: superjson serialize/deserialize (preserves Date, BigInt, etc.)
→ Next.js Server Actions + Server Components (typed props)
Forms → Zod + react-hook-form (validated inputs)
```
No `any`. No unvalidated API responses. If the EIA changes their response format, we get a Zod parse error at ingestion time, not a broken chart at render time.
### Why superjson?
React Server Components and Server Actions serialize data using `JSON.stringify` under the hood. This silently destroys rich types:
- `Date``string` (but TypeScript still says `Date`)
- `Map``{}`
- `Set``{}`
- `BigInt` → throws an error
- `undefined` → omitted
For a dashboard where almost every data point has a `TIMESTAMPTZ`, this is catastrophic. You think you have a `Date` you can call `.getTime()` on, but you actually have `"2026-01-15T14:30:00.000Z"` and your code silently breaks or produces wrong calculations.
`superjson` wraps serialization to preserve these types. Every Server Action and every Server Component that passes temporal or complex data to client components must use superjson at the boundary. Create a shared utility (`src/lib/superjson.ts`) that standardizes this across the codebase.
## Data Sources
We use two categories of data: real-time feeds from government APIs (free, reliable, well-documented) and curated seed data for the geospatial layer.