Local testing
The public edition is the sandbox: the same issuance and verification code as production, seeded with test document types and pre-made API keys, without accounts or billing.
What the seed gives you
One organization, one issuer, one verifier, and four document types — PID as SD-JWT VC, PID as mdoc, Age Verification as mdoc, mDL as mdoc — wired into six issuance profiles and six verification profiles. Plus one iss_ and one ver_ API key, taken from your environment:
PUBLIC_EDITION_ISSUER_API_KEY=iss_<keyId>_<secret>
PUBLIC_EDITION_VERIFIER_API_KEY=ver_<keyId>_<secret>
PUBLIC_EDITION_AUTH_CODE_ENABLED=true # adds three authorization-code profiles
DIAGNOSTICS_ENABLED=true # enables the diagnostics timeline
The seed is idempotent, so re-running it is safe.
Run it
From a checkout, the wizard sets up Postgres, Valkey and the env files, then starts everything:
just dev-prepare --preset=public
pnpm dev
just seed-public
Without a checkout, run the published images — ghcr.io/lutralabs/lutra-id-public-backend and ghcr.io/lutralabs/lutra-id-public-frontend — against Postgres and Valkey, setting PUBLIC_BASE_URL, FRONTEND_URL and the two API keys above.
| Service | Port |
|---|---|
| Backend API | 3001 |
| Public frontend | 3002 |
| Dashboard frontend | 3000 |
Reaching it from a phone
Wallets need HTTPS and a publicly resolvable host, so localhost will not do. just expose puts Caddy and an ngrok tunnel in front of the stack and rewrites PUBLIC_BASE_URL for you; just expose-kill tears it down.
Test credentials are cryptographically real but chain to a test platform CA. Production verifiers will reject them, and wallets will only accept them once the root is installed — see Trust and production.
Differences from production
The public edition has no email delivery, no bulk offers and no API key management; keys come from the environment. In exchange it is the only edition exposing issuance status, the diagnostics timeline, and the platform root CA endpoint.