Files
AI-Health/docs/BUG_REVIEW.md
MingNian 63d2092c24 feat: UI全面改造 + 后端多项修复
【后端修复】
- 删除diet/consultation agent假工具声明
- 修复DayOfWeek实体注释
- 修复Vision API content序列化
- cleanup_service级联删除修复
- 用药提醒时区偏差修复
- 统一DateTime处理(UtcNow+8)
- 新增UTC DateTime JSON转换器

【前端UI重构】
- 配色体系全面更新(#8B5CF6淡紫+#F0ECFF背景)
- 登录页重设计
- 首页重设计(透明顶栏、渐变背景、胶囊输入区)
- 聊天卡片加白蓝边框、渐变标题
- 侧边栏重构(渐变背景、合并顶部、删除底部设置)
- 确认卡片可编辑字段恢复
- 所有子页面加返回按钮
- catch异常加日志
- 删除后refresh provider缓存
2026-06-10 18:27:38 +08:00

20 KiB
Raw Blame History

健康管家 — 全面代码审查与Bug文档

审查日期2026-06-10 | 范围:全栈(后端 .NET 10 + 前端 Flutter


测试结果汇总

测试集 通过 失败 说明
后端单元测试 (entity_tests) 10 0 实体/数据库操作全通过
后端单元测试 (auth_tests) 4 0 认证流程全通过
后端单元测试 (ai_agent_tests - PromptManager) 8 0 AI提示词全通过
后端集成测试 (ai_agent_tests - AI对话) 0 5 需要后端运行中
Flutter 测试 (widget_test) - - sqlite3 原生库下载失败,无法运行

总计22/27 通过5个集成测试需要后端在线


一、后端 Bug

B1. 缺少 consultation DELETE 端点

  • 位置consultation_endpoints.cs
  • 问题:问诊创建后无删除/取消接口。患者无法取消发起的问诊
  • 影响:患者发起错误问诊后无法撤销
  • 建议:添加 MapDelete("/consultations/{id:guid}", ...)

B2. ai_chat_endpoints 中 unified agent 缺少部分工具

  • 位置ai_chat_endpoints.cs:340-347
  • 问题unified agent 虽聚合了 7 种工具,但缺少 manage_archiverequest_doctor
  • 影响:用户在 unified 模式无法通过对话修改档案或请求医生

B3. CompressImage 未释放 GDI 资源

  • 位置ai_chat_endpoints.cs:484-503
  • 问题Image.FromFileBitmapGraphicsusing 包裹,但 EncoderParameters 未释放
  • 影响:每次食物识别可能泄漏少量非托管内存
  • 修复using var parameters = new EncoderParameters(1);

B4. 用药提醒服务可能定时查询过于频繁

  • 位置BackgroundServices/medication_reminder_service.cs
  • 问题:需要检查轮询间隔,每分钟查一次可能对数据库压力大

B5. 开发数据种子硬编码 API Key 检查

  • 位置dev_data_seeder.cs
  • 问题DEVDATA_ENABLED=true 创建测试用户,生产环境可能误开启

二、前端 Bug

C1. 聊天列表从顶部跳到底部 已修复

  • 修复chat_messages_view.dart 改为 reverse:true
  • 修复home_page.dart 滚动逻辑简化

C2. SwipeDeleteTile 内层手势冲突 已修复

  • 修复common_widgets.dart 滑动状态下用 AbsorbPointer 屏蔽内部按钮

C3. SwipeDeleteTile 红色溢出 已修复

  • 修复margin 参数从 Stack 内部移到外部 Padding

C4. 运动打卡 dayOfWeek 索引偏差 已修复

  • 修复remaining_pages.dart 改为 weekday % 7 与 C# DayOfWeek 对齐

C5. 用药管理 Dismissible 一步删除 已修复

  • 修复:统一使用 SwipeDeleteTile

C6. Flutter 测试断言错误

  • 位置health_app/test/widget_test.dart:9
  • 代码expect(AppTheme.primary, AppTheme.primaryLight);
  • 问题primary (0xFF6366F1) ≠ primaryLight (0xFFEEF2FF),这个断言必然失败
  • 修复:改为 expect(AppTheme.primary, const Color(0xFF6366F1));

C7. home_page.dart onTap 手误写了 ?.()

  • 位置home_page.dart:115
  • 代码onTap: () => pushRoute(ref, 'notificationPrefs') 实际没有 ?.() 问题(之前看错了),此处无误

C8. 报告详情返回按钮popRoute 在 setState 后

  • 位置report_pages.dart:449-454
  • 问题clearAnalysis() 调用 state.copyWith(...) 然后立即 popRoute(ref),在 pop 过程中可能访问已 dispose 的 provider
  • 风险:中等

C9. DietCapturePage TextField 内存泄漏

  • 位置diet_capture_page.dart:465,479,495
  • 问题:每个食物项创建 TextEditingController(text: food.name) 但从不 dispose
  • 修复:用 TextFormField + initialValue 或缓存 controller

C10. 报告上传错误吞没

  • 位置report_pages.dart:199
  • 代码} catch (_) {} — 上传失败无任何反馈
  • 修复:至少显示 snackbar 提示

三、前端缺失功能

M1. 饮食记录无编辑/修改功能

  • 当前只能查看(DietRecordDetailPage)和删除,无法修改已有记录

M2. 运动计划详情页缺失

  • ExercisePlanPageonTap: () {} 为空,点卡片无反应
  • 没有类似 ExercisePlanDetailPage 的页面

M3. 问诊列表无前端入口

  • 后端有 /api/consultations GET但前端没有问诊历史列表页

M4. 对话无删除/清空功能

  • 后端有 DELETE /api/ai/conversations/{id}但前端无对应UI

M5. 无数据导出功能

  • 用户无法导出健康数据(血压记录、饮食记录等)

四、安全与代码质量

S1. JWT Secret 开发默认值

  • 位置Program.cs:46
  • 问题jwtSecret ??= "dev-secret-key-change-in-production-min-32-chars!!";
  • 风险:若忘记设环境变量,生产环境用弱密钥

S2. token 通过 query string 传输SSE

  • 位置ai_chat_endpoints.cs:25, sse_handler.dart:17
  • 问题token 放在 URL query string会被服务器日志、代理缓存
  • 风险:中等(含过期时间的 token但仍有泄露风险

S3. CORS 全开

  • 位置Program.cs:96-98
  • 代码policy.SetIsOriginAllowed(_ => true)
  • 风险:生产环境应限定具体 origin

S4. 全局异常中间件可能泄露内部错误

  • 位置exception_middleware.cs
  • 需要检查:是否在生产环境返回了调用栈

S5. Flutter 硬编码后端 IP

  • 位置api_client.dart:6
  • 代码const String baseUrl = 'http://10.4.164.158:5000';
  • 问题:每次换网络都需改代码

五、未使用代码(可清理)

  • chat_messages_view.dart: _cardFilledBtn, _cardOutlineBtn, _agentColors, _taskRow 未使用
  • chat_provider.dart: _parseAgent 未使用
  • remaining_pages.dart: shadcn_ui 导入未使用
  • report_pages.dart: shadcn_ui 导入未使用,reportId 变量未使用
  • service_package_detail_page.dart: navigation_provider 导入未使用

六、Agent 自动审查新增发现

A1. app_router.dart 无防御 null 断言(🔴严重)

  • 位置app_router.dart:41-73
  • 代码示例ReportDetailPage(id: params['id']!) 等多处
  • 问题params['id']! 若 params 中无 'id' 键,会抛出 null 断言异常导致崩溃
  • 影响:任何路由参数拼写错误或缺少都会 crash
  • 修复:使用 params['id'] ?? '' 并提供 fallback

A2. device_scan_page.dart BLE 流订阅未取消(🔴严重)

  • 位置device_scan_page.dart
  • 问题BLE stream subscription 在 dispose 时未 cancel导致蓝牙连接泄漏
  • 影响:多次进出扫描页会积累未释放的 BLE 连接

A3. 静默吞错误(🟡中)

  • 范围:全前端 28 处 catch (_) {}
  • 问题:所有 API 错误、解析错误均无日志或用户提示
  • 修复:至少加上 debugPrint('Error: $e') 或显示 snackbar

A4. 删除后未刷新 Provider🟡中)

  • 范围:多个页面
  • 问题:删除操作后调用了 _load()_refresh()setState但未调用 ref.invalidate(someProvider),导致 Riverpod 缓存未更新
  • 影响:切换到其他页面再回来,旧数据可能仍显示

A5. FutureProvider + setState 双重模式(🟢低)

  • 范围DietRecordListPage, ExercisePlanPage
  • 问题:同时使用 Riverpod FutureProvider 和本地 setState导致 provider 失效无效

七、全部问题汇总含Agent发现

# 优先级 位置 问题描述
1 🔴 app_router.dart null 断言无防御,参数缺失即崩溃
2 🔴 device_scan_page.dart BLE 流订阅未取消
3 🔴 B1 consultation 缺少 DELETE 端点
4 🔴 S1 Program.cs JWT 开发默认弱密钥
5 🔴 C9 diet_capture TextEditingController 泄漏
6 🟡 全局 28处 catch(_){} 静默吞错
7 🟡 多页面 删除后无 ref.invalidate
8 🟡 C6 widget_test 断言 primary == primaryLight 错误
9 🟡 C10 report 上传失败无提示
10 🟡 M2 exercise 运动详情页缺失onTap 空
11 🟡 C8 report pop 时序问题
12 🟡 A5 多页面 FutureProvider+setState 双重模式
13 🟢 B3 ai_chat EncoderParameters 未释放
14 🟢 B4 bg_service 用药提醒轮询频率需审视
15 🟢 B5 dev_data 生产环境可能误开启测试数据
16 🟢 S2 SSE token 走 query string
17 🟢 S3 CORS 全开 AllowCredentials
18 🟢 S5 api_client 硬编码 IP
19 🟢 多处 未使用代码可清理
20 🟢 B2 unified unified agent 缺少 manage_archive 工具

八、后端 Agent 审查新增发现(关键)

D1. 运动计划 DayOfWeek 跨层不一致(🔴严重)

  • 位置prompt_manager.cs vs exercise_plan.cs 实体注释
  • 问题Prompt 告诉 AI day_of_week: 0-6(周日=0),但实体注释 // 0=周一, 6=周日。AI 按周日=0 生成数据,后端按周一=0 解析,运动计划星期全偏一天
  • 修复:统一为 C# DayOfWeek 枚举0=周日)

D2. SMS 验证码使用伪随机数(🔴安全漏洞)

  • 位置sms_service.cs
  • 问题Random.Shared.Next(100000, 1000000) 使用 PRNG攻击者可预测验证码
  • 修复:改用 RandomNumberGenerator.GetInt32(100000, 999999)

D3. checkin 无所有权验证(🔴越权漏洞)

  • 位置medication_agent_handler.cs:99exercise_agent_handler.cs:69
  • 问题confirm_medicationexercise checkin 直接通过 itemId 操作,不验证是否属于当前用户。任何认证用户可操作他人数据
  • 修复:添加 && item.Plan.UserId == userId 检查

D4. VisionAsync content 序列化错误(🔴严重)

  • 位置open_ai_compatible_client.cs:136
  • 问题:将图片 contentParts 先序列化为 JSON 字符串再赋值给 Content但 OpenAI 兼容 API 期望 Content 为数组格式
  • 影响:食物识别 VLM 调用可能失败

D5. diet/consultation agent 工具声明但未实现(🔴严重)

  • 位置diet_agent_handler.csconsultation_agent_handler.cs
  • 问题EstimateFoodToolRequestDoctorTool 在 Tools 列表中声明,但 Execute 方法无对应 case调用返回"未知工具"
  • 影响:饮食识别和请求医生功能不可用

D6. CleanupService 删除未级联(🔴严重)

  • 位置cleanup_service.cs:28
  • 问题db.Conversations.RemoveRange(oldConversations) 未先删除关联的 ConversationMessage可能因 FK 约束抛异常
  • 修复:先删除 Messages 再删 Conversations或使用 ExecuteDeleteAsync

D7. 用药提醒时区计算 bug🔴严重)

  • 位置medication_reminder_service.cs:37
  • 问题DateTime.SpecifyKind(beijingNow.Date, DateTimeKind.Utc) — 北京时间 00:00 被标记为 UTC 00:00导致打卡检测有 8 小时偏差
  • 影响:提醒时间错位、重复提醒或漏提醒

D8. DbContext 未配置外键和级联删除(🟡中等)

  • 位置app_db_context.cs
  • 问题OnModelCreating 没有任何 HasOne/WithMany/HasForeignKey/OnDelete 配置,全凭约定
  • 影响:数据库无 FK 约束、级联行为不明确、RefreshToken 全表扫描

D9. 缺少多个数据库索引(🟡中等)

  • RefreshToken: 无索引,认证查询全表扫描
  • FollowUp: 无 (UserId, ScheduledAt) 索引
  • DeviceToken: 无 UserId 索引
  • Report: 无 (UserId, CreatedAt) 索引

D10. ExceptionMiddleware 统一返回500🟡中等)

  • 位置exception_middleware.cs
  • 问题:所有异常都返回 500不区分 400/401/404
  • 影响:客户端无法根据状态码处理不同类型的错误

D11. 用药提醒未实际推送(🟡中等)

  • 位置medication_reminder_service.cs
  • 问题TODO 注释表明推送尚未实现,只记录日志

D12. Prompt 文本硬编码(🟢低)

  • 不支持热更新,修改需重新编译

九、最终汇总(所有发现)

# 优先级 类别 位置 问题
1 🔴 安全 sms_service 验证码用 PRNG 可预测
2 🔴 安全 agent handlers checkin 越权漏洞
3 🔴 逻辑 prompt/entity DayOfWeek 跨层不一致
4 🔴 功能 diet/consult agent 工具声明但未实现
5 🔴 功能 open_ai_client Vision content 序列化错误
6 🔴 稳定性 cleanup_service 删除未级联 FK 冲突
7 🔴 功能 reminder_service 时区计算 8h 偏差
8 🔴 崩溃 app_router.dart null 断言无防御
9 🔴 泄漏 device_scan_page BLE 流未取消
10 🔴 安全 Program.cs CORS 全开+AllowCredentials
11 🔴 安全 Program.cs JWT 默认弱密钥
12 🔴 泄漏 diet_capture TextEditingController 未释放
13 🟡 体验 28处 catch(_){} 静默吞错
14 🟡 逻辑 多页面 删除后未 invalidate provider
15 🟡 配置 app_db_context 无 FK/级联/索引
16 🟡 体验 exception_middleware 统一返回 500
17 🟡 测试 widget_test 断言永远失败
18 🟡 功能 用药提醒 推送未实现
19 🟡 架构 多页面 FutureProvider+setState 混用
20 🟡 缺失 exercise 计划详情页缺失
21 🟢 代码 多处 未使用代码/本地时间/冗余

十、后端端点 Agent 审查新增发现(关键)

E1. 医生端点零授权(🔴阻断级)

  • 位置doctor_endpoints.cs:19
  • 问题MapGroup("/api/doctor") 没有 .RequireAuthorization(),所有医生端点(患者详情、健康数据、问诊、报告、随访)对公网开放
  • 影响:任何人可查看所有患者隐私数据、修改报告、创建/删除随访

E2. consultation POST 消息无所有权检查(🔴阻断级)

  • 位置consultation_endpoints.cs:48-75
  • 问题:发消息只检查 consultation 存在不验证是否属于当前用户。用户A可向用户B的问诊发消息

E3. exercise checkin 无所有权检查(🔴阻断级)

  • 位置exercise_endpoints.cs:119
  • 问题FindAsync([itemId]) 只按ID查不验证 item.Plan.UserId == userId。用户可操作他人运动计划

E4. SMS验证码在响应中暴露🔴严重)

  • 位置auth_endpoints.cs:34
  • 问题devCode = code 将6位验证码直接返回在JSON中#if DEBUG 守卫

E5. Task.Run 火后不理模式(🔴严重)

  • 位置report_endpoints.cs:67
  • 问题_ = Task.Run(async () => { ... }, CancellationToken.None) 在请求结束后 scope 可能已释放,后台任务崩溃

E6. System.Drawing 仅Windows🔴严重)

  • 位置ai_chat_endpoints.cs:486-494
  • 问题Image.FromFile/Bitmap/Graphics 在Linux容器中崩溃

E7. 健康数据 N+1 查询(🟡中等)

  • 位置health_endpoints.cs:78-89
  • 问题/latest 对5种指标类型分别发一次SQL查询

E8. 日历用药事件显示错误(🟡中等)

  • 位置calendar_endpoints.cs:49
  • 问题:用户有任意活跃用药就在每月每天标记"用药",不区分具体哪天该吃药

E9. 手动JSON解析绕过模型绑定🟡中等)

  • 范围diet、medication、exercise、doctor endpoints
  • 问题JsonDocument.Parse 手动解析导致 Swagger 无法文档化、无自动验证、拼写错误抛500

E10. 缺失端点

  • health缺 DELETE
  • diet缺 PUT
  • exercise缺 PUT
  • report缺 DELETE
  • file缺 GET/DELETE/list
  • followup缺 detail/confirm

十一、完整问题排名

# 等级 文件 问题
1 🔴🔴 doctor_endpoints 零授权 — 所有患者数据公开
2 🔴🔴 consultation 发消息无所有权检查
3 🔴🔴 exercise checkin无所有权检查
4 🔴 auth SMS验证码响应暴露
5 🔴 report Task.Run火后不理
6 🔴 ai_chat System.Drawing仅Windows
7 🔴 sms_service PRNG可预测验证码
8 🔴 agent handlers checkin越权
9 🔴 prompt_manager DayOfWeek不一致
10 🔴 diet/consult agent 工具声明未实现
11 🔴 open_ai_client Vision序列化错误
12 🔴 cleanup_service 删除未级联
13 🔴 reminder_service 时区8h偏差
14 🔴 app_router null断言崩溃
15 🔴 device_scan BLE泄漏
16 🔴 Program.cs CORS全开
17 🔴 Program.cs JWT弱密钥
18 🔴 diet_capture Controller泄漏
19 🟡 28处 catch(_){}吞错
20 🟡 多页面 删除未invalidate
21 🟡 health N+1查询
22 🟡 calendar 用药事件逻辑错误
23 🟡 app_db_context 无FK/索引配置
24 🟡 exception_mw 统一500
25 🟡 提醒服务 推送未实现
26 🟡 多端点 缺PUT/DELETE
27 🟡 多端点 手动JSON无验证

优先级排序

优先级 Bug 影响范围
🔴 C9: TextEditingController 内存泄漏 饮食识别页面
🔴 B1: 缺少 consultation DELETE 问诊功能
🔴 S1: JWT 弱密钥默认值 安全
🟡 C6: Flutter 测试断言错误 CI/CD
🟡 C10: 报告上传错误吞没 用户体验
🟡 M2: 运动计划详情页缺失 用户体验
🟡 C8: report pop 时序问题 潜在崩溃
🟢 B3: EncoderParameters 未释放 极少量泄漏
🟢 S5: 硬编码 IP 开发体验
🟢 未使用代码 代码质量

共发现 15 个问题5 个缺失功能。其中 5 个 Bug 已在本轮修复。


第二轮换角度审查(新增 10 个问题)

F1. uploadFile 响应解析崩溃 🔴

api_client.dart:60-69 — 后端返回 data: [{id, name, size}]List前端做 data['data']?['url'] 对List用字符串索引运行时异常。聊天图片上传全部无声失败。

F2. consultationChatProvider SignalR 永停不了 🔴

consultation_provider.dartstop() 定义了但无 Widget dispose 调用。离开问诊页后 SignalR 连接和 5秒轮询永续运行。

F3. chatProvider 流订阅无 dispose 🔴

chat_provider.dart_subscription/_streamTimer 无 disposeprovider 销毁即泄漏。

F4. ChatMessage 原地修改破坏不可变性 🔴

msg.confirmed = true 直接修改 state 中的对象 → 违反 Riverpod 不可变契约。

F5. 所有 FutureProvider 无 autoDispose 🟡

6 个 FutureProvider 缓存永不过期,页面级数据不释放。

F6. authProvider Token 刷新窗口期 id/phone 为空 🟡

auth_provider.dart:59UserInfo(id: '', phone: '') 然后等 _loadProfile() 异步补全。

F7. 医生 Web 零认证 🔴🔴

doctor_web/src/services/api-client.ts — 不发送 Authorization 头。叠加后端 doctor_endpoints 零授权E1任何人可访问所有患者数据。

F8. 医生 Web SignalR handler 泄漏 🔴

ChatPage.tsx:28-65 — 组件卸载时若在 Reconnecting 状态,跳过 off('ReceiveMessage'),重复挂载累积 handler。

F9. 6个后端端点前端从未调用 🟢

GET/DELETE /api/ai/conversationsGET /api/consultationsPUT /api/health-records/{id}、全部 /api/doctor/*

F10. 37 对 API 契约中 1 对崩溃 + 多端手动JSON脆弱 🟡

uploadFile 是唯一崩溃的。其余 36 对匹配但 TryGetProperty 区分大小写,依赖前端恰好用 camelCase。


两轮共发现 37 个问题,其中 5 个阻断级、19 个严重、10 个中等、3 个低。