Mission Control Frontend (frontend/)
This package is the Next.js web UI for OpenClaw Mission Control.
- Talks to the Mission Control backend over HTTP (typically
http://localhost:8000). - Uses React Query for data fetching.
- Can optionally enable Clerk authentication (disabled by default unless you provide a real Clerk publishable key).
Prerequisites
- Node.js (recommend 18+) and npm
- Backend running locally (see
../backend/README.mdif present) or run the stack via Docker Compose from repo root.
Local development
From frontend/:
npm install
# set env vars (see below)
cp .env.example .env.local
npm run dev
Open http://localhost:3000.
LAN development
To bind Next dev server to all interfaces:
npm run dev:lan
Environment variables
The frontend reads configuration from standard Next.js env files (.env.local, .env, etc.).
Required
NEXT_PUBLIC_API_URL
Base URL of the backend API.
- Default for local dev:
http://localhost:8000 - Used by the generated API client and helpers (see
src/lib/api-base.tsandsrc/api/mutator.ts).
Example:
NEXT_PUBLIC_API_URL=http://localhost:8000
Optional: Clerk authentication
Clerk is optional.
The app only enables Clerk when NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY looks like a real key.
Implementation detail: we gate on a conservative regex (pk_test_... / pk_live_...) in src/auth/clerkKey.ts.
Env vars
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY- If unset/blank/placeholder, Clerk is treated as disabled.
CLERK_SECRET_KEY- Required only if you enable Clerk features that need server-side verification.
- Redirect URLs (optional; used by Clerk UI flows):
NEXT_PUBLIC_CLERK_SIGN_IN_FORCE_REDIRECT_URLNEXT_PUBLIC_CLERK_SIGN_UP_FORCE_REDIRECT_URLNEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URLNEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL
Important: frontend/.env.example contains placeholder values like YOUR_PUBLISHABLE_KEY.
Those placeholders are not valid keys and are intentionally treated as “Clerk disabled”.
How the frontend talks to the backend
API base URL
The client builds URLs using NEXT_PUBLIC_API_URL (normalized to remove trailing slashes).
Generated API client (Orval + React Query)
We generate a typed client from the backend OpenAPI schema using Orval:
- Config:
orval.config.ts - Output:
src/api/generated/* - Script:
npm run api:gen
By default, Orval reads:
ORVAL_INPUT(if set), otherwisehttp://127.0.0.1:8000/openapi.json
Example:
# from frontend/
ORVAL_INPUT=http://localhost:8000/openapi.json npm run api:gen
Auth header / Clerk token injection
All Orval-generated requests go through the custom mutator (src/api/mutator.ts).
It will:
- set
Content-Type: application/jsonwhen there is a body and you didn’t specify a content type - add
Authorization: Bearer <token>automatically if Clerk is enabled and there is an active Clerk session in the browser - parse errors into an
ApiErrorwith status + parsed response body
Common commands
From frontend/:
npm run dev # start dev server
npm run build # production build
npm run start # run the built app
npm run lint # eslint
npm run test # vitest (with coverage)
npm run test:watch # watch mode
npm run api:gen # regenerate typed API client via Orval
Docker
There is a frontend/Dockerfile used by the root compose.yml.
If you’re working on self-hosting, prefer running compose from the repo root so the backend/db are aligned with the documented ports/env.
Troubleshooting
NEXT_PUBLIC_API_URL is not set
The API client throws if NEXT_PUBLIC_API_URL is missing.
Fix:
cp .env.example .env.local
# then edit .env.local if your backend URL differs
Frontend loads, but API calls fail (CORS / network errors)
- Confirm backend is up: http://localhost:8000/healthz
- Confirm
NEXT_PUBLIC_API_URLpoints to the correct host/port. - If accessing from another device (LAN), use a reachable backend URL (not
localhost).
Clerk redirects / auth UI shows unexpectedly
Clerk should be off unless you set a real pk_test_... or pk_live_... publishable key.
- Remove/blank
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEYin your.env.localto force Clerk off.
Dev server blocked by origin restrictions
next.config.ts sets allowedDevOrigins for dev proxy safety.
If you see repeated proxy errors (often ECONNRESET), make sure your dev server hostname and browser URL match (e.g. localhost vs 127.0.0.1), and that your origin is included in allowedDevOrigins.
Notes:
- Local dev should work via
http://localhost:3000andhttp://127.0.0.1:3000. - LAN dev should work via the configured LAN IP (e.g.
http://192.168.1.101:3000) only if you bind the dev server to all interfaces (npm run dev:lan). - If you bind Next to
127.0.0.1only, remote LAN clients won’t connect.