Files
hms/docs/discussions/2026-05-13-development-process-retrospective.md
iven 5905742080 docs: 开发流程阶段总结与优化 — 多专家组发散式讨论
8 类开发问题归纳(175 次 fix 分析)、3 个连锁效应案例、
6 位专家流程改进建议、Feature DoD 清单、P0/P1/P2 行动方案。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 13:33:49 +08:00

23 KiB
Raw Blame History

HMS 开发流程阶段总结与优化 — 多专家组发散式讨论

日期: 2026-05-13 | 参与者: iven, Claude六位虚拟专家 数据基准: 770 次提交 / 175 次 fix22.7%/ 近月 24% fix 率 关联: 质量系统性预防方案 | 六维度分析


1. 背景与数据概览

HMS 项目自 2026-04-10 首次提交以来,历经 33 天密集开发,累计 770 次提交。系统已从 MVP 成长为包含 17 个 Rust crate、297 个前端文件、66 个小程序页面的中型医疗 SaaS 平台。

但开发过程中暴露了一个不可忽视的信号:近 1/4 的提交在修 bug

1.1 核心数据

指标 含义
总提交 770 次 33 天,日均 23 次
fix 类型提交 175 次22.7% 近 1/4 的提交在修 bug
近月 fix 率 151/630 = 24.0% 趋势未改善
单次批量 fix 最高 16 个问题 角色测试 V3 一轮发现 16 个
角色测试总发现 27 个独立问题4 轮) 测试→发现→修复周期长
V1→V2 审计 新增 21 个问题 新代码持续引入新 bug

1.2 fix 提交类别分布(全部 175 次)

类别 次数 占比 典型模式
前后端接口不一致 ~35 20% 字段名/路径/类型不匹配
权限/菜单/路由 ~25 14% 权限码散落、菜单不可见
安全(租户隔离/PII ~25 14% SQL 注入、越权、CORS
小程序特有问题 ~28 16% 登录态、平台限制、Storage
后端开发了前端未集成 ~10 6% 硬编码假数据、缺失对接
数据库/迁移 ~15 9% 表名错误、SQL 方言、幂等性
状态管理/竞态 ~15 9% 事件链断裂、CAS、并发
其他(编译/UX/AI ~22 13% 类型错误、AI 模型适配

1.3 时间线上的问题密度

4 月 10-15 日  ██████  基础设施搭建 + 首批权限问题fix 15 次)
4 月 16-22 日   ████████  核心医疗模块 + 安全首次审计fix 28 次)
4 月 23-28 日   ██████████  内容管理+AI+透析扩展fix 35 次,高峰)
4 月 29-5 月 4  ██████████  V1 审计 + 质量加固fix 30 次)
5 月 5-8 日     ████████████  角色测试 4 轮迭代fix 45 次,最高峰)
5 月 9-13 日    ████████  媒体库+轮播图+Copilotfix 22 次)

观察fix 密度在 5 月 5-8 日达到最高峰,原因是 4 轮角色测试集中发现了 27 个问题。这表明大量 bug 在引入后数天甚至数周才被发现,而非在开发时就被拦截。


2. 问题目录 — 八类问题的具体案例与根因

2.1 前后端接口不一致(~35 次 fix占比最高

这是出现频率最高的问题类型,贯穿整个项目周期。

问题 A字段名不匹配

  • 后端 DTO 用 consultation_type,前端写 type → 请求 422
  • 后端 DTO 用 planned_date,前端写 due_date → 数据丢失
  • 后端返回 unread_count_patient,前端读 unread_count → 显示 NaN
  • commit: c53f562 fix(web,miniprogram): 端到端测试修复 + 33 接口字段对齐

问题 B请求体结构不匹配

  • 后端 CreateFollowUpRecordReq 要求 {task_id, result, patient_condition},前端传 {task_id, content:{text}} → 422
  • commit: 8316281 fix(miniprogram): 修复 API 接口字段对齐 -- 33 接口端到端验证
  • commit: fbb28e6 fix(miniprogram): submitRecord 补充 task_id 字段

问题 C返回数据格式不匹配

  • 后端 Vec<(NaiveDate, f64)> 序列化为数组 [[date, value]],前端期望对象 [{date, value}] → 趋势图不显示
  • commit: 1f8fd04 fix(health): 趋势图数据不显示 -- 后端 DTO 元组转结构体

问题 D遗漏字段

  • 后端文章列表 API 缺少 version 字段,前端更新时无法做乐观锁 → 更新覆盖
  • commit: 96b952c fix(health): 文章列表 API 补充 version 字段

根因:后端 Rust DTO 和前端 TypeScript 接口各自维护,没有任何自动同步机制。后端改了字段名,前端不知道。


2.2 权限/菜单/路由问题(~25 次 fix持续时间最长

从 4 月 11 日到 5 月 10 日,权限相关 fix 持续出现 29 天,是最顽固的问题类别。

问题 A权限码格式不统一

  • seed 迁移用冒号分隔 health:patient:listhandler 检查用点号 health.patient.list所有权限检查返回 403
  • commit: 0d7d3af fix(auth): 权限编码冒号改点号 + 补充缺失权限

问题 B菜单三重配置遗漏

  • 媒体库菜单不可见,排查发现三个独立问题:
    1. parent_id 查找条件错误(指向不存在的父菜单)
    2. menu INSERT 缺少 permission 字段
    3. 缺少 menu_roles 角色关联
  • commit: edb4b65 fix(health): 修复媒体库和轮播图菜单不可见 -- 三重修复

问题 C路由注册方式导致中间件泄漏

  • Axum .merge() 导致 middleware 泄漏到整个路由树,公开端点被加了认证中间件
  • 改用 .nest() 隔离后才修复
  • commit: 84b671d fix(server+health): 修复路由 middleware 泄漏

问题 D权限码缺 .list 导致 403

  • 每个实体需要 .list + .manage 两个权限码,漏掉 .list 列表页直接 403
  • 这个问题在 CLAUDE.md 反模式中已有警告,但仍反复出现

根因:权限系统涉及 4 层同步handler 权限码 → seed 迁移 → 前端路由 meta → 菜单可见性),每加一个功能需手动同步 4 处,遗漏率几乎 100%。


2.3 安全问题(~25 次 fix4 轮审计才收敛)

问题 ASQL 注入

  • action_inbox_service.rsformat! 拼接 patient_id/user_id 到 SQL → 注入向量
  • commit: 2b90db4 fix(health): P0 安全修复

问题 BFHIR 越权

  • allowed_patient_ids 已声明但未在查询层强制执行 → 第三方可访问非授权患者数据
  • commit: 2b90db4 + 4828713 fix(health): FHIR 子查询添加 tenant_id 过滤

问题 C开发配置泄漏到生产

  • JWT Secret 硬编码 "dev-secret-key" 作为 fallback
  • CORS 通配符 * 在生产环境生效
  • commit: f7bf5a8 fix(server): CORS 生产环境拒绝通配符

问题 D默认放行模式

  • OAuth 端点无权限检查、限流默认放行、Redis 不可达时直接放行
  • 每次安全审计都发现同类问题:开发便利优先,生产安全靠人工事后加固
  • commit: 080d2cb fix(security): 限流 fail-closed + 多租户安全加固

根因:缺乏"安全默认"原则。所有新端点默认放行,需要开发者主动加限制 → 必然遗漏。


2.4 小程序特有问题(~28 次 fix

问题 A登录态管理混乱

  • 退出登录后刷新仍保持登录态Storage 未清理)
  • useDidShow 生命周期中认证恢复失败
  • 页面间用 Storage 传递数据,刷新后丢失
  • commit: 3c828bf + 6632985 + f75bc19

问题 B微信平台限制未适配

  • <image> 不支持 HTTP URL轮播图 404
  • 域名白名单未配置
  • commit: 4788e19 fix(health,miniprogram): 轮播图改用相对路径

问题 C关怀模式老年适配

  • 非线性放大计算错误,页面尺寸异常
  • 20px 字号低于适老阈值 22px
  • commit: 4335f7e + 257ca94

根因:小程序 124 文件 0 测试,质量保障完全真空。所有问题靠手动发现。


2.5 后端开发了但前端未集成(~10 次 fix

问题 A前端仍用硬编码假数据

  • 运营仪表盘、统计页、系统信息页在 API 就绪后仍显示假数据
  • commit: 2e4d98c fix(web): 统计页空列表接入真实 API + 运营待办去硬编码

问题 B新端点已开发但未对接

  • GET /health/vital-signs/today 后端已开发,前端未调用
  • commit: d26a847 fix(health): 对接今日体征摘要新端点

问题 C后端返回关联数据但前端仍显示原始 ID

  • 告警详情显示原始 patient_id / rule_id未做关联展示
  • commit: 0acf901 fix(web): 告警详情显示患者名和规则标题替代原始 ID

根因:前后端开发节奏不同步,后端先完成但无机制追踪前端是否已集成。


2.6 数据库/迁移问题(~15 次 fix

问题 A表名单复数混用

  • Entity 定义用 tenant(单数),迁移 SQL 写 tenants(复数)→ 外键引用失败
  • commit: a174f88 fix(migration): 修复表名 tenants 改为 tenant

问题 BSQL 方言不兼容

  • PostgreSQL DELETE 不支持 LIMIT,迁移脚本写成了 MySQL 语法
  • commit: d5c9654 fix(db): 修复 SQL 语法 + RLS 动态表名查询

问题 C迁移非幂等

  • 多次执行同一迁移会报唯一约束冲突
  • commit: 99dad17 fix(server+health): 修复迁移幂等性

根因:迁移脚本缺乏在 fresh database 上的自动验证。


2.7 状态管理/竞态条件(~15 次 fix

问题 AToken 刷新并发竞态

  • 同一 refresh token 并发使用两次,先查后改非原子操作 → token 失效
  • commit: 3e1413a fix(auth): 修复 Token 刷新并发竞态条件

问题 B事件链断裂

  • consultation.new_messagelab_report.reviewed 事件已发布但消费者未注册 → 功能静默失败
  • commit: ef0b784 fix(health): 修复两条断裂事件链

问题 CCAS 条件过严

  • 预约 CAS 精确匹配排班时段,时区偏移导致匹配失败
  • commit: 9b8c2ff fix(health): 预约 CAS 从精确匹配改为范围匹配

根因事件消费者注册无启动时检查CAS 操作缺乏统一封装。


2.8 编译/UX/AI 等其他问题(~22 次 fix

编译/类型错误 — 10 处 TypeScript 编译错误(fb809f1、Rust 类型不匹配(7ab89f5 AI 模型适配 — qwen3 thinking 模式导致输出为空(b1a96ac)、分析结果 JSON 嵌套(1f91dcc UX 微调 — 文章预览尺寸(6269815)、仪表盘浮点精度(0721733

这类问题量小且影响有限,不作为流程优化重点。


3. 连锁效应分析 — "修一个,冒两个"

开发过程中最让人沮丧的不是单个 bug而是修了 A 之后发现 B 也坏了。以下是三个典型案例。

3.1 媒体库五连修5 月 10 日5 次连续 fix

step 1: 实现媒体库 + 轮播图feat 提交 ×5
step 2: fix — 图片不显示,缺 /uploads Vite 代理
step 3: fix — 修完路径后图片 401需要 JWT token
step 4: fix — Web 修好了,小程序轮播图又 404HTTP 限制)
step 5: fix — 图片修好了,菜单看不到(三重配置遗漏)
step 6: fix — 迁移外键引用表名错误

一个功能5 次 fix每次只发现一类问题。 如果有功能完成检查清单DoD第一步就能发现所有 5 类问题。

3.2 权限系统贯穿全周期4 月 11 日 → 5 月 10 日29 天未收敛)

4/11  fix: 权限编码冒号→点号 + 补充缺失权限
4/16  fix: 移除权限 fallback必须显式分配
4/24  fix: 修复路由 middleware 泄漏
4/25  fix: 权限同步 + 迁移幂等性
5/05  fix: 权限同步修复(又发现遗漏)
5/06  fix: 权限守卫、权限配置问题
5/07  fix: 权限越权(角色测试发现)
5/10  fix: 菜单不可见(媒体库,又是权限问题)

29 天内持续出现,每次修了"一处"但"其他处"仍然不一致。 根本原因是权限定义散落在 4 处,没有单一真相源。

3.3 角色测试四轮迭代5 月 5-8 日10 次批量 fix

第 1 轮: 发现 5 个共性问题 → fix
第 2 轮: 发现 8 个问题 → fix
第 3 轮: 发现 4 个共性问题 → fix
第 4 轮: 发现 7 个问题 → fix
       小程序多角色找茬: 16 个问题 → fix
       小程序 V2: 11 个问题 → fix
       小程序 V3: 8 个问题 → fix
       业务链路测试: 3 类问题 → fix

10 次批量 fix 才收敛。 如果每个功能在开发时就有基本的端到端验证,这些问题在第一次角色测试前就应该被拦截。

3.4 连锁效应的根本原因

根本原因 表现 涉及的 fix 次数
缺少功能完成检查清单 每次只修一类问题,不全面验证 ~60 次
同步点散落在多处 修了一处忘了另一处 ~40 次
验证滞后 开发时不验证,测试/审计时集中发现 ~50 次

4. 六位专家发散讨论

基于以上问题目录,召集六位虚拟专家从不同视角讨论流程改进方案。

专家 1流程架构师 — "为什么同样的问题反复出现?"

核心论点24% fix 率不是代码质量问题,是流程缺失问题。

  1. 缺少 Feature DoD功能完成定义

    • 现状:代码写完 → 提交 → 下一个功能。没有统一的完成标准。
    • 媒体库 5 次 fix 说明:每次只验证了一类问题,没有"全量验证"步骤。
    • 建议:建立 Feature DoD 清单,写入 CLAUDE.md每个功能标记"完成"前必须逐项检查。
  2. 反馈周期太长

    • bug 在引入后数天甚至数周才被发现(角色测试时),修复成本指数级增长。
    • 角色测试 4 轮才收敛27 → 11 → 8 → 3而不是一轮完成。
    • 建议:每个功能完成时立即做 5-10 分钟的端到端手动验证。
  3. 没有"破坏性变更"意识

    • 新增迁移/路由/权限时不检查是否影响已有功能。
    • V1→V2 审计发现 21 个新问题,说明新代码持续引入回归。
    • 建议CI 增加基于 diff 的定向回归测试。

"如果只能改一件事" 建立 Feature DoD 清单并强制执行。


专家 2质量工程专家 — "测试是写代码前的契约,不是写完后的补救"

核心论点:测试金字塔倒挂严重,前端几乎无自动化保障。

  1. 后端测试量大但结构性缺陷

    • 999 个测试函数,但异步测试仅 184 个18.4%)。
    • 并发预约、事件消费、多租户隔离等核心路径缺异步集成测试。
    • 预约并发 bug 只在角色测试时被发现,单元测试无法捕获。
  2. 前端测试覆盖率严重不足

    • Web297 文件 / 62 测试文件1:4.8
    • 小程序124 文件 / 0 测试 — 质量保障真空
    • 小程序 31 次 fix 中大部分是状态管理和 API 对接问题,自动化测试完全可以预防。
  3. 缺少"错误预算"概念

    • fix 率 24% 没有目标、没有趋势监控。
    • 建议:设定 fix 率目标 < 15%,每周跟踪趋势。

"如果只能改一件事" 给小程序补 service 层测试。124 文件 0 测试是最大质量真空。


专家 3安全审计专家 — "安全靠设计时预防,不靠事后发现"

核心论点25 次安全 fix 中 80% 可以通过安全 lint 在提交前拦截。

  1. 安全修复模式高度重复

    • 每次都是同一个模式:默认放行 → 发现问题 → 收紧。
    • CORS 通配符、OAuth 无权限、FHIR 越权、限流放行 — 本质都是"默认放行"。
    • 建议:建立"安全默认"原则 — 所有新端点默认拒绝,必须显式声明权限。
  2. 租户隔离反复遗漏

    • 从 4 月 11 日到 5 月 5 日24 天内租户隔离问题出现 5 次。
    • 每次审计都发现新的遗漏点。
    • 建议:租户过滤统一中间件,禁止手写 tenant_id 过滤。

"如果只能改一件事" 在 CLAUDE.md 增加"新增端点安全检查清单"。


专家 4DevOps/自动化专家 — "人能记住的事,不应该靠人记住"

核心论点24% fix 率的本质是手动同步成本。

  1. 权限码 4 处手动同步是最大系统性 bug 源

    • handler / seed / 路由 meta / 菜单 — 每加一个功能同步 4 处,遗漏率 100%。
    • 12+ 次权限相关 fix每次都是"忘了同步第 N 处"。
    • 建议:permissions.yaml 单一真相源 + 构建时自动生成。
  2. 缺少 CI 质量门禁

    • 当前只有 cargo check + cargo test,没有权限完整性检查、路径一致性检查、安全 lint。
    • 建议CI 增加 4 个门禁(权限/路径/安全/覆盖率)。
  3. OpenAPI 注解 33%,前端完全不用 spec

    • 后端生成 spec前端手写路径两边必然分叉。
    • 建议openapi-typescript 自动生成前端 API 客户端。

"如果只能改一件事" 实施 permissions.yaml 单一真相源。消除 12+ 次 fix 的根因。


专家 5产品/需求管理专家 — "功能冻结≠冻结完成,而是冻结了技术债"

核心论点:需求推进速度 > 质量保障速度。

  1. 6 个冻结模块是隐性成本

    • 护理计划 44 分、班次 41 分 — 完成度极低但持续占用编译体积和认知负担。
    • 建议:冻结超时策略 — 冻结 > 2 周自动触发决策(完成或移除)。
  2. 缺少质量红线

    • 770 次提交中 24% 是 fix说明需求推进速度远超质量保障速度。
    • 建议fix 率 > 20% 时新功能需额外审批。
  3. 缺少"最小可验证增量"

    • 媒体库一次提交 5+ 个 crate 的改动,验证只能事后进行。
    • 建议:拆分为更小的可验证增量,每步有明确验证标准。

"如果只能改一件事" 设定质量红线 — fix 率 > 20% 时优先偿还技术债。


专家 6技术债务分析师 — "债务不可怕,可怕的是不可见"

核心论点:技术债缺乏可视化管理。

  1. 已完成的技术债偿还

    • event.rs 2871 行 → 已拆分为 13 个领域文件
    • module.rs 1595 行 → 已拆分为 13 个子模块
  2. 未处理的技术债

    • erp-health 仍为巨石189 文件12 子域)
    • utoipa 注解 33%
    • 小程序 0 测试
    • 6 个冻结模块
  3. 建议:建立技术债看板

    • 量化每项债务的"利息"(修复频率 × 修复成本)
    • 每个迭代 20% 时间用于偿还

"如果只能改一件事" 建立技术债看板,让债务利息可视化。


5. 共识与行动方案

5.1 六位专家的共识

# 共识 专家一致性
C1 24% fix 率是系统性流程问题,非个别代码质量问题 6/6
C2 权限码 4 处手动同步是最高优先级的自动化目标 6/6
C3 小程序 0 测试是最大质量真空 5/6
C4 缺少 Feature DoD 是 fix 反复出现的直接原因 6/6
C5 前后端接口不一致的根因是缺少契约自动同步 6/6
C6 新需求推进速度 > 质量保障速度 6/6

5.2 分歧与权衡

议题 观点 A 观点 B 建议
新功能 vs 技术债 设质量红线fix > 20% 停新功能 过于刚性,影响交付 软红线fix > 20% 时新功能需额外审批
权限注册表方案 YAML 单一真相源 + 自动生成 改造成本高,先用 lint 分两步:先 lint 拦截,再迁移 YAML
小程序测试策略 先补 service 层接口测试 先补关键页面 E2E service 层优先(投入产出比更高)
冻结模块处理 立即决定:完成或移除 等有资源时处理 冻结超时> 2 周自动触发决策

5.3 行动方案(按优先级排序)

P0 — 立即实施1-2 天见效)

# 行动 投入 消除的 fix 类别
P0-1 建立 Feature DoD 清单,写入 CLAUDE.md 2h 权限遗漏、菜单不可见、安全默认、前后端不一致
P0-2 新增端点安全检查清单,写入 CLAUDE.md 1h CORS/OAuth/限流/脱敏遗漏
P0-3 CLAUDE.md 增加前后端同步检查项 1h 字段名/路径/类型不匹配

P1 — 本周实施3-5 天见效)

# 行动 投入 消除的 fix 类别
P1-1 权限注册完整性 CI 检查handler 权限码 vs seed 一致性 4h 权限码不一致
P1-2 API 路径一致性 CI 检查:前端 API 路径 vs 后端 OpenAPI spec 1d 前后端路径分叉
P1-3 小程序 service 层测试29 个文件) 2d 小程序 API 对接问题
P1-4 createProtectedRoute() wrapper — 不声明权限码则无法创建路由 0.5d 路由守卫遗漏

P2 — 下阶段实施(持续改进)

# 行动 投入 效果
P2-1 permissions.yaml 单一真相源 + 自动生成 3-5d 根除权限同步问题
P2-2 openapi-typescript 自动生成前端 API 客户端 2-3d 根除路径分叉
P2-3 冻结模块策略(完成/移除/超时) 1d 减少隐性技术债
P2-4 技术债看板建立 1d 债务可视化
P2-5 fix 率趋势监控(每周跟踪) 0.5d 质量趋势感知

5.4 度量体系

指标 当前值 目标值 测量方式
fix 率 24% < 15% fix 提交数 / 总提交数
权限同步遗漏 12+ 次/月 0 次 CI 检查结果
前端测试文件 62/297 120/297 文件计数
小程序测试 0 文件 29 service 全覆盖 文件计数
单次批量 fix 16 个 < 5 个 单次提交修复数

5.5 质量红线

红线 触发条件 行动
fix 率 > 20% 连续 2 周 新功能需额外审批
单次批量 fix > 10 单次提交 回溯 DoD 是否执行
安全 CRITICAL 审计发现 立即修复,暂停其他

附录 AFeature DoD 清单(建议版本)

每个功能标记"完成"前,必须通过以下检查清单:

## Feature DoD — 功能完成检查清单

### 后端
- [ ] Entity 包含所有标准字段id/tenant_id/created_at/updated_at/deleted_at/version
- [ ] Handler 添加 require_permission 权限守卫
- [ ] 权限码已写入 seed 迁移(.list + .manage
- [ ] utoipa 注解已添加OpenAPI 文档可见)
- [ ] Service 层核心路径有单元/集成测试
- [ ] 多租户隔离正确tenant_id 过滤)
- [ ] 输入验证完整(必填字段 + 格式校验)
- [ ] 错误处理统一AppError不 panic
- [ ] 关键操作有 tracing 日志

### 前端Web
- [ ] API 路径与后端 OpenAPI spec 一致
- [ ] 路由使用 createProtectedRoute 并声明权限码
- [ ] 菜单配置已更新(可见性 + 权限关联)
- [ ] 错误状态有用户友好提示
- [ ] 不使用 any 类型

### 前端(小程序)
- [ ] Service 层接口契约与后端 DTO 一致
- [ ] 登录态处理正确useDidShow 恢复)
- [ ] 长者模式适配完成
- [ ] 无硬编码路径

### 安全
- [ ] 新增端点有权限声明(非默认放行)
- [ ] 敏感数据有脱敏/加密处理
- [ ] 用户输入已验证和消毒
- [ ] 无 CORS 通配符

### 验证
- [ ] cargo check 全 workspace 通过
- [ ] cargo test 全部通过
- [ ] 浏览器中手动验证功能正常
- [ ] 相关路由权限按角色测试通过

结论

核心洞察24% fix 率的根因不是"代码写得不好",而是"流程让好代码也容易出错"。

权限散落 4 处、前后端类型各自维护、缺少完成检查清单、验证滞后 — 这些是系统性问题,需要系统性解决。

最有效的三件事:

  1. Feature DoD2h 投入)— 让每次提交都经过全量检查
  2. 权限/路径 CI 一致性检查1-2d 投入)— 让不一致无法通过 CI
  3. 小程序 service 层测试2d 投入)— 填补最大质量真空

这三件事做完,预计 fix 率可从 24% 降至 15% 以下。