对应 5 份设计规格,共 75 个 Task: 1. 性能优化 (12 Task) — 批量INSERT/N+1内联name/合并COUNT/按需重绘/chunk拆分 2. 安全纵深防御 (8 Task) — RLS/行级数据范围/Redis session_key/审计哈希链 3. 事件驱动架构 (10 Task) — 11个缺失事件补发/LISTEN+NOTIFY/schema版本化 4. 前端工程化 (10 Task) — hook统一/组件拆分/Bundle优化 5. 可观测性运维 (10 Task) — 深度健康检查/Prometheus/OTel/生产Docker/告警
5.4 KiB
性能优化实施计划
设计规格:
docs/superpowers/specs/2026-04-26-performance-optimization-design.md日期: 2026-04-26 | 状态: draft | 总周期: 3 周
Phase 1: 后端批量插入优化(Week 1, P0)
Task 1: device_reading_service batch_insert_readings 改为 SeaORM insert_many
涉及文件: crates/erp-health/src/service/device_reading_service.rs
步骤: 将 batch_insert_readings() 中 for 循环逐条 model.insert(db).await 替换为构建 Vec<ActiveModel> 后调用 insert_many() + on_conflict(columns([...]).do_nothing())。补充 50 条模拟数据的批量插入测试。
验收: cargo test -p erp-health device_reading 通过;500 条插入延迟 < 100ms。
Task 2: device_reading_service upsert_hourly_aggregates 批量化
涉及文件: crates/erp-health/src/service/device_reading_service.rs
步骤: 批量查出已存在的聚合记录(按 patient_id + device_type + hour),分为"新增"和"更新"两组,分别 insert_many 和批量 update,事务包装。补充同一小时多次 upsert 的聚合精度测试。
验收: 聚合值(avg/min/max)精度与优化前一致;cargo test 通过。
Phase 2: 前端 N+1 根治(Week 2, P0)
Task 3: 后端 appointment_service list 返回 patient_name/doctor_name
涉及文件: crates/erp-health/src/service/appointment_service.rs, dto/mod.rs, handler/mod.rs
步骤: 列表 DTO 增加 patient_name/doctor_name 字段,service 查询中 find_also_related 或子查询关联 users 表获取 display_name,handler 层映射到响应 DTO。保持 Option 类型向后兼容。
验收: GET /api/v1/health/appointments 每条记录含 name 字段。
Task 4: 后端 consultation_service / follow_up_service 同样内联 name
涉及文件: consultation_service.rs, follow_up_service.rs, dto/mod.rs
步骤: consultation list 添加 patient_name/doctor_name,follow_up list 添加 patient_name,复用 Task 3 的 JOIN 模式。
验收: 两个列表 API 响应均含 name 字段;cargo test 通过。
Task 5: 前端 AppointmentList 移除 nameCache,改用内联字段
涉及文件: apps/web/src/pages/health/AppointmentList.tsx
步骤: 移除 nameCache useState 及逐条请求 name 的 useEffect,表格列直接使用后端返回的 patient_name/doctor_name,消除 fetchData 对 nameCache 的依赖。
验收: Network 面板仅 1 个列表 API 请求;首屏 < 500ms(20 条记录)。
Task 6: 前端 ConsultationList / FollowUpTaskList 同样改造
涉及文件: ConsultationList.tsx, FollowUpTaskList.tsx
步骤: 两个页面移除 nameCache,使用内联 name 字段。验证无 N+1 请求。
验收: 两个页面 Network 面板无 N+1 请求;pnpm build 通过。
Phase 3: 后端查询优化(Week 3, P1)
Task 7: stats_service 合并多次 COUNT 为 GROUP BY
涉及文件: crates/erp-health/src/service/stats_service.rs
步骤: 6 个统计函数从多次 COUNT 合并为 SELECT status, COUNT(*) GROUP BY status + 应用层 HashMap 聚合。compute_avg_field 用宏生成静态 SQL 常量替代 format! 拼接。编写对比测试确认 GROUP BY 与多次 COUNT 结果一致。
验收: get_follow_up_statistics 查询次数从 4 降为 1;compute_avg_field 不再 format! 拼接。
Task 8: patient_service get_health_summary 用 tokio::join! 并行化
涉及文件: crates/erp-health/src/service/patient_service.rs
步骤: get_health_summary() 中 4 次 .await 改为 tokio::join! 并行执行,各查询错误独立处理(未找到返回 None)。
验收: 并行化后返回数据与串行一致;cargo test 通过。
Task 9: alert_engine 预加载规则批量评估
涉及文件: crates/erp-health/src/service/alert_engine.rs
步骤: 批量查询患者最近 cooldown 期间所有 alerts 构建 HashSet<rule_id>,按 device_type 批量查最新 hourly 记录后在内存匹配规则条件。重构为:批量加载 -> 内存过滤 -> 批量生成告警。
验收: 10 条规则评估查询次数从 ~20 降为 2-3;cargo test 通过。
Phase 4: 前端渲染优化(Week 3, P2)
Task 10: PluginCRUDPage columns useMemo + 拆分子组件
涉及文件: apps/web/src/pages/PluginCRUDPage.tsx
步骤: columns 包裹 useMemo(() => [...], [schema]),搜索栏/分页/表格拆为独立子组件。
验收: 输入搜索时 columns 不重建;pnpm build 通过。
Task 11: PluginGraphPage 按需重绘
涉及文件: apps/web/src/pages/PluginGraphPage.tsx
步骤: 移除持续 requestAnimationFrame 循环,改为数据变更 useEffect 触发单次重绘 + ResizeObserver 监听容器变化。
验收: 静态页面时 CPU 占用 < 1%;pnpm build 通过。
Task 12: vite.config.ts manualChunks 拆分 heavy deps
涉及文件: apps/web/vite.config.ts
步骤: manualChunks 配置 vendor-charts(@ant-design/charts) / vendor-flow(@xyflow/react) / vendor-editor(@wangeditor/editor),对应路由改用 React.lazy 动态加载。
验收: 主 bundle gzip 体积降低 200KB+;图表/流程图/编辑器按需加载。
执行原则
- 每 Task 完成后立即提交 — 不积压,保持可追溯
- Phase 1-2 为 P0 — 批量插入和 N+1 根治直接影响生产性能
- cargo test + pnpm build 必须通过 — 每个 Task 完成后验证