6.5 KiB
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.pemdev/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.b64anddev/keys/ml-dsa-44-secret.b64 - Ed25519 keypair →
dev/keys/ed25519-public.b64anddev/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
- Install
mkcert(OS package manager or https://github.com/FiloSottile/mkcert) - Clone the repository (all committed artifacts are already present)
- Run
scripts/setup-dev.sh— installs the root CA and writes.env.dev - Add the hosts file entries for
test.locqr.devandapi.locqr.dev - Load the extension unpacked from
extension/dist/(orextension/once built)
Rotating dev keys
If the signing keys must be rotated (e.g. after an accidental exposure):
- Delete
dev/keys/*anddev/certs/test-registration.b64 - Run
scripts/setup-dev.sh— regenerates keys, patches constants, reissues the registration cert - Commit all changed files
- All other developers re-run
scripts/setup-dev.shon 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).