Files
julian dbf1fa17d7 wiki: document dev environment (WSL networking, workflow)
Capture hard-won dev knowledge that was only in commit messages:

- wsl-dev-networking: WSL2 NAT blocks UDP broadcast (device discovery can't
  reach the LAN); fix is mirrored networking (.wslconfig, Win11 22H2+), plus the
  gotchas that remained after — multiple interfaces, subnet-directed broadcast,
  localhost->IPv6 stall. Alternatives for non-mirrored setups.
- local-dev-workflow: first-time setup, pnpm dev, and the gotchas (the
  strip-types dev-server hang -> tsx, the 127.0.0.1 proxy fix, .env loading,
  seeding into the right DB).
- device-discovery: corrected the old "broadcast permission (EACCES)" note — the
  real cause was the lib not enabling SO_BROADCAST for global 255.255.255.255;
  documented the three verified broadcast gotchas + I/O serialization.
- schema: add a `reference` page type; new "Dev environment" index section; log.

Links lint clean; both new pages well-connected.
2026-06-14 13:09:35 +02:00

2.7 KiB

type, tags, sources, updated
type tags sources updated
reference
parking
dev-environment
workflow
2026-06-15

Local Dev Workflow

Dev-environment reference, not product architecture. How to run the stack locally and the gotchas that have bitten us. For device testing under WSL also read wsl-dev-networking.

First-time setup

pnpm install
cp apps/server/.env.example apps/server/.env     # then fill in JWT_SECRET
#   JWT_SECRET=$(openssl rand -hex 32)            # server refuses to start without a strong one
pnpm --filter @parking/db exec drizzle-kit migrate   # create the SQLite schema
pnpm seed:admin                                   # create the first admin (see [[local-jwt-auth]])

apps/server/.env and the *.sqlite files are gitignored (local-only). Leave NODE_ENV unset in dev so the auth cookies aren't Secure-only (Vite dev is plain http).

Running

pnpm dev      # turbo runs both: Vite (web, :5173) + Fastify (server, :3000)

Open http://localhost:5173. The Vite dev proxy forwards /api + /health to the backend, so the SPA and API are same-origin and the local-jwt-auth works without CORS. Production uses an nginx reverse proxy (deploy/nginx.conf) for the same same-origin setup.

Gotchas (all fixed, recorded so they don't recur)

  • Server dev must not be node --experimental-strip-types src/index.ts. Type-stripping does not rewrite .js import specifiers to .ts, so it crashed with ERR_MODULE_NOT_FOUND and silently never started — the symptom was the SPA hanging for minutes (the Vite proxy waiting on a dead backend), then finally erroring. The dev script uses tsx watch instead.
  • Vite proxy → 127.0.0.1, not localhost. localhost resolves to IPv6 ::1 first while the backend binds IPv4; Node's proxy can stall on the v6 attempt. Same class of "slow then works" hang, worse under WSL2 mirrored mode (wsl-dev-networking).
  • .env must actually be loaded. The server reads process.env only; the dev/start scripts load the file via Node's --env-file-if-exists=.env. An empty JWT_SECRET= makes the server fail-fast at boot.
  • Seed into the DB the server reads. seed:admin and the server must use the same DATABASE_URL; running via pnpm seed:admin (which loads apps/server/.env) keeps them aligned.

Useful one-offs

  • First admin: pnpm seed:admin (prompts; blank username → admin). Non-interactive: ADMIN_USER=.. ADMIN_PASS=.. pnpm seed:admin. Reset a password: add FORCE=1.
  • Hardware test scripts (UHPPOTE): apps/server/scripts/uhppote-listen.mjs (live events), uhppote-relay.mjs (guarded door-open). See uhppote-controller.