local-development
Running functions and web app locally, troubleshooting emulator issues, Storybook. Use when running or debugging locally.
SKILL.md.claude/skills/local-development/SKILL.md
GitHubLocal Development
When to Use
Use this skill when running the web app or functions locally, troubleshooting emulator issues, or running Storybook.
Important
The user runs functions and web app locally for testing. Claude writes code and creates PRs -- Claude does NOT deploy or run dev servers.
Running Functions Locally (user runs this)
pnpm exec nx run functions:serve
This command:
- Builds the functions
- Copies
.env.devtodist/apps/functions/.env - Starts watch mode for rebuilds (background)
- Runs
firebase serve --only functions --project=devon port 5001
Running Web App Locally (user runs this)
pnpm exec nx run maple-spruce:dev
Runs on http://localhost:3000. On localhost the app auto-connects to the Functions emulator (port from NEXT_PUBLIC_FUNCTIONS_EMULATOR_PORT, default 5001). Auth stays on real dev by default; to run fully against emulators (auth included — e.g. sign in as a seeded emulator user), set NEXT_PUBLIC_AUTH_EMULATOR_PORT (opt-in). Next only inlines NEXT_PUBLIC_* from .env files reliably, so put these in apps/maple-spruce/.env.local (gitignored) rather than the shell. The portal e2e (tools/run-portal-e2e.sh) does exactly this.
Portal E2E (role scoping)
./tools/run-portal-e2e.sh # emulators + next dev + Playwright
Drives the real app in a browser: seeds an admin + an mt-teacher into the emulators, signs in through the login form, asserts the role-filtered shell. First browser-level proof of the scoped-roles wiring (epic #49).
Running Storybook
pnpm exec nx run maple-spruce:storybook
# Opens http://localhost:6006
Building Storybook:
pnpm exec nx run maple-spruce:build-storybook
# Output: dist/storybook/maple-spruce
Running Unit Tests
Each project owns a vitest.config.mts; the @nx/vitest plugin infers its test target.
pnpm test # nx run-many -t test: every project, cached
pnpm exec nx affected -t test # only projects your change can affect
pnpm exec nx test domain # one project
pnpm exec nx test domain -- src/lib/artist.spec.ts # one file
pnpm test:coverage # root run of all project configs + merged coverage (what CI gates on)
New library with specs? Give it a config, or tools/check-vitest-projects.ts fails CI:
pnpm exec nx g @nx/vitest:configuration --project=<name> --testEnvironment=node.
Its generated config uses the deprecated nxViteTsPaths()/nxCopyAssetsPlugin(); swap them for
tsconfigPaths() from vite-tsconfig-paths like every other config here.
Running Integration Tests (user runs this)
Integration tests run Cloud Functions against real Firebase emulators. Requires Java installed (for Firestore emulator).
All-in-one (builds functions, copies .env, starts emulators, runs tests, shuts down):
pnpm exec nx run functions-integration-tests:e2e-with-emulators
Manual (useful when iterating on tests — keep emulators running):
# Terminal 1: Build and start emulators
pnpm exec nx run functions:build
cp .env.dev dist/apps/functions/.env
firebase emulators:start --project=dev --only auth,firestore,functions
# Terminal 2: Run tests (repeat as needed)
pnpm exec nx run functions-integration-tests:e2e
Emulator ports: Auth (9099), Firestore (8080), Functions (5001), UI (4000)
Deployment
User decides when to deploy to dev. Production deploys automatically via CI/CD on merge to main.
Troubleshooting Local Functions
Emulator prompts for environment variables
The Firebase emulator is not finding the .env file. This happens when:
- The build clears
dist/apps/functions/before the.envis copied - A stale watch process is interfering
Fix:
# Kill any stale processes
pkill -f "firebase serve"
pkill -f "nx run functions"
# Clean and restart
rm -rf dist/apps/functions
pnpm exec nx run functions:serve
Why this happens:
- Firebase reads
.envfromdist/apps/functions/ - The
nx run functions:buildclears this directory - The serve command copies
.env.devafter build, before starting the emulator - If ordering is wrong or stale processes exist, the emulator starts without the
.env
Key indicator it's working:
i functions: Loaded environment variables from .env.