Web client (UI)
Run the nivq web client — the browser UI users open. A static single-page app served by nginx (or any webserver), configured at runtime so one build runs anywhere — Docker, Kubernetes, or bare metal.
The three install paths — Quickstart, Kubernetes, Bare metal — bring up the API. The web client is the browser UI your users open, and it ships as a separate static single-page app: built once, served by a webserver, pointed at your nivq API. You run it alongside the API in every mode.
One build, configured at runtime
The UI is a plain static bundle. The settings that change per deployment — your API URL, auth server, OIDC client id — are read at runtime, not baked into the build. So the same image (or the same dist/ folder) runs in every environment with no rebuild; you just point it at your API.
Pull the image
The web client is a private image (ghcr.io/nivorbit/images/nivq-web), same registry and login as the API. It's a static build behind nginx on port 8080, non-root:
docker pull ghcr.io/nivorbit/images/nivq-web:0.2.2Configure it — at runtime
Two equivalent ways; pick whichever fits your platform.
A. Environment variables (recommended for Docker & Kubernetes)
On start, the container renders its config from environment variables. Only NIVQ_API_BASE_URL is required:
| Variable | Default | What it is |
|---|---|---|
NIVQ_API_BASE_URL | (required) | Your nivq API URL (BACKEND_URL), as reached from the browser |
NIVQ_AUTH_SERVER_URL | = NIVQ_API_BASE_URL | OIDC issuer — the API is its own identity provider, so leave it |
NIVQ_CLIENT_ID | nivq-app | OIDC client id — leave it unless you changed it on the API |
NIVQ_WORKSPACE_NAME | NivQ | Name shown in the UI |
NIVQ_PRIMARY_COLOR | #f35553 | Brand accent colour |
docker run -d --name nivq-web -p 3000:8080 \
-e NIVQ_API_BASE_URL=https://api.example.com \
ghcr.io/nivorbit/images/nivq-web:0.2.2B. A config file (for mounting, or serving on your own webserver)
The app reads /config/default.json at startup. Leave NIVQ_API_BASE_URL unset and mount your own file — it's used as-is:
{
"apiBaseUrl": "https://api.example.com",
"authServerUrl": "https://api.example.com",
"clientId": "nivq-app",
"scope": "openid profile email",
"workspaceName": "Your Company",
"primaryColor": "#f35553"
}docker run -d --name nivq-web -p 3000:8080 \
-v ./config/default.json:/usr/share/nginx/html/config/default.json:ro \
ghcr.io/nivorbit/images/nivq-web:0.2.2Open http://localhost:3000 — you should land on the sign-in page. Put TLS in front of it in production, just like the API.
Serve it on your own webserver
Don't want the container? The build is a plain static bundle (dist/). Copy it to your webserver's docroot, drop a config/default.json beside it (option B above), and serve it. Two rules make an SPA work:
- Fall back to
index.htmlfor unknown routes (client-side routing) — but not for/config/,/assets/, or/locales/, so a missing file there returns404rather than HTML. - Never cache
/config/default.json, so config edits take effect on reload.
Starter configs ship in the repo: deploy/nginx.conf and deploy/apache.conf (mod_rewrite + mod_headers).
How sign-in fits together
nivq signs users in with OIDC (Authorization Code + PKCE) against the API itself — there's no separate auth server to run. On boot, the API automatically registers the web client with a redirect URI of <FRONTEND_URL>/auth/callback. Two rules follow:
- Set the API's
FRONTEND_URLto the web client's public URL (e.g.https://app.example.com). - Serve the web client at exactly that URL.
The match is exact — if the SPA is loaded from any other origin, the API rejects the login. After that, sign-in goes through whichever provider you configured on the API (Google, Microsoft, GitHub — see Authentication & SSO); the web client shows those as buttons.
One origin, set on both sides
The web client's public URL, the API's FRONTEND_URL, and NIVQ_API_BASE_URL (or apiBaseUrl) all have to agree. A login that bounces back to the sign-in page is almost always an origin mismatch here.
Per deployment mode
- Docker / Compose — add the
nivq-webservice next to the API; the Quickstart compose already includes it. - Bare metal — run the same container with a reverse proxy in front, or serve
dist/on the webserver you already run. See Bare metal. - Kubernetes — the Helm chart deploys the web client too when you enable it. See Kubernetes.