Stand Up the Web Client¶
What this is: deploying the browser client — the alternative to the Android app for getting onto the WayPoint network. See System overview. When you'd do it: standing up a new deployment, or adding a browser entry-point to an existing one. How long it takes: an hour for the cloud path if your Directory and a server are already live; a few minutes for the local/Docker path.
The web client is an AdonisJS application that serves a real-time tactical map and handles user login. It needs two things to do its job: a Directory (to authenticate users and issue identity tokens) and a server (a Zenoh relay, reached over WSS, to actually carry traffic). Stand those up first — this runbook is Step 4 in the deployment order; follow Stand up a deployment for the right sequence.
Who can do this: a deployment engineer with access to the GCP project (for the cloud path) or a Docker host. The web client has no in-Directory registration step — you do not need an Admin for the provisioning itself, but users still need to be onboarded to the Directory before they can log in.
The shape of it¶
flowchart LR
A["Engineer provisions<br/>the web VM<br/>(or Docker host)"] --> B["Point it at the<br/>Directory (OIDC)<br/>and a server (WSS)"]
B --> C["Users browse<br/>to the site"]
C --> D["Directory handles<br/>passkey login;<br/>issues session"]
D --> E["User sees the<br/>live tactical map"]
Before you start¶
- A running Directory — the web client uses it for OIDC login. The demo Directory is at
https://auth.bedrockdefence.com. - At least one running server (relay) — users won't see map data without one. Note its
WSS endpoint (e.g.
wss://demo.bedrockdefence.com:7447). - For the cloud path:
tofu(OpenTofu) andgcloudinstalled and authenticated. - For the Docker path: Docker installed and a PostgreSQL instance reachable.
Step 1 — Provision the web client¶
There are two paths. Use the cloud path for real deployments.
Option A — Cloud (recommended)¶
Production web environments are a COS VM running Caddy + AdonisJS + Cloud SQL Auth Proxy,
backed by a Cloud SQL PG17 instance. This lives in the infrastructure repo. For a new
environment, copy terraform/environments/web-demo/ to a new directory and adjust
variables.tf. For the existing demo environment, apply from the existing stack:
Before the first tofu apply, the web-demo stack requires Telesto AIS feed credentials
in Secret Manager. Put TELESTO_HOST, TELESTO_PORT, TELESTO_CLIENT_CERT_B64,
TELESTO_CLIENT_KEY_B64, and TELESTO_CA_CERT_B64 into a local .env file and run:
tofu apply creates the VM, a static IP, and a Cloud SQL PG17 instance. Web secrets
(app-key, db-password, cloudsql-postgres) are auto-generated by Terraform and stored
in Secret Manager — you don't mint them manually.
After the first apply, the web app also needs a service identity token so it can poll
the Directory's /api/revoked-principals endpoint. This is a Directory-signed IdentityToken,
issued the same way as any service device — there is no node ace command for it; you
mint it from the Directory admin UI:
- Sign in to the Directory as an Admin, click Devices → Create Device.
- Give it a callsign (e.g. web-demo), set Platform Type to gateway (a service platform, so it receives a Directory-signed identity), and add at least one coverage cell.
- On the Device Created page, download the Identity Token as a
.binfile.
Then upload that file as the web service token:
The VM fetches the token from Secret Manager on every boot. Without it, the revocation cache fails to prime and logins fail closed.
DNS must resolve before Caddy can provision its TLS certificate:
Option B — Docker¶
For a local or lab environment, the web repo contains a docker-compose.yml that starts
a PostgreSQL instance:
Then copy and configure the environment file:
To run the app in a single container instead:
docker build -t waypoint-web .
docker run -d \
--name waypoint-web \
-p 3333:3333 \
-e NODE_ENV=production \
-e APP_KEY=<your-app-key> \
-e DB_HOST=<db-host> \
-e DB_PASSWORD=<db-password> \
waypoint-web
For development, after docker compose up -d to start the database:
The app starts at http://localhost:3333. Migrations run automatically on dev startup.
Step 2 — Point the web client at your Directory and server¶
Directory (for login)¶
The web client authenticates users via OIDC against your Directory. Set the Terraform variable (cloud path) or environment variable (Docker path):
| Config key | What it does | Example |
|---|---|---|
directory_url (Terraform) / WAYPOINT_OIDC_ISSUER_URL (env) |
Directory OIDC issuer URL | https://auth.bedrockdefence.com |
WAYPOINT_OIDC_CLIENT_ID |
OIDC client ID registered in the Directory | — |
WAYPOINT_OIDC_CLIENT_SECRET |
OIDC client secret | — |
On the cloud path, the OIDC client secret is pulled from Secret Manager automatically
(bedrock-<env>-webauth-client-secret). No manual realm/client setup is required — the
auth stack provisions it and the web module consumes it.
To disable password login and rely on passkeys/OIDC only:
| Variable | Default | Effect |
|---|---|---|
WAYPOINT_DISABLE_PASSWORD_AUTH |
false |
Set true to hide the password login form |
WAYPOINT_ENABLE_WEBAUTHN |
false |
Set true to enable passkey (FIDO2/WebAuthn) login |
Server / relay (for map traffic)¶
The web client opens a Zenoh session over WSS to reach the relay network. Set:
| Config key | What it does | Example |
|---|---|---|
zenoh_router_endpoints (Terraform) |
Comma-separated Zenoh WSS endpoints the browser connects to | wss://demo.bedrockdefence.com:7447 |
On the cloud path this is a Terraform variable in variables.tf (default: empty, which
means the browser fails closed with no map data). Set it to the WSS address of your server
before applying.
On the Docker path, set the equivalent environment variable as exposed by the running
AdonisJS app (surface it via .env — check web/start/env.ts for the exact name the
app validates at startup).
Step 3 — Users sign in¶
Once the web client is up and pointed at the Directory, users browse to the site (e.g.
https://app.bedrockdefence.com). The login flow is handled by the Directory: the web
client redirects to the Directory's OIDC endpoint, the user authenticates with their
passkey, and the Directory issues a session back to the web client.
Users must already be onboarded in the Directory before they can log in. If a user isn't provisioned yet, see Onboard an operator.
How to know it worked¶
- The site loads at the configured hostname without a certificate warning.
- A user can click Log in, authenticate with their passkey on the Directory, and land on the tactical map.
- The map shows live unit positions for the area covered by the connected server.
- Other users connected to the same server appear on the map.
If something goes wrong¶
-
Can't log in at all — OIDC error or redirect loop. The
WAYPOINT_OIDC_ISSUER_URL/directory_urlis wrong, or the OIDC client secret hasn't been uploaded. Check that the Directory is reachable and that thebedrock-<env>-webauth-client-secretSecret Manager value exists. Also check that the web service identity token has been uploaded — without it, logins fail closed (the revocation cache can't prime). -
Can't log in — "user not found" or access denied. The user hasn't been onboarded to the Directory yet. See Onboard an operator.
-
Site loads but the map is empty / no other users appear. The
zenoh_router_endpointsvariable is empty or pointing at the wrong address, or no server is running that covers the users' area. Check the server's WSS endpoint and make sure a server is live and covers the relevant geohash cells. See Add a server. -
Site won't load — certificate error. DNS hasn't propagated yet, or Caddy couldn't provision a Let's Encrypt certificate. DNS must resolve to the static IP before Caddy can issue the cert. Check with
dig app.bedrockdefence.comand compare againsttofu output static_ipin theweb-demostack. -
Database not reachable. On the cloud path, the Cloud SQL Auth Proxy sidecar handles the connection — check that the VM's service account has the
roles/cloudsql.clientrole and that the Cloud SQL instance is running. Tail the serial console:
See also¶
- Operator training index
- Stand up a deployment — the full deployment order (web is Step 4)
- Set up the Directory — must be live before the web client
- Add a server — must be live for map data to flow
- Onboard an operator — users need Directory accounts before they can log in
- The
infrastructurerepo —terraform/environments/web-demo/for the full cloud provisioning walkthrough - The
webrepo —README.mdfor Docker build/run and environment variable reference
Verified against directory@e8287cd / web@80e3ec2 on 2026-06-07 — provisioning: infrastructure repo terraform/environments/web-demo/; client config: web repo README.md. The web service token is a Directory-signed IdentityToken minted from the admin Devices flow (devices_service.ts, device_credentials.edge) — there is no directory:create-service-token ace command. Production containers have no node ace access (directory start/routes.ts, keys_controller.ts); node ace generate:key here is the dev/lab APP_KEY bootstrap only (web/directory README.md) — production app keys are auto-generated by Terraform.