docs(wiki): Phase B+C完成 — middleware/saas/security/memory 5节模板重构
- middleware.md: 集成契约+3不变量+执行流 (157→136行) - saas.md: 移除安全重复→引用security.md+Token Pool算法 (231→173行) - security.md: 吸收saas认证内容成为安全唯一真相源 (158→199行) - memory.md: 最大压缩363→147行+Hermes洞察提炼+4不变量 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
315
wiki/saas.md
315
wiki/saas.md
@@ -1,105 +1,31 @@
|
||||
---
|
||||
title: SaaS 平台
|
||||
updated: 2026-04-21
|
||||
updated: 2026-04-22
|
||||
status: active
|
||||
tags: [module, saas, auth, billing]
|
||||
tags: [module, saas, billing, relay]
|
||||
---
|
||||
|
||||
# SaaS 平台
|
||||
|
||||
> 从 [[index]] 导航。关联模块: [[routing]] [[chat]]
|
||||
> 从 [[index]] 导航。关联模块: [[routing]] [[chat]] [[security]]
|
||||
|
||||
## 设计思想
|
||||
## 设计决策
|
||||
|
||||
**核心定位: SaaS 是 Tauri 桌面端的中枢,不是独立 Web 应用。**
|
||||
|
||||
关键决策:
|
||||
1. **Token Pool** — 桌面端不持有 LLM API Key,SaaS 维护共享 Key 池,RPM/TPM 轮换
|
||||
2. **JWT + Cookie 双通道** — Tauri 用 OS keyring 存 JWT,浏览器用 HttpOnly cookie
|
||||
3. **计费闭环** — 配额实时递增 → 聚合器调度 → mock 支付路由
|
||||
4. **Admin V2** — 17 页管理后台,管理模型/用户/计费/知识库
|
||||
| 决策 | 为什么 |
|
||||
|------|--------|
|
||||
| Token Pool 集中管理 | 桌面端不持有 LLM API Key,SaaS 维护共享 Key 池做 RPM/TPM 轮换,支持用量追踪和计费 |
|
||||
| 16 模块目录划分 | 按业务域高内聚:auth/relay/billing/knowledge/model_config/account/agent_template/industry/role/prompt/scheduled_task/telemetry/migration/models/tasks/workers |
|
||||
| 137 routes + 13 路由模块 | main.rs 用 `.merge()` 统一注册,每个模块独立维护路由 |
|
||||
| 7 后台 Workers | 用量记录/聚合、限流清理、token 清理、embedding 生成等异步任务解耦 |
|
||||
| 认证与安全 | 详见 [[security]] |
|
||||
|
||||
## 功能清单
|
||||
## 关键文件 + 数据流
|
||||
|
||||
| 功能 | 描述 | 入口文件 | 状态 |
|
||||
|------|------|----------|------|
|
||||
| 用户认证 | 注册/登录/JWT刷新/登出 | auth/handlers.rs | ✅ |
|
||||
| TOTP 2FA | 设置/验证/禁用 | auth/handlers.rs | ✅ |
|
||||
| Token Pool | RPM/TPM 轮换 Key 分配 | relay/handlers.rs | ✅ |
|
||||
| 聊天中转 | OpenAI 兼容 relay | relay/handlers.rs | ✅ |
|
||||
| 计费系统 | 配额递增/订阅/支付回调 | billing/ | ✅ |
|
||||
| 用户管理 | CRUD/状态/设备/token | account/ | ✅ |
|
||||
| 模型管理 | Provider/模型/Key CRUD | model_config/ | ✅ |
|
||||
| Agent 模板 | 模板 CRUD + 自动分配 | agent_template/ | ✅ |
|
||||
| 知识库 | 分类/条目/搜索/pgvector | knowledge/ | ✅ |
|
||||
| Prompt 管理 | 版本控制/回滚 | prompt/ | ✅ |
|
||||
| 角色权限 | RBAC + 权限模板 | role/ | ✅ |
|
||||
| 行业配置 | 行业 CRUD + 账户分配 | industry/ | ✅ |
|
||||
| 定时任务 | 任务调度 CRUD | scheduled_task/ | ✅ |
|
||||
| 用量统计 | Telemetry 上报/查询 | telemetry/ | ✅ |
|
||||
| 配置同步 | 项 CRUD/分析/seed/sync/diff | migration/ | ✅ |
|
||||
| Admin Dashboard | 系统概览 + 运营指标 | account/admin_routes | ✅ |
|
||||
| Mock 支付 | 开发环境模拟支付 | billing/mock_routes | ✅ |
|
||||
### SaaS 模块结构
|
||||
|
||||
## 代码逻辑
|
||||
|
||||
### 认证流
|
||||
|
||||
```
|
||||
用户登录 (POST /api/v1/auth/login)
|
||||
→ Argon2id + OsRg 盐验证密码
|
||||
→ 签发 JWT (Claims: user_id, role, pwv)
|
||||
→ set_auth_cookies():
|
||||
zclaw_access_token (path:/api, 2h TTL, HttpOnly)
|
||||
zclaw_refresh_token (path:/api/v1/auth, 7d TTL, HttpOnly)
|
||||
Secure: dev=false, prod=true | SameSite=Strict
|
||||
|
||||
前端存储:
|
||||
→ Tauri: OS keyring → saasStore.token
|
||||
→ 浏览器: HttpOnly Cookie (JS 不可读)
|
||||
→ localStorage: saasUrl + account 信息 (非敏感)
|
||||
```
|
||||
|
||||
### Token 池 + 限流
|
||||
|
||||
```
|
||||
SaaS Relay 收到 LLM 请求 (POST /api/v1/relay/chat/completions)
|
||||
→ 验证 JWT → 提取 user_id
|
||||
→ 从 Token Pool 选择可用 Key (RPM/TPM 轮换)
|
||||
→ 转发请求到真实 LLM API
|
||||
→ 记录 usage (record_usage worker)
|
||||
→ 返回响应
|
||||
|
||||
限流规则:
|
||||
→ /api/auth/login: 5次/分钟/IP (防暴力) + 持久化到 PostgreSQL
|
||||
→ /api/auth/register: 3次/小时/IP (防刷注册)
|
||||
→ 公共端点: 20次/分钟/IP
|
||||
```
|
||||
|
||||
### 密码安全
|
||||
|
||||
```
|
||||
JWT password_version (pwv):
|
||||
→ JWT Claims 含 pwv 字段
|
||||
→ 每次验证 JWT 时比对 Claims.pwv vs DB.pwv
|
||||
→ 修改密码 → DB.pwv 递增 → 所有旧 JWT 自动失效
|
||||
|
||||
密码存储: Argon2id + OsRg 随机盐
|
||||
TOTP 加密: AES-256-GCM + 随机 Nonce
|
||||
```
|
||||
|
||||
### Token 刷新
|
||||
|
||||
```
|
||||
POST /api/v1/auth/refresh
|
||||
→ 验证 refresh_token (单次使用)
|
||||
→ 旧 refresh_token 撤销到 DB (rotation 校验)
|
||||
→ 签发新 access + refresh token
|
||||
```
|
||||
|
||||
### SaaS 模块结构(代码验证)
|
||||
|
||||
16 个模块目录 (`crates/zclaw-saas/src/`):
|
||||
16 个目录 (`crates/zclaw-saas/src/`):
|
||||
|
||||
```
|
||||
account/ agent_template/ auth/ billing/ industry/
|
||||
@@ -107,124 +33,141 @@ knowledge/ migration/ model_config/ models/ prompt/
|
||||
relay/ role/ scheduled_task/ tasks/ telemetry/ workers/
|
||||
```
|
||||
|
||||
### SaaS API 分布
|
||||
### 核心文件
|
||||
|
||||
137 个 `.route()` 调用,13 个路由模块 (main.rs `.merge()` 注册)。
|
||||
| 文件 | 职责 |
|
||||
|------|------|
|
||||
| `crates/zclaw-saas/src/main.rs` | 路由注册入口 (13 个 .merge()) |
|
||||
| `crates/zclaw-saas/src/relay/handlers.rs` | 聊天中转 + Token Pool 分配 |
|
||||
| `crates/zclaw-saas/src/billing/` | 配额递增/订阅/支付回调 |
|
||||
| `crates/zclaw-saas/src/knowledge/` | 知识库 CRUD + pgvector (最大模块, 24 routes) |
|
||||
| `crates/zclaw-saas/src/workers/` | 7 个后台 Worker |
|
||||
| `crates/zclaw-saas/migrations/` | SQL 迁移 (38 文件, 42 CREATE TABLE) |
|
||||
| `admin-v2/src/pages/` | 17 页管理后台 |
|
||||
| `desktop/src/lib/saas-client.ts` | 前端 SaaS API 客户端 |
|
||||
| `desktop/src/store/saasStore.ts` | SaaS 认证状态 |
|
||||
|
||||
| 模块 | 路由注册 | 说明 |
|
||||
|------|----------|------|
|
||||
| auth | handlers.rs | 登录/注册/刷新/2FA |
|
||||
| relay | relay/ | 聊天中转/模型列表/任务 |
|
||||
| billing | billing/ + callback_routes | 配额/订阅/支付 |
|
||||
| knowledge | knowledge/ | 知识库 CRUD + pgvector (最大模块) |
|
||||
| model_config | model_config/ | Provider + 模型管理 |
|
||||
| account | account/ | 用户管理 |
|
||||
| agent_template | agent_template/ | Agent 模板 |
|
||||
| role | role/ | 角色 + 权限 |
|
||||
| telemetry | telemetry/ | 用量统计 |
|
||||
| prompt | prompt/ | Prompt 模板 |
|
||||
| scheduled_task | scheduled_task/ | 定时任务 CRUD |
|
||||
| industry | industry/ | 行业配置管理 (V13 新增) |
|
||||
| migration | migration/ | Schema 迁移 |
|
||||
### 数据流
|
||||
|
||||
```
|
||||
桌面端请求 (ChatPanel)
|
||||
→ Tauri invoke / HTTP SSE
|
||||
→ SaaS Relay (POST /api/v1/relay/chat/completions)
|
||||
→ JWT 验证 → Token Pool 选择 Key → LLM API
|
||||
→ SSE 流式返回
|
||||
→ 桌面端 streamStore.onDelta 渲染
|
||||
```
|
||||
|
||||
### 集成契约
|
||||
|
||||
| 方向 | 接口 | 说明 |
|
||||
|------|------|------|
|
||||
| Called by <-- desktop | Tauri invoke / HTTP SSE | Chat relay, billing, auth |
|
||||
| Calls --> relay handlers | POST /api/v1/relay/chat/completions | Token Pool RPM/TPM 轮换 |
|
||||
| Provides --> admin | 137 routes | User/billing/knowledge/model 管理 |
|
||||
|
||||
### API 分布
|
||||
|
||||
| 模块 | 路由数 | 核心端点 |
|
||||
|------|--------|---------|
|
||||
| knowledge | 24 | 分类/条目/搜索/上传/版本/结构化 |
|
||||
| model_config | 19 | Provider/模型/Key/模型组/用量 |
|
||||
| billing | 12 | 订阅/用量/支付/mock/回调/invoice |
|
||||
| account | 12 | CRUD/状态/token/设备/操作日志/dashboard |
|
||||
| agent_template | 11 | 模板 CRUD + 创建 Agent + 分配 |
|
||||
| auth | 9 | POST /auth/{register,login,refresh,logout} + TOTP + password |
|
||||
| industry | 8 | 行业 CRUD + 账户分配 |
|
||||
| migration | 8 | 配置项 CRUD + 分析/seed/sync/diff |
|
||||
| prompt | 6 | Prompt CRUD + 版本/回滚 |
|
||||
| role | 6 | 角色/权限模板 CRUD |
|
||||
| telemetry | 4 | 上报/统计/日报/审计 |
|
||||
| relay | 5 | POST /relay/chat/completions + GET /relay/models |
|
||||
| scheduled_task | 2 | 定时任务 CRUD |
|
||||
|
||||
### 数据表 (42 CREATE TABLE)
|
||||
|
||||
38 个 SQL 迁移文件 (21 up + 17 down),42 个 `CREATE TABLE` 语句。
|
||||
|
||||
核心表: users, agents, conversations, messages, billing_*, knowledge_*, model_configs, roles, permissions, scheduled_tasks, telemetry, agent_templates, saas_schema_version, user_profiles, trajectory_records, industries, account_industries
|
||||
|
||||
## 代码逻辑
|
||||
|
||||
### Token Pool RPM/TPM 轮换算法
|
||||
|
||||
```
|
||||
SaaS Relay 收到请求
|
||||
→ 验证 JWT → 提取 user_id
|
||||
→ Token Pool 选择 Key:
|
||||
1. priority ASC (高优先级优先)
|
||||
2. last_used_at ASC (最久未用优先)
|
||||
3. cooldown 检查 (跳过冷却中的 Key)
|
||||
4. RPM/TPM 滑动窗口检查 (当前窗口是否超限)
|
||||
→ 转发请求到 LLM API
|
||||
→ record_usage worker 异步记录
|
||||
```
|
||||
|
||||
### Workers (7 个)
|
||||
|
||||
| Worker | 文件 | 职责 |
|
||||
|--------|------|------|
|
||||
| record_usage | workers/ | 用量记录 (relay 后异步) |
|
||||
| aggregate_usage | workers/ | 用量聚合 (日报/月报) |
|
||||
| generate_embedding | workers/ | 内容分块 (embedding deferred, pgvector 就绪) |
|
||||
| log_operation | workers/ | 操作日志 |
|
||||
| cleanup_rate_limit | workers/ | 限流记录清理 |
|
||||
| cleanup_refresh_tokens | workers/ | 刷新 token 清理 |
|
||||
| record_usage | workers/ | 用量记录 |
|
||||
| update_last_used | workers/ | 模型最后使用更新 |
|
||||
| aggregate_usage | workers/ | 用量聚合 |
|
||||
| generate_embedding | workers/ | 内容分块 (embedding deferred) |
|
||||
| update_last_used | workers/ | 模型最后使用时间更新 |
|
||||
|
||||
## API 接口
|
||||
### 计费流程
|
||||
|
||||
~118 个唯一路由,分布在 13 个模块中(详见上方「SaaS API 分布」和各模块 `mod.rs`)。
|
||||
```
|
||||
用户请求 relay → quota_check_middleware 检查月度配额
|
||||
→ 通过: relay 正常执行
|
||||
→ record_usage worker 递增 relay_requests + input_tokens
|
||||
→ aggregate_usage worker 定期聚合
|
||||
→ 超额: 返回 429 QuotaExceeded
|
||||
```
|
||||
|
||||
| 模块 | 路由数 | 核心端点 |
|
||||
|------|--------|---------|
|
||||
| auth | 9 | POST /auth/{register,login,refresh,logout} + TOTP + password |
|
||||
| relay | 5 | POST /relay/chat/completions + GET /relay/models |
|
||||
| billing | 12 | 订阅/用量/支付/mock/回调/invoice |
|
||||
| knowledge | 24 | 分类/条目/搜索/上传/版本/分析/结构化 |
|
||||
| model_config | 19 | Provider/模型/Key/模型组/用量 |
|
||||
| account | 12 | CRUD/状态/token/设备/操作日志/dashboard |
|
||||
| agent_template | 11 | 模板 CRUD + 创建 Agent + 分配 |
|
||||
| industry | 8 | 行业 CRUD + 账户分配 |
|
||||
| prompt | 6 | Prompt CRUD + 版本/回滚 |
|
||||
| role | 6 | 角色/权限模板 CRUD |
|
||||
| telemetry | 4 | 上报/统计/日报/审计 |
|
||||
| scheduled_task | 2 | 定时任务 CRUD |
|
||||
| migration | 8 | 配置项 CRUD + 分析/seed/sync/diff |
|
||||
## 活跃问题 + 陷阱
|
||||
|
||||
## 测试链路
|
||||
| 问题 | 级别 | 说明 |
|
||||
|------|------|------|
|
||||
| Admin 用量统计显示 0/0 | P2 Open | Dashboard 17 requests / 6304 tokens,但 Usage 页 0/0,数据源不一致 |
|
||||
| 桌面端 Token 统计为 0 | P2 Open | 前端 token 统计未接通后端数据源 |
|
||||
| Deepseek 中转任务卡 processing | P3 Open | 特定模型 relay 任务状态不更新 |
|
||||
| Embedding 生成未实现 | 长期 | pgvector 索引就绪,generate_embedding worker 逻辑空 |
|
||||
| AuthGuard 竞态条件 | P1 Deferred | 并发请求时可能绕过认证 |
|
||||
|
||||
| 功能 | 测试文件 | 说明 |
|
||||
|------|---------|------|
|
||||
| 认证 | `crates/zclaw-saas/tests/auth_test.rs` | 注册/登录/刷新/登出 |
|
||||
| 认证安全 | `crates/zclaw-saas/tests/auth_security_test.rs` | 安全边界场景 |
|
||||
| 账户 | `crates/zclaw-saas/tests/account_test.rs` | CRUD/token/设备 |
|
||||
| 账户安全 | `crates/zclaw-saas/tests/account_security_test.rs` | 安全边界 |
|
||||
| Agent 模板 | `crates/zclaw-saas/tests/agent_template_test.rs` | 模板 CRUD |
|
||||
| 计费 | `crates/zclaw-saas/tests/billing_test.rs` | 计划/订阅/支付 |
|
||||
| 知识库 | `crates/zclaw-saas/tests/knowledge_test.rs` | CRUD/搜索 |
|
||||
| 模型配置 | `crates/zclaw-saas/tests/model_config_test.rs` | Provider/模型/Key |
|
||||
| 模型配置扩展 | `crates/zclaw-saas/tests/model_config_extended_test.rs` | 扩展覆盖 |
|
||||
| Prompt | `crates/zclaw-saas/tests/prompt_test.rs` | 版本管理 |
|
||||
| 权限矩阵 | `crates/zclaw-saas/tests/permission_matrix_test.rs` | 角色/权限 |
|
||||
| Relay | `crates/zclaw-saas/tests/relay_test.rs` | 聊天中转 |
|
||||
| Relay 验证 | `crates/zclaw-saas/tests/relay_validation_test.rs` | 请求验证 |
|
||||
| 角色 | `crates/zclaw-saas/tests/role_test.rs` | 角色 CRUD |
|
||||
| 定时任务 | `crates/zclaw-saas/tests/scheduled_task_test.rs` | 任务 CRUD |
|
||||
| Telemetry | `crates/zclaw-saas/tests/telemetry_test.rs` | 上报/查询 |
|
||||
| 配置同步 | `crates/zclaw-saas/tests/migration_test.rs` | sync/diff/seed |
|
||||
| Admin 启动 | `crates/zclaw-saas/tests/smoke_saas.rs` | 启动冒烟 |
|
||||
| Admin V2 UI | `admin-v2/tests/pages/*.test.tsx` (17文件) | 每页独立测试 |
|
||||
| 桌面端 SaaS | `tests/desktop/connectionStore.adminRouting.test.ts` | Admin 路由 |
|
||||
| 桌面端集成 | `tests/desktop/integration/zclaw-api.test.ts` | API 集成 |
|
||||
陷阱:
|
||||
- SaaS 数据库需要 PostgreSQL (`docker-compose.yml`),不是 SQLite
|
||||
- Token Pool 的 RPM/TPM 是滑动窗口不是固定窗口,测试时注意时间边界
|
||||
- `saas-config.toml` 支持 `${ENV_VAR}` 环境变量插值
|
||||
- knowledge 是最大模块 (24 routes),修改时影响面广
|
||||
|
||||
## 关联模块
|
||||
## 变更日志
|
||||
|
||||
- [[routing]] — SaaS Relay 是 Tauri 的主路径
|
||||
- [[chat]] — 聊天请求经过 SaaS relay 中转
|
||||
- [[memory]] — knowledge_chunks 表有 pgvector 索引
|
||||
| 日期 | 变更 | 提交 |
|
||||
|------|------|------|
|
||||
| 2026-04-21 | Embedding 接通 + 自学习 A/B 线 | — |
|
||||
| 2026-04-17 | E2E 测试 129 链路,7 Bug 修复 | — |
|
||||
| 2026-04-15 | Heartbeat 统一健康系统 | — |
|
||||
| 2026-04-12 | 行业配置 + 管家主动性全栈 5 Phase | — |
|
||||
| 2026-04-09 | Hermes Intelligence Pipeline 4 Chunk | 684 tests PASS |
|
||||
|
||||
## 关键文件
|
||||
### 测试覆盖
|
||||
|
||||
| 文件 | 职责 |
|
||||
|------|------|
|
||||
| `crates/zclaw-saas/src/main.rs` | 路由注册入口 (13个 .merge()) |
|
||||
| `crates/zclaw-saas/src/auth/handlers.rs` | 认证端点 |
|
||||
| `crates/zclaw-saas/src/relay/` | 聊天中转 |
|
||||
| `crates/zclaw-saas/src/billing/` | 计费 |
|
||||
| `crates/zclaw-saas/src/knowledge/` | 知识库 |
|
||||
| `crates/zclaw-saas/src/workers/` | 7 个后台 Worker |
|
||||
| `crates/zclaw-saas/migrations/` | SQL 迁移 (38 文件) |
|
||||
| `admin-v2/src/pages/` | 17 页管理后台(含 Dashboard/Accounts/Billing/Industries/Knowledge/Prompts/Roles/ScheduledTasks/Config 等) |
|
||||
| `desktop/src/lib/saas-client.ts` | 前端 SaaS API 客户端 |
|
||||
| `desktop/src/store/saasStore.ts` | SaaS 认证状态 |
|
||||
|
||||
## 安全
|
||||
|
||||
完整审计: `docs/features/SECURITY_PENETRATION_TEST_V1.md`
|
||||
- CORS 白名单 (生产缺失拒绝启动)
|
||||
- Cookie Secure (dev=false, prod=true)
|
||||
- JWT 签名密钥 >= 32 字符 (release fallback 拒绝启动)
|
||||
- 独立 TOTP 加密密钥
|
||||
|
||||
## 已知问题
|
||||
|
||||
- ⚠️ **Admin 用量统计显示 0/0** — P2 Open。Dashboard 显示 17 requests / 6304 tokens,但 Usage 页显示 0/0,数据源不一致
|
||||
- ⚠️ **SaaS Embedding 生成未实现** — Open。pgvector 索引就绪,`generate_embedding.rs` Worker 存在但生成逻辑未实现
|
||||
- ⚠️ **AuthGuard 竞态条件** — P1-04 Deferred。并发请求时可能绕过认证
|
||||
- ✅ **Dashboard 404** — BUG-H1 已修复。`/api/v1/admin/dashboard` 路由注册遗漏
|
||||
- ✅ **invoice_id 未暴露** — BUG-M1 已修复
|
||||
- ✅ **非 Admin 返回 404 而非 403** — BUG-M4 已修复 (admin_guard_middleware)
|
||||
| 功能 | 测试文件 |
|
||||
|------|---------|
|
||||
| 认证流程 | `crates/zclaw-saas/tests/auth_test.rs` |
|
||||
| 认证安全 | `crates/zclaw-saas/tests/auth_security_test.rs` |
|
||||
| 账户 CRUD | `crates/zclaw-saas/tests/account_test.rs` |
|
||||
| 账户安全 | `crates/zclaw-saas/tests/account_security_test.rs` |
|
||||
| 计费 | `crates/zclaw-saas/tests/billing_test.rs` |
|
||||
| 知识库 | `crates/zclaw-saas/tests/knowledge_test.rs` |
|
||||
| 模型配置 | `crates/zclaw-saas/tests/model_config_test.rs` |
|
||||
| Prompt | `crates/zclaw-saas/tests/prompt_test.rs` |
|
||||
| 权限矩阵 | `crates/zclaw-saas/tests/permission_matrix_test.rs` |
|
||||
| Relay | `crates/zclaw-saas/tests/relay_test.rs` |
|
||||
| Relay 验证 | `crates/zclaw-saas/tests/relay_validation_test.rs` |
|
||||
| 角色 | `crates/zclaw-saas/tests/role_test.rs` |
|
||||
| 定时任务 | `crates/zclaw-saas/tests/scheduled_task_test.rs` |
|
||||
| Telemetry | `crates/zclaw-saas/tests/telemetry_test.rs` |
|
||||
| 配置同步 | `crates/zclaw-saas/tests/migration_test.rs` |
|
||||
|
||||
Reference in New Issue
Block a user