26 KiB
26 KiB
项目全面审查报告(合并版)
审查日期: 2026-04-02
审查范围: 后端 Go + 前端 React/TypeScript + PRD 对齐 + API 文档 + E2E 测试 + 安全 + 前后端一致性 + 架构性能
审查方法: 多智能体并行审查(后端审查、前端审查、PRD 缺口分析、API 文档审查、一致性审查、性能审查)
报告版本: v1.0(合并两轮审查结果,已交叉核对去重)
一、执行摘要
综合评分
| 维度 | 得分 | 说明 |
|---|---|---|
| 后端代码质量 | 7.5/10 | 架构清晰,安全基础扎实,但存在 1 个严重问题和 8 个重要问题 |
| 前端代码质量 | 7.0/10 | 安全设计良好(内存 Token、window guard),但存在 4 个严重问题和 22 个重要问题 |
| 前后端一致性 | 2.0/10 | 根本性协议层不匹配,响应格式全面错位 |
| 架构性能执行 | 5.5/10 | SQLite、N+1 查询、无界导出严重制约扩展性 |
| 功能完整度 | 8.5/10 | 核心功能完整,主要缺口在前端缺失页面和批量操作 |
| E2E 覆盖度 | 6.0/10 | 15 个场景覆盖主流程,但多为"页面存在"级验证 |
| API 文档准确度 | 4.0/10 | 遗漏 38 个端点 |
| 综合评分 | 5.1/10 | 核心链路可用,但一致性和性能是最大短板 |
问题统计(已去重)
| 严重级别 | 后端 | 前端 | 一致性 | 性能 | 总计 |
|---|---|---|---|---|---|
| 🔴 严重 | 1 | 4 | 18 | 4 | 27 |
| 🟡 重要 | 8 | 22 | 14 | 15 | 59 |
| 💭 轻微 | 12 | 8 | 8 | 7 | 35 |
| 总计 | 21 | 34 | 40 | 26 | 121 |
注:总计 121 是各维度问题数之和,部分问题在多个维度被提及(如 context.Background() 同时出现在后端和性能审查中),实际独立问题约 95 个。
去重说明
以下问题在两轮审查中重复出现,已合并:
context.Background()滥用:后端审查 + 性能审查 → 合并为 5 处具体位置- Token 刷新重试非幂等请求:前端审查 (C03) + 一致性审查 (CONSISTENCY-27) → 合并
- stats N+5 查询:后端审查 (PERF-02) + 性能审查 (PERF-05) → 合并
- ProfileSecurityPage mega-component:前端审查 + 性能审查 (PERF-22) → 合并
- WebhooksPage 客户端过滤:前端审查 + 性能审查 (PERF-23) → 合并
- L1Cache 并发问题:性能审查 (PERF-11, PERF-15) → 合并
- 导出无界查询:性能审查 (PERF-03) → 独立
二、🔴 严重问题清单(27 个)
2.1 后端严重问题(1 个)
| ID | 文件 | 问题 | 影响 |
|---|---|---|---|
| SEC-NEW-01 | internal/auth/sso.go |
SSO 会话存储在无界内存 map,无清理机制 | 内存泄漏、重启丢失所有 SSO 会话、DoS 风险 |
2.2 前端严重问题(4 个)
| ID | 文件 | 问题 | 影响 |
|---|---|---|---|
| C01 | LoginPage.tsx:76-79 |
设备指纹存储在 localStorage | XSS 可读取设备追踪信息 |
| C02 | ProfileSecurityPage.tsx:308-314 |
TOTP 流程从 localStorage 读取设备指纹 | XSS 可注入恶意设备指纹 |
| C03 | client.ts:210-221 |
Token 刷新重试可能重复执行非幂等请求 | 可能导致重复创建用户等操作 |
| C04 | oauth.ts:3 |
Open redirect 验证不充分 | 可能被利用进行开放重定向攻击 |
2.3 一致性严重问题(18 个)
| ID | 前端 | 后端 | 问题 |
|---|---|---|---|
| CONSISTENCY-01 | client.ts:240-245 |
ALL handlers | 响应格式协议不匹配:前端期望 {code, data, message},后端返回裸 JSON |
| CONSISTENCY-02 | users.ts:23-24 |
user_handler.go:76-81 |
响应 key: items vs users,分页: page/page_size vs offset/limit |
| CONSISTENCY-03 | roles.ts:11-15 |
role_handler.go:52-55 |
响应 key: items vs roles,缺 page/page_size |
| CONSISTENCY-04 | roles.ts:38-40 |
role_handler.go:160 |
前端期望数组,后端返回 {permissions: [...]} |
| CONSISTENCY-05 | permissions.ts:22-23 |
permission_handler.go:52-55 |
前端期望数组,后端返回 {permissions, total} |
| CONSISTENCY-06 | permissions.ts:14-15 |
permission_handler.go:153 |
前端期望数组,后端返回 {permissions: tree} |
| CONSISTENCY-07 | devices.ts:10-14 |
device_handler.go:63-68 |
响应 key: items vs devices |
| CONSISTENCY-08 | devices.ts:18-22 |
device_handler.go:198-203 |
响应 key: items vs devices |
| CONSISTENCY-09 | webhooks.ts:35-47 |
webhook_handler.go:26 |
响应 key: data vs webhooks |
| CONSISTENCY-10 | login-logs.ts:12-22 |
log_handler.go:43-48 |
响应 key: list vs logs,size vs page_size |
| CONSISTENCY-11 | operation-logs.ts:12-22 |
log_handler.go:52 |
响应 key: list vs logs |
| CONSISTENCY-12 | devices.ts:58-59 |
device_handler.go:308-314 |
前端发送 body current_device_id,后端读 header X-Device-ID |
| CONSISTENCY-13 | profile.ts:52-53 |
user_handler.go:160-162 |
前端发送 current_password,后端期望 old_password |
| CONSISTENCY-14 | auth.ts:129-130 |
totp_handler.go:38 |
前端期望 totp_enabled,后端返回 enabled |
| CONSISTENCY-15 | auth.ts:34-36 |
auth_handler.go:136-141 |
字段完全错位:capabilities 响应格式 |
| CONSISTENCY-16 | types/auth.ts:80-84 |
auth_handler.go:243-247 |
前端 email 可选后端必填;前端发 nickname 后端不收 |
| CONSISTENCY-17 | types/auth.ts:71-78 |
auth_handler.go:22-28 |
前端发 phone_code,后端不收 |
| CONSISTENCY-18 | types/auth.ts:114-118 |
password_reset_handler.go:65-68 |
前端发 confirm_password,后端不收 |
2.4 性能严重问题(4 个,已去重)
| ID | 文件 | 问题 | 影响 |
|---|---|---|---|
| PERF-01 | middleware/auth.go:131-197 |
认证中间件 N+1 查询:每个请求 7-8 次 DB 查询 | 1000 并发 = 7000-8000 DB 查询/秒 |
| PERF-02 | middleware/auth.go:210-221 |
isUserActive 每次请求都执行 SELECT * | 缓存命中也无法避免 |
| PERF-03 | login_log.go:118-139 |
导出/无分页查询加载全表到内存 | 百万级日志表 OOM |
| PERF-04 | auth.go:482-487 |
无界 goroutine + context.Background() | DB 降级时 goroutine 泄漏 → 连接池耗尽 |
三、🟡 重要问题清单(59 个)
3.1 后端重要问题(8 个)
| ID | 文件 | 问题 |
|---|---|---|
| SEC-02 | internal/api/middleware/auth.go |
isJTIBlacklisted 使用 context.Background() |
| SEC-03 | internal/service/auth.go |
登录日志 goroutine 无生命周期管理 |
| SEC-04 | internal/service/webhook.go |
Webhook deliver() 使用 context.Background() |
| CORR-01 | internal/api/handler/auth_handler.go |
handleError 返回原始错误信息给客户端 |
| CORR-02 | internal/api/handler/sso_handler.go |
SSO handler 未检查类型断言(panic 风险) |
| SEC-05 | internal/service/sms.go |
短信验证码使用非恒定时间比较 |
| PERF-01 | internal/api/middleware/ratelimit.go |
SlidingWindowLimiter cleanupInt 死代码 |
| PERF-02 | internal/service/stats.go |
GetUserStats 5+ 次独立 DB 查询(N+5 模式) |
3.2 前端重要问题(22 个)
| ID | 文件 | 问题 |
|---|---|---|
| I01 | client.ts:247 |
DOMException 检测脆弱 |
| I02 | AuthProvider.tsx:129-183 |
session restoration useEffect 空依赖 |
| I03 | auth-session.ts:1-101 |
全局可变状态不响应式 |
| I04 | AdminLayout.tsx:107-114 |
resize 事件无防抖 |
| I05 | UsersPage.tsx:148-157 |
handlers 未 useCallback |
| I06 | UsersPage.tsx:222-358 |
table columns 在组件体内定义 |
| I07 | RolesPage.tsx:101-200 |
table columns 在组件体内定义 |
| I08 | DevicesPage.tsx:131-249 |
table columns 在组件体内定义 |
| I09 | LoginLogsPage.tsx:102-180 |
table columns 在组件体内定义 |
| I10 | OperationLogsPage.tsx:82-158 |
table columns 在组件体内定义 |
| I11 | WebhooksPage.tsx:112-207 |
table columns 在组件体内定义 |
| I12 | ProfileSecurityPage.tsx:394-589 |
4 组 table columns 在 946 行组件内定义 |
| I13 | WebhooksPage.tsx:74-82 |
客户端过滤 + 分页替代服务端 |
| I14 | client.ts:300-342 |
download() 不检查 Content-Type |
| I15 | login-logs.ts + import-export.ts |
triggerFileDownload 重复定义 |
| I16 | ProfileSecurityPage.tsx:152-173 |
OAuth callback hash 解析可能多次触发 |
| I17 | UserEditDrawer.tsx:29 |
Form.useForm() 缺少类型参数 |
| I18 | RoleFormModal.tsx:26 |
Form.useForm() 缺少类型参数 |
| I19 | RolePermissionsModal.tsx:103 |
Tree defaultExpandAll 性能问题 |
| I20 | SettingsPage.tsx:17-48 |
硬编码静态数据 |
| I21 | client.ts:172 |
并发刷新竞态条件 |
| I22 | vite.config.js |
无代码分割配置 |
3.3 一致性重要问题(14 个)
| ID | 问题 |
|---|---|
| CONSISTENCY-19 | 用户状态:前端数字 vs 后端字符串 |
| CONSISTENCY-20 | 角色状态:前端数字 vs 后端字符串 |
| CONSISTENCY-21 | 权限状态:前端数字 vs 后端字符串 |
| CONSISTENCY-22 | 设备状态:前端数字 vs 后端字符串 |
| CONSISTENCY-23 | 分页参数:前端 page/page_size vs 后端 offset/limit |
| CONSISTENCY-24 | 用户更新:前端发 7 字段,后端只收 2 个 |
| CONSISTENCY-25 | 登录方式:前端只支持 username,后端支持 account/email/phone |
| CONSISTENCY-26 | CSRF Token:响应未包装 |
| CONSISTENCY-27 | Token 重试:401 重试所有方法(含 POST/PUT/DELETE) |
| CONSISTENCY-28 | OAuth 授权:后端返回格式不匹配 |
| CONSISTENCY-29 | OAuth 交换:后端返回格式不匹配 |
| CONSISTENCY-30 | 用户角色:后端返回空 stub |
| CONSISTENCY-31 | 分配角色:后端返回 stub 但状态码 200 |
| CONSISTENCY-32 | 统计接口:后端返回 stub |
3.4 性能重要问题(15 个,已去重)
| ID | 类别 | 文件 | 问题 |
|---|---|---|---|
| PERF-05 | 数据库 | user.go:89-106 |
List() 总是 COUNT + SELECT(2 次查询) |
| PERF-06 | 数据库 | stats.go:54-86 |
Dashboard stats 8+ 次顺序查询 |
| PERF-07 | 数据库 | role.go:179-201 |
GetAncestorIDs 顺序单行查询(最多 5 层) |
| PERF-08 | 数据库 | custom_field.go:126-149 |
BatchSet 事务内 N 次顺序查询 |
| PERF-09 | 数据库 | user.go:163-188 |
LIKE '%keyword%' 4 列无全文索引 |
| PERF-10 | 数据库 | device.go:156-167 |
GetActiveDevices/GetTrustedDevices 无分页 |
| PERF-11 | 内存 | cache/l1.go:95-105 |
L1Cache updateAccessOrder O(n) 切片操作 |
| PERF-12 | 并发 | cache/l1.go:42-71 |
L1Cache Get 使用写锁而非读锁 |
| PERF-13 | HTTP | router/router.go:92-98 |
无响应压缩中间件 |
| PERF-14 | HTTP | router/router.go |
大多数路由无请求体大小限制 |
| PERF-15 | HTTP | operation_log.go:49-54 |
操作日志中间件为每个写请求分配 4KB 缓冲 |
| PERF-16 | Bundle | vite.config.js:9-15 |
无代码分割配置 |
| PERF-17 | Runtime | ProfileSecurityPage.tsx:74-946 |
946 行 mega-component |
| PERF-18 | Network | ProfileSecurityPage.tsx:117-127 |
6 个并行 API 调用无请求去重 |
| PERF-19 | 架构 | config/config.go:735-767 |
无会话管理扩展性(多实例无法强制登出) |
四、💭 轻微问题清单(35 个)
4.1 后端轻微问题(12 个)
| ID | 文件 | 问题 |
|---|---|---|
| MIN-01 | auth_handler.go:132 |
CSRF token 返回硬编码 "not_implemented" |
| MIN-02 | device_handler.go:325-343 |
parseDuration 未使用变量 |
| MIN-03 | sso_handler.go:96 |
SSO implicit flow 忽略错误 |
| MIN-04 | email.go:116 |
邮箱验证码非恒定时间比较 |
| MIN-05 | export.go:286 |
导入模板包含明文示例密码 |
| MIN-06 | auth.go:272-281 |
generateUniqueUsername 最多 1000 次 DB 查询 |
| MIN-07 | auth_email.go:91-95 |
邮件激活 goroutine 使用请求 context |
| MIN-08 | sso.go:177 |
generateSecureToken 忽略 rand.Read 错误 |
| MIN-09 | totp.go:138 |
TOTP 恢复码删除错误被忽略 |
| MIN-10 | webhook.go:247 |
Webhook retry time.AfterFunc 无清理 |
| MIN-11 | validator.go:138-144 |
SanitizeXSS 编码后立即解码 — 无操作 |
| MIN-12 | user_handler.go:44-51 |
CreateUser handler 绕过 service 密码策略 |
4.2 前端轻微问题(8 个)
| ID | 文件 | 问题 |
|---|---|---|
| M01 | AdminLayout.tsx:245-251 |
折叠切换按钮缺 ARIA 属性 |
| M02 | AdminLayout.tsx:256-274 |
面包屑使用 <a> 而非 <Link> |
| M03 | ErrorBoundary.tsx:37 |
错误边界使用 window.location.href 重置 |
| M04 | client.ts:88 |
parseJsonResponse 使用类型断言 |
| M05 | csrf.ts:51-66 |
resolveApiBaseUrl 重复定义 |
| M06 | oauth.ts:17-27 |
parseOAuthCallbackHash 不验证 hash 格式 |
| M07 | PermissionsPage.tsx:110-157 |
buildTreeData 每次渲染创建新对象 |
| M08 | login-logs.ts:68 |
导出文件名时区依赖 |
4.3 一致性轻微问题(8 个)
| ID | 问题 |
|---|---|
| CONSISTENCY-33 | OAuth: 前端发送 return_to 参数,后端不读取 |
| CONSISTENCY-34 | 短信验证码: 前端期望 void,后端返回对象 |
| CONSISTENCY-35 | 头像上传: 前端期望对象,后端返回 stub |
| CONSISTENCY-36 | 导出字段: 前端发送逗号分隔字符串 |
| CONSISTENCY-37 | 日志导出格式: 格式参数传递方式需确认 |
| CONSISTENCY-38 | TOTP 验证: 前端期望 void,后端返回 {verified: true} |
| CONSISTENCY-39 | 社交账号: 前端期望数组,后端返回包装对象 |
| CONSISTENCY-40 | 设备指纹: 前端无持久化设备标识 |
4.4 性能轻微问题(7 个)
| ID | 类别 | 文件 | 问题 |
|---|---|---|---|
| PERF-20 | 数据库 | user.go:136-139 |
UpdateLastLogin 使用 map[string]interface{} |
| PERF-21 | 内存 | auth.go:267-281 |
generateUniqueUsername 最多 1001 次查询 |
| PERF-22 | 并发 | middleware/auth.go:152-157 |
祖先 ID 收集未并行化 |
| PERF-23 | HTTP | client.ts:20 |
全局 30s 超时对所有请求统一应用 |
| PERF-24 | Runtime | UsersPage.tsx:222-358 |
columns 未 useMemo |
| PERF-25 | Runtime | PermissionsPage.tsx:110-157 |
buildTreeData 每次渲染递归 |
| PERF-26 | Network | client.ts:200-221 |
401 重试未检查 body 是否可流式传输 |
五、PRD 缺口分析
5.1 功能实现状态
| 功能模块 | 状态 | 说明 |
|---|---|---|
| 邮箱注册 + 激活 | ✅ | 完整实现,E2E 覆盖 |
| 手机号注册 | ✅ | 完整实现 |
| 社交账号登录(9 平台) | ✅ | 完整实现 |
| TOTP 双因素认证 | ✅ | 完整实现,SHA256 |
| 密码重置(邮箱/短信) | ✅ | 完整实现 |
| RBAC 权限管理 | ✅ | 角色继承已修复 |
| 用户管理 CRUD | ✅ | E2E 覆盖 |
| 设备信任管理 | ⚠️ | API 完整,登录流程信任检查已接入 |
| 异地登录检测 | ⚠️ | AnomalyDetector 已注入,缺 GeoIP |
| 批量操作 | ❌ | 前端无批量操作 UI |
| 管理员管理页 | ❌ | 后端 API 存在,前端页缺失 |
| 系统设置页 | ❌ | 前端页缺失 |
| 全局设备管理页 | ❌ | 后端 API 存在,前端页缺失 |
| CAS/SAML SSO | ❌ | PRD 标注可选,建议 v2.0 |
| SDK(Java/Go/Rust) | ❌ | 未实现,建议 v2.0 |
| 防重放攻击 | ❌ | Nonce 机制未实现 |
5.2 E2E 覆盖场景(15 个)
| # | 场景 | 覆盖深度 | 说明 |
|---|---|---|---|
| 1 | admin-bootstrap | 🔵 深度 | 完整引导 → 登录 → 登出流程 |
| 2 | public-registration | 🔵 深度 | 注册 → 登录 → 登出流程 |
| 3 | email-activation | 🔵 深度 | 注册 → 收取邮件 → 激活 → 登录 → 登出 |
| 4 | login-surface | 🔵 深度 | 登录页 UI、capabilities、未登录重定向 |
| 5 | auth-workflow | 🔵 深度 | 登录 → 用户详情 → 角色分配 → 创建用户 → 登出 |
| 6 | responsive-login | 🔵 深度 | 三视口登录页验证 |
| 7 | desktop-mobile-navigation | 🔵 深度 | 桌面导航 + 移动端抽屉菜单 |
| 8 | user-management-crud | 🔵 深度 | 创建 → 编辑 → 详情 → 筛选 → 删除 |
| 9 | role-management-crud | 🟡 中等 | 角色列表 + 权限分配弹窗 |
| 10 | device-management | 🟡 中等 | 页面导航 + 列表显示 |
| 11 | login-logs | 🟡 中等 | 页面导航 + 列表显示 |
| 12 | operation-logs | 🟡 中等 | 页面导航 + 列表显示 |
| 13 | webhook-management | 🟡 中等 | 页面导航 + 列表显示 |
| 14 | profile-and-security | 🟡 中等 | 个人资料 + 安全设置可见性 |
| 15 | dashboard-stats | 🟡 中等 | 仪表盘统计卡片验证 |
5.3 API 文档缺口
- 代码有但文档无: 38 个端点
- 自定义字段管理: 7 个端点未记录
- 主题管理: 7 个端点未记录
- SSO: 5 个端点未记录
- 管理员设备管理: 5 个端点未记录
- 邮箱/手机绑定: 6 个端点未记录
- 其他: 8 个端点未记录
六、安全审查
6.1 安全优势
- ✅ 密码使用 Argon2id 哈希
- ✅ 敏感数据使用 crypto/rand 生成
- ✅ Webhook URL 有 SSRF 保护
- ✅ 接口限流已配置(含 refresh 接口)
- ✅ Access Token 仅存储在内存中
- ✅ 前端安装 window guard 阻断 alert/confirm/prompt/open
- ✅ CSRF Token 支持
- ✅ JWT JTI 黑名单机制
- ✅ TOTP 使用 SHA256(已从 SHA1 修复)
- ✅ JTI 使用纯随机 16 字节(已修复可预测时间戳)
6.2 安全风险
| 风险 | 严重级别 | 说明 |
|---|---|---|
| 响应格式协议不匹配 | 🔴 | 所有 API 调用都会失败 |
| SSO 会话内存泄漏 | 🔴 | 无界 map 无清理 |
| 设备指纹 localStorage | 🔴 | XSS 可读取/注入 |
| Open redirect 验证不足 | 🔴 | 可能被利用 |
| 认证中间件 N+1 查询 | 🔴 | 每请求 7-8 次 DB 查询 |
| 导出无界查询 | 🔴 | 全表加载到内存 |
| 非恒定时间比较 | 🟡 | SMS/邮箱验证码 |
| 错误信息泄露 | 🟡 | 返回原始错误给客户端 |
| context.Background() 滥用 | 🟡 | 5 处使用 |
| Token 重试非幂等请求 | 🟡 | 可能重复操作 |
| SSO 类型断言未检查 | 🟡 | panic 风险 |
七、历史问题修复状态
| 问题 | 状态 | 备注 |
|---|---|---|
| OAuth ValidateToken 始终返回 true | ✅ 已修复 | |
| JTI 含可预测时间戳 | ✅ 已修复 | 改为 crypto/rand 纯随机 |
| TOTP 使用 SHA1 | ✅ 已修复 | 已切到 SHA256 |
| Refresh 接口无限流 | ✅ 已修复 | refresh 路由已挂限流中间件 |
| Webhook SSRF 风险 | ✅ 已修复 | 安全 URL 校验已在链路中 |
| Webhook context.Background() | ⚠️ 部分修复 | 有超时但仍用 Background |
| 邮件 goroutine context 问题 | ❌ 未修复 | |
| SlidingWindowLimiter 清理死代码 | ❌ 未修复 | |
| stats N+5 查询 | ❌ 未修复 | |
| TOTP 恢复码删除非原子 | ❌ 未修复 | |
| ValidateRecoveryCode 非恒定时间比较 | ❌ 未修复 |
八、架构扩展性评估
| 用户规模 | 状态 | 说明 |
|---|---|---|
| 100 用户 | ✅ 就绪 | SQLite 可处理轻量并发 |
| 1,000 用户 | ⚠️ 有风险 | 登录突发(>50/sec)会导致 SQLite 写入争用 |
| 10,000 用户 | ❌ 不可用 | SQLite 写入串行化成为硬瓶颈 |
10,000 用户前必须完成的变更:
- 迁移到 PostgreSQL
- 合并认证中间件查询为 1-2 次缓存查找
- 添加 Redis 作为共享缓存层
- 流式导出替代内存加载
- 添加自动化日志清理 cron
九、优先级建议
P0:必须立即修复(阻塞生产部署)
| # | 问题 | 来源 | 修复方案 |
|---|---|---|---|
| 1 | 响应格式协议不匹配(CONSISTENCY-01) | 一致性 | 添加 Gin 响应包装中间件,或重写前端 client.ts |
| 2 | SSO 会话内存泄漏(SEC-NEW-01) | 后端 | 添加后台清理 goroutine 或持久化到 Redis/DB |
| 3 | 设备指纹 localStorage(C01, C02) | 前端 | 改为内存存储或 sessionStorage |
| 4 | Open redirect 验证不足(C04) | 前端 | 使用 URL 构造函数验证同源 |
| 5 | 认证中间件 N+1 查询(PERF-01, 02) | 性能 | 合并为单次 JOIN 查询,user.Status 纳入缓存 |
| 6 | 导出无界查询(PERF-03) | 性能 | 添加 LIMIT 或实现游标分页流式导出 |
| 7 | 关键字段错位(CONSISTENCY-12, 13, 14, 15) | 一致性 | 修复 4 个端点的字段名不匹配 |
| 8 | 无界 goroutine(PERF-04) | 性能 | 添加 context.WithTimeout |
P1:当前迭代解决
| # | 问题 | 来源 | 修复方案 |
|---|---|---|---|
| 9 | 标准化响应 Key(CONSISTENCY-02 到 11) | 一致性 | 所有列表端点统一 {items, total, page, page_size} |
| 10 | 标准化状态类型(CONSISTENCY-19 到 22) | 一致性 | 后端改为接受数字值 |
| 11 | 修复分页参数(CONSISTENCY-23) | 一致性 | 后端接受 page/page_size |
| 12 | context.Background() 滥用(SEC-02, 03, 04) | 后端 | 5 处全部修复 |
| 13 | 非恒定时间比较(SEC-05, MIN-04) | 后端 | SMS/邮箱验证码使用 subtle.ConstantTimeCompare |
| 14 | 错误信息泄露(CORR-01) | 后端 | 错误分类,不返回原始错误 |
| 15 | SSO 类型断言(CORR-02) | 后端 | 使用 comma-ok 惯用法 |
| 16 | Dashboard stats 查询(PERF-06) | 性能 | 合并为单次 GROUP BY 查询 |
| 17 | L1Cache 并发(PERF-12) | 性能 | Get 使用 RLock |
| 18 | Token 重试非幂等(C03, CONSISTENCY-27) | 前端/一致性 | 仅重试 GET/HEAD |
| 19 | table columns 性能(I06-I12) | 前端 | 所有页面 columns 使用 useMemo |
| 20 | ProfileSecurityPage 拆分(I12, PERF-17) | 前端/性能 | 拆分为子组件 |
| 21 | 补充 API 文档 38 个端点 | PRD 缺口 | 从 router.go 自动生成文档骨架 |
P2:下一轮优化
| # | 问题 | 来源 | 修复方案 |
|---|---|---|---|
| 22 | 迁移到 PostgreSQL(PERF-28) | 性能 | 添加 PostgreSQL 迁移路径 |
| 23 | 添加 Redis 共享缓存(PERF-29, 30) | 性能 | Redis 作为主缓存层 |
| 24 | 前端代码分割(I22, PERF-16) | 前端/性能 | manualChunks 拆分 vendor |
| 25 | WebhooksPage 服务端过滤(I13, PERF-23) | 前端/性能 | 传递 keyword/statusFilter 到 API |
| 26 | 添加响应压缩(PERF-13) | 性能 | gin-contrib/gzip |
| 27 | 实现 Stub 端点(CONSISTENCY-30, 31, 32) | 一致性 | 实现 GetUserRoles, AssignRoles, Stats |
| 28 | 补齐前端缺失页面 | PRD 缺口 | 管理员管理页、系统设置页、全局设备管理页 |
| 29 | 深化 E2E 测试覆盖 | E2E 缺口 | 忘记密码、社交绑定、角色 CRUD、导入导出 |
| 30 | 防重放攻击 Nonce 机制 | PRD 缺口 | 实现 Nonce 机制 |
| 31 | 代码重复提取(I15, M05) | 前端 | triggerFileDownload, resolveApiBaseUrl |
| 32 | 表单类型安全(I17, I18) | 前端 | Form.useForm() 添加类型参数 |
十、当前项目真实状态
可以说
- 后端核心功能完整,go vet/build/test 全绿
- 前端主后台已成型,15 个页面已实现
- 浏览器级真实 E2E 已覆盖 15 个场景
- 代码架构清晰(handler → service → repository,service → API → component)
- 安全基础扎实(Argon2id、crypto/rand、SSRF 保护、window guard)
- 72 个端点 URL 路由全部正确匹配
不可以说
- "全部功能已闭环"(前端缺 3 个页面 + 批量操作)
- "E2E 测试已充分"(15 个场景多为页面存在级验证)
- "API 文档已完整"(遗漏 38 个端点)
- "无安全风险"(27 个严重问题待修复)
- "前后端已对齐"(响应格式协议不匹配,40 个一致性问题)
- "性能已优化"(SQLite、N+1 查询、无界导出制约扩展性)
最诚实的表述
后端能力比较完整,前端主后台已经成型,代码架构清晰,安全基础扎实。但存在两个根本性短板:一是前后端响应格式协议不匹配(所有 API 调用都会失败),二是架构性能受 SQLite 和 N+1 查询制约,无法扩展到 10,000 用户规模。
如果按"可审计、可重复、可对外诚实宣称"的标准看,当前还差最后几步:
- 修复响应格式协议不匹配(阻塞所有功能)
- 修复 27 个严重问题
- 补齐 3 个前端缺失页面
- 深化 E2E 测试覆盖深度
- 同步 API 文档
- 迁移到 PostgreSQL(如需支持 10,000+ 用户)
十一、审查方法说明
审查轮次
| 轮次 | 范围 | 发现问题数 |
|---|---|---|
| 第一轮 | 后端 Go + 前端 React/TypeScript + PRD 对齐 + API 文档 + E2E 测试 + 安全 | 55 个 |
| 第二轮 | 前后端一致性 + 架构性能执行 | 72 个 |
| 合并去重后 | 全维度 | 95 个独立问题 |
审查覆盖
- 后端: 30+ Go 文件(internal/api、service、repository、middleware、auth、config、database、cmd)
- 前端: 50+ TypeScript/TSX 文件(pages、components、services、lib、app)
- 一致性: 13 个前端服务文件 × 对应后端 handler 交叉比对
- 文档: PRD、API.md、历史审查报告、项目状态文档
- E2E: 15 个测试场景覆盖度分析
去重规则
以下问题在两轮审查中重复出现,已合并计数:
context.Background()滥用:后端审查 + 性能审查 → 合并为 5 处具体位置- Token 刷新重试非幂等请求:前端审查 (C03) + 一致性审查 (CONSISTENCY-27) → 合并
- stats N+5 查询:后端审查 (PERF-02) + 性能审查 (PERF-05/06) → 合并
- ProfileSecurityPage mega-component:前端审查 + 性能审查 (PERF-17) → 合并
- WebhooksPage 客户端过滤:前端审查 + 性能审查 (PERF-23) → 合并
- L1Cache 问题:性能审查 (PERF-11, PERF-12) → 合并
- table columns 性能:前端审查 (I06-I12) + 性能审查 (PERF-24) → 合并
- 代码分割:前端审查 (I22) + 性能审查 (PERF-16) → 合并