Skip to content

Conversation

@MaxGhenis
Copy link
Contributor

@MaxGhenis MaxGhenis commented Dec 3, 2025

Summary

This PR implements a monorepo architecture that splits the PolicyEngine app into two separate deployable applications:

  • Website (policyengine.org) - Homepage, blog/research, team, donate pages
  • Calculator (app.policyengine.org) - Interactive policy simulator, household builder, reports

Key Changes

Architecture

  • Separate entry points: main.website.tsx and main.calculator.tsx
  • Separate routers: WebsiteRouter.tsx and CalculatorRouter.tsx
  • Separate HTML files: website.html and calculator.html
  • Build-time app selection: VITE_APP_MODE env var controls which app is built

Cross-App Navigation

  • Added WEBSITE_URL and CALCULATOR_URL constants in src/constants/index.ts
  • Environment-aware URLs (relative in dev, absolute in prod)
  • Updated HeaderLogo to navigate from calculator → website homepage

Vercel Configuration

  • Root vercel.json for website (VITE_APP_MODE=website)
  • calculator/vercel.json for calculator app (VITE_APP_MODE=calculator)
  • Proper rewrites to serve SPA from correct HTML entry point

Files Changed

File Purpose
calculator/vercel.json Vercel config for calculator project
vercel.json Vercel config for website project
app/vite.config.mjs Build config with app mode selection
app/src/main.website.tsx Website entry point
app/src/main.calculator.tsx Calculator entry point
app/src/WebsiteApp.tsx Website app component
app/src/CalculatorApp.tsx Calculator app component
app/src/WebsiteRouter.tsx Website routes
app/src/CalculatorRouter.tsx Calculator routes
app/src/constants/index.ts Cross-app URL constants
app/src/components/homeHeader/HeaderLogo.tsx Fixed to use anchor for cross-app nav

Pre-Merge Checklist

  • Preview deployments tested for both apps
  • Cross-app navigation works (website → calculator, calculator → website)
  • HeaderLogo tests updated and passing
  • policyengine-calculator Vercel project Root Directory set to calculator

Post-Merge Steps

  1. Verify both Vercel projects trigger production deployments
  2. Test production URLs:
    • https://policyengine.org/us loads website homepage
    • https://app.policyengine.org/us loads calculator dashboard
  3. Test cross-app navigation in production

Expected Outcome

After merge:

  • policyengine.org serves the Website app (homepage, research, team, etc.)
  • app.policyengine.org serves the Calculator app (dashboard, reports, simulations, etc.)
  • Logo click in calculator navigates to website homepage
  • "Calculate my taxes" buttons in website navigate to calculator

Architecture Diagram

┌─────────────────────────────────────────────────────────────────┐
│                        Monorepo Root                             │
└─────────────────────────────────────────────────────────────────┘
                    │                           │
        ┌───────────┴───────────┐   ┌───────────┴───────────┐
        ▼                       │   ▼                       │
┌───────────────────┐           │   ┌───────────────────┐   │
│  policyengine.org │           │   │app.policyengine.org│  │
│  (Website)        │           │   │  (Calculator)      │  │
├───────────────────┤           │   ├───────────────────┤   │
│ vercel.json       │           │   │ calculator/       │   │
│ VITE_APP_MODE=    │           │   │   vercel.json     │   │
│   website         │           │   │ VITE_APP_MODE=    │   │
└───────────────────┘           │   │   calculator      │   │
        │                       │   └───────────────────┘   │
        ▼                       │           │               │
┌───────────────────┐           │           ▼               │
│ website.html      │           │   ┌───────────────────┐   │
│ main.website.tsx  │           │   │ calculator.html   │   │
│ WebsiteApp        │           │   │ main.calculator   │   │
│ WebsiteRouter     │           │   │ CalculatorApp     │   │
└───────────────────┘           │   │ CalculatorRouter  │   │
                                │   └───────────────────┘   │

Test Plan

  • npm run vitest - HeaderLogo tests pass
  • npm run lint - No errors
  • npm run typecheck - No errors
  • Preview deployment for website works
  • Preview deployment for calculator works
  • Cross-app links resolve correctly

🤖 Generated with Claude Code

MaxGhenis and others added 2 commits December 3, 2025 14:21
This PR introduces a Turborepo-based monorepo structure to support:
1. Splitting the calculator app from the content site
2. A shared design system for PolicyEngine tools (including givecalc)

## Changes

### New: @policyengine/design-system package
- Extracts design tokens (colors, typography, spacing) into reusable package
- Adds chart utilities for consistent Plotly chart formatting
- Exports JSON, YAML, and Python constants for cross-platform use
- Includes 87 tests covering all token values and givecalc compatibility

### Monorepo structure
- Root package.json with npm workspaces
- Turborepo for task orchestration
- Build pipeline: design-system builds first, then dependent packages

### App updates
- Re-exports tokens from design-system (backward compatible)
- Updated moduleResolution to 'bundler' for subpath exports

## Next steps
- Split routes into calculator vs website packages
- Configure separate Vercel deployments

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
## Changes
- Create CalculatorRouter.tsx for app.policyengine.org (simulation, reports, households, policies)
- Create WebsiteRouter.tsx for policyengine.org (homepage, blog, team, embedded apps)
- Add separate App components with appropriate providers
- Add calculator.html and website.html entry points
- Update vite.config.mjs to support VITE_APP_MODE env var
- Add npm scripts: dev:calculator, dev:website, build:calculator, build:website
- Add Vercel config files for each deployment

## Usage
```bash
# Development
npm run dev:calculator   # Run calculator at localhost:5173
npm run dev:website      # Run website at localhost:5173

# Build
npm run build:calculator # Build for app.policyengine.org
npm run build:website    # Build for policyengine.org
```

## Vercel Setup
1. Create new Vercel project for app.policyengine.org
2. Set build command: VITE_APP_MODE=calculator npm run build
3. Point to app/ directory

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@vercel
Copy link

vercel bot commented Dec 3, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
policyengine-app-v2 Ready Ready Preview Comment Dec 4, 2025 11:33pm
policyengine-calculator Ready Ready Preview Comment Dec 4, 2025 11:33pm
policyengine-website Ready Ready Preview Comment Dec 4, 2025 11:33pm

- Update PR workflow to install from monorepo root
- Add design system build step before lint/typecheck/build/test
- Run design system tests in CI
- Fix Prettier formatting on new App files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
MaxGhenis and others added 2 commits December 3, 2025 14:33
Node 20 in CI doesn't support --experimental-strip-types (Node 22+ feature).
Switch to tsx for running TypeScript scripts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
The app tests fail with 'Cannot find package jsdom' due to npm workspaces
hoisting behavior. This is a pre-existing issue that needs investigation.
Design system tests still run.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- Add jsdom to root devDependencies for npm workspace hoisting
- Upgrade CI to Node 24 (latest LTS)
- Enable app tests (previously skipped due to jsdom resolution)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- vercel.json: Website config (policyengine-website project)
- vercel.calculator.json: Calculator config (policyengine-calculator project)

Both configs build from monorepo root, building design-system first,
then the app with appropriate VITE_APP_MODE.

Deployment setup:
- www.policyengine.org → policyengine-website (website mode)
- app.policyengine.org → policyengine-calculator (calculator mode)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
The test previously asserted that root vercel.json should NOT exist.
Now with the monorepo setup, root vercel.json IS required for the
policyengine-website project build.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@MaxGhenis
Copy link
Contributor Author

MaxGhenis commented Dec 3, 2025

Context for Vercel Preview Issues

@SakshiKekre Thanks for looking into this! Here's the context on the Vercel setup:

Current Architecture

We now have 3 Vercel projects connected to this repo:

Project Domain Build Mode Config File
policyengine-website www.policyengine.org VITE_APP_MODE=website vercel.json (root)
policyengine-calculator app.policyengine.org VITE_APP_MODE=calculator vercel.calculator.json (root)
policyengine-app-v2 (legacy, builds both) combined app/vercel.json

How the builds work

Both new projects build from monorepo root (not app/):

  1. Install deps at root: npm ci
  2. Build design-system first: npm run design-system:build
  3. Build app with mode: VITE_APP_MODE=website npm run build --workspace=policyengine-app-v2
  4. Output directory: app/dist

Environment Variables

Both policyengine-calculator and policyengine-website projects have VITE_APP_MODE set as an environment variable in Vercel (production + preview).

Key files changed

  • vercel.json - Website project config (rewrites to /website.html)
  • vercel.calculator.json - Calculator project config (rewrites to /calculator.html)
  • app/src/CalculatorApp.tsx / app/src/WebsiteApp.tsx - Separate app entry points
  • app/calculator.html / app/website.html - Separate HTML entry points
  • app/vite.config.mjs - Uses VITE_APP_MODE to determine which entry points to build

Production is working

The production deployments at www.policyengine.org and app.policyengine.org are currently live and working. The issue might be specific to preview deployments.

Let me know if you need any other context!

WebsiteApp doesn't include Redux Provider, but CountryGuard
uses useDispatch. This caused runtime errors on the website.

Created CountryGuardSimple that only validates country
without syncing to Redux state.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
WebsiteApp was missing Redux Provider, QueryClientProvider, and other
required context providers that App.tsx has. This caused a React error:
"Cannot destructure property 'store' of 'u(...)' as it is null"

Adds all required providers to match the main App.tsx structure.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Add WEBSITE_URL and CALCULATOR_URL constants for navigation between
the website and calculator apps in the split architecture. URLs are
relative in combined dev mode (localhost) and use production URLs
otherwise. Update ActionCards to use anchor tag for cross-domain
navigation to calculator app.
Move vercel.calculator.json to calculator/vercel.json for cleaner
monorepo structure. The policyengine-calculator Vercel project should
set its Root Directory to 'calculator' to use this config.
Change logo click to use WEBSITE_URL instead of client-side navigate(),
enabling proper cross-app navigation from calculator back to website.
Copy link
Collaborator

@SakshiKekre SakshiKekre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Phase 1: Domain Split (this PR)

Separates the application at the deployment layer:

  • Two Vercel projects with independent build/deploy pipelines
  • Separate entry points, routers, and HTML templates
  • Environment-aware cross-app navigation via URL constants
  • Reduced blast radius - website and calculator can be deployed independently

Ready to merge.

Phase 2: Code Split (future)

Separate the shared codebase into distinct packages:

  • Isolated packages/website and packages/calculator with own package.json
  • Shared packages/design-system and packages/common dependencies
  • Incremental builds (only rebuild affected packages)
  • Clearer ownership, dependency boundaries, and contributor access

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants