--- title: SaaS 平台 updated: 2026-04-22 status: active tags: [module, saas, billing, relay] --- # SaaS 平台 > 从 [[index]] 导航。关联模块: [[routing]] [[chat]] [[security]] ## 设计决策 **核心定位: SaaS 是 Tauri 桌面端的中枢,不是独立 Web 应用。** | 决策 | 为什么 | |------|--------| | 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]] | ## 关键文件 + 数据流 ### SaaS 模块结构 16 个目录 (`crates/zclaw-saas/src/`): ``` account/ agent_template/ auth/ billing/ industry/ knowledge/ migration/ model_config/ models/ prompt/ relay/ role/ scheduled_task/ tasks/ telemetry/ workers/ ``` ### 核心文件 | 文件 | 职责 | |------|------| | `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 认证状态 | ### 数据流 ``` 桌面端请求 (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) 核心表: 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 清理 | | update_last_used | workers/ | 模型最后使用时间更新 | ### 计费流程 ``` 用户请求 relay → quota_check_middleware 检查月度配额 → 通过: relay 正常执行 → record_usage worker 递增 relay_requests + input_tokens → aggregate_usage worker 定期聚合 → 超额: 返回 429 QuotaExceeded ``` ## 活跃问题 + 陷阱 | 问题 | 级别 | 说明 | |------|------|------| | 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 | 并发请求时可能绕过认证 | 陷阱: - SaaS 数据库需要 PostgreSQL (`docker-compose.yml`),不是 SQLite - Token Pool 的 RPM/TPM 是滑动窗口不是固定窗口,测试时注意时间边界 - `saas-config.toml` 支持 `${ENV_VAR}` 环境变量插值 - knowledge 是最大模块 (24 routes),修改时影响面广 ## 变更日志 | 日期 | 变更 | 提交 | |------|------|------| | 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/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` |