Skip to content

Commit 0cf050d

Browse files
anth-volkclaude
andcommitted
Initial scaffold from dashboard plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 73f2ea9 commit 0cf050d

32 files changed

+2656
-0
lines changed

.claude/settings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"plugins": {
3+
"marketplaces": ["PolicyEngine/policyengine-claude"],
4+
"auto_install": ["dashboard-builder@policyengine-claude"]
5+
}
6+
}

.github/workflows/ci.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: CI
2+
on: [push, pull_request]
3+
jobs:
4+
test:
5+
runs-on: ubuntu-latest
6+
steps:
7+
- uses: actions/checkout@v4
8+
- uses: actions/setup-node@v4
9+
with:
10+
node-version: 20
11+
- uses: oven-sh/setup-bun@v2
12+
- run: bun install --frozen-lockfile
13+
- run: bunx vitest run
14+
- run: bun run build

.gitignore

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# dependencies
2+
/node_modules
3+
/.pnp
4+
.pnp.js
5+
6+
# testing
7+
/coverage
8+
9+
# next.js
10+
/.next/
11+
/out/
12+
13+
# production
14+
/build
15+
16+
# misc
17+
.DS_Store
18+
*.pem
19+
20+
# debug
21+
npm-debug.log*
22+
yarn-debug.log*
23+
yarn-error.log*
24+
25+
# local env files
26+
.env*.local
27+
.env
28+
29+
# vercel
30+
.vercel
31+
32+
# typescript
33+
*.tsbuildinfo
34+
next-env.d.ts
35+
36+
# bun
37+
bun.lock
38+
39+
# Python
40+
__pycache__/
41+
*.py[cod]
42+
*.egg-info/
43+
.venv/

CLAUDE.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# va-reform-dashboard
2+
3+
An interactive calculator that lets users model the impact of reforms to the Child Tax Credit (CTC), Earned Income Tax Credit (EITC), and income tax rates at both the federal and Virginia state levels for Virginia residents. Users configure their household and adjust reform parameters, then see household-level impacts via line charts and summary metrics, plus statewide impacts via microsimulation.
4+
5+
## Architecture
6+
7+
- Next.js App Router with Tailwind CSS v4 and @policyengine/ui-kit theme
8+
- @policyengine/ui-kit for standard UI components (Header, SidebarLayout, Tabs, MetricCard, charts, inputs)
9+
- Custom Modal backend (gateway + worker pattern) for household and statewide microsimulation
10+
- Frontend polling via @tanstack/react-query for async computation results
11+
- Two endpoints: `household-impact` (fast, ~10-40s) and `statewide-impact` (slow, ~2-5 min microsimulation)
12+
13+
## Development
14+
15+
```bash
16+
bun install
17+
make dev # Deploy worker + start gateway + frontend (random port)
18+
make dev-frontend # Frontend only (uses production API or NEXT_PUBLIC_API_URL)
19+
make dev-backend # Gateway only (worker must already be deployed)
20+
```
21+
22+
## Testing
23+
24+
```bash
25+
make test # Frontend tests (vitest)
26+
make test-backend # Backend tests (pytest)
27+
```
28+
29+
## Build
30+
31+
```bash
32+
make build
33+
```
34+
35+
## Design standards
36+
- Uses Tailwind CSS v4 with @policyengine/ui-kit/theme.css (single import for all tokens)
37+
- @policyengine/ui-kit for all standard UI components
38+
- Primary teal: `bg-teal-500` / `text-teal-500`
39+
- Semantic colors: `bg-primary`, `text-foreground`, `text-muted-foreground`
40+
- Font: Inter (via next/font/google)
41+
- Sentence case for all headings
42+
- Charts use `fill="var(--chart-1)"` for series colors
43+
- Recharts axes use `niceTicks` with `domain={["auto", "auto"]}`
44+
- Negative currency formatted as `-$100` not `$-100`

Makefile

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
.PHONY: dev dev-frontend dev-backend deploy-worker
2+
.PHONY: build test test-backend lint clean
3+
4+
# Deploy worker functions, then start gateway + frontend
5+
dev:
6+
@echo "Deploying worker functions..."
7+
@unset MODAL_TOKEN_ID MODAL_TOKEN_SECRET && modal deploy backend/app.py
8+
@echo "Starting gateway (ephemeral)..."
9+
@modal serve backend/modal_app.py & MODAL_PID=$$!; \
10+
sleep 5; \
11+
MODAL_URL="https://policyengine--va-reform-dashboard-fastapi-app-dev.modal.run"; \
12+
PORT=$$(python3 -c 'import socket; s=socket.socket(); s.bind(("",0)); print(s.getsockname()[1]); s.close()'); \
13+
echo "Gateway: $$MODAL_URL"; \
14+
echo "Frontend: http://localhost:$$PORT"; \
15+
NEXT_PUBLIC_API_URL=$$MODAL_URL PORT=$$PORT bun run dev; \
16+
kill $$MODAL_PID 2>/dev/null
17+
18+
# Frontend only (uses production API or NEXT_PUBLIC_API_URL if set)
19+
dev-frontend:
20+
@PORT=$$(python3 -c 'import socket; s=socket.socket(); s.bind(("",0)); print(s.getsockname()[1]); s.close()'); \
21+
echo "Starting dev server on http://localhost:$$PORT"; \
22+
PORT=$$PORT bun run dev
23+
24+
# Backend only (gateway in dev mode — worker must already be deployed)
25+
dev-backend:
26+
modal serve backend/modal_app.py
27+
28+
# Deploy worker functions to Modal (required before gateway can spawn jobs)
29+
deploy-worker:
30+
unset MODAL_TOKEN_ID MODAL_TOKEN_SECRET && modal deploy backend/app.py
31+
32+
build:
33+
bun run build
34+
35+
test:
36+
bunx vitest run
37+
38+
test-backend:
39+
cd backend && uv run pytest
40+
41+
lint:
42+
bun run lint
43+
44+
clean:
45+
rm -rf .next node_modules

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Virginia tax and benefit reform calculator
2+
3+
An interactive PolicyEngine calculator for modeling the impact of federal and Virginia state tax and benefit reforms on households and statewide.
4+
5+
## Getting started
6+
7+
```bash
8+
bun install
9+
make dev
10+
```
11+
12+
## Stack
13+
14+
- **Frontend:** Next.js 14 (App Router), Tailwind CSS v4, @policyengine/ui-kit, Recharts
15+
- **Backend:** Modal (gateway + worker), policyengine-us
16+
- **Testing:** Vitest
17+
- **Deployment:** Vercel (frontend), Modal (backend)

__tests__/page.test.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { describe, it, expect } from 'vitest'
2+
import { render, screen } from '@testing-library/react'
3+
import Home from '../app/page'
4+
5+
describe('Home page', () => {
6+
it('renders the dashboard title', () => {
7+
render(<Home />)
8+
expect(
9+
screen.getByText('Virginia tax and benefit reform calculator'),
10+
).toBeDefined()
11+
})
12+
13+
it('renders household configuration section', () => {
14+
render(<Home />)
15+
expect(screen.getByText('Household configuration')).toBeDefined()
16+
})
17+
18+
it('renders both tab options', () => {
19+
render(<Home />)
20+
expect(screen.getByText('Household impact')).toBeDefined()
21+
expect(screen.getByText('Statewide impact')).toBeDefined()
22+
})
23+
24+
it('renders reform parameter sections', () => {
25+
render(<Home />)
26+
expect(screen.getByText('Federal income tax')).toBeDefined()
27+
expect(screen.getByText('Federal Child Tax Credit')).toBeDefined()
28+
expect(screen.getByText('Federal EITC')).toBeDefined()
29+
expect(screen.getByText('Virginia income tax')).toBeDefined()
30+
expect(screen.getByText('Virginia EITC')).toBeDefined()
31+
})
32+
})

app/globals.css

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@import "tailwindcss";
2+
@import "@policyengine/ui-kit/theme.css";
3+
4+
body {
5+
font-family: var(--font-sans);
6+
color: var(--foreground);
7+
background: var(--background);
8+
-webkit-font-smoothing: antialiased;
9+
-moz-osx-font-smoothing: grayscale;
10+
}

app/layout.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import './globals.css'
2+
import { Inter } from 'next/font/google'
3+
import type { Metadata } from 'next'
4+
5+
const inter = Inter({ subsets: ['latin'] })
6+
7+
export const metadata: Metadata = {
8+
title: 'Virginia tax and benefit reform calculator - PolicyEngine',
9+
description:
10+
'An interactive calculator that lets users model the impact of reforms to the Child Tax Credit, Earned Income Tax Credit, and income tax rates at both the federal and Virginia state levels.',
11+
icons: { icon: '/favicon.svg' },
12+
}
13+
14+
export default function RootLayout({
15+
children,
16+
}: {
17+
children: React.ReactNode
18+
}) {
19+
return (
20+
<html lang="en">
21+
<body className={inter.className}>{children}</body>
22+
</html>
23+
)
24+
}

0 commit comments

Comments
 (0)