docs: resolve merge conflicts with master
This commit is contained in:
96
docs/00-style-guide.md
Normal file
96
docs/00-style-guide.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# Documentation style guide
|
||||
|
||||
This repository aims for a NetBox-like style: clear, technical, and written for working engineers.
|
||||
|
||||
## Voice and tone
|
||||
|
||||
- **Direct and technical.** Prefer short sentences and specific nouns.
|
||||
- **Narrative flow.** Describe how the system behaves, not how the doc was produced.
|
||||
- **Calm, professional tone.** Avoid hype.
|
||||
- **Assume competence, not context.** Define repo-specific terms once, then reuse them.
|
||||
|
||||
## Page structure (default)
|
||||
|
||||
Use a consistent, scan-friendly layout.
|
||||
|
||||
1. **Title**
|
||||
2. **1–3 sentence intro**
|
||||
- What this page covers and who it’s for.
|
||||
3. **Deep dives / Related docs** (optional but common)
|
||||
- Links to more detailed pages.
|
||||
4. **Main content**
|
||||
- Prefer sections that match user intent: “Quickstart”, “How it works”, “Configuration”, “Common workflows”, “Troubleshooting”.
|
||||
5. **Next steps** (optional)
|
||||
- Where to go next.
|
||||
|
||||
## Headings and conventions
|
||||
|
||||
- Prefer **verb-led** headings when describing procedures: “Run migrations”, “Regenerate the client”.
|
||||
- Prefer **intent-led** headings when describing concepts: “How requests flow”, “Auth model”.
|
||||
- Use numbered steps when order matters.
|
||||
- Keep headings short; avoid long parentheticals.
|
||||
|
||||
## Cross-linking
|
||||
|
||||
- Treat the numbered IA pages in `docs/` as **entrypoints**.
|
||||
- Link to deep dives instead of duplicating content.
|
||||
- Use readable link text:
|
||||
- Good: “Deployment guide” → `docs/deployment/README.md`
|
||||
- Avoid: ``docs/deployment/README.md``
|
||||
|
||||
## Link formatting rules
|
||||
|
||||
- Use markdown links: `[Deployment guide](deployment/README.md)`.
|
||||
- Use relative paths that work in GitHub and typical markdown renderers.
|
||||
- Keep code formatting for:
|
||||
- commands (`make check`)
|
||||
- environment variables (`NEXT_PUBLIC_API_URL`)
|
||||
- literal file paths when you mean “this exact file on disk” (not as a navigational link)
|
||||
|
||||
## Avoided phrases (and what to use instead)
|
||||
|
||||
Avoid doc-meta language:
|
||||
|
||||
- Avoid: “evidence basis”, “evidence anchors”, “this page is intentionally…”
|
||||
- Prefer:
|
||||
- “Source of truth: …” (only when it matters)
|
||||
- “See also: …”
|
||||
- Just link the file or section.
|
||||
|
||||
Avoid hedging:
|
||||
|
||||
- Avoid: “likely”, “probably”, “should” (unless it’s a policy decision)
|
||||
- Prefer: state what the code does, and point to the file.
|
||||
|
||||
## Preferred patterns
|
||||
|
||||
- **Start here** blocks for role-based entry.
|
||||
- **Common workflows** sections with copy/paste commands.
|
||||
- **Troubleshooting** sections with symptoms → checks → fixes.
|
||||
- **Footguns** called out explicitly when they can cause outages or confusing behavior.
|
||||
|
||||
## Example rewrites
|
||||
|
||||
### Example 1: remove doc-meta “evidence” language
|
||||
|
||||
Before:
|
||||
> Evidence basis: consolidated from repo root `README.md`, `.github/workflows/ci.yml`, `Makefile`.
|
||||
|
||||
After:
|
||||
> This page describes the development workflow that matches CI: setup, checks, and common local loops.
|
||||
|
||||
### Example 2: prefer readable links over code-formatted paths
|
||||
|
||||
Before:
|
||||
- See `docs/deployment/README.md` for deployment.
|
||||
|
||||
After:
|
||||
- See the [Deployment guide](deployment/README.md).
|
||||
|
||||
### Example 3: replace “first pass” filler with a clear scope boundary
|
||||
|
||||
Before:
|
||||
- Non-goals (first pass)
|
||||
|
||||
After:
|
||||
- Out of scope
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
Mission Control is the **web UI + HTTP API** for operating OpenClaw. It’s where you manage boards, tasks, agents, approvals, and (optionally) gateway connections.
|
||||
|
||||
> Auth note: **Clerk is required for production**. The codebase includes gating so CI/local can run without “real” keys, but real deployments should configure Clerk.
|
||||
> Auth note: Mission Control supports two auth modes: `local` (shared bearer token) and `clerk`.
|
||||
|
||||
## Components
|
||||
|
||||
@@ -48,14 +48,17 @@ Common UI-driven data shapes:
|
||||
- “boards/tasks” views → board/task CRUD + streams.
|
||||
- “activity feed” → activity/events endpoints.
|
||||
|
||||
### 2) Authentication (Clerk)
|
||||
### 2) Authentication (`local` or Clerk)
|
||||
|
||||
- **Frontend**: Clerk is enabled only when a publishable key is present/valid.
|
||||
- Gating/wrappers: `frontend/src/auth/clerkKey.ts`, `frontend/src/auth/clerk.tsx`.
|
||||
- **Frontend → backend**: API calls attach `Authorization: Bearer <token>` when available.
|
||||
- Token injection: `frontend/src/api/mutator.ts` (uses `window.Clerk.session.getToken()`).
|
||||
- **Backend**: validates inbound auth and resolves a user context.
|
||||
- Implementation: `backend/app/core/auth.py` (uses `clerk_backend_api` SDK with `CLERK_SECRET_KEY`).
|
||||
- **Frontend**:
|
||||
- `local`: token entry + token storage (`frontend/src/components/organisms/LocalAuthLogin.tsx`, `frontend/src/auth/localAuth.ts`).
|
||||
- `clerk`: Clerk wrappers/hooks (`frontend/src/auth/clerk.tsx`).
|
||||
- **Frontend → backend**:
|
||||
- API calls attach `Authorization: Bearer <token>` from local mode token or Clerk session token (`frontend/src/api/mutator.ts`).
|
||||
- **Backend**:
|
||||
- `local`: validates `LOCAL_AUTH_TOKEN`.
|
||||
- `clerk`: validates Clerk request state via `clerk_backend_api` + `CLERK_SECRET_KEY`.
|
||||
- Implementation: `backend/app/core/auth.py`.
|
||||
|
||||
### 3) Agent automation surface (`/api/v1/agent/*`)
|
||||
|
||||
|
||||
@@ -68,12 +68,12 @@ Clerk:
|
||||
|
||||
Template: `frontend/.env.example`.
|
||||
|
||||
- `NEXT_PUBLIC_API_URL` (required)
|
||||
|
||||
Clerk:
|
||||
- `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY`
|
||||
- `CLERK_SECRET_KEY`
|
||||
- redirect URLs (`NEXT_PUBLIC_CLERK_*`)
|
||||
| Variable | Required? | Purpose | Default / example | Footguns |
|
||||
|---|---:|---|---|---|
|
||||
| `NEXT_PUBLIC_API_URL` | **yes** | Backend base URL used by the browser | `http://localhost:8000` | Must be browser-reachable |
|
||||
| `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` | **yes** | Enables Clerk in the frontend | (none) | Must be a real publishable key |
|
||||
| `NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL` | optional | Fallback redirect | `/boards` | — |
|
||||
| `NEXT_PUBLIC_CLERK_AFTER_SIGN_OUT_URL` | optional | Post-logout redirect | `/` | — |
|
||||
|
||||
## Minimal dev configuration
|
||||
|
||||
@@ -103,6 +103,11 @@ Evidence: `backend/app/main.py`, `backend/app/core/config.py`.
|
||||
- `CORS_ORIGINS` is a comma-separated list.
|
||||
- It must include the frontend origin (e.g. `http://localhost:3000`) or browser requests will fail.
|
||||
|
||||
## Common footguns
|
||||
|
||||
- **Frontend env template vs runtime env**: `frontend/.env.example` is a template and `compose.yml` intentionally does **not** load it at runtime. Use user-managed `frontend/.env` (for Compose) or `frontend/.env.local` (for Next dev).
|
||||
- **`NEXT_PUBLIC_API_URL` reachability**: must work from the browser’s network context (host), not only from within the Docker network.
|
||||
|
||||
## Troubleshooting config issues
|
||||
|
||||
- UI loads but API calls fail / Activity feed blank → `NEXT_PUBLIC_API_URL` is missing/incorrect.
|
||||
|
||||
@@ -44,21 +44,56 @@ Evidence: `backend/app/main.py` includes routers from `backend/app/api/*`.
|
||||
|---|---|---|
|
||||
| `activity.py` | `/activity` | Activity listing and task-comment feed endpoints. |
|
||||
| `agent.py` | `/agent` | Agent-scoped API routes for board operations and gateway coordination. |
|
||||
| `agents.py` | `/agents` | Agent lifecycle and streaming endpoints. |
|
||||
| `approvals.py` | `/boards/{board_id}/approvals` | Approval list/create/update + streaming. |
|
||||
| `auth.py` | `/auth` | Auth bootstrap endpoints. |
|
||||
| `board_group_memory.py` | `/board-groups/{group_id}/memory` and `/boards/{board_id}/group-memory` | Board-group memory CRUD + streaming. |
|
||||
| `board_groups.py` | `/board-groups` | Board group CRUD + snapshot + heartbeat apply. |
|
||||
| `board_memory.py` | `/boards/{board_id}/memory` | Board memory CRUD + streaming. |
|
||||
| `board_onboarding.py` | `/boards/{board_id}/onboarding` | Onboarding flows (user+agent). |
|
||||
| `boards.py` | `/boards` | Board CRUD + snapshots. |
|
||||
| `gateway.py` | `/gateways` | Gateway session inspection APIs (org admin). |
|
||||
| `gateways.py` | `/gateways` | Gateway CRUD + templates sync (org admin). |
|
||||
| `metrics.py` | `/metrics` | Dashboard metrics. |
|
||||
| `organizations.py` | `/organizations` | Org + invites/membership flows. |
|
||||
| `souls_directory.py` | `/souls-directory` | Search/fetch souls directory entries. |
|
||||
| `tasks.py` | `/boards/{board_id}/tasks` | Task CRUD + comments + streaming. |
|
||||
| `users.py` | `/users` | User self-service profile endpoints. |
|
||||
| `agents.py` | `/agents` | Thin API wrappers for async agent lifecycle operations. |
|
||||
| `approvals.py` | `/boards/{board_id}/approvals` | Approval listing, streaming, creation, and update endpoints. |
|
||||
| `auth.py` | `/auth` | Authentication bootstrap endpoints for the Mission Control API. |
|
||||
| `board_group_memory.py` | `/board-groups/{group_id}/memory` and `/boards/{board_id}/group-memory` | Board-group memory CRUD and streaming endpoints. |
|
||||
| `board_groups.py` | `/board-groups` | Board group CRUD, snapshot, and heartbeat endpoints. |
|
||||
| `board_memory.py` | `/boards/{board_id}/memory` | Board memory CRUD and streaming endpoints. |
|
||||
| `board_onboarding.py` | `/boards/{board_id}/onboarding` | Board onboarding endpoints for user/agent collaboration. |
|
||||
| `boards.py` | `/boards` | Board CRUD and snapshot endpoints. |
|
||||
| `gateway.py` | `/gateways` | Thin gateway session-inspection API wrappers. |
|
||||
| `gateways.py` | `/gateways` | Thin API wrappers for gateway CRUD and template synchronization. |
|
||||
| `metrics.py` | `/metrics` | Dashboard metric aggregation endpoints. |
|
||||
| `organizations.py` | `/organizations` | Organization management endpoints and membership/invite flows. |
|
||||
| `souls_directory.py` | `/souls-directory` | API routes for searching and fetching souls-directory markdown entries. |
|
||||
| `tasks.py` | `/boards/{board_id}/tasks` | Task API routes for listing, streaming, and mutating board tasks. |
|
||||
| `users.py` | `/users` | User self-service API endpoints for profile retrieval and updates. |
|
||||
|
||||
## Backend API layer notes (how modules are organized)
|
||||
|
||||
Evidence: `backend/app/main.py`, `backend/app/api/*`, `backend/app/api/deps.py`.
|
||||
|
||||
### Conventions
|
||||
|
||||
- Each file under `backend/app/api/*` typically declares an `APIRouter` (`router = APIRouter(...)`) and defines endpoints with decorators like `@router.get(...)`, `@router.post(...)`, etc.
|
||||
- Board-scoped modules embed `{board_id}` in the prefix (e.g. `/boards/{board_id}/tasks`).
|
||||
- Streaming endpoints usually expose **SSE** endpoints at `.../stream` (see `sse-starlette` usage).
|
||||
|
||||
### Where key behaviors live
|
||||
|
||||
- **Router wiring / base prefix**: `backend/app/main.py` mounts these routers under `/api/v1/*`.
|
||||
- **Auth / access control** is mostly expressed through dependencies (see `backend/app/api/deps.py`):
|
||||
- `require_admin_auth` — require an authenticated *admin user*.
|
||||
- `require_admin_or_agent` — allow either an admin user or an authenticated agent.
|
||||
- `get_board_for_actor_read` / `get_board_for_actor_write` — enforce board access for the calling actor.
|
||||
- `require_org_member` / `require_org_admin` — enforce org membership/admin for user callers.
|
||||
- **Agent-only surface**: `backend/app/api/agent.py` uses `get_agent_auth_context` (X-Agent-Token) and contains board/task/memory endpoints specifically for automation.
|
||||
|
||||
### Module-by-module map (prefix, key endpoints, and pointers)
|
||||
|
||||
This is a “where to look” index, not a full OpenAPI dump. For exact parameters and response shapes, see:
|
||||
- route module file (`backend/app/api/<module>.py`)
|
||||
- schemas (`backend/app/schemas/*`)
|
||||
- models (`backend/app/models/*`)
|
||||
- services (`backend/app/services/*`)
|
||||
|
||||
| Module | Prefix (under `/api/v1`) | Key endpoints (examples) | Main deps / auth | Pointers (schemas/models/services) |
|
||||
|---|---|---|---|---|
|
||||
| `activity.py` | `/activity` | `GET /activity` (events); `GET /activity/task-comments` + `/stream` | `require_admin_or_agent`, `require_org_member` | `app/models/activity_events.py`, `app/schemas/activity_events.py` |
|
||||
| `agent.py` | `/agent` | agent automation surface: boards/tasks/memory + gateway coordination | `get_agent_auth_context` (X-Agent-Token) | `backend/app/core/agent_auth.py`, `backend/app/services/openclaw/*` |
|
||||
| `agents.py` | `/agents` | agent lifecycle + SSE stream + heartbeat | org-admin gated for user callers; some endpoints allow agent access via deps | `app/schemas/agents.py`, `app/services/openclaw/provisioning_db.py` |
|
||||
| `approvals.py` | `/boards/{board_id}/approvals` | list/create/update approvals + `/stream` | `require_admin_or_agent` + board access deps | `app/models/approvals.py`, `app/schemas/approvals.py` |
|
||||
|
||||
## Where authorization is enforced
|
||||
|
||||
|
||||
137
docs/12-backend-core.md
Normal file
137
docs/12-backend-core.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# Backend core modules (auth/config/logging/errors)
|
||||
|
||||
> Evidence basis: repo https://github.com/abhi1693/openclaw-mission-control @ commit `c3490630a4503d9c8142aaa3abf542e0d00b5035`.
|
||||
|
||||
This page documents the backend “core” layer under `backend/app/core/*` plus the API dependency module `backend/app/api/deps.py`.
|
||||
|
||||
It’s written for maintainers who need to answer:
|
||||
|
||||
- “Where does configuration come from?”
|
||||
- “How do user vs agent auth work?”
|
||||
- “Where are authorization decisions enforced?”
|
||||
- “What’s the error envelope / request-id behavior?”
|
||||
- “How is logging structured and how do I get request-context in logs?”
|
||||
|
||||
## Start here (reading order)
|
||||
|
||||
1. `backend/app/core/config.py` — settings + env file loading
|
||||
2. `backend/app/core/logging.py` — structured logging + request context
|
||||
3. `backend/app/core/error_handling.py` — request-id middleware + exception envelope
|
||||
4. `backend/app/core/auth.py` — Clerk/user auth resolution
|
||||
5. `backend/app/core/agent_auth.py` — agent token auth resolution
|
||||
6. `backend/app/api/deps.py` — how routes declare and enforce access
|
||||
|
||||
## Configuration: loading & precedence
|
||||
|
||||
**Primary file:** `backend/app/core/config.py`
|
||||
|
||||
Key facts:
|
||||
- Uses `pydantic-settings` (`BaseSettings`) to load typed settings from environment.
|
||||
- Env files are loaded regardless of current working directory:
|
||||
- `backend/.env` (via `DEFAULT_ENV_FILE`)
|
||||
- then `.env` (repo root) as an additional source
|
||||
- See `Settings.model_config.env_file=[DEFAULT_ENV_FILE, ".env"]`.
|
||||
- Unknown env vars are ignored (`extra="ignore"`).
|
||||
|
||||
Notable settings (security-sensitive in **bold**):
|
||||
- `DATABASE_URL` / `database_url`
|
||||
- `CORS_ORIGINS` / `cors_origins`
|
||||
- `DB_AUTO_MIGRATE` / `db_auto_migrate`
|
||||
- **`CLERK_SECRET_KEY` / `clerk_secret_key`** (must be non-empty; validator enforces it)
|
||||
- `CLERK_API_URL`, `CLERK_VERIFY_IAT`, `CLERK_LEEWAY`
|
||||
- logging knobs: `LOG_LEVEL`, `LOG_FORMAT`, `LOG_USE_UTC`, `REQUEST_LOG_SLOW_MS`, `REQUEST_LOG_INCLUDE_HEALTH`
|
||||
|
||||
### Deployment implication
|
||||
|
||||
- If a deployment accidentally starts the backend with an empty/placeholder `CLERK_SECRET_KEY`, the backend will fail settings validation at startup.
|
||||
|
||||
## Auth model split
|
||||
|
||||
The backend supports two top-level actor types:
|
||||
|
||||
- **User** (human UI / admin) — resolved from the `Authorization: Bearer <token>` header via Clerk.
|
||||
- **Agent** (automation) — resolved from `X-Agent-Token: <token>` (and optionally `Authorization: Bearer <token>` for agent callers).
|
||||
|
||||
### User auth (Clerk) — `backend/app/core/auth.py`
|
||||
|
||||
What it does:
|
||||
- Uses the `clerk_backend_api` SDK to authenticate requests (`authenticate_request(...)`) using `CLERK_SECRET_KEY`.
|
||||
- Resolves a `AuthContext` containing `actor_type="user"` and a `User` model instance.
|
||||
- The module includes helpers to fetch user profile details from Clerk (`_fetch_clerk_profile`) and to delete a Clerk user (`delete_clerk_user`).
|
||||
|
||||
Security-sensitive notes:
|
||||
- Treat `CLERK_SECRET_KEY` as a credential; never log it.
|
||||
- This code calls Clerk API endpoints over the network (timeouts and error handling matter).
|
||||
|
||||
### Agent auth (token hash) — `backend/app/core/agent_auth.py`
|
||||
|
||||
What it does:
|
||||
- Requires a token header for protected agent endpoints:
|
||||
- Primary header: `X-Agent-Token`
|
||||
- Optional parsing: `Authorization: Bearer ...` (only in `get_agent_auth_context`, and only if `accept_authorization=True`)
|
||||
- Validates token by comparing it against stored `agent_token_hash` values in the DB (`verify_agent_token`).
|
||||
- “Touches” agent presence (`last_seen_at`, `status`) on authenticated requests.
|
||||
- For safe methods (`GET/HEAD/OPTIONS`), it commits immediately so read-only polling still shows the agent as online.
|
||||
|
||||
Security-sensitive notes:
|
||||
- Token verification iterates over agents with a token hash. If this grows large, consider indexing/lookup strategy.
|
||||
- Never echo full tokens in logs; current code logs only a prefix on invalid tokens.
|
||||
|
||||
## Authorization enforcement: `backend/app/api/deps.py`
|
||||
|
||||
This module is the primary “policy wiring” for most routes.
|
||||
|
||||
Key concepts:
|
||||
|
||||
- `require_admin_auth(...)`
|
||||
- Requires an authenticated *admin user*.
|
||||
- `require_admin_or_agent(...)` → returns `ActorContext`
|
||||
- Allows either:
|
||||
- admin user (user auth via Clerk), or
|
||||
- authenticated agent (agent auth via X-Agent-Token).
|
||||
|
||||
Board/task access patterns:
|
||||
- `get_board_for_actor_read` / `get_board_for_actor_write`
|
||||
- Enforces that the caller (user or agent) has the correct access to the board.
|
||||
- Agent access is restricted if the agent is bound to a specific board (`agent.board_id`).
|
||||
- `get_task_or_404`
|
||||
- Loads a task and ensures it belongs to the requested board.
|
||||
|
||||
Org access patterns (user callers):
|
||||
- `require_org_member` and `require_org_admin`
|
||||
- Resolve/require active org membership.
|
||||
- Provide an `OrganizationContext` with `organization` + `member`.
|
||||
|
||||
Maintainer tip:
|
||||
- When debugging a “why is this 403/401?”, start by checking the route’s dependency stack (in the route module) and trace through the relevant dependency in `deps.py`.
|
||||
|
||||
## Logging: structure + request context
|
||||
|
||||
**Primary file:** `backend/app/core/logging.py`
|
||||
|
||||
Highlights:
|
||||
- Defines a custom TRACE level (`TRACE_LEVEL = 5`).
|
||||
- Uses `contextvars` to carry `request_id`, `method`, and `path` across async tasks.
|
||||
- `AppLogFilter` injects `app`, `version`, and request context into each log record.
|
||||
- Supports JSON output (`JsonFormatter`) and key=value (`KeyValueFormatter`) formats.
|
||||
|
||||
Where request context gets set:
|
||||
- `backend/app/core/error_handling.py` middleware calls:
|
||||
- `set_request_id(...)`
|
||||
- `set_request_route_context(method, path)`
|
||||
|
||||
## Error envelope + request-id
|
||||
|
||||
**Primary file:** `backend/app/core/error_handling.py`
|
||||
|
||||
Key behaviors:
|
||||
- Installs a `RequestIdMiddleware` (ASGI) that:
|
||||
- Accepts client-provided `X-Request-Id` or generates one.
|
||||
- Adds `X-Request-Id` to the response.
|
||||
- Emits structured “http.request.*” logs, including “slow request” warnings.
|
||||
- Error responses include `request_id` when available:
|
||||
- Validation errors (`422`) return `{detail: <errors>, request_id: ...}`.
|
||||
- Other HTTP errors are wrapped similarly.
|
||||
|
||||
Maintainer tip:
|
||||
- When debugging incidents, ask for the `X-Request-Id` from the client and use it to locate backend logs quickly.
|
||||
@@ -10,6 +10,9 @@ This folder is the canonical documentation set for Mission Control.
|
||||
|
||||
## Table of contents (IA)
|
||||
|
||||
- [Style guide](00-style-guide.md)
|
||||
|
||||
|
||||
1. [Overview](01-overview.md)
|
||||
2. [Quickstart](02-quickstart.md)
|
||||
3. [Development](03-development.md)
|
||||
@@ -17,6 +20,7 @@ This folder is the canonical documentation set for Mission Control.
|
||||
5. [Architecture](05-architecture.md)
|
||||
6. [Configuration](06-configuration.md)
|
||||
7. [API reference](07-api-reference.md)
|
||||
- [Frontend API + auth modules](frontend-api-auth.md)
|
||||
8. [Agents & skills](08-agents-and-skills.md)
|
||||
9. [Ops / runbooks](09-ops-runbooks.md)
|
||||
10. [Troubleshooting](10-troubleshooting.md)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Mission Control is the **web UI + HTTP API** for operating OpenClaw. It’s where you manage boards, tasks, agents, approvals, and (optionally) gateway connections.
|
||||
|
||||
> Auth note: **Clerk is required for now** (current product direction). The codebase includes gating so CI/local can run with placeholders, but real deployments should configure Clerk.
|
||||
> Auth note: Mission Control supports two auth modes: `local` (shared bearer token) and `clerk`.
|
||||
|
||||
At a high level:
|
||||
- The **frontend** is a Next.js app used by humans.
|
||||
@@ -29,10 +29,11 @@ flowchart LR
|
||||
- Routes/pages: `frontend/src/app/*` (Next.js App Router)
|
||||
- API utilities: `frontend/src/lib/*` and `frontend/src/api/*`
|
||||
|
||||
**Auth (Clerk, required)**
|
||||
- Clerk is required for real deployments and currently required by backend config (see `backend/app/core/config.py`).
|
||||
- Frontend uses Clerk when keys are configured; see `frontend/src/auth/clerkKey.ts` and `frontend/src/auth/clerk.tsx`.
|
||||
- Backend authenticates requests using the Clerk SDK and `CLERK_SECRET_KEY`; see `backend/app/core/auth.py`.
|
||||
**Auth (`local` or Clerk)**
|
||||
- `local` mode authenticates a shared bearer token (`LOCAL_AUTH_TOKEN`) and resolves a local user context.
|
||||
- `clerk` mode verifies Clerk JWTs using `CLERK_SECRET_KEY`.
|
||||
- Frontend mode switch + wrappers: `frontend/src/auth/clerk.tsx`, `frontend/src/auth/localAuth.ts`, and `frontend/src/components/providers/AuthProvider.tsx`.
|
||||
- Backend mode switch: `backend/app/core/config.py` and `backend/app/core/auth.py`.
|
||||
|
||||
|
||||
### Backend (FastAPI)
|
||||
@@ -64,9 +65,13 @@ Mission Control can call into an OpenClaw Gateway over WebSockets.
|
||||
2. Frontend calls backend endpoints under `/api/v1/*`.
|
||||
3. Backend reads/writes Postgres.
|
||||
|
||||
### Auth (Clerk — required)
|
||||
- **Frontend** uses Clerk when keys are configured (see `frontend/src/auth/*`).
|
||||
- **Backend** authenticates requests using the Clerk SDK and `CLERK_SECRET_KEY` (see `backend/app/core/auth.py`).
|
||||
### Auth (`local` or Clerk)
|
||||
- **Frontend**:
|
||||
- `local`: token entry screen + session storage token (`frontend/src/components/organisms/LocalAuthLogin.tsx`, `frontend/src/auth/localAuth.ts`).
|
||||
- `clerk`: Clerk wrappers/hooks (`frontend/src/auth/clerk.tsx`).
|
||||
- **Backend**:
|
||||
- `local`: validates `Authorization: Bearer <LOCAL_AUTH_TOKEN>`.
|
||||
- `clerk`: validates Clerk request state with SDK + `CLERK_SECRET_KEY`.
|
||||
### Agent access (X-Agent-Token)
|
||||
Automation/agents can use the “agent” API surface:
|
||||
- Endpoints under `/api/v1/agent/*` (router: `backend/app/api/agent.py`).
|
||||
@@ -92,7 +97,7 @@ Backend:
|
||||
Frontend:
|
||||
- `frontend/src/app/` — Next.js routes
|
||||
- `frontend/src/components/` — UI components
|
||||
- `frontend/src/auth/` — Clerk gating/wrappers
|
||||
- `frontend/src/auth/` — auth mode helpers (`clerk` and `local`)
|
||||
- `frontend/src/lib/` — utilities + API base
|
||||
|
||||
## Where to start reading code
|
||||
@@ -106,7 +111,7 @@ Backend:
|
||||
Frontend:
|
||||
1. `frontend/src/app/*` — main UI routes
|
||||
2. `frontend/src/lib/api-base.ts` — backend calls
|
||||
3. `frontend/src/auth/*` — Clerk integration (gated for CI/local)
|
||||
3. `frontend/src/auth/*` — auth mode integration (`local` + Clerk)
|
||||
|
||||
## Related docs
|
||||
- Self-host (Docker Compose): see repo root README: [Quick start (self-host with Docker Compose)](../../README.md#quick-start-self-host-with-docker-compose)
|
||||
|
||||
@@ -15,7 +15,9 @@ When running Compose, you get:
|
||||
- Health check: `GET /healthz`
|
||||
- **Frontend UI** (Next.js) on `http://localhost:${FRONTEND_PORT:-3000}`
|
||||
|
||||
Auth (Clerk) is **required** right now. You must configure Clerk keys for the frontend and backend (`CLERK_SECRET_KEY`).
|
||||
Auth is configurable per deployment:
|
||||
- `AUTH_MODE=local` (self-host default; shared bearer token)
|
||||
- `AUTH_MODE=clerk` (Clerk JWT auth; backend requires `CLERK_SECRET_KEY`)
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -30,6 +32,9 @@ From repo root:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
|
||||
# REQUIRED for local mode:
|
||||
# set LOCAL_AUTH_TOKEN in .env to a non-placeholder value with at least 50 characters.
|
||||
|
||||
docker compose -f compose.yml --env-file .env up -d --build
|
||||
```
|
||||
|
||||
@@ -86,7 +91,7 @@ These persist across `docker compose down`.
|
||||
### Root `.env` (Compose)
|
||||
|
||||
- Copy the template: `cp .env.example .env`
|
||||
- Edit values as needed (ports, Clerk URLs/keys, etc.)
|
||||
- Edit values as needed (ports, auth mode, tokens, API URL, etc.)
|
||||
|
||||
Compose is invoked with:
|
||||
|
||||
@@ -110,49 +115,57 @@ Instead, it supports an optional user-managed env file:
|
||||
|
||||
If present, Compose will load it.
|
||||
|
||||
## Clerk (auth) notes
|
||||
## Authentication modes
|
||||
|
||||
Clerk is currently required.
|
||||
Mission Control supports two deployment auth modes:
|
||||
|
||||
### Frontend (Clerk keys)
|
||||
- `AUTH_MODE=local`: shared bearer token auth (self-host default)
|
||||
- `AUTH_MODE=clerk`: Clerk JWT auth
|
||||
|
||||
Create `frontend/.env` (this file is **not** committed; `compose.yml` loads it if present):
|
||||
### Local mode (self-host default)
|
||||
|
||||
Set in `.env` (repo root):
|
||||
|
||||
```env
|
||||
# Frontend → Backend
|
||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
||||
|
||||
# Frontend → Clerk
|
||||
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=YOUR_PUBLISHABLE_KEY
|
||||
CLERK_SECRET_KEY=YOUR_SECRET_KEY
|
||||
|
||||
# Optional (but recommended) redirects
|
||||
NEXT_PUBLIC_CLERK_SIGN_IN_FORCE_REDIRECT_URL=/boards
|
||||
NEXT_PUBLIC_CLERK_SIGN_UP_FORCE_REDIRECT_URL=/boards
|
||||
NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL=/boards
|
||||
NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL=/boards
|
||||
AUTH_MODE=local
|
||||
LOCAL_AUTH_TOKEN=replace-with-random-token-at-least-50-characters
|
||||
```
|
||||
|
||||
### Backend (auth)
|
||||
Set frontend mode (optional override in `frontend/.env`):
|
||||
|
||||
The backend authenticates requests using the Clerk SDK and **`CLERK_SECRET_KEY`** (see `backend/app/core/auth.py`).
|
||||
```env
|
||||
NEXT_PUBLIC_AUTH_MODE=local
|
||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
||||
```
|
||||
|
||||
Create `backend/.env` (this file is **not** committed) with at least:
|
||||
Users enter `LOCAL_AUTH_TOKEN` in the local login screen.
|
||||
|
||||
### Clerk mode
|
||||
|
||||
Set in `.env` (repo root):
|
||||
|
||||
```env
|
||||
AUTH_MODE=clerk
|
||||
```
|
||||
|
||||
Create `backend/.env` with at least:
|
||||
|
||||
```env
|
||||
CLERK_SECRET_KEY=sk_test_your_real_key
|
||||
|
||||
# Optional tuning
|
||||
CLERK_API_URL=https://api.clerk.com
|
||||
CLERK_VERIFY_IAT=true
|
||||
CLERK_LEEWAY=10.0
|
||||
```
|
||||
|
||||
Then either:
|
||||
1) update `compose.yml` to load `backend/.env` (recommended), or
|
||||
2) pass the values via `services.backend.environment`.
|
||||
Create `frontend/.env` with at least:
|
||||
|
||||
**Security:** treat `CLERK_SECRET_KEY` like a password. Do not commit it.
|
||||
```env
|
||||
NEXT_PUBLIC_AUTH_MODE=clerk
|
||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
||||
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_your_real_key
|
||||
```
|
||||
|
||||
**Security:** treat `LOCAL_AUTH_TOKEN` and `CLERK_SECRET_KEY` like passwords. Do not commit them.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
||||
109
docs/frontend-api-auth.md
Normal file
109
docs/frontend-api-auth.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# Frontend API client and auth integration
|
||||
|
||||
This page documents the frontend integration points you’ll touch when changing how the UI talks to the backend or how auth is applied.
|
||||
|
||||
## Related docs
|
||||
|
||||
- [Architecture](05-architecture.md)
|
||||
- [Configuration](06-configuration.md)
|
||||
- [API reference](07-api-reference.md)
|
||||
|
||||
## API base URL
|
||||
|
||||
The frontend uses `NEXT_PUBLIC_API_URL` as the single source of truth for where to send API requests.
|
||||
|
||||
- Code: `frontend/src/lib/api-base.ts`
|
||||
- Behavior:
|
||||
- reads `process.env.NEXT_PUBLIC_API_URL`
|
||||
- normalizes by trimming trailing slashes
|
||||
- throws early if missing/invalid
|
||||
|
||||
In Docker Compose, `compose.yml` sets `NEXT_PUBLIC_API_URL` both:
|
||||
- as a **build arg** (for `next build`), and
|
||||
- as a **runtime env var**.
|
||||
|
||||
## API client layout
|
||||
|
||||
### Generated client
|
||||
|
||||
- Location: `frontend/src/api/generated/*`
|
||||
- Generator: **Orval**
|
||||
- Config: `frontend/orval.config.ts`
|
||||
- Script: `cd frontend && npm run api:gen`
|
||||
- Convenience target: `make api-gen`
|
||||
|
||||
By default, Orval reads the backend OpenAPI schema from:
|
||||
- `ORVAL_INPUT` (if set), otherwise
|
||||
- `http://127.0.0.1:8000/openapi.json`
|
||||
|
||||
Output details (from `orval.config.ts`):
|
||||
- Mode: `tags-split`
|
||||
- Target index: `frontend/src/api/generated/index.ts`
|
||||
- Schemas: `frontend/src/api/generated/model`
|
||||
- Client: `react-query`
|
||||
- All requests go through the custom mutator below.
|
||||
|
||||
### Custom fetch / mutator
|
||||
|
||||
All generated requests go through:
|
||||
|
||||
- Code: `frontend/src/api/mutator.ts`
|
||||
- What it does:
|
||||
- resolves `NEXT_PUBLIC_API_URL` and builds the full request URL
|
||||
- sets `Content-Type: application/json` when there’s a body
|
||||
- injects `Authorization: Bearer <token>` when a Clerk session token is available
|
||||
- converts non-2xx responses into a typed `ApiError` (status + parsed response)
|
||||
|
||||
## Auth enablement and token injection
|
||||
|
||||
### Clerk enablement (publishable key gating)
|
||||
|
||||
Clerk is enabled in the frontend only when `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` looks valid.
|
||||
|
||||
- Gating helper (dependency-free): `frontend/src/auth/clerkKey.ts`
|
||||
- UI-safe wrappers/hooks: `frontend/src/auth/clerk.tsx`
|
||||
- provides `SignedIn`, `SignedOut`, `SignInButton`, `SignOutButton`, `useUser`, and `useAuth`
|
||||
- returns safe fallbacks when Clerk is disabled (to allow secretless builds/prerender)
|
||||
|
||||
### Token injection
|
||||
|
||||
When the UI makes an API request, the mutator attempts to read a token from the Clerk session:
|
||||
|
||||
- Code: `frontend/src/api/mutator.ts` (`resolveClerkToken()`)
|
||||
- If a token is available, the request includes:
|
||||
- `Authorization: Bearer <token>`
|
||||
|
||||
### Route protection (middleware)
|
||||
|
||||
Request-time route protection is implemented via Next.js middleware:
|
||||
|
||||
- Code: `frontend/src/proxy.ts`
|
||||
- Behavior:
|
||||
- when Clerk is enabled: uses `clerkMiddleware()` to enforce auth on non-public routes
|
||||
- when Clerk is disabled: passes all requests through
|
||||
|
||||
## Common workflows
|
||||
|
||||
### Update the backend API and regenerate the client
|
||||
|
||||
1. Run the backend so OpenAPI is available:
|
||||
|
||||
```bash
|
||||
# from repo root
|
||||
cp backend/.env.example backend/.env
|
||||
make backend-migrate
|
||||
cd backend && uv run uvicorn app.main:app --reload --port 8000
|
||||
```
|
||||
|
||||
2. Regenerate the client:
|
||||
|
||||
```bash
|
||||
# from repo root
|
||||
make api-gen
|
||||
|
||||
# or from frontend/
|
||||
ORVAL_INPUT=http://127.0.0.1:8000/openapi.json npm run api:gen
|
||||
```
|
||||
|
||||
3. Review diffs under `frontend/src/api/generated/*`.
|
||||
|
||||
@@ -59,8 +59,10 @@ Recommended approach:
|
||||
|
||||
Secrets guidelines:
|
||||
|
||||
- **Clerk auth is required for now**: you must configure Clerk keys/JWKS for the app to work.
|
||||
- Never commit Clerk secret key.
|
||||
- Choose auth mode explicitly:
|
||||
- `AUTH_MODE=local`: set `LOCAL_AUTH_TOKEN` to a random value with at least 50 characters
|
||||
- `AUTH_MODE=clerk`: configure Clerk keys
|
||||
- Never commit `LOCAL_AUTH_TOKEN` or Clerk secret key.
|
||||
- Prefer passing secrets as environment variables from the host (or use Docker secrets if you later
|
||||
migrate to Swarm/K8s).
|
||||
- Rotate secrets if they ever hit logs.
|
||||
@@ -75,7 +77,7 @@ sudo git clone https://github.com/abhi1693/openclaw-mission-control.git mission-
|
||||
cd mission-control
|
||||
|
||||
cp .env.example .env
|
||||
# edit .env with real values (domains, Clerk keys, etc.)
|
||||
# edit .env with real values (domains, auth mode + secrets, etc.)
|
||||
|
||||
docker compose -f compose.yml --env-file .env up -d --build
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user