fix: 系统性预防角色测试高频问题(5 方案落地)
P0 — 默认拒绝 + 强制守卫: - 创建 routeConfig.ts 作为前端路由权限的单一真相源 - TypeScript 强制每个路由声明非空权限数组,不可能遗漏 - 自动生成 ROUTE_PERMISSIONS 和 FROZEN_ROUTES - 修正 3 个前端权限码不匹配后端 P0 — CI 权限扫描: - 新增 tools/check_permissions.py 校验脚本 - 发现并修复 tenant.manage 未注册问题 P1 — 聚合接口容错: - erp-core 新增 safe_aggregate 工具函数 - 仪表盘统计 handler 重构 P1 — 状态机一致性自检: - validation.rs 新增 3 个自检测试 fix: lint-staged eslint Windows 兼容性
This commit is contained in:
85
docs/discussions/2026-05-08-quality-systemic-prevention.md
Normal file
85
docs/discussions/2026-05-08-quality-systemic-prevention.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# 质量问题系统性预防方案
|
||||
|
||||
> 日期: 2026-05-08 | 参与者: iven, Claude
|
||||
> 触发: 4 轮角色测试发现 27 个问题,归纳出 5 种高频模式,分析根因后制定根治方案
|
||||
|
||||
## 背景
|
||||
|
||||
2026-05-06 至 2026-05-07 进行了 4 轮角色测试(5 角色 × 220+ API 项 + 175 前端交互项),共发现 27 个独立问题,已修复 22 个,剩余 5 个待处理。
|
||||
|
||||
归纳出 5 种高频模式:
|
||||
1. 权限配置散落(9/27 = 33%)
|
||||
2. 后端类型/状态不一致(5/27 = 19%)
|
||||
3. 前后端 API 路径分叉(4/27 = 19%)
|
||||
4. 缺少全局容错(3/27 = 11%)
|
||||
5. 默认放行模式(6/27 = 22%)
|
||||
|
||||
共性深层问题:**系统缺乏"定义一次,到处生效"的约束机制**。
|
||||
|
||||
## 讨论要点
|
||||
|
||||
### 方案 1:权限注册表(单一真相源)
|
||||
|
||||
**问题**:权限码散落在 4 处(handler 字符串 / seed 迁移 SQL / 前端路由 meta / 菜单可见性),每加一个页面需手动同步 4 处。
|
||||
|
||||
**方案**:创建 `permissions.yaml` 作为唯一定义源,构建时自动生成:
|
||||
- Rust 侧权限常量
|
||||
- seed 迁移 INSERT 语句
|
||||
- 前端路由权限映射
|
||||
- 菜单可见性配置
|
||||
|
||||
**优先级**:P2(投入 3-5 天,最彻底但成本最高)
|
||||
|
||||
### 方案 2:API 契约自动同步
|
||||
|
||||
**问题**:后端 utoipa 生成 OpenAPI spec,前端完全不用,手动硬编码路径。
|
||||
|
||||
**方案**:从 OpenAPI spec 自动生成前端 API 客户端(openapi-typescript),消除路径拼写错误和类型不匹配。
|
||||
|
||||
**优先级**:P2(投入 2-3 天,需改造 service 层)
|
||||
|
||||
### 方案 3:状态机 + 类型安全 Seed
|
||||
|
||||
**问题**:告警 seed 数据 `status=active`,代码状态机只认 `pending` → 全部操作 422;`escalation_level` INT2 vs Entity i32 → 查询 500。
|
||||
|
||||
**方案**:
|
||||
- 3a:状态机定义从代码注释提升为一等公民(宏定义 + 编译期校验)
|
||||
- 3b:Seed 数据校验测试(验证 seed 的 status 字段值在合法状态列表中)
|
||||
|
||||
**优先级**:3b P1(投入 1 天),3a P2(投入 2-3 天)
|
||||
|
||||
### 方案 4:聚合接口防御性模式
|
||||
|
||||
**问题**:仪表盘统计 API 内部查 5 个子指标,任一失败 → 整个 500。
|
||||
|
||||
**方案**:在 `erp-core` 封装 `safe_aggregate` 工具函数,单个子查询失败返回零值/默认值。
|
||||
|
||||
**优先级**:P1(投入半天)
|
||||
|
||||
### 方案 5:默认拒绝 + 强制守卫
|
||||
|
||||
**问题**:路由守卫和菜单渲染默认放行,开发者需要主动加限制 → 容易遗漏。
|
||||
|
||||
**方案**:
|
||||
- 5a:`createProtectedRoute()` wrapper — 不声明权限码则无法创建路由(编译期强制)
|
||||
- 5b:CI 扫描未注册权限的后端端点
|
||||
- 5c:新端点 lint 检查
|
||||
|
||||
**优先级**:P0(5a 半天,5b 1-2 天)
|
||||
|
||||
## 实施优先级
|
||||
|
||||
| 优先级 | 方案 | 投入 | 收益 |
|
||||
|--------|------|------|------|
|
||||
| P0 | 5a — `createProtectedRoute` wrapper | 半天 | 杜绝路由守卫遗漏 |
|
||||
| P0 | 5b — CI 扫描未注册权限的端点 | 1-2 天 | 立即堵住权限遗漏 |
|
||||
| P1 | 4 — `safe_aggregate` 工具函数 | 半天 | 杜绝聚合接口 500 |
|
||||
| P1 | 3b — Seed 数据状态校验测试 | 1 天 | 杜绝 seed/代码不一致 |
|
||||
| P2 | 2 — OpenAPI 生成前端客户端 | 2-3 天 | 杜绝路径分叉 |
|
||||
| P2 | 1 — 权限注册表 YAML | 3-5 天 | 统一权限管理 |
|
||||
|
||||
## 结论
|
||||
|
||||
核心思路:让"对的事情"变成"唯一能做的事情"。靠人记得加权限、记得同步路径、记得容错,注定会遗漏。把约束嵌入构建流程和代码框架,错自然就犯不了。
|
||||
|
||||
先做 P0+P1(2-3 天见效),P2 作为下一阶段质量基建。
|
||||
Reference in New Issue
Block a user