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

57 lines
2.7 KiB
Markdown

---
type: reference
tags: [parking, dev-environment, workflow]
sources: []
updated: 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
```bash
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
```bash
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|cookie 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]].