locqr/dev.md

189 lines
6.8 KiB
Markdown

# Development environment
The LOCQR development environment is four components running locally, wired
together by a single setup script. Running the script once produces a fully
functional environment; re-running it on a new machine reproduces the same
environment without regenerating any committed artifacts.
---
## Components
| Component | Directory | Default URL |
|---|---|---|
| Test website | `website/` | `https://test.locqr.dev:5173` |
| Server (Java/Spring) | `server/` | `https://api.locqr.dev:3000` |
| Web companion stub | `companion/` | `https://test.locqr.dev:5174` |
| Browser extension | `extension/` | Loaded unpacked in browser |
All four must run simultaneously for end-to-end testing. Start order:
server stub → extension (load unpacked) → test website → companion stub.
---
## Setup script
**`scripts/setup-dev.sh`** (or `setup-dev.js`) — run once per machine.
Idempotent: re-running it on an existing environment is safe and changes
nothing if all committed artifacts are already in place.
### What it does
**1. mkcert**
Checks that `mkcert` is installed; prints install instructions and exits if
not. Installs the local CA (`mkcert -install`) if not already trusted. Exports
the root CA certificate to `dev/certs/rootCA.pem` for sharing with other
developers.
Generates TLS certificates if not already present:
- `dev/certs/test.locqr.dev.pem` + `test.locqr.dev-key.pem`
- `dev/certs/api.locqr.dev.pem` + `api.locqr.dev-key.pem`
The generated cert files are committed to the repository. On other machines
the script skips generation and just installs the root CA, making the
committed certs trusted.
**2. Signing keypairs**
Checks for committed keypair files. If present, reads them. If absent
(first-ever run on a clean checkout), generates them and prints a reminder
to commit the result.
- ML-DSA-44 keypair → `dev/keys/ml-dsa-44-public.b64` and
`dev/keys/ml-dsa-44-secret.b64`
- Ed25519 keypair → `dev/keys/ed25519-public.b64` and
`dev/keys/ed25519-secret.b64`
These are dev-only artifacts. The production server never commits key material;
the dev stub does. The files are clearly namespaced under `dev/` to prevent
confusion with production secrets.
**3. Pinned constants**
Patches the public key constants into the source files that carry them:
| Constant | File |
|---|---|
| `BACKEND_PUBLIC_KEY_B64` | `extension/src/constants.ts` |
| `ED25519_PUBLIC_KEY_B64` | `extension/src/constants.ts` |
| `ED25519_PUBKEY` | `companion/src/constants.ts` (web stub) |
| `ED25519_PUBKEY` | `mobile/src/main/java/.../Constants.kt` (native, when it exists) |
**4. Test registration certificate**
Issues a registration certificate for `test.locqr.dev` signed with the
ML-DSA-44 dev key. Writes it to `dev/certs/test-registration.b64`. The
server stub reads this file at startup and serves it from a known endpoint.
The test website fetches it on load and passes it to `locqr.init()`.
**5. Extension identity**
Checks that `extension/key.pem` is present. If missing (first-ever run),
generates it and prints a reminder to commit it. This file pins the unpacked
extension's ID; committing it ensures the ID is stable across machines and
rebuilds. The test website and the extension manifest both use the ID derived
from this key.
**6. Environment files**
Writes `server/.env.dev` with the dev signing key paths and local domain
config for the non-JVM components (companion web stub, test website), and
prints the equivalent as environment variable exports for the server, which
reads configuration the Spring way (environment variables / `application.yml`,
not a `.env` file). Not committed (listed in `.gitignore`), as paths may
differ per machine.
```
ML_DSA_44_SECRET_KEY_PATH=../../dev/keys/ml-dsa-44-secret.b64
ED25519_SECRET_KEY_PATH=../../dev/keys/ed25519-secret.b64
TEST_DOMAIN=test.locqr.dev
API_PORT=3000
```
The server's `application.yml` reads the same four settings from environment
variables of the same names, with dev-friendly defaults baked in so it runs
locally without them being set explicitly (see `server/claude.md`).
---
## Hardcoded defaults
These values are baked into the script and into the extension manifest. They
can be overridden by passing arguments to the setup script but the defaults
are what every developer uses unless there is a specific reason to change them.
| Setting | Default |
|---|---|
| Test site domain | `test.locqr.dev` |
| API domain | `api.locqr.dev` |
| Test site port | `5173` |
| API port | `3000` |
| Companion stub port | `5174` |
These domains require a hosts file entry on each machine:
```
127.0.0.1 test.locqr.dev
127.0.0.1 api.locqr.dev
```
The setup script checks for these entries and prints instructions if they are
missing. It does not modify the hosts file automatically.
---
## Committed artifacts
These files are generated once and committed. They must not be regenerated
unless there is a deliberate decision to rotate keys or change domains, as
regeneration would invalidate every other developer's environment.
```
dev/
├── certs/
│ ├── rootCA.pem ← mkcert CA cert; import on new machines
│ ├── test.locqr.dev.pem
│ ├── test.locqr.dev-key.pem
│ ├── api.locqr.dev.pem
│ ├── api.locqr.dev-key.pem
│ └── test-registration.b64 ← ML-DSA-44 signed cert for test.locqr.dev
└── keys/
├── ml-dsa-44-public.b64
├── ml-dsa-44-secret.b64 ← dev only; never use in production
├── ed25519-public.b64
└── ed25519-secret.b64 ← dev only; never use in production
extension/
└── key.pem ← pins the unpacked extension ID
```
---
## Adding a new machine
1. Install `mkcert` (OS package manager or https://github.com/FiloSottile/mkcert)
2. Clone the repository (all committed artifacts are already present)
3. Run `scripts/setup-dev.sh` — installs the root CA and writes `.env.dev`
4. Add the hosts file entries for `test.locqr.dev` and `api.locqr.dev`
5. Load the extension unpacked from `extension/dist/` (or `extension/` once
built)
6. `cd companion && npm install && npm run build`, then
`node scripts/serve-companion.js` — companion/dist/ isn't committed, so
this step is required before the companion stub is reachable at all
(unlike website/, which has no build step of its own)
---
## Rotating dev keys
If the signing keys must be rotated (e.g. after an accidental exposure):
1. Delete `dev/keys/*` and `dev/certs/test-registration.b64`
2. Run `scripts/setup-dev.sh` — regenerates keys, patches constants, reissues
the registration cert
3. Commit all changed files
4. All other developers re-run `scripts/setup-dev.sh` on their next pull
The extension constants will change, requiring a rebuild of the extension.
The extension ID is unaffected (it is derived from `key.pem`, which is not
rotated).