# ZCLAW SaaS 后台系统设计规格 > 日期: 2026-03-27 > 状态: 待审阅 > 范围: 独立 SaaS 后端服务 (Rust + Axum) + 独立 Web 管理后台 (React + TypeScript) ## 1. 概述 ### 1.1 问题陈述 ZCLAW 当前是纯桌面单用户应用,缺少用户账号系统、API 服务端、多租户支持和请求中转能力。所有 LLM 调用直接从桌面端发起,API 密钥存储在本地环境变量或 OS Keyring,模型配置散落在 TOML 文件和 localStorage 中。这限制了多用户协作、集中管控和资源优化。 ### 1.2 设计目标 1. 为 ZCLAW 添加独立 SaaS 后端,提供账号权限、模型配置、请求中转、配置迁移四大能力 2. 桌面端通过简单配置切换即可接入 SaaS(改 `base_url` + 添加 API Token) 3. MVP 阶段支持 <100 用户,后续可扩展至更大规模 ### 1.3 用户决策 | 决策点 | 选择 | |--------|------| | 部署形态 | 独立 SaaS 后端服务 | | 技术栈 | Rust + Axum | | 实施顺序 | 按依赖顺序: 账号→API→中转→迁移 | | 管理界面 | 独立 React Web 管理后台 | | 用户规模 | MVP <100 用户 | | 支持模型 | 智谱 GLM, 通义千问, Kimi, DeepSeek | | 代码位置 | 同仓库 workspace 成员 `crates/zclaw-saas/` | --- ## 2. 架构 ### 2.1 系统架构图 ``` ┌─────────────────────┐ ┌─────────────────────────────────────────┐ │ ZCLAW 桌面客户端 │ │ SaaS 后端服务 │ │ (Tauri + React) │ │ (Rust + Axum) │ │ │ │ │ │ OpenAiDriver ──────┼────►│ /api/v1/relay/chat/completions │ │ (改 base_url) │ │ → 权限检查 → 队列 → 转发 → 流式响应 │ │ │ │ │ │ SaaSConfigClient ──┼────►│ /api/v1/config/sync │ │ (配置同步) │ │ → 配置覆盖/冲突检测 │ │ │ │ │ │ Model Picker ──────┼────►│ /api/v1/catalog/models │ │ (模型目录) │ │ → 动态模型列表 │ └─────────────────────┘ └─────────────────────────────────────────┘ │ ▼ ┌───────────────┐ │ SQLite (WAL) │ │ saas-data.db │ └───────────────┘ ┌──────────────────────────────────────────────────────┐ │ 管理后台 (React + TypeScript) │ │ /admin/accounts /admin/providers /admin/relay │ │ /admin/roles /admin/usage /admin/migration │ └──────────────────────────────────────────────────────┘ ``` ### 2.2 Crate 依赖 ``` zclaw-types (无依赖,复用 ID/错误/消息类型) ↑ zclaw-saas (→ types + axum/sqlx/argon2/jsonwebtoken) ↑ (通过 API) desktop/ (→ 通过 HTTP API 调用 SaaS) saas-admin/ (→ 通过 HTTP API 调用 SaaS) ``` ### 2.3 文件结构 ``` crates/zclaw-saas/ Cargo.toml src/ lib.rs # 模块声明 main.rs # 入口 error.rs # SaaS 错误类型 config.rs # SaaS 服务器配置 (TOML) db.rs # 数据库初始化 + 迁移 state.rs # AppState auth/ mod.rs jwt.rs # JWT 创建/验证 password.rs # Argon2 哈希 totp.rs # TOTP 2FA middleware.rs # Axum 认证中间件 account/ mod.rs types.rs # Account/Role/Permission 类型 handlers.rs # HTTP 处理器 service.rs # 业务逻辑 model_config/ mod.rs types.rs # Provider/Model/APIKey 类型 handlers.rs # HTTP 处理器 service.rs # 业务逻辑 relay/ mod.rs types.rs # 请求/响应/队列类型 handlers.rs # HTTP 处理器 (代理端点) service.rs # 队列管理、调度、批处理 provider_impl.rs # 提供商特定转发逻辑 migration/ mod.rs types.rs # ConfigItem/SyncRecord 类型 handlers.rs # HTTP 处理器 service.rs # 配置分析和同步逻辑 saas-admin/ # 独立 React 管理后台 package.json src/ App.tsx pages/ Login.tsx Dashboard.tsx accounts/ providers/ api-keys/ usage/ relay/ migration/ roles/ logs/ ``` --- ## 3. 数据库设计 ### 3.1 概述 - 引擎: SQLite WAL 模式 - 文件: 独立于桌面端 `~/.zclaw/data.db`,默认 `./saas-data.db` - 迁移: 版本化 schema,启动时自动迁移 ### 3.2 完整 Schema ```sql -- Schema 版本控制 CREATE TABLE IF NOT EXISTS saas_schema_version ( version INTEGER PRIMARY KEY ); -- ============================================================ -- 模块一: 账号权限 -- ============================================================ CREATE TABLE IF NOT EXISTS accounts ( id TEXT PRIMARY KEY, -- UUID v4 username TEXT NOT NULL UNIQUE, email TEXT NOT NULL UNIQUE, password_hash TEXT NOT NULL, -- Argon2id display_name TEXT NOT NULL DEFAULT '', avatar_url TEXT, role TEXT NOT NULL DEFAULT 'user', -- 'super_admin' | 'admin' | 'user' status TEXT NOT NULL DEFAULT 'active', -- 'active' | 'disabled' | 'suspended' totp_secret TEXT, -- 加密存储 totp_enabled INTEGER NOT NULL DEFAULT 0, last_login_at TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS idx_accounts_email ON accounts(email); CREATE INDEX IF NOT EXISTS idx_accounts_role ON accounts(role); CREATE TABLE IF NOT EXISTS api_tokens ( id TEXT PRIMARY KEY, -- UUID account_id TEXT NOT NULL, name TEXT NOT NULL, -- e.g. "桌面客户端" token_hash TEXT NOT NULL, -- SHA256(token) token_prefix TEXT NOT NULL, -- 前 8 字符用于展示 permissions TEXT NOT NULL DEFAULT '[]', -- JSON 权限数组 last_used_at TEXT, expires_at TEXT, -- NULL = 永不过期 created_at TEXT NOT NULL, revoked_at TEXT, FOREIGN KEY (account_id) REFERENCES accounts(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_api_tokens_account ON api_tokens(account_id); CREATE INDEX IF NOT EXISTS idx_api_tokens_hash ON api_tokens(token_hash); CREATE TABLE IF NOT EXISTS roles ( id TEXT PRIMARY KEY, -- 'super_admin' | 'admin' | 'user' | 自定义 UUID name TEXT NOT NULL, -- 显示名称 (中文) description TEXT, permissions TEXT NOT NULL DEFAULT '[]', -- JSON 权限数组 is_system INTEGER NOT NULL DEFAULT 0, -- 系统角色不可删除 created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS permission_templates ( id TEXT PRIMARY KEY, -- UUID name TEXT NOT NULL, -- e.g. "标准用户", "只读用户" description TEXT, permissions TEXT NOT NULL DEFAULT '[]', -- JSON 权限数组 created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS operation_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, account_id TEXT, -- NULL = 系统操作 action TEXT NOT NULL, -- e.g. "account.create", "model.update" target_type TEXT, -- e.g. "account", "api_key", "model" target_id TEXT, details TEXT, -- JSON 详情 ip_address TEXT, created_at TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS idx_op_logs_account ON operation_logs(account_id); CREATE INDEX IF NOT EXISTS idx_op_logs_action ON operation_logs(action); CREATE INDEX IF NOT EXISTS idx_op_logs_time ON operation_logs(created_at); -- ============================================================ -- 模块二: 模型配置 -- ============================================================ CREATE TABLE IF NOT EXISTS providers ( id TEXT PRIMARY KEY, -- UUID name TEXT NOT NULL UNIQUE, -- e.g. 'zhipu', 'qwen', 'kimi', 'deepseek' display_name TEXT NOT NULL, -- e.g. '智谱 AI' api_key TEXT, -- 服务端提供商 API 密钥 (加密存储) base_url TEXT NOT NULL, api_protocol TEXT NOT NULL DEFAULT 'openai', -- 'openai' | 'anthropic' enabled INTEGER NOT NULL DEFAULT 1, rate_limit_rpm INTEGER, -- 每分钟请求数 rate_limit_tpm INTEGER, -- 每分钟 token 数 config_json TEXT DEFAULT '{}', -- 提供商特定配置 created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS models ( id TEXT PRIMARY KEY, -- UUID provider_id TEXT NOT NULL, model_id TEXT NOT NULL, -- 传给 API 的模型标识 alias TEXT NOT NULL, -- 显示名称 context_window INTEGER NOT NULL DEFAULT 8192, max_output_tokens INTEGER NOT NULL DEFAULT 4096, supports_streaming INTEGER NOT NULL DEFAULT 1, supports_vision INTEGER NOT NULL DEFAULT 0, enabled INTEGER NOT NULL DEFAULT 1, pricing_input REAL DEFAULT 0, -- 每 1K token 价格 pricing_output REAL DEFAULT 0, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, UNIQUE(provider_id, model_id), FOREIGN KEY (provider_id) REFERENCES providers(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_models_provider ON models(provider_id); CREATE TABLE IF NOT EXISTS account_api_keys ( id TEXT PRIMARY KEY, -- UUID account_id TEXT NOT NULL, provider_id TEXT NOT NULL, key_value TEXT NOT NULL, -- API 密钥 (加密存储) key_label TEXT, -- e.g. "主密钥", "备用密钥" permissions TEXT NOT NULL DEFAULT '[]', -- JSON: 可访问的模型 ID 列表 enabled INTEGER NOT NULL DEFAULT 1, last_used_at TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, revoked_at TEXT, FOREIGN KEY (account_id) REFERENCES accounts(id) ON DELETE CASCADE, FOREIGN KEY (provider_id) REFERENCES providers(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_account_api_keys_account ON account_api_keys(account_id); CREATE TABLE IF NOT EXISTS usage_records ( id INTEGER PRIMARY KEY AUTOINCREMENT, account_id TEXT NOT NULL, provider_id TEXT NOT NULL, model_id TEXT NOT NULL, input_tokens INTEGER NOT NULL DEFAULT 0, output_tokens INTEGER NOT NULL DEFAULT 0, latency_ms INTEGER, status TEXT NOT NULL DEFAULT 'success', -- 'success' | 'error' | 'rate_limited' error_message TEXT, created_at TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS idx_usage_account ON usage_records(account_id); CREATE INDEX IF NOT EXISTS idx_usage_time ON usage_records(created_at); -- ============================================================ -- 模块三: 中转服务 -- ============================================================ CREATE TABLE IF NOT EXISTS relay_tasks ( id TEXT PRIMARY KEY, -- UUID account_id TEXT NOT NULL, provider_id TEXT NOT NULL, model_id TEXT NOT NULL, request_hash TEXT NOT NULL, -- 用于去重 status TEXT NOT NULL DEFAULT 'queued', -- 'queued' | 'processing' | 'completed' | 'failed' priority INTEGER NOT NULL DEFAULT 0, attempt_count INTEGER NOT NULL DEFAULT 0, max_attempts INTEGER NOT NULL DEFAULT 3, request_body TEXT NOT NULL, -- JSON: 转发的请求体 response_body TEXT, -- JSON: 响应体 input_tokens INTEGER DEFAULT 0, output_tokens INTEGER DEFAULT 0, error_message TEXT, queued_at TEXT NOT NULL, started_at TEXT, completed_at TEXT, created_at TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS idx_relay_status ON relay_tasks(status); CREATE INDEX IF NOT EXISTS idx_relay_account ON relay_tasks(account_id); CREATE INDEX IF NOT EXISTS idx_relay_provider ON relay_tasks(provider_id); -- ============================================================ -- 模块四: 配置迁移 -- ============================================================ CREATE TABLE IF NOT EXISTS config_items ( id TEXT PRIMARY KEY, -- UUID category TEXT NOT NULL, -- 'llm' | 'agent' | 'security' | 'hands' | 'skills' | 'tools' | 'logging' | 'desktop' | 'server' key_path TEXT NOT NULL, -- e.g. 'llm.default_provider' value_type TEXT NOT NULL, -- 'string' | 'integer' | 'float' | 'boolean' | 'array' | 'object' current_value TEXT, -- JSON 编码的当前值 default_value TEXT, -- JSON 编码的默认值 source TEXT NOT NULL DEFAULT 'local', -- 'local' | 'saas' | 'override' description TEXT, -- 中文描述 requires_restart INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, UNIQUE(category, key_path) ); CREATE INDEX IF NOT EXISTS idx_config_category ON config_items(category); CREATE TABLE IF NOT EXISTS config_sync_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, account_id TEXT NOT NULL, client_fingerprint TEXT NOT NULL, action TEXT NOT NULL, -- 'push' | 'pull' | 'conflict' config_keys TEXT NOT NULL, -- JSON: 受影响的配置键 client_values TEXT, -- JSON: 客户端值 saas_values TEXT, -- JSON: SaaS 值 resolution TEXT, -- 'client_wins' | 'saas_wins' | 'manual' created_at TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS idx_sync_account ON config_sync_log(account_id); ``` --- ## 4. 模块一: 账号权限管理 ### 4.1 认证机制 | 机制 | 实现 | 用途 | |------|------|------| | 密码 | Argon2id (argon2 crate) | 账号登录 | | JWT | HMAC-SHA256 (jsonwebtoken crate) | 管理后台会话 | | TOTP 2FA | totp-rs crate | 可选双因素认证 | | API Token | SHA-256 哈希存储 | 桌面客户端/程序化访问 | **JWT Payload**: `{ sub: account_id, role: "admin", exp: timestamp }` **API Token 格式**: `zclaw_<48 random bytes>`,仅创建时展示一次 ### 4.2 认证中间件 ```rust // auth/middleware.rs pub struct AuthContext { pub account_id: Uuid, pub role: AccountRole, pub permissions: Vec, pub auth_method: AuthMethod, // Jwt | ApiToken } // 中间件从 Authorization: Bearer 或 X-API-Key: 提取身份 // 将 AuthContext 注入 request extensions ``` ### 4.3 角色与权限 权限使用字符串常量,检查时匹配字符串列表: ```rust pub mod permissions { pub const ACCOUNT_READ: &str = "account:read"; pub const ACCOUNT_WRITE: &str = "account:write"; pub const ACCOUNT_ADMIN: &str = "account:admin"; pub const PROVIDER_MANAGE: &str = "provider:manage"; pub const MODEL_MANAGE: &str = "model:manage"; pub const RELAY_USE: &str = "relay:use"; pub const RELAY_ADMIN: &str = "relay:admin"; pub const CONFIG_READ: &str = "config:read"; pub const CONFIG_WRITE: &str = "config:write"; pub const ADMIN_FULL: &str = "admin:full"; } ``` | 角色 | 权限 | |------|------| | `super_admin` | `admin:full` (授权检查时直接放行) | | `admin` | account:read/write/admin, provider:manage, model:manage, relay:use/admin, config:read/write | | `user` | relay:use, config:read | ### 4.4 API 端点 | 方法 | 路径 | 权限 | 说明 | |------|------|------|------| | POST | `/api/v1/auth/register` | admin:full | 创建账号 | | POST | `/api/v1/auth/login` | 公开 | 登录返回 JWT | | POST | `/api/v1/auth/refresh` | JWT | 刷新 JWT | | POST | `/api/v1/auth/totp/setup` | JWT | 获取 TOTP 设置 URI | | POST | `/api/v1/auth/totp/verify` | JWT | 验证并启用 TOTP | | POST | `/api/v1/auth/totp/disable` | JWT | 禁用 TOTP | | GET | `/api/v1/accounts` | account:read | 账号列表 | | GET | `/api/v1/accounts/:id` | 本人/account:read | 账号详情 | | PATCH | `/api/v1/accounts/:id` | 本人/account:write | 更新账号 | | PATCH | `/api/v1/accounts/:id/status` | account:admin | 启用/禁用 | | GET | `/api/v1/tokens` | - (本人) | 列出 API 令牌 | | POST | `/api/v1/tokens` | - (本人) | 创建令牌 | | DELETE | `/api/v1/tokens/:id` | - (本人) | 撤销令牌 | | GET | `/api/v1/roles` | account:read | 角色列表 | | POST | `/api/v1/roles` | account:admin | 创建自定义角色 | | PUT | `/api/v1/roles/:id` | account:admin | 更新角色权限 | | DELETE | `/api/v1/roles/:id` | account:admin | 删除自定义角色 | | GET | `/api/v1/permission-templates` | account:read | 模板列表 | | POST | `/api/v1/permission-templates` | account:admin | 创建模板 | | POST | `/api/v1/permission-templates/:id/apply` | account:admin | 批量应用 | | GET | `/api/v1/logs/operations` | account:read | 操作日志 (分页) | ### 4.5 关键数据结构 ```rust pub struct Account { pub id: Uuid, pub username: String, pub email: String, pub password_hash: String, // skip_serializing pub display_name: String, pub avatar_url: Option, pub role: AccountRole, pub status: AccountStatus, pub totp_enabled: bool, pub last_login_at: Option>, pub created_at: DateTime, pub updated_at: DateTime, } pub enum AccountRole { SuperAdmin, Admin, User } pub enum AccountStatus { Active, Disabled, Suspended } ``` --- ## 5. 模块二: 模型与 API 配置中心 ### 5.1 提供商管理 提供商存储服务端 API 密钥 (加密) 和基础配置。管理员创建提供商后,可为每个提供商添加多个模型。 **API 密钥加密**: AES-256-GCM,密钥通过 HKDF-SHA256 从服务器 JWT 密钥派生。 ### 5.2 账号级 API 密钥 每个账号可以为每个提供商配置独立的 API 密钥。密钥权限 (JSON 数组) 控制该密钥可访问的模型 ID 列表。支持: - 生成: 创建新密钥,返回明文 (仅一次) - 轮换: 生成新密钥替换旧密钥 - 禁用: 临时禁用 - 撤销: 永久删除 ### 5.3 使用量统计 每次中转请求完成后记录 `usage_records`。统计查询使用 SQL 聚合,MVP 阶段不需要预计算视图。 ### 5.4 API 端点 | 方法 | 路径 | 权限 | 说明 | |------|------|------|------| | GET | `/api/v1/providers` | 认证用户 | 提供商列表 | | POST | `/api/v1/providers` | provider:manage | 创建提供商 | | GET | `/api/v1/providers/:id` | 认证用户 | 提供商详情 | | PATCH | `/api/v1/providers/:id` | provider:manage | 更新提供商 | | DELETE | `/api/v1/providers/:id` | provider:manage | 删除提供商 | | GET | `/api/v1/providers/:id/models` | 认证用户 | 模型列表 | | GET | `/api/v1/models` | 认证用户 | 模型列表 | | POST | `/api/v1/models` | model:manage | 创建模型 | | GET | `/api/v1/models/:id` | 认证用户 | 模型详情 | | PATCH | `/api/v1/models/:id` | model:manage | 更新模型 | | DELETE | `/api/v1/models/:id` | model:manage | 删除模型 | | GET | `/api/v1/keys` | - (本人) | API Key 列表 | | POST | `/api/v1/keys` | - (本人) | 创建 API Key | | DELETE | `/api/v1/keys/:id` | - (本人) | 撤销 API Key | | POST | `/api/v1/keys/:id/rotate` | - (本人) | 轮换 API Key | | GET | `/api/v1/usage` | - (本人) | 使用量统计 | ### 5.5 初始种子数据 从 `config/chinese-providers.toml` 导入: | 提供商 | 模型 | |--------|------| | 智谱 AI | GLM-4-Plus, GLM-4-Flash, GLM-4V-Plus, GLM-Z1-AirX | | 通义千问 | Qwen-Max, Qwen-Plus, Qwen-Turbo, Qwen-VL-Max | | Kimi | moonshot-v1-8k, moonshot-v1-32k, moonshot-v1-128k | | DeepSeek | deepseek-chat, deepseek-reasoner | --- ## 6. 模块三: 模型请求中转服务 ### 6.1 请求流 ``` 桌面客户端 POST /api/v1/relay/chat/completions Headers: Authorization: Bearer 或 X-API-Key: Body: { model: "glm-4-plus", messages: [...], stream: true } ↓ 认证中间件 → 提取 account_id + permissions ↓ 权限检查 → relay:use ↓ 提供商解析 → models 表查找 provider_id → providers 表获取 base_url + api_protocol ↓ API 密钥解析 → account_api_keys 表获取该账号的提供商密钥 ↓ 速率限制检查 → 令牌桶算法 ↓ 队列调度 → tokio::sync::mpsc (如并发已满则排队) ↓ 转发请求 → reqwest::Client POST 到上游提供商 ↓ 流式响应 → SSE 转发给客户端 (stream: true) ↓ 记录使用量 → usage_records 表 ``` ### 6.2 队列与调度 ```rust pub struct RelayService { queues: Arc>>, // 每提供商独立队列 semaphores: Arc>>, // 并发控制 clients: Arc>, // 每提供商 HTTP 客户端 config: RelayConfig, } ``` - 每提供商一个 mpsc channel (容量 100) - 每提供商一个 Semaphore 控制并发 (默认 5) - Worker task 从 channel 拉取请求并执行 ### 6.3 速率限制 令牌桶算法: - RPM (每分钟请求数): `tokio::sync::Semaphore` + 定时释放 - TPM (每分钟 token 数): 基于最近一分钟 `usage_records` 的 SQL 查询 ### 6.4 错误处理与重试 - 瞬态错误 (超时, 5xx): 指数退避重试 (1s, 2s, 4s),最多 3 次 - 客户端错误 (4xx, 认证失败): 立即返回,不重试 - 提供商不可用: 标记 provider disabled,通知管理员 ### 6.5 API 端点 | 方法 | 路径 | 权限 | 说明 | |------|------|------|------| | POST | `/api/v1/relay/chat/completions` | relay:use | 中转聊天补全 (支持流式) | | GET | `/api/v1/relay/status` | relay:admin | 队列状态/提供商健康 | | GET | `/api/v1/relay/tasks` | relay:admin | 任务列表 | | GET | `/api/v1/relay/tasks/:id` | relay:admin | 任务详情 | | DELETE | `/api/v1/relay/tasks/:id` | relay:admin | 取消排队任务 | | POST | `/api/v1/relay/retry/:id` | relay:admin | 重试失败任务 | ### 6.6 桌面端集成 桌面端 `OpenAiDriver` 将 `base_url` 指向 SaaS 中转: ``` 原来: base_url = "https://open.bigmodel.cn/api/paas/v4" 改为: base_url = "https://saas.zclaw.example.com/api/v1/relay" 添加: X-API-Key: zclaw_xxxxx (账号的 API Token) ``` 中转保持 OpenAI 兼容格式,桌面端无需任何协议适配。 --- ## 7. 模块四: 系统配置迁移分析 ### 7.1 迁移优先级分类 基于 `config/config.toml`、`config/chinese-providers.toml`、`config/security.toml` 分析: **Critical (必须迁移)**: - `llm.providers[].api_key` — API 密钥应服务端管理 - `llm.providers[].base_url` — 提供商端点集中管控 - `llm.providers[].models[]` — 模型目录从 SaaS 下发 - `llm.default_provider` — 默认提供商可按账号配置 - `llm.default_model` — 默认模型可按账号配置 **High (重要)**: - `llm.requests_per_minute` / `llm.tokens_per_minute` — 按账号限流 - `llm.max_retries` / `llm.retry_delay` — 重试策略 - `security.auth.token_expiration` — 认证配置 - `security.rate_limit.*` — 限流配置 **Medium (有益)**: - `agent.defaults.max_sessions` — 会话限制 - `hands.default_approval_mode` — 默认审批模式 - `skills.execution_timeout` — 技能超时 **Low (可选)**: - `desktop.ui.*` — UI 偏好 - `logging.level` — 日志级别 **Local Only (不迁移)**: - `server.host/port` — 服务端特有 - `agent.defaults.workspace` — 本地文件路径 - `security.shell_exec.*` — 本地安全策略 - `tools.fs.allowed_paths` — 本地文件路径 - `logging.file.path` — 本地文件路径 ### 7.2 同步协议 ``` 桌面客户端 SaaS 服务端 │ │ │ POST /api/v1/config/sync │ │ { action: "push", │ │ fingerprint: "machine_xxx", │ │ snapshot: { ... } } │ │ ──────────────────────────────► │ │ │ 比对 SaaS 存储 │ { updates: [...], │ │ conflicts: [...] } │ │ ◄────────────────────────────── │ │ │ │ 应用更新 / 提示冲突 │ │ │ ``` **冲突解决策略**: - `source: "saas"` / `"override"` → 默认 saas_wins - `source: "local"` → 默认 client_wins - 管理员可按配置项覆盖 ### 7.3 API 端点 | 方法 | 路径 | 权限 | 说明 | |------|------|------|------| | GET | `/api/v1/migration/report` | config:read | 迁移分析报告 | | POST | `/api/v1/migration/analyze` | config:read | 分析配置快照 | | GET | `/api/v1/migration/items` | config:read | 配置项列表 | | PUT | `/api/v1/migration/items/:id` | config:write | 更新配置项 | | PUT | `/api/v1/migration/items/batch` | config:write | 批量更新 | | POST | `/api/v1/config/sync` | - (本人) | 客户端↔SaaS 同步 | | GET | `/api/v1/config/snapshot` | config:read | SaaS 配置快照 | | GET | `/api/v1/config/diff` | config:read | 客户端与 SaaS 差异 | --- ## 8. 管理后台前端 ### 8.1 技术栈 React 18 + TypeScript + Tailwind CSS + Recharts + React Router ### 8.2 页面清单 | 路径 | 模块 | 说明 | |------|------|------| | `/admin/login` | 通用 | 登录页 (JWT 认证) | | `/admin/dashboard` | 通用 | 概览仪表板 (账号数/使用量/中转状态) | | `/admin/accounts` | M1 | 账号列表 (搜索/角色筛选/状态筛选) | | `/admin/accounts/:id` | M1 | 账号详情 (编辑/查看令牌/查看日志) | | `/admin/roles` | M1 | 角色权限矩阵编辑 | | `/admin/templates` | M1 | 权限模板 CRUD + 批量应用 | | `/admin/logs` | M1 | 操作日志 (分页/筛选/时间范围) | | `/admin/profile` | M1 | 个人设置 (密码/2FA/显示名) | | `/admin/providers` | M2 | 提供商卡片 (状态/模型数) | | `/admin/providers/:id` | M2 | 提供商详情/编辑 | | `/admin/providers/:id/models` | M2 | 模型表格 (添加/编辑/禁用) | | `/admin/api-keys` | M2 | API 密钥管理 (创建/轮换/撤销) | | `/admin/usage` | M2 | 使用量仪表板 (图表/按提供商/按模型/按日期) | | `/admin/relay/dashboard` | M3 | 中转状态 (队列/提供商健康/实时指标) | | `/admin/relay/tasks` | M3 | 任务列表 (状态筛选/取消/重试) | | `/admin/migration/report` | M4 | 迁移分析报告 (分类统计/优先级图表) | | `/admin/migration/items` | M4 | 配置项管理 (分类/优先级/来源筛选) | | `/admin/config/sync-log` | M4 | 同步日志 (冲突详情/解决记录) | --- ## 9. 实施阶段 ### Phase 1: 基础 + 账号模块 1. `crates/zclaw-saas/` 基础结构 (Cargo.toml, db.rs, config.rs, state.rs, error.rs) 2. `auth/` 模块 (JWT, Argon2, TOTP, 中间件) 3. `account/` 模块 (CRUD, 角色, 模板, 操作日志) 4. `saas-admin/` 脚手架 (登录 + 账号管理页面) 5. 验证: 注册→登录→创建 API Token→操作日志 ### Phase 2: 模型配置模块 1. `model_config/` 模块 (提供商/模型 CRUD) 2. 种子数据导入 (`chinese-providers.toml`) 3. 账号 API 密钥管理 + 使用量统计 4. 管理后台: 提供商/模型/API 密钥/使用量 5. 验证: 创建提供商→添加模型→分配密钥→查看使用量 ### Phase 3: 中转服务模块 1. `relay/` 模块 (队列, 调度, 流式转发) 2. 速率限制 + 重试逻辑 3. 管理后台: 中转仪表板/任务列表 4. 桌面端集成 (改 `base_url`) 5. 验证: 桌面端→中转→提供商→流式响应→使用量记录 ### Phase 4: 配置迁移模块 1. `migration/` 模块 (配置分析, 同步协议) 2. 种子配置项 (从 TOML 文件分析) 3. 桌面端 `SaaSConfigClient` 4. 更新 `KernelConfig::load()` 支持 SaaS 覆盖 5. 验证: 配置同步→覆盖→冲突检测→解决 --- ## 10. 验证方案 ### 每阶段验证 1. `cargo build -p zclaw-saas` — 编译通过 2. `cargo test -p zclaw-saas` — 单元测试通过 3. `curl` 测试每个 API 端点 4. 管理后台操作 → 验证数据库状态 ### 最终端到端验证 1. **完整流程**: 注册账号 → 登录 → 创建 API Token → 配置提供商 → 桌面端通过中转调用模型 → 查看使用量 → 配置同步 2. **安全验证**: JWT 过期拒绝、权限不足拒绝、API Token 撤销后拒绝、TOTP 强制验证 3. **错误处理**: 提供商不可用降级、速率限制触发排队、队列溢出错误、配置冲突检测 --- ## 11. 关键参考文件 | 文件 | 用途 | |------|------| | `crates/zclaw-kernel/src/config.rs` | LlmConfig/ApiProtocol 模式参考 | | `crates/zclaw-memory/src/schema.rs` | SQL schema 模式参考 | | `crates/zclaw-runtime/src/driver/openai.rs` | 中转转发实现参考 | | `crates/zclaw-runtime/src/driver/mod.rs` | LlmDriver trait 参考 | | `config/chinese-providers.toml` | 提供商种子数据源 | | `config/config.toml` | 配置迁移分析源 | | `config/security.toml` | 安全配置迁移分析源 | | `desktop/src-tauri/src/secure_storage.rs` | 密钥加密存储参考 | | `desktop/src-tauri/src/lib.rs` | Tauri 命令模式参考 |