Files
zclaw_openfang/docs/superpowers/specs/2026-03-28-post-debug-remediation-design.md
iven 5fdf96c3f5 chore: 提交所有工作进度 — SaaS 后端增强、Admin UI、桌面端集成
包含大量 SaaS 平台改进、Admin 管理后台更新、桌面端集成完善、
文档同步、测试文件重构等内容。为 QA 测试准备干净工作树。
2026-03-29 10:46:41 +08:00

8.4 KiB
Raw Blame History

联合调试后修复行动计划

日期: 2026-03-28 来源: 联合调试报告 V1 + 专家代码审查 状态: 执行中


一、修复优先级矩阵

P0 — 阻塞级(必须立即修复)

# 问题 模块 影响 修复方案
P0-1 SSE Relay 死锁 relay/service.rs 流式中转完全不可用 blocking_lock()tokio::sync::Mutex 或 channel
P0-2 Token 过期无法刷新 auth/mod.rs 自动续期失效,用户被迫重新登录 middleware 对 /auth/refresh 路径跳过过期检查
P0-3 设备清理 SQL 崩溃 main.rs:58 stale devices 永远不清理 TEXT 比较: 绑定 rfc3339 字符串替代 NOW()

P1 — 功能缺陷(本周修复)

# 问题 模块 影响 修复方案
P1-1 注册返回类型不匹配 auth/handlers.rs 桌面端注册后无法自动登录 register handler 返回含 token 的响应
P1-2 account_api_keys 未被 Relay 消费 relay/handlers.rs 用户级 API Key 无效 relay 优先查 account_api_keys回退到 provider key
P1-3 TOTP nonce 硬编码 auth/totp.rs 相同明文+相同密钥产生相同密文 使用随机 nonce
P1-4 Config 5 端点缺审计日志 migration/handlers.rs 配置变更无 audit trail 添加 log_operation() 调用
P1-5 Admin 缺路由守卫 admin/src URL 直通可绕过侧边栏 添加 AuthGuard 组件
P1-6 SSE usage 计数竞态 relay/service.rs token 使用量记录为 0 stream 结束后同步记录 usage

P2 — 代码质量(下周修复)

# 问题 模块 修复方案
P2-1 35 个时间戳字段为 TEXT db.rs + 全部 service ALTER TABLE → TIMESTAMPTZ + chrono::DateTime
P2-2 dashboard_stats 7 次串行查询 account/service.rs 合并为 1-2 次 SQL
P2-3 6 个端点缺 OpenAPI 文档 各 handlers 添加 #[utoipa::path]
P2-4 computeConfigDiff/syncConfig 未调用 desktop 迁移向导统一调用路径
P2-5 list_providers 返回禁用项 model_config/service.rs 添加 enabled=true 过滤

P3 — 长期改进

# 问题 方案
P3-1 Token 创建/撤销无权限控制 添加 token:manage / key:manage 权限
P3-2 12 个 self-scoped handler 无显式权限 评估是否需要细粒度权限
P3-3 SSRF DNS rebinding 风险 DNS 解析后二次检查
P3-4 邮箱验证过于简单 使用 email 格式正则或 validator crate
P3-5 限流内存状态不共享 Redis/分布式限流(多实例时)

二、P0 修复详细方案

P0-1: SSE Relay 死锁

根因: relay/service.rs 中 SSE 流式响应使用 std::sync::Mutex::blocking_lock()inspect() 回调内。Tokio 运行时在等待锁时阻塞 worker thread导致死锁。

修复: 替换为 tokio::sync::Mutex 或使用 tokio::sync::watch channel 传递状态。

// Before (deadlock):
let state = Arc::new(std::sync::Mutex::new(RelayState::new()));
stream.inspect(move |chunk| {
    let mut s = state.blocking_lock(); // DEADLOCK in async context
    ...
})

// After (async-safe):
let state = Arc::new(tokio::sync::Mutex::new(RelayState::new()));
// Use tokio::spawn for async lock acquisition

P0-2: Token 过期无法刷新

根因: auth middleware 在请求到达 handler 前验证 JWT 有效性。过期的 JWT 被中间件拦截返回 401永远到不了 /auth/refresh handler。

修复: 中间件对 refresh 路径放行,或在 refresh handler 中独立验证 expired token 的签名。

// middleware.rs - 在 JWT 验证前添加路径检查
if request.path() == "/api/v1/auth/refresh" {
    // 跳过过期检查,仅验证签名
    return verify_signature_only(token);
}

P0-3: 设备清理 SQL 类型不匹配

根因: last_seen_at 为 TEXT 类型SQL NOW() - INTERVAL '90 days' 返回 TIMESTAMPTZ。

修复: 使用 rfc3339 字符串比较TEXT 排序等价于时间排序)。

// Before:
sqlx::query("DELETE FROM devices WHERE last_seen_at < NOW() - INTERVAL '90 days'")

// After:
let cutoff = (chrono::Utc::now() - chrono::Duration::days(90)).to_rfc3339();
sqlx::query("DELETE FROM devices WHERE last_seen_at < $1").bind(&cutoff)

三、P1 修复详细方案

P1-1: 注册返回类型不匹配

问题: 桌面端 saasStore.register() 期望响应包含 token 字段(SaaSLoginResponse),但后端 register handler 返回 AccountPublic(无 token

修复: register handler 在创建账号后自动签发 JWT返回与 login 一致的响应格式。

P1-2: account_api_keys 未被 Relay 消费

问题: relay handler 仅查找 provider 级 API key忽略了 account_api_keys 表。

修复: relay 查找顺序: account_api_keys → provider.api_key → 401

P1-3: TOTP nonce 硬编码

问题: AES-256-GCM 使用固定 nonce "zclaw_totp_nce",违反加密语义安全性。

修复: 每次加密生成随机 12-byte nonce存储在密文前缀中。

P1-4: Config 端点审计日志

问题: create/update/delete/seed/sync 5 个 config 端点无 operation_logs 记录。

修复: 每个 handler 在执行后调用 log_operation()

P1-5: Admin 路由守卫

问题: 侧边栏权限已修复,但 URL 直通仍可访问页面。

修复: 添加 AuthGuard 组件包裹 dashboard layout。

P1-6: SSE usage 计数竞态

问题: usage 记录通过 tokio::spawn + 1s sleep 异步写入,与 stream 消费者竞争,导致 token 计数为 0。

修复: stream 结束后同步记录 usage使用 stream on_complete 回调)。


四、执行计划

Week 1: P0 修复 (3 项)

任务 文件 验证
Day 1 P0-1 SSE 死锁修复 relay/service.rs 流式请求不死锁
Day 2 P0-2 Token 刷新修复 auth/mod.rs + middleware.rs 过期 token 可刷新
Day 3 P0-3 设备清理修复 + 集成测试 main.rs 清理 SQL 正常执行

Week 1-2: P1 修复 (6 项)

任务 文件
Day 4 P1-1 注册返回类型 auth/handlers.rs
Day 5 P1-2 Relay API Key 消费 relay/handlers.rs + service.rs
Day 6 P1-3 TOTP nonce 随机化 auth/totp.rs
Day 7 P1-4 Config 审计日志 migration/handlers.rs
Day 8 P1-5 Admin 路由守卫 admin/src
Day 9 P1-6 SSE usage 同步记录 relay/service.rs

Week 3: P2 修复 (5 项)

任务
Day 10-11 P2-1 时间戳类型迁移 (35 字段)
Day 12 P2-2 dashboard 查询优化
Day 13 P2-3~P2-5 OpenAPI + 未调用方法 + 过滤

五、验证策略

每个 P0 修复的验证标准

P0 验证方法 通过标准
P0-1 发送 SSE 流式请求 响应流完整传输,无死锁,无超时
P0-2 等待 token 过期后 refresh 新 token 有效,后续请求正常
P0-3 执行设备清理任务 SQL 正常执行,删除 >90天设备

回归测试

每次 P0/P1 修复后,重新执行联合调试报告中已通过的 20 个测试用例,确保不回退。


六、专家结论

安全工程师结论

P0-1 (SSE 死锁) 是最高优先级 — 它意味着 Relay 核心功能完全不可用。P1-3 (TOTP nonce) 虽然不会直接被利用,但违反加密基本原则,应在 P1 中修复。P3 级的权限细粒度改进是长期安全加固方向。

后端架构师结论

35 个 TEXT 时间戳字段是系统性技术债。短期用 rfc3339 字符串比较可以工作ISO 8601 文本排序等价时间排序),但中长期必须迁移到 TIMESTAMPTZ。SEED_ROLES 中 NOW() 与 to_rfc3339() 格式不一致也需要在迁移时解决。

前端负责人结论

P1-1 (注册返回类型不匹配) 是前端最迫切的修复 — 它阻塞了新用户注册流程。Admin 路由守卫 (P1-5) 是用户体验和安全的双重需求。

QA 主管结论

12 项未执行测试中B-03 (Relay SSE)、C-01 (新用户旅程)、C-03 (TOTP) 风险最高。建议在 P0 修复后立即补充执行,覆盖率为先。

DevOps 结论

服务在测试期间中断说明需要1) 进程管理systemd/windows service2) 健康检查告警 3) 日志持久化。建议在 P0 修复后添加基础的运维监控。