fix: 系统性预防角色测试高频问题(5 方案落地)
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled

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:
iven
2026-05-08 08:52:16 +08:00
parent 645ec39e8b
commit c82f7bda1d
11 changed files with 594 additions and 90 deletions

View 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 天,最彻底但成本最高)
### 方案 2API 契约自动同步
**问题**:后端 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状态机定义从代码注释提升为一等公民宏定义 + 编译期校验)
- 3bSeed 数据校验测试(验证 seed 的 status 字段值在合法状态列表中)
**优先级**3b P1投入 1 天3a P2投入 2-3 天)
### 方案 4聚合接口防御性模式
**问题**:仪表盘统计 API 内部查 5 个子指标,任一失败 → 整个 500。
**方案**:在 `erp-core` 封装 `safe_aggregate` 工具函数,单个子查询失败返回零值/默认值。
**优先级**P1投入半天
### 方案 5默认拒绝 + 强制守卫
**问题**:路由守卫和菜单渲染默认放行,开发者需要主动加限制 → 容易遗漏。
**方案**
- 5a`createProtectedRoute()` wrapper — 不声明权限码则无法创建路由(编译期强制)
- 5bCI 扫描未注册权限的后端端点
- 5c新端点 lint 检查
**优先级**P05a 半天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+P12-3 天见效P2 作为下一阶段质量基建。