335 lines
8.3 KiB
Markdown
335 lines
8.3 KiB
Markdown
|
|
# 02. Component Breakdown And API Contracts
|
||
|
|
|
||
|
|
## 1. Component Breakdown
|
||
|
|
|
||
|
|
## 1.1 Control Plane Components
|
||
|
|
|
||
|
|
| Component | Runtime | Responsibility | Notes |
|
||
|
|
|---|---|---|---|
|
||
|
|
| Hub Web/API | Next.js 16 + Node | Admin UI, customer portal, public APIs, tenant APIs | Keep existing app, add route groups and API contracts below. |
|
||
|
|
| Billing Engine | Node worker + Prisma | Usage aggregation, pool accounting, overage invoicing | Hourly usage compaction + end-of-period invoice sync. |
|
||
|
|
| Provisioning Orchestrator | Existing automation worker | Order state machine and provisioning job dispatch | Keep and harden existing job pipeline. |
|
||
|
|
| Notification Gateway | Node service | Push notifications, email alerts, approval prompts | Expo push + email provider adapters. |
|
||
|
|
| Onboarding Classifier | Lightweight service | Business-type classification + starter bundle recommendation | Cheap fast model profile; capped context. |
|
||
|
|
|
||
|
|
## 1.2 Tenant Components (Per VPS)
|
||
|
|
|
||
|
|
| Component | Runtime | Responsibility | State Store |
|
||
|
|
|---|---|---|---|
|
||
|
|
| OpenClaw Gateway | Node 22+ upstream | Agent runtime, sessions, tool orchestration | OpenClaw JSON/JSONL storage |
|
||
|
|
| Safety Wrapper Plugin | TypeScript package | Classification, gating, hooks, metering, Hub sync | SQLite (`safety.db`) |
|
||
|
|
| Egress Proxy | Node/Rust sidecar | Outbound redaction + transport enforcement | In-memory + policy cache |
|
||
|
|
| Execution Adapters | Local modules | Shell/Docker/file/env and tool REST adapters | Audit log in SQLite |
|
||
|
|
| Secrets Vault | SQLite + encryption | Secret values, rotation history, fingerprints | `vault.db` |
|
||
|
|
|
||
|
|
## 1.3 Deprecated Components (Explicitly Out)
|
||
|
|
|
||
|
|
- `letsbe-orchestrator`: behavior studied for migration inputs only.
|
||
|
|
- `letsbe-sysadmin-agent`: executor patterns ported, service itself not retained.
|
||
|
|
- `letsbe-mcp-browser`: replaced by OpenClaw native browser tooling.
|
||
|
|
|
||
|
|
## 2. API Design Rules (Applies To All Contracts)
|
||
|
|
|
||
|
|
- Base path versioning: `/api/v1/...`
|
||
|
|
- JSON request/response with strict schema validation.
|
||
|
|
- Idempotency required on mutating tenant commands (`Idempotency-Key` header).
|
||
|
|
- Authn/authz split by channel:
|
||
|
|
- Tenant channel: `Bearer <tenant_api_key>` (hash stored server-side)
|
||
|
|
- Mobile/customer channel: session JWT + RBAC
|
||
|
|
- Public website onboarding: scoped API key + anti-abuse limits
|
||
|
|
- All mutating endpoints emit audit event rows.
|
||
|
|
- All time fields are ISO 8601 UTC.
|
||
|
|
|
||
|
|
## 3. Hub ↔ Tenant API Contracts
|
||
|
|
|
||
|
|
## 3.1 Register Tenant Node
|
||
|
|
|
||
|
|
`POST /api/v1/tenant/register`
|
||
|
|
|
||
|
|
Purpose: first boot registration from Safety Wrapper.
|
||
|
|
|
||
|
|
Request:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"registrationToken": "rt_...",
|
||
|
|
"orderId": "ord_...",
|
||
|
|
"agentVersion": "safety-wrapper@0.1.0",
|
||
|
|
"openclawVersion": "2026.2.26",
|
||
|
|
"hostname": "cust-vps-001",
|
||
|
|
"capabilities": ["browser", "exec", "docker", "approval_queue"]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Response `201`:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"tenantApiKey": "tk_live_...",
|
||
|
|
"tenantId": "ten_...",
|
||
|
|
"heartbeatIntervalSec": 30,
|
||
|
|
"configEtag": "cfg_9f1a...",
|
||
|
|
"time": "2026-02-26T20:15:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 3.2 Heartbeat + Pull Deltas
|
||
|
|
|
||
|
|
`POST /api/v1/tenant/heartbeat`
|
||
|
|
|
||
|
|
Purpose: status signal plus lightweight config/update pull.
|
||
|
|
|
||
|
|
Request:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"tenantId": "ten_...",
|
||
|
|
"server": {
|
||
|
|
"uptimeSec": 86400,
|
||
|
|
"diskPct": 61.2,
|
||
|
|
"memPct": 57.8,
|
||
|
|
"openclawHealthy": true
|
||
|
|
},
|
||
|
|
"agents": [
|
||
|
|
{"agentId": "marketing", "status": "online", "autonomyLevel": 2}
|
||
|
|
],
|
||
|
|
"pendingApprovals": 1,
|
||
|
|
"lastAppliedConfigEtag": "cfg_9f1a..."
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Response `200`:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"configChanged": true,
|
||
|
|
"nextConfigEtag": "cfg_9f1b...",
|
||
|
|
"commands": [],
|
||
|
|
"clock": "2026-02-26T20:15:30Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 3.3 Pull Full Tenant Config
|
||
|
|
|
||
|
|
`GET /api/v1/tenant/config?etag=cfg_9f1a...`
|
||
|
|
|
||
|
|
Response `200` includes:
|
||
|
|
|
||
|
|
- agent definitions (SOUL/TOOLS refs, model profile)
|
||
|
|
- autonomy policy
|
||
|
|
- external comms gate unlock map
|
||
|
|
- command classification ruleset checksum
|
||
|
|
- tool registry template version
|
||
|
|
|
||
|
|
## 3.4 Approval Request / Resolve
|
||
|
|
|
||
|
|
`POST /api/v1/tenant/approval-requests`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"tenantId": "ten_...",
|
||
|
|
"requestId": "apr_...",
|
||
|
|
"agentId": "marketing",
|
||
|
|
"class": "yellow_external",
|
||
|
|
"tool": "listmonk.send_campaign",
|
||
|
|
"humanSummary": "Send campaign 'March Offer' to 1,204 recipients",
|
||
|
|
"expiresAt": "2026-02-27T20:15:30Z",
|
||
|
|
"context": {"recipientCount": 1204}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
`GET /api/v1/tenant/approval-requests/{requestId}` returns `PENDING|APPROVED|DENIED|EXPIRED`.
|
||
|
|
|
||
|
|
## 3.5 Usage Ingestion
|
||
|
|
|
||
|
|
`POST /api/v1/tenant/usage-buckets`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"tenantId": "ten_...",
|
||
|
|
"buckets": [
|
||
|
|
{
|
||
|
|
"hour": "2026-02-26T20:00:00Z",
|
||
|
|
"agentId": "marketing",
|
||
|
|
"model": "openrouter/deepseek-v3.2",
|
||
|
|
"inputTokens": 12000,
|
||
|
|
"outputTokens": 3800,
|
||
|
|
"cacheReadTokens": 6400,
|
||
|
|
"cacheWriteTokens": 0,
|
||
|
|
"webSearchCalls": 3,
|
||
|
|
"webFetchCalls": 1
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 3.6 Backup Status
|
||
|
|
|
||
|
|
`POST /api/v1/tenant/backup-status`
|
||
|
|
|
||
|
|
Tracks last run, duration, snapshot ID, integrity verification state.
|
||
|
|
|
||
|
|
## 4. Customer/Mobile API Contracts
|
||
|
|
|
||
|
|
## 4.1 Agent And Autonomy Management
|
||
|
|
|
||
|
|
- `GET /api/v1/customer/agents`
|
||
|
|
- `PATCH /api/v1/customer/agents/{agentId}`
|
||
|
|
- `PATCH /api/v1/customer/agents/{agentId}/autonomy`
|
||
|
|
- `PATCH /api/v1/customer/agents/{agentId}/external-comms-gate`
|
||
|
|
|
||
|
|
Autonomy update request:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"autonomyLevel": 2,
|
||
|
|
"externalComms": {
|
||
|
|
"defaultLocked": true,
|
||
|
|
"toolUnlocks": [
|
||
|
|
{"tool": "chatwoot.reply_external", "enabled": true, "expiresAt": null}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 4.2 Approval Queue
|
||
|
|
|
||
|
|
- `GET /api/v1/customer/approvals?status=pending`
|
||
|
|
- `POST /api/v1/customer/approvals/{id}` with `{ "decision": "approve" | "deny" }`
|
||
|
|
|
||
|
|
## 4.3 Usage And Billing
|
||
|
|
|
||
|
|
- `GET /api/v1/customer/usage/summary`
|
||
|
|
- `GET /api/v1/customer/usage/by-agent`
|
||
|
|
- `GET /api/v1/customer/billing/current-period`
|
||
|
|
- `POST /api/v1/customer/billing/payment-method`
|
||
|
|
|
||
|
|
## 4.4 Realtime Channels
|
||
|
|
|
||
|
|
- `GET /api/v1/customer/events/stream` (SSE fallback)
|
||
|
|
- `WS /api/v1/customer/ws` (chat updates, approvals, status)
|
||
|
|
|
||
|
|
## 5. Public Website/Onboarding API Contracts
|
||
|
|
|
||
|
|
## 5.1 Business Classification
|
||
|
|
|
||
|
|
`POST /api/v1/public/onboarding/classify`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"sessionId": "onb_...",
|
||
|
|
"messages": [
|
||
|
|
{"role": "user", "content": "I run a 5-person digital agency"}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Response:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"businessType": "agency",
|
||
|
|
"confidence": 0.91,
|
||
|
|
"recommendedBundle": "agency_core_v1",
|
||
|
|
"followUpQuestion": "Do you need ticketing or only chat?"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 5.2 Bundle Quote
|
||
|
|
|
||
|
|
`POST /api/v1/public/onboarding/quote`
|
||
|
|
|
||
|
|
Returns min tier, projected token pool, monthly estimate, and Stripe checkout seed payload.
|
||
|
|
|
||
|
|
## 5.3 Order Creation
|
||
|
|
|
||
|
|
`POST /api/v1/public/orders` with strict schema + anti-fraud controls.
|
||
|
|
|
||
|
|
## 6. Safety Wrapper Internal Contract (Local Only)
|
||
|
|
|
||
|
|
Local Unix socket JSON-RPC interface between plugin orchestration and execution layer.
|
||
|
|
|
||
|
|
Method examples:
|
||
|
|
|
||
|
|
- `exec.run`
|
||
|
|
- `docker.compose`
|
||
|
|
- `file.read`
|
||
|
|
- `file.write`
|
||
|
|
- `env.update`
|
||
|
|
- `tool.http.call`
|
||
|
|
|
||
|
|
Example request:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": "rpc_1",
|
||
|
|
"method": "tool.http.call",
|
||
|
|
"params": {
|
||
|
|
"tool": "ghost",
|
||
|
|
"operation": "posts.create",
|
||
|
|
"secretRefs": ["ghost_admin_key"],
|
||
|
|
"payload": {"title": "..."}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Guarantees:
|
||
|
|
|
||
|
|
- Secrets passed only as references, never raw values in request logs.
|
||
|
|
- Execution engine resolves references inside isolated process boundary.
|
||
|
|
- Full request/result hashes persisted for audit traceability.
|
||
|
|
|
||
|
|
## 7. Tool Registry Contract
|
||
|
|
|
||
|
|
`tool-registry.json` shape (tenant-local):
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"version": "2026-02-26",
|
||
|
|
"tools": [
|
||
|
|
{
|
||
|
|
"id": "chatwoot",
|
||
|
|
"baseUrl": "https://chat.customer-domain.tld",
|
||
|
|
"auth": {"type": "bearer_secret_ref", "ref": "chatwoot_api_token"},
|
||
|
|
"adapters": ["contacts.list", "conversation.reply"],
|
||
|
|
"externalCommsOperations": ["conversation.reply_external"],
|
||
|
|
"cheatsheet": "/opt/letsbe/cheatsheets/chatwoot.md"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 8. Error Contract And Retries
|
||
|
|
|
||
|
|
Standard error envelope:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"error": {
|
||
|
|
"code": "APPROVAL_REQUIRED",
|
||
|
|
"message": "Operation requires approval",
|
||
|
|
"requestId": "req_...",
|
||
|
|
"retryable": true,
|
||
|
|
"details": {"approvalRequestId": "apr_..."}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Common error codes:
|
||
|
|
|
||
|
|
- `AUTH_INVALID`
|
||
|
|
- `TENANT_UNKNOWN`
|
||
|
|
- `APPROVAL_REQUIRED`
|
||
|
|
- `APPROVAL_EXPIRED`
|
||
|
|
- `CLASSIFICATION_BLOCKED`
|
||
|
|
- `SECRET_REF_UNRESOLVED`
|
||
|
|
- `POLICY_VERSION_MISMATCH`
|
||
|
|
- `RATE_LIMITED`
|
||
|
|
|
||
|
|
## 9. API Compatibility And Change Policy
|
||
|
|
|
||
|
|
- Backward-compatible additions: allowed in-place.
|
||
|
|
- Breaking changes: new version path (`/api/v2`).
|
||
|
|
- Deprecation window: minimum 60 days for tenant APIs.
|
||
|
|
- Contract tests run in CI for Hub, Safety Wrapper, Mobile, and Website clients.
|