# Wundklar · local harness

One command boots Postgres, MinIO, the API and Expo web for a numbered slot so parallel tickets never collide.

The product runs offline on the device and talks to a Worker, so a local
developer loop must stand up Postgres, an S3-compatible store, the API with
CORS preflight, and Expo web served from the same host so the session cookie
stays same-site across ports. The harness
[`scripts/wundklar-harness.mjs`](https://github.com/CarlosZiegler/wundklare/blob/main/scripts/wundklar-harness.mjs)
does that for a numbered slot; the detailed walkthrough is in
[`docs/wundklar/HARNESS.md`](https://github.com/CarlosZiegler/wundklare/blob/main/docs/wundklar/HARNESS.md).

## Run [#run]

```bash
pnpm wk:harness --slot 42 --seed demo
pnpm wk:harness:smoke --slot 42
```

For slot `NN` the API answers on `http://127.0.0.1:31NN`, Expo web on
`http://127.0.0.1:82NN` and MinIO on `http://127.0.0.1:93NN`. Every component
binds to `127.0.0.1` so the session cookie stays same-site across the two
ports. The mailbox for OTP and invitations is written to
`.scratch/wundklar-v1/harness/NN/mailbox.json`.

CORS preflight is answered only for exact origins in `CORS_ORIGIN`
(comma-separated, `Vary: Origin`, credentials true, inert when unset) on
`/api/rpc/*` and `/api/auth/*`; Better Auth trusts the same list. The smoke
script
[`scripts/wundklar-harness-smoke.mjs`](https://github.com/CarlosZiegler/wundklare/blob/main/scripts/wundklar-harness-smoke.mjs)
checks preflight, a credentialed RPC call and a presigned PUT / GET round-trip.

## Semaphore [#semaphore]

Harnesses are heavy. The locked wrapper
`~/work/wundklare-wt/.locks/wk-sem.sh harness 2 -- pnpm wk:harness --slot NN`
blocks until one of the two machine-wide slots is free; a ticket that needs
one starts it as a background job and polls with a bounded `timeout` loop.

## Seed and enrolment [#seed-and-enrolment]

`--seed demo` loads the synthetic seed described in
[`docs/wundklar/HARNESS.md`](https://github.com/CarlosZiegler/wundklare/blob/main/docs/wundklar/HARNESS.md):
Lindenhof Pflege (Dortmund) with Mehmet Aydın (PDL), Jana Wiegand, Tobias
Brandt, Leonie Faber and Svenja Kühn, their tours and Karl Albers' active
wound W-0142. The dev enrolment route
[`/dev/enrol`](https://github.com/CarlosZiegler/wundklare/blob/main/apps/web/src/routes/dev.enrol.tsx)
takes a `?user=` query, enrols the browser as a device with PIN `246810`
and downloads the day, provided `EXPO_PUBLIC_WUNDKLAR_DEV_ENROL=1` and the
dev TOTP master are set in the environment.

Stop the harness explicitly by the PID the wrapper reported, and remove the
`wundklar-s3-<slot>` container before you report done; the semaphore does not
clean up idle sessions.

