2026-02-07 15:38:22 +00:00
# Mission Control Frontend (`frontend/`)
2026-02-01 22:25:28 +05:30
2026-02-07 15:38:22 +00:00
This package is the **Next.js ** web UI for OpenClaw Mission Control.
2026-02-01 22:25:28 +05:30
2026-02-07 15:38:22 +00:00
- Talks to the Mission Control **backend ** over HTTP (typically `http://localhost:8000` ).
- Uses **React Query ** for data fetching.
2026-02-11 19:10:23 +05:30
- Supports two auth modes:
- **local** shared bearer token mode (self-host default)
- **clerk** mode
2026-02-07 15:38:22 +00:00
## Prerequisites
- Node.js (recommend **18+ ** ) and npm
- Backend running locally (see `../backend/README.md` if present) **or ** run the stack via Docker Compose from repo root.
## Local development
From `frontend/` :
2026-02-01 22:25:28 +05:30
```bash
2026-02-07 15:38:22 +00:00
npm install
# set env vars (see below)
cp .env.example .env.local
2026-02-01 22:25:28 +05:30
npm run dev
```
2026-02-07 15:38:22 +00:00
Open http://localhost:3000.
### LAN development
To bind Next dev server to all interfaces:
```bash
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`
2026-03-03 02:40:28 +05:30
Base URL of the backend API (or `auto` ).
2026-02-07 15:38:22 +00:00
2026-03-03 02:40:28 +05:30
- Default: `auto` (resolved in browser as `http(s)://<current-host>:8000` )
2026-02-07 15:38:22 +00:00
- Used by the generated API client and helpers (see `src/lib/api-base.ts` and `src/api/mutator.ts` ).
Example:
```env
2026-03-03 02:40:28 +05:30
NEXT_PUBLIC_API_URL=auto
2026-02-07 15:38:22 +00:00
```
2026-02-11 19:10:23 +05:30
### Authentication mode
2026-02-07 15:38:22 +00:00
2026-02-11 19:10:23 +05:30
Set `NEXT_PUBLIC_AUTH_MODE` to one of:
2026-02-07 15:38:22 +00:00
2026-02-11 19:10:23 +05:30
- `local` (default for self-host)
- `clerk`
2026-02-07 15:38:22 +00:00
2026-02-11 19:10:23 +05:30
For `local` mode:
- users enter the token in the local login screen
- requests use that token as `Authorization: Bearer ...`
For `clerk` mode, configure:
2026-02-07 15:38:22 +00:00
- `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY`
2026-02-11 19:13:23 +05:30
- optional `NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL`
- optional `NEXT_PUBLIC_CLERK_AFTER_SIGN_OUT_URL`
2026-02-07 15:38:22 +00:00
## 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), otherwise
- `http://127.0.0.1:8000/openapi.json`
Example:
```bash
# 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/json` when there is a body and you didn’ t specify a content type
2026-02-11 19:10:23 +05:30
- add `Authorization: Bearer <token>` automatically from local mode token or Clerk session
2026-02-07 15:38:22 +00:00
- parse errors into an `ApiError` with status + parsed response body
2026-02-12 08:00:21 +00:00
## Mobile / responsive UI validation
When changing UI intended to be mobile-ready, validate in Chrome (or similar) using the device toolbar at common widths (e.g. **320px ** , **375px ** , **768px ** ).
Quick checklist:
2026-02-13 00:31:32 +05:30
2026-02-12 08:00:21 +00:00
- No horizontal scroll
- Primary actions reachable without precision taps
- Focus rings visible when tabbing
- Modals/popovers not clipped
2026-02-07 15:38:22 +00:00
## Common commands
From `frontend/` :
```bash
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` .
2026-02-10 16:05:49 +05:30
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.
2026-02-07 15:38:22 +00:00
## Troubleshooting
2026-03-03 02:40:28 +05:30
### `NEXT_PUBLIC_API_URL` and remote hosts
2026-02-07 15:38:22 +00:00
2026-03-03 02:40:28 +05:30
If unset or set to `auto` , the client uses `http(s)://<current-host>:8000` .
If your backend is on a different host/port, set `NEXT_PUBLIC_API_URL` explicitly.
2026-02-07 15:38:22 +00:00
Fix:
```bash
cp .env.example .env.local
# then edit .env.local if your backend URL differs
```
2026-02-01 22:25:28 +05:30
2026-02-07 15:38:22 +00:00
### Frontend loads, but API calls fail (CORS / network errors)
2026-02-01 22:25:28 +05:30
2026-02-07 15:38:22 +00:00
- Confirm backend is up: http://localhost:8000/healthz
- Confirm `NEXT_PUBLIC_API_URL` points to the correct host/port.
- If accessing from another device (LAN), use a reachable backend URL (not `localhost` ).
2026-02-01 22:25:28 +05:30
2026-02-11 19:10:23 +05:30
### Wrong auth mode UI
2026-02-01 22:25:28 +05:30
2026-02-11 19:10:23 +05:30
- Ensure `NEXT_PUBLIC_AUTH_MODE` matches backend `AUTH_MODE` .
- For local mode, set `NEXT_PUBLIC_AUTH_MODE=local` .
- For Clerk mode, set `NEXT_PUBLIC_AUTH_MODE=clerk` and a real Clerk publishable key.
2026-02-01 22:25:28 +05:30
2026-02-07 15:38:22 +00:00
### Dev server blocked by origin restrictions
2026-02-01 22:25:28 +05:30
2026-02-07 19:10:05 +00:00
`next.config.ts` sets `allowedDevOrigins` for dev proxy safety.
2026-02-01 22:25:28 +05:30
2026-02-07 19:17:53 +00:00
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` .
2026-02-01 22:25:28 +05:30
2026-02-07 19:17:53 +00:00
Notes:
2026-02-08 21:17:26 +05:30
2026-02-07 19:17:53 +00:00
- Local dev should work via `http://localhost:3000` and `http://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.1` only, remote LAN clients won’ t connect.