181 lines
7.2 KiB
Markdown
181 lines
7.2 KiB
Markdown
# 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` 未调用 | 统一迁移向导调用路径 |
|