# SaaS + Tauri 联合调试测试报告 > **ARCHIVED — 此报告已过时** > > 本报告记录 2026-03-28 的联合调试结果。相关修复已全部合并。 > > **请参考最新文档** → [README.md](./README.md) | [00-saas-overview.md](./08-saas-platform/00-saas-overview.md) > **测试日期**: 2026-03-28 (原文标注有误) > **测试环境**: Windows 11 + PostgreSQL 17 + Rust SaaS @ 127.0.0.1:8080 > **测试范围**: SaaS 后端 API + Tauri 桌面端集成层 + Admin 前端 --- ## 一、测试执行摘要 | 阶段 | 用例数 | 通过 | 失败 | 发现 | 状态 | |------|--------|------|------|------|------| | P0 安全 | 2 | 2 | 0 | 0 | ✅ 已修复验证 | | A 类功能 | 15 | 13 | 1 | 1 | ✅ models 已修复 | | B 类数据 | 5 | 3 | 1 | 1 | ⚠ 部分验证 | | C 类流程 | 5 | N/A | N/A | N/A | ⏸ 服务中断 | | D 类异常 | 7 | N/A | N/A | N/A | ⚸ 服务中断 | | Admin 专项 | 2 | 2 | 0 | 0 | ✅ 已修复 | **总计**: 36 个测试用例, 20 通过, 2 失败, 2 新发现, 12 未执行 --- ## 二、已确认通过的测试 (20/36) ### P0 安全修复 — 全部通过 ✅ | ID | 测试项 | 结果 | 详情 | |----|--------|------|------| | T-CRIT-01 | `sync_config` 权限检查 | **PASS** | user 角色 → 403 "权限不足: 需要 config:write 权限" | | T-CRIT-02 | `/api/health` 端点 | **PASS** | 返回 "ok", HTTP 200 | ### A 类功能模块 — 13/15 通过 | ID | 测试项 | 结果 | 详情 | |----|--------|------|------| | A-01 | 用户注册 | **PASS** | 201 Created, 返回完整 AccountPublic | | A-01b | 重复注册 | **PASS** | 409 CONFLICT | | A-02 | 正确密码登录 | **PASS** | 200 + JWT token + account | | A-02b | 错误密码登录 | **PASS** | 401 AUTH_ERROR | | A-02c | GET /auth/me | **PASS** | 返回完整用户信息 | | A-02d | Token 刷新 | **PASS** | 200 + 新 JWT token | | A-04a | user 创建 Provider | **PASS** | 403 "权限不足: 需要 provider:manage 权限" | | A-04b | ~~GET /models~~ | **FAIL→FIXED** | 原 500 (SQL参数错误), → 修复后 200 | | A-05a | 设备注册 | **PASS** | 200 + UPSERT 语义正确 | | A-05b | 重复设备注册 | **PASS** | 200, 不重复创建 | | A-05c | 设备心跳 | **PASS** | 200 | | A-05d | 设备列表 | **PASS** | 返回注册的设备 | | A-06a | 密码修改 | **PASS** | 200 + 旧密码失效验证 | | A-06b | 错误旧密码 | **PASS** | 401 AUTH_ERROR | | A-07 | API Token 创建/认证 | **PASS** | zclaw_ 前缀 token, /me 正常 | ### B 类数据测试 — 3/5 通过 | ID | 测试项 | 结果 | 详情 | |----|--------|------|------| | B-01 | Config seed | **PASS** | 创建 13 个默认配置项 | | B-02a | Config diff | **PASS** | 返回 conflict 比对正确 | | B-02b | Config sync push | **PASS** | 返回 {updated, created, skipped} | | ~~B-02c~~ | ~~`created` 计数修复~~ | **FIXED** | 原 created=0 → 修复后 push 新 key 时 created=1 | | B-03 | ~~GET /models~~ | **FAIL→FIXED** | SQL 参数绑定错误 500 → 已修复 | ### Admin 专项 — 2/2 通过 | ID | 测试项 | 结果 | 详情 | |----|--------|------|------| | E-01 | 权限过滤逻辑 | **PASS** | 已修复: 基于 permissions 数组过滤 | | E-02 | 分页连接 API | **PASS** | 已确认 5 个页面均传递分页参数 | --- ## 三、发现并修复的 Bug 汇总 ### 已修复 (5 项) | # | 严重性 | 问题 | 文件 | 修复 | |---|--------|------|------|------| | 1 | **CRITICAL** | `sync_config` 无权限检查 | [migration/handlers.rs:90](crates/zclaw-saas/src/migration/handlers.rs#L90) | 添加 `check_permission(&ctx, "config:write")` | | 2 | **HIGH** | `GET /models` SQL 参数绑定错误 | [model_config/service.rs:135](crates/zclaw-saas/src/model_config/service.rs#L135) | `LIMIT $2 OFFSET $3` → `LIMIT $1 OFFSET $2` | | 3 | **MEDIUM** | `sync_config` merge 分支双重计数 | [migration/service.rs:352](crates/zclaw-saas/src/migration/service.rs#L352) | `skipped += 1` 仅在 `else` 分支执行 | | 4 | **MEDIUM** | `sync_config` created 计数永远为 0 | [migration/service.rs:311](crates/zclaw-saas/src/migration/service.rs#L311) | push 模式创建新 config_item 时递增 | | 5 | **HIGH** | Admin 权限过滤逻辑错误 | [layout.tsx:107](admin/src/app/(dashboard)/layout.tsx#L107) | 基于 ROLE_PERMISSIONS 映射过滤 | ### 新发现 (2 项) | # | 严重性 | 问题 | 详情 | |---|--------|------|------| | 6 | **LOW** | 中文 display_name JSON 解析失败 | 注册时 display_name 含中文字符报 "invalid unicode code point",| 7 | **LOW** | 设备清理 SQL 类型不匹配 | 日志: "操作符不存在: text < timestamp with time zone" | --- ## 四、未执行的测试 (12 项) 服务在测试过程中断(环境限制),以下测试用例留待下次执行: | 阶段 | 未执行项 | |------|---------| | B 类 | Relay 中转流式/非流式、错误码映射、Token 自动刷新 | | C 类 | 新用户完整旅程、Admin 管理流程、TOTP 2FA、配置迁移向导、多设备管理 | | D 类 | 断网恢复、Token 过期、上游异常、并发竞争、SSRF 防护、限流、输入验证 | --- ## 五、修复的代码变更清单 ### 1. crates/zclaw-saas/src/migration/handlers.rs ```rust // 修复前: 无权限检查 // 修复后: 添加 check_permission pub async fn sync_config(...) -> SaasResult<...> { check_permission(&ctx, "config:write")?; // 新增 ... } ``` ### 2. crates/zclaw-saas/src/model_config/service.rs ```rust // 修复前: LIMIT $2 OFFSET $3 (无 provider_id 时参数不匹配) // 修复后: LIMIT $1 OFFSET $2 FROM models ORDER BY provider_id, alias LIMIT $1 OFFSET $2 ``` ### 3. crates/zclaw-saas/src/migration/service.rs ```rust // 修复 1: created 从不可变变为可变 let mut created = 0i64; // 原: let created = 0i64; // 修复 2: push 模式下 SaaS 不存在的 key 创建新配置项 } else { let id = uuid::Uuid::new_v4().to_string(); sqlx::query("INSERT INTO config_items ...")...; created += 1; } // 修复 3: merge 分支双重计数 Bug } else { skipped += 1; } // 移除了原来在 if let Some 外面的 skipped += 1 ``` ### 4. admin/src/app/(dashboard)/layout.tsx ```typescript // 修复: 添加 ROLE_PERMISSIONS 映射和基于权限的过滤逻辑 const ROLE_PERMISSIONS = { super_admin: ['admin:full', ...], admin: ['account:admin', 'provider:manage', ...], user: ['model:read', 'relay:use', 'config:read'], }; // 使用 account.permissions.includes(item.permission) 过滤 ``` --- ## 六、遗留问题与建议 ### P0 — 需立即修复 无(CRITICAL 已修复) ### P1 — 功能缺陷 | # | 问题 | 建议 | |---|------|------| | P1-1 | `account_api_keys` 未被 Relay 消费 | Relay handler 查找用户级 Key,回退到 provider 级 | | P1-2 | Config 5 端点缺审计日志 | 添加 `log_operation()` 调用 | | P1-3 | Admin 前端缺路由守卫 | 添加 AuthGuard 组件 | ### P2 — 代码质量 | # | 问题 | 建议 | |---|------|------| | P2-1 | 6 个端点缺 OpenAPI 文档 | 补充 `#[utoipa::path]` | | P2-2 | 设备清理 SQL 类型不匹配 | `last_seen_at` 字段类型修正 | | P2-3 | 中文 display_name JSON 解析 | UTF-8 编码处理 | | P2-4 | dashboard_stats 7 次串行查询 | 合并为单次 SQL | | P2-5 | `computeConfigDiff`/`syncConfig` 未调用 | 统一迁移向导调用路径 |