Local Setup
Prerequisites
Section titled “Prerequisites”- Node.js >= 18
- pnpm >= 9
- Git
Quick Start (First Time)
Section titled “Quick Start (First Time)”One command bootstraps everything — installs deps, runs migrations, seeds the database, starts all dev servers, and health-checks each service:
git clone <repo-url>cd constructionpnpm dev:updev:up performs these steps automatically:
- Installs dependencies (
pnpm install) - Runs all D1 database migrations
- Seeds the dev database with a test tenant + admin account
- Starts API, Portal, and Intake Form dev servers
- Health-checks each service
- Seeds 50 mock leads via the intake webhook
- Prints a summary with URLs and test credentials
After the first run, a .dev-ready marker file is created. Subsequent pnpm dev:up calls skip the install/migrate/seed steps and go straight to starting servers.
Daily Development
Section titled “Daily Development”pnpm dev:up # Start all servicespnpm dev:down # Stop all services (kills wrangler, vite, astro)Dev Scripts
Section titled “Dev Scripts”| Script | Command | Purpose |
|---|---|---|
| Start all | pnpm dev:up | Full bootstrap + start all 3 dev servers |
| Stop all | pnpm dev:down | Kill all dev processes, verify ports are free |
| Re-init | pnpm dev:init | Force re-run migrations + seed (no server start) |
| Full reset | pnpm dev:nuke | Wipe all local state (node_modules, DB, build artifacts) |
After dev:nuke, run pnpm dev:up to rebuild from scratch.
Services & Ports
Section titled “Services & Ports”| App | Default Port | URL |
|---|---|---|
| API | 8201 | http://localhost:8201/api/v1/health |
| Portal | 8200 | http://localhost:8200/login |
| Intake Form | 8202 | http://localhost:8202/contractor |
| Docs | 8203 | http://localhost:8203 |
Ports are configurable via config/.tenant.dev.env:
DEV_PORT_PORTAL=8200DEV_PORT_API=8201DEV_PORT_INTAKE=8202Starting Services Individually
Section titled “Starting Services Individually”pnpm dev:api # API only (port 8201)pnpm dev:portal # Portal only (port 8200)# Intake: cd apps/lead-intake-form-pwa && pnpm dev# Docs: cd apps/docs && pnpm devTest Credentials
Section titled “Test Credentials”| Field | Value |
|---|---|
suadmin@dev.local | |
| Password | Set via DEFAULT_SUADMIN_PASSWORD env var |
This account is an admin role with full access to all portal features.
API Proxy
Section titled “API Proxy”The portal dev server proxies /api/v1/* requests to the API at http://localhost:8201. This is configured in apps/project-work-portal/vite.config.ts. In production, Cloudflare Pages Functions handle the proxy.
Database
Section titled “Database”ContractorHub uses Cloudflare D1 (SQLite) with Drizzle ORM.
# Run migrations manuallycd apps/api && pnpm db:migrate
# Re-seed (idempotent — uses INSERT OR IGNORE)cd apps/api && node scripts/seed-account.mjs all
# Full DB reset (nuke wrangler state + re-migrate + re-seed)rm -rf apps/api/.wrangler && cd apps/api && pnpm db:migrate && node scripts/seed-account.mjs allMigrations are in apps/api/migrations/ and run in alphabetical order.
Running Tests
Section titled “Running Tests”# All unit + integration testspnpm test
# Specific packagespnpm test:shared # packages/sharedcd apps/api && pnpm test # API (unit + integration)cd apps/project-work-portal && pnpm test # Portal unit tests
# E2E tests (auto-starts API + Portal servers)cd apps/project-work-portal && npx playwright test
# Single E2E specnpx playwright test quote-buildernpx playwright test quote-share
# Type checkingcd apps/project-work-portal && pnpm tsc --noEmitTenant Configuration
Section titled “Tenant Configuration”Tenant settings live in config/.tenant.dev.env (committed, for development) and config/.tenant.env (production, gitignored).
Key settings: company name, phone, email, office address, dev ports. See the Tenant Config reference for all available fields.
Troubleshooting
Section titled “Troubleshooting”Port already in use: Run pnpm dev:down to kill stale processes, then retry pnpm dev:up.
Database errors after pulling new migrations: Delete .dev-ready to force re-initialization:
rm .dev-ready && pnpm dev:upFull clean start:
pnpm dev:nuke && pnpm dev:upWrangler stale state: If D1 errors persist after migration changes:
rm -rf apps/api/.wrangler && pnpm dev:up