feat: 新增管理后台前端项目及安全加固
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

refactor(saas): 重构认证中间件与限流策略
- 登录限流调整为5次/分钟/IP
- 注册限流调整为3次/小时/IP
- GET请求不计入限流

fix(saas): 修复调度器时间戳处理
- 使用NOW()替代文本时间戳
- 兼容TEXT和TIMESTAMPTZ列类型

feat(saas): 实现环境变量插值
- 支持${ENV_VAR}语法解析
- 数据库密码支持环境变量注入

chore: 新增前端管理界面
- 基于React+Ant Design Pro
- 包含路由守卫/错误边界
- 对接58个API端点

docs: 更新安全加固文档
- 新增密钥管理规范
- 记录P0安全项审计结果
- 补充TLS终止说明

test: 完善配置解析单元测试
- 新增环境变量插值测试用例
This commit is contained in:
iven
2026-03-31 00:11:33 +08:00
parent 6821df5f44
commit eb956d0dce
129 changed files with 11913 additions and 863 deletions

View File

@@ -0,0 +1,366 @@
# ZCLAW Admin V2 与 Desktop 系统定位设计
> 日期: 2026-03-30
> 状态: Draft
> 范围: Admin V2 定位 + Desktop 集成 + Token Pool + Agent 模板
## 1. 系统定位
### 1.1 Admin V2 — 资源管理与配置中心
**目标用户**: 系统管理员、运营人员
**核心职责**:
1. **账号管理** — 用户 CRUD、角色权限、LLM 路由模式配置
2. **Token 池管理** — 多提供商多密钥的统一池化管理,解决 Coding Plan 套餐的时段限额和资源浪费问题
3. **行业 Agent 模板** — 预调教好的行业 Agent 人设(含 soul.md、system_prompt、工具集供 Desktop 首次使用时获取
4. **系统监控** — 用量统计、日志审计、配置管理
### 1.2 Desktop (Agent 会话端) — 终端用户界面
**目标用户**: 终端用户AI Agent 操作者)
**核心职责**:
1. **智能对话** — 流式响应、多模型切换、上下文管理
2. **Agent 管理** — 创建、配置、切换 Agent支持从 SaaS 模板初始化)
3. **自主能力** — Hands 触发、工作流编排、技能调用
4. **智能成长** — Agent 通过对话逐步成长,记忆、反思、身份演化
### 1.3 数据流
```
Admin V2 (配置) → SaaS API → PostgreSQL
Desktop (登录) → SaaS API → 拉取 AccountProfile { llm_routing, available_templates }
┌─────────┴──────────┐
│ │
relay 模式 local 模式
│ │
SaaS Relay Tauri Kernel
│ │
Key Pool 旋转 本地 API Key
│ │
LLM Provider LLM Provider
```
---
## 2. 账号级 LLM 路由
### 2.1 背景
国内 LLM 厂商推出 Coding Plan 套餐,但套餐有时段使用量限额。每个 Desktop 客户端各自配置 API Key 会造成资源浪费。在 Admin 端搭建 Token 池,多账号共享密钥资源,成本更优。
### 2.2 数据层
`accounts` 表新增:
```sql
ALTER TABLE accounts ADD COLUMN llm_routing TEXT NOT NULL DEFAULT 'local'
CHECK (llm_routing IN ('relay', 'local'));
COMMENT ON COLUMN accounts.llm_routing IS 'LLM路由模式: relay=SaaS中转, local=本地直连';
```
默认值 `local`,保持向后兼容。
### 2.3 API 层
**登录响应扩展**:
`POST /api/v1/auth/login``GET /api/v1/auth/me` 返回值增加:
```typescript
{
token: string;
refresh_token: string;
account: {
id: string;
username: string;
role: string;
llm_routing: 'relay' | 'local'; // 新增
// ... 现有字段
}
}
```
**Admin 端账号管理**:
`PATCH /api/v1/accounts/:id` 请求体支持 `llm_routing` 字段更新,仅 `account:admin` 权限可修改。
### 2.4 Desktop 行为
`saasStore` 登录成功后读取 `account.llm_routing`,写入 `connectionStore`
- `'relay'` → 使用 `SaaSClient.chatCompletion()` 走 SaaS Relay无需启动本地 Kernel
- `'local'` → 使用 `KernelClient` 走本地 Tauri Kernel
路由模式在登录时确定,会话期间不变。切换需要管理员修改 + 用户重新登录。
---
## 3. Token Pool / Key Pool 管理
### 3.1 现状
后端 Key Pool 已完整实现:
- `select_best_key()`: 优先级排序 + RPM/TPM 滑窗检查
- `mark_key_429()`: 429 自动冷却 + `Retry-After` 支持
- `record_key_usage()`: 分钟粒度用量记录
- SSRF 防护、加密存储、降级回退
Admin UI 为只读(仅显示密钥列表),缺少添加/切换/删除操作。
### 3.2 Admin UI 补全
Providers 页面 Key Pool Modal 升级为完整管理:
| 操作 | 交互 | 说明 |
|------|------|------|
| 添加密钥 | 点击"添加"按钮 → 弹出表单 | 字段: label, key_value, priority, max_rpm(可选), max_tpm(可选) |
| 启用/禁用 | 切换 Switch 组件 | 调用 `PUT /providers/:id/keys/:keyId/toggle` |
| 删除密钥 | 点击删除 → Popconfirm 确认 | 调用 `DELETE /providers/:id/keys/:keyId` |
| 状态展示 | 表格列 | 每个密钥显示: 状态、priority、RPM/TPM 配额、当前窗口用量、总用量 |
前端使用 `providerService.addKey()`, `providerService.toggleKey()`, `providerService.deleteKey()` — 这些 service 方法已定义但未使用,直接接入即可。
### 3.3 缺陷修复
| 缺陷 | 修复方案 | 优先级 |
|------|---------|--------|
| `key_usage_window` 无清理 | Scheduler 增加定时任务,清理 >24h 的窗口记录 | P1 |
| 同优先级无负载分散 | `select_best_key()` 加入"最近最少使用"次排序 | P2 |
| `quota_reset_interval` 未使用 | 移除字段或实现按 interval 重置配额逻辑 | P3 |
---
## 4. 行业 Agent 模板系统
### 4.1 背景
通过预设行业 Agent 模板(如医疗行业),预先调教好完整的 Agent 人设。Desktop 端首次使用时从 SaaS 获取完整模板配置,之后 Agent 由用户对话驱动逐步成长,不再与模板同步。
### 4.2 数据层 — 扩展 agent_templates
```sql
ALTER TABLE agent_templates ADD COLUMN soul_content TEXT;
ALTER TABLE agent_templates ADD COLUMN scenarios TEXT NOT NULL DEFAULT '[]';
ALTER TABLE agent_templates ADD COLUMN welcome_message TEXT;
ALTER TABLE agent_templates ADD COLUMN quick_commands TEXT NOT NULL DEFAULT '[]';
ALTER TABLE agent_templates ADD COLUMN personality TEXT;
ALTER TABLE agent_templates ADD COLUMN communication_style TEXT;
ALTER TABLE agent_templates ADD COLUMN emoji TEXT;
ALTER TABLE agent_templates ADD COLUMN version INTEGER NOT NULL DEFAULT 1;
ALTER TABLE agent_templates ADD COLUMN source_id TEXT UNIQUE;
```
字段说明:
| 字段 | 类型 | 说明 |
|------|------|------|
| `soul_content` | TEXT | SOUL.md 人格配置全文 (Markdown) |
| `scenarios` | JSON | 场景标签数组,如 `["临床辅助", "文献检索"]` |
| `welcome_message` | TEXT | 首次问候语 |
| `quick_commands` | JSON | 快捷指令数组 `[{label, prompt}]` |
| `personality` | TEXT | 人格预设: professional/friendly/creative/concise |
| `communication_style` | TEXT | 沟通风格描述文本 |
| `emoji` | TEXT | Agent 图标 |
| `version` | INT | 模板版本号,用于新用户获取最新版 |
| `source_id` | TEXT | 模板唯一标识,用于 Desktop 去重 |
### 4.3 种子模板示例 — 医疗行业
```typescript
{
name: "医疗助手",
source_id: "medical-assistant-v1",
category: "healthcare",
description: "医疗行业专业 AI 助手,熟悉临床流程、医学文献和诊疗规范",
emoji: "🏥",
personality: "professional",
system_prompt: "你是一位专业的医疗AI助手具备以下能力:\n1. 临床辅助诊断建议\n2. 医学文献检索与解读\n3. 用药参考与相互作用检查\n4. 诊疗规范查询\n\n注意: 你的建议仅供参考,不能替代专业医生诊断。",
soul_content: `# SOUL.md
## 人格特质
- 专业严谨,使用准确的医学术语
- 耐心细致,对每个问题都给予充分解答
- 保守审慎,涉及诊断和用药建议时始终提示"仅供参考"
- 持续学习,关注最新医学研究进展
## 沟通风格
- 使用专业但易懂的语言
- 适当使用类比解释复杂医学概念
- 对不确定的内容明确标注置信度
- 主动提醒风险和注意事项
## 边界
- 不做明确诊断,只提供参考意见
- 不推荐处方药的具体用法用量
- 遇到紧急情况建议立即就医
`,
scenarios: ["临床辅助", "文献检索", "诊断建议", "用药参考", "病历整理"],
welcome_message: "你好我是你的医疗AI助手。我可以帮你检索文献、解读检查报告、提供诊疗参考意见。请注意我的建议仅供参考不能替代专业医生的诊断。有什么我可以帮你的吗",
quick_commands: [
{ label: "文献检索", prompt: "请帮我检索关于 {topic} 的最新医学文献" },
{ label: "用药查询", prompt: "请查询 {drug} 的药理作用、适应症和注意事项" },
{ label: "检查解读", prompt: "请帮我解读以下检查报告: {report}" },
{ label: "诊疗参考", prompt: "关于 {symptom} 的诊疗参考方案" }
],
model: "claude-sonnet-4-6",
tools: ["browser", "researcher", "collector"],
temperature: 0.3,
max_tokens: 4096,
communication_style: "使用专业但易懂的语言,适当使用类比,对不确定内容标注置信度"
}
```
### 4.4 API 层
**新增端点**:
| 端点 | 方法 | 权限 | 说明 |
|------|------|------|------|
| `/api/v1/agent-templates/available` | GET | 任何已认证 | 返回可浏览模板列表 (id, name, category, emoji, description, source_id) |
| `/api/v1/agent-templates/:id/full` | GET | 任何已认证 | 返回完整模板 (含 soul_content, welcome_message, quick_commands 等) |
**现有端点扩展**:
`POST /api/v1/agent-templates``POST /api/v1/agent-templates/:id` (update) 请求体支持所有新增字段。
### 4.5 Desktop 消费流程
```
1. 登录成功
→ saasStore 调用 GET /agent-templates/available
→ 缓存模板列表到 saasStore.availableTemplates
2. 用户创建 Agent首次 / 新建)
→ AgentOnboardingWizard 增加 Step 0: 选择行业模板
→ 展示 Grid 卡片emoji + 名称 + 分类 + 描述)
→ 两个入口: "空白 Agent" / "从模板创建"
3. 选择模板后
→ 调用 GET /agent-templates/:id/full 获取完整配置
→ 映射到 Desktop Clone + Kernel Agent:
| SaaS 字段 | Desktop 目标 |
|---------------------|-------------------------------------|
| name | Clone.name |
| emoji | Clone.emoji |
| personality | Clone.personality |
| scenarios | Clone.scenarios |
| communication_style | Clone.communicationStyle |
| model | Clone.model |
| system_prompt | → Kernel agent system_prompt |
| soul_content | → identity.updateFile('soul', ...) |
| welcome_message | → 首条消息展示 |
| quick_commands | → 本地缓存,快捷指令面板 |
| temperature | → Kernel agent config |
| max_tokens | → Kernel agent config |
| tools | → Kernel agent tools |
4. 创建完成
→ Agent 在本地成长
→ 不再与 SaaS 模板同步
→ 模板更新仅影响新用户
```
---
## 5. Admin V2 UI 变更汇总
### 5.1 Accounts 页面
- 编辑 Modal 增加 "LLM 路由模式" 字段
- 下拉选项: "SaaS 中转 (Token 池)" / "本地直连"
- 表格增加路由模式列
### 5.2 Providers 页面
- Key Pool Modal 从只读升级为完整管理
- 增加 "添加密钥" 按钮 → 表单 (label, key, priority, RPM, TPM)
- 密钥行增加启用/禁用 Switch 和删除按钮
- 增加用量统计展示
### 5.3 Agent Templates 页面
- 创建/编辑 Modal 增加新字段: emoji, personality, soul_content (大文本编辑器), scenarios (多选标签), welcome_message, quick_commands (动态列表), communication_style
- 列表增加 emoji 列和 category 筛选
- 预览功能: 展示模板效果(模拟 Agent 外观)
---
## 6. Desktop 端变更汇总
### 6.1 saasStore
- 登录响应增加 `llm_routing` 解析
- 新增 `fetchAvailableTemplates()` 方法
- 新增 `availableTemplates` 状态
### 6.2 connectionStore
- `connect()` 根据账号 `llm_routing` 选择路径
- relay 模式: 使用 `SaaSClient.chatCompletion()`
- local 模式: 保持现有 `KernelClient` 逻辑
### 6.3 AgentOnboardingWizard
- 新增 Step 0: 行业模板选择
- 模板 Grid 展示 (从 saasStore.availableTemplates 渲染)
- 选择模板后预填后续步骤默认值
### 6.4 agentStore
- 新增 `createFromTemplate(template)` 方法
- 映射模板字段到 Clone + Kernel Agent
---
## 7. 文件变更清单
### SaaS 后端 (Rust)
| 文件 | 变更 |
|------|------|
| `crates/zclaw-saas/migrations/` | 新增 migration: accounts 加 llm_routing, agent_templates 加扩展字段 |
| `crates/zclaw-saas/src/account/types.rs` | AccountInfo 增加 llm_routing 字段 |
| `crates/zclaw-saas/src/account/handlers.rs` | update_account 支持 llm_routing |
| `crates/zclaw-saas/src/auth/handlers.rs` | login/me 响应增加 llm_routing |
| `crates/zclaw-saas/src/agent_template/types.rs` | 扩展 Create/Update/Info 类型 |
| `crates/zclaw-saas/src/agent_template/service.rs` | 支持 soul_content 等新字段 |
| `crates/zclaw-saas/src/agent_template/mod.rs` | 新增 /available 和 /:id/full 路由 |
| `crates/zclaw-saas/src/relay/key_pool.rs` | 加入 LRU 次排序 |
| `crates/zclaw-saas/src/scheduler.rs` | 新增 key_usage_window 清理任务 |
| `crates/zclaw-saas/src/db.rs` | 扩展种子模板数据 |
### Admin V2 (TypeScript)
| 文件 | 变更 |
|------|------|
| `admin-v2/src/pages/Accounts.tsx` | 编辑 Modal 增加 LLM 路由模式字段 |
| `admin-v2/src/pages/Providers.tsx` | Key Pool Modal 升级为完整管理 |
| `admin-v2/src/pages/AgentTemplates.tsx` | 创建/编辑 Modal 增加扩展字段 |
| `admin-v2/src/services/providers.ts` | 接入已有的 addKey/toggleKey/deleteKey |
| `admin-v2/src/services/agent-templates.ts` | 新增 getFull 方法 |
| `admin-v2/src/types/index.ts` | 扩展类型定义 |
### Desktop (TypeScript)
| 文件 | 变更 |
|------|------|
| `desktop/src/store/saasStore.ts` | 增加 llm_routing 解析 + fetchAvailableTemplates |
| `desktop/src/store/connectionStore.ts` | connect() 按 routing 模式选择路径 |
| `desktop/src/store/agentStore.ts` | 新增 createFromTemplate() |
| `desktop/src/components/AgentOnboardingWizard.tsx` | 新增 Step 0: 模板选择 |
| `desktop/src/lib/saas-client.ts` | 新增 fetchAvailableTemplates + fetchTemplateFull |
---
## 8. 不在范围内
以下事项本次设计不涉及:
- AccountTier / 订阅等级体系
- 实时配置推送 (WebSocket)
- 模板市场 / 用户自定义模板上传
- Token 池计费 / 用量配额限制
- Desktop 端路由模式用户自选 (由 Admin 统一管控)