Files
hms/docs/discussions/2026-05-08-quality-systemic-prevention.md
iven c82f7bda1d
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
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 兼容性
2026-05-08 08:52:16 +08:00

86 lines
3.5 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.
# 质量问题系统性预防方案
> 日期: 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 作为下一阶段质量基建。