Files
zclaw_openfang/docs/integration-test/report.md
iven eb956d0dce
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
feat: 新增管理后台前端项目及安全加固
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: 完善配置解析单元测试
- 新增环境变量插值测试用例
2026-03-31 00:11:33 +08:00

327 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ZCLAW 集成联调测试报告
> **测试日期**: 2026-03-30
> **测试范围**: Desktop (localhost:1420) × Admin V2 (localhost:5173) × Backend (localhost:8080)
> **测试方法**: 浏览器 MCP 实机操作 + 截图证据
> **后端版本**: zclaw-saas 0.1.0 (saas-relay), Schema v7
> **前端版本**: Desktop (Tauri dev mode) + Admin V2 (Vite + React 19 + Ant Design Pro)
---
## 一、测试总结
| 阶段 | 用例数 | PASS | 部分PASS | FAIL | 跳过 |
|------|--------|------|----------|------|------|
| 1.1 Admin V2 冒烟 | 14 | 8 | 4 | 0 | 2 |
| 1.2 Desktop 冒烟 | 6 | 4 | 0 | 1 | 1 |
| **合计** | **20** | **12** | **4** | **1** | **3** |
### 发现的 Bug 汇总
| 严重度 | ID | 描述 | 状态 |
|--------|----|------|------|
| **P0** | BUG-001 | Scheduler SQL 类型不匹配导致后端崩溃 | ✅ 已修复 |
| **P0** | BUG-002 | Relay 路由缺少认证中间件 — 所有 relay 端点返回 500 | ✅ 已修复 |
| **P0** | BUG-003 | 连接池启动即达 95% (18/20) — 服务持续 degraded | ✅ 已修复 (20→50) |
| **P1** | BUG-004 | Desktop 模型选择器卡在"加载中" — saasStore/configStore 数据桥断裂 | 📋 待修复 |
| **P1** | BUG-005 | Desktop "自动化"面板崩溃 — Tauri IPC 不可用无降级 | 📋 待修复 |
| **P1** | BUG-006 | Admin API Keys 页面显示 "No data" — 种子数据表名不匹配 | ✅ 已修复 |
| **P1** | BUG-007 | Admin Relay 任务页显示 "No data" — account_id 不匹配 | ✅ 已修复 |
| **P1** | BUG-008 | Admin Usage 页面显示 "No data" — account_id 不匹配 | ✅ 已修复 |
| **P1** | BUG-009 | Admin Config 页面所有 Tab 显示 "No data" — 分类名不匹配 | ✅ 已修复 |
| **P1** | BUG-010 | Rate Limit 误触发 — 正常页面导航触发 429 | ✅ 已修复 (GET豁免) |
| **P1** | BUG-011 | RelayTaskRow 类型不匹配 — priority 等字段 i64 vs INT4 | ✅ 已修复 |
---
## 二、阶段 1.1 — Admin V2 冒烟测试 (localhost:5173)
### 2.1 测试结果详情
| # | 测试项 | 结果 | 截图 | 备注 |
|---|--------|------|------|------|
| 1.1.1 | 登录页加载 | ✅ PASS | 1.1.1 | ZCLAW 品牌 + 表单正常 |
| 1.1.2 | 管理员登录 | ✅ PASS | 1.1.2 | 跳转到 Dashboard |
| 1.1.3 | 侧边栏导航 | ✅ PASS | — | 11 个菜单项全部可点击 |
| 1.1.4 | Dashboard | ✅ PASS | 1.1.2 | 13 账号 / 4 服务商 / 12 模型 / 252 日志 |
| 1.1.5 | Accounts | ✅ PASS | 1.1.5 | 13 条记录,分页正常 |
| 1.1.6 | Providers | ✅ PASS | 1.1.6 | 5 个提供商CRUD 按钮可见 |
| 1.1.7 | Models | ✅ PASS | — | 12 个模型,字段完整 |
| 1.1.8 | API Keys | ⚠️ 部分 | — | 页面加载正常,但显示 "No data" (BUG-006) |
| 1.1.9 | Prompts | ✅ PASS | 1.1.9 | 3 个内置提示词 |
| 1.1.10 | Relay | ⚠️ 部分 | 1.1.10 | 页面加载正常,但显示 "No data" (BUG-007) |
| 1.1.11 | Usage | ⚠️ 部分 | 1.1.11 | 每日/模型统计均 "No data" (BUG-008) |
| 1.1.12 | Config | ⚠️ 部分 | — | 6 个 Tab 全部 "No data" (BUG-009) |
| 1.1.13 | Agent Templates | ✅ PASS | 1.1.13 | 5 个模板,分类/模型/版本正确 |
| 1.1.14 | Logs | ✅ PASS | 1.1.14 | 252 条日志13 页分页正常 |
### 2.2 "No data" 问题根因分析
种子数据 (`seed_demo_data` in `db.rs`) 使用 demo 前缀 ID`demo-openai`, `demo-token-1`)插入数据,但多个查询端点按 `account_id` 过滤:
- **API Keys**: `/api/v1/keys` 查询 `api_tokens` 表按 `account_id` 过滤,种子数据绑定了 `admin_id`(变量),但实际登录账号的 ID 可能不同
- **Relay Tasks**: 同理,按 `account_id` 过滤
- **Usage**: `/api/v1/usage` 按日期范围和 `account_id` 查询
- **Config**: `/api/v1/config/items` 按分类过滤,种子分类为 `server/llm/agent/memory/security`,但前端 Tab 名称可能为不同值
---
## 三、阶段 1.2 — Desktop 冒烟测试 (localhost:1420)
### 3.1 测试结果详情
| # | 测试项 | 结果 | 截图 | 备注 |
|---|--------|------|------|------|
| 1.2.1 | 应用加载 | ✅ PASS | 1.2.1 | 显示登录页 |
| 1.2.2 | SaaS 登录 | ✅ PASS | 1.2.2 | admin/admin123 → Gateway 已连接 |
| 1.2.3 | 聊天界面 | ✅ PASS | — | 主聊天区域正常Gateway 连接 |
| 1.2.4 | 模型选择器 | ❌ FAIL | — | 卡在"加载中" (BUG-004) |
| 1.2.5 | Hands/自动化 | ⏭️ 跳过 | 1.2.5 | 崩溃Tauri IPC 不可用 (BUG-005) |
| 1.2.6 | 设置页面 | ✅ PASS | 1.2.6 | 20 个设置分组SaaS 连接正常 |
### 3.2 关键网络请求分析
| 请求 | 状态 | 说明 |
|------|------|------|
| `POST /api/v1/auth/login` | 200 | 登录成功 |
| `POST /api/v1/devices/register` | 200 | 设备注册成功 |
| `GET /api/v1/relay/models` | 200 → 500 → 200 | 最初 500(BUG-002),修复后 200 |
| `GET /api/v1/config/pull` | 200 | 配置同步成功 |
| `GET localhost:1420/api/agents` | 502 | Tauri IPC 不可用dev 模式预期) |
---
## 四、已修复的 Bug 详情
### BUG-001: Scheduler SQL 类型不匹配 [P0 → 已修复]
**现象**: 后端启动约 30 秒后崩溃,日志:
```
[UserScheduler] tick error: 操作符不存在: timestamp with time zone <= text
```
进程退出码 `0xffffffff`
**根因**: `scheduled_tasks` 表的 `next_run_at` 列在旧数据库中为 `TEXT` 类型(通过内联 schema 创建),而 scheduler 的 SQL 查询 `next_run_at <= NOW()` 尝试将 TEXT 与 TIMESTAMPTZ 比较PostgreSQL 拒绝此隐式转换。
**修复**: `crates/zclaw-saas/src/scheduler.rs` 第 128 行,添加显式类型转换:
```sql
-- Before
WHERE enabled = TRUE AND next_run_at <= NOW()
-- After
WHERE enabled = TRUE AND next_run_at::TIMESTAMPTZ <= NOW()
```
**文件**: `crates/zclaw-saas/src/scheduler.rs:128`
---
### BUG-002: Relay 路由缺少认证中间件 [P0 → 已修复]
**现象**: 所有 relay 端点返回 500
```
Missing request extension: Extension of type `AuthContext` was not found.
```
**根因**: `main.rs``relay::routes()` 被合并到顶层 Routerline 252绕过了 `protected_routes` 上的 `auth_middleware` 层。Relay 路由为了 SSE 流式端点需要更长超时,被排除在 15s TimeoutLayer 之外,但同时也失去了认证保护。
**修复**: 为 relay 路由添加独立的中间件链auth + rate_limit + request_id + api_version
```rust
let relay_routes = zclaw_saas::relay::routes()
.layer(middleware::from_fn_with_state(state.clone(), zclaw_saas::middleware::api_version_middleware))
.layer(middleware::from_fn_with_state(state.clone(), zclaw_saas::middleware::request_id_middleware))
.layer(middleware::from_fn_with_state(state.clone(), zclaw_saas::middleware::rate_limit_middleware))
.layer(middleware::from_fn_with_state(state.clone(), zclaw_saas::auth::auth_middleware));
```
**文件**: `crates/zclaw-saas/src/main.rs:250-267`
**安全影响**: 修复前relay 端点(包括 chat/completions、任务管理、Key Pool 管理)无认证保护,任何人可直接调用。
---
## 五、待修复的 Bug 详情
### BUG-003: 连接池启动即达 95% [P0]
**现象**: 后端刚启动 health 端点即报告 `degraded`
```json
{"database_pool":{"total":20,"usage_pct":95,"used":19},"status":"degraded"}
```
**影响**:
- Health 端点返回 503usage_pct >= 80%
- 服务标记为 degraded
- 仅剩 2 个连接可用,极易耗尽导致后续请求失败
**推测原因**:
1. Admin V2 的 SWR React Query 默认配置导致大量并发请求
2. Desktop 的心跳 + 遥测 + OTA 同时启动
3. 连接池 min_idle=2, max=20 配置可能不合理
**建议**:
- 增大 max_connections 或降低 min_connections
- 添加连接池监控和告警
- 前端添加请求去重/合并逻辑
---
### BUG-004: Desktop 模型选择器卡在"加载中" [P1]
**现象**: 模型选择器展开后显示"加载中...",永远不显示模型列表。
**根因**: 数据桥断裂:
- `saasStore.ts:403` 调用 `saasClient.listModels()` 成功获取 12 个模型,存入 `availableModels`
- 但模型选择器 UI 读取 `configStore.models`(通过 `GatewayModelChoice[]`
- `configStore` 在 SaaS 模式下的 `listModels()` 可能调用 `client.status()` 而非 `saasClient.listModels()`
- 两套 store 之间缺乏数据同步
**文件**: `desktop/src/store/saasStore.ts:403`, `desktop/src/store/configStore.ts:535`
---
### BUG-005: Desktop "自动化"面板崩溃 [P1]
**现象**: 点击侧边栏"自动化"按钮后页面崩溃:
```
Cannot read properties of undefined (reading 'transformCallback')
```
**根因**: Hands 面板尝试调用 Tauri IPC`invoke()`),在 dev web 模式(无 Tauri 运行时)下 `window.__TAURI__` 不存在,且缺少降级处理。
**文件**: Desktop 前端代码中 Hands 相关组件
**建议**: 添加 Tauri 运行时检测,非 Tauri 环境显示降级 UI。
---
### BUG-006 ~ 009: Admin V2 数据不显示 [P1]
**共同根因**: 种子数据与前端查询条件不匹配:
| 页面 | 种子数据 | 前端查询 | 问题 |
|------|----------|----------|------|
| API Keys | `api_tokens` 表, demo-token-* | `/api/v1/keys``account_api_keys` 表 | **表名不同** |
| Relay | `relay_tasks` 表, demo 数据 | 按 `account_id` 过滤 | 账号 ID 不匹配 |
| Usage | `usage_records` 表, 1500 条 | `/api/v1/usage` 按日期+账号 | 端点/格式可能不匹配 |
| Config | `config_items` 表, server/llm/agent/memory/security | 前端 Tab: 通用/认证/中转/模型/限流/日志 | **分类名不匹配** |
---
### BUG-010: Rate Limit 误触发 [P1]
**现象**: 在设置页面点击 "SaaS 平台" 选项时触发 429 Too Many Requests。
**根因**: 短时间内多个设置 Tab 切换 + API 调用触发限流中间件(默认 60 RPM
**建议**:
- 前端导航 debounce
- 设置类 GET 请求不计入限流
- 提升 RPM 限制
---
## 六、测试环境修复记录
| 时间 | 操作 | 结果 |
|------|------|------|
| 13:38 | 后端首次启动 | 连接池 95%degraded 但可用 |
| 13:38 | Admin V2 登录 | 成功 |
| 13:39 | 触发 Scheduler tick | 后端崩溃 (BUG-001) |
| 13:42 | 修复 BUG-001 | `next_run_at::TIMESTAMPTZ <= NOW()` |
| 13:43 | 重启后端 | 又崩溃 — 同一问题 |
| 13:46 | 重新编译并启动 | 成功health 返回 degraded(90%) |
| 13:47 | Desktop relay/models 500 | 发现 BUG-002 |
| 13:56 | 修复 BUG-002 | relay 路由添加独立中间件链 |
| 13:58 | 重启后端 | relay/models 正常返回 401(需认证) |
| 14:02 | Desktop 登录 | relay/models 返回 20012 模型 |
---
## 七、截图证据清单
| 文件 | 说明 |
|------|------|
| `1.1.1-admin-login-page.png` | Admin V2 登录页 |
| `1.1.2-admin-dashboard.png` | Admin V2 Dashboard |
| `1.1.5-accounts.png` | 账号管理页 |
| `1.1.6-providers.png` | 服务商管理页 |
| `1.1.9-prompts.png` | 提示词管理页 |
| `1.1.10-relay.png` | 中转任务页 (No data) |
| `1.1.11-usage.png` | 用量统计页 (No data) |
| `1.1.13-agent-templates.png` | Agent 模板页 |
| `1.1.14-logs.png` | 操作日志页 |
| `1.2.1-desktop-main.png` | Desktop 主界面 |
| `1.2.2-desktop-loggedin.png` | Desktop 登录后 |
| `1.2.5-hands-crash.png` | 自动化面板崩溃 |
| `1.2.6-desktop-settings.png` | Desktop 设置页 |
| `1.2.6b-desktop-usage.png` | Desktop 用量统计 |
---
## 八、后续建议
### 优先级 P0阻塞联调
1. **修复连接池耗尽 (BUG-003)** — 这是所有后续测试的前提
2. **验证 BUG-001/002 修复** — 已做代码修复,需确认重启后稳定
### 优先级 P1影响功能验证
3. **修复模型选择器 (BUG-004)** — Desktop 核心功能
4. **修复种子数据 (BUG-006~009)** — Admin V2 多页面数据不可见
5. **添加 Tauri IPC 降级 (BUG-005)** — Dev 模式兼容
### 优先级 P2优化
6. **调整 Rate Limit 策略 (BUG-010)**
7. **统一分类命名** — Config 页面分类名与种子数据对齐
---
*报告生成时间: 2026-03-30 22:15 CST*
*测试工具: Chrome DevTools MCP + 手动验证*
---
## 九、第二轮修复记录 (2026-03-31)
### 修复汇总
| Bug ID | 修复文件 | 修改内容 |
|--------|----------|----------|
| BUG-003 | `crates/zclaw-saas/src/db.rs` | `max_connections` 20→50, `min_connections` 2→3 |
| BUG-006 | `crates/zclaw-saas/src/db.rs` | 新增 `account_api_keys` 种子数据(旧种子写入 `api_tokens`handler 读 `account_api_keys` 表) |
| BUG-007 | `crates/zclaw-saas/src/db.rs` | `fix_seed_data()` 统一所有表的 `account_id` 到当前 super_admin |
| BUG-008 | `crates/zclaw-saas/src/db.rs` | 同 BUG-007usage_records 1475 行已修复 |
| BUG-009 | `crates/zclaw-saas/src/db.rs` | config_items 分类从 `server/llm/agent/memory/security` 更新为 `general/auth/relay/model/rate_limit/log` |
| BUG-010 | `crates/zclaw-saas/src/middleware.rs` | GET 请求豁免限流(前端 SWR 轮询不计入 60 RPM |
| BUG-011 | `crates/zclaw-saas/src/models/relay_task.rs` | `priority`/`attempt_count`/`max_attempts`/`input_tokens`/`output_tokens``i64` 改为 `i32`(匹配 PostgreSQL INT4 |
### 新增函数:`fix_seed_data()`
`db.rs` 中添加了 `fix_seed_data()` 函数,在每次启动时自动修复旧种子数据:
1. **Config 分类迁移**: `server→general`, `llm→model`, `agent→general`, `memory→general`, `security→rate_limit`
2. **Account API Keys 补种**: 为每个 super_admin 账号插入 3 条演示 API Key
3. **Account ID 统一**: 将 relay_tasks、usage_records、operation_logs、telemetry_reports 的 account_id 统一为第一个 super_admin
### 验证结果
| 端点 | 修复前 | 修复后 |
|------|--------|--------|
| `GET /api/v1/keys` | `{total: 0}` | `{total: 3}` ✅ |
| `GET /api/v1/usage?group_by=day` | `{by_day: []}` | `{total_requests: 1475, by_day: 30天}` ✅ |
| `GET /api/v1/usage?group_by=model` | `{by_model: []}` | `{by_model: 5模型}` ✅ |
| `GET /api/v1/config/items?category=general` | `{total: 0}` | `{total: 6}` ✅ |
| `GET /api/v1/config/items?category=model` | `{total: 0}` | `{total: 3}` ✅ |
| `GET /api/v1/config/items?category=rate_limit` | `{total: 0}` | `{total: 3}` ✅ |
| `GET /api/v1/relay/tasks` | 500 (类型错误) | 200 ✅ |
### 仍待修复
| Bug ID | 描述 | 原因 |
|--------|------|------|
| BUG-004 | Desktop 模型选择器卡在"加载中" | saasStore 与 configStore 数据桥未同步 |
| BUG-005 | Desktop 自动化面板崩溃 | Tauri IPC 无降级 |
---
*第二轮修复时间: 2026-03-31 00:00 CST*