Files
AI-Health/docs/project_deep_review.md

387 lines
18 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-06-17
## 1. 分析范围与结论概览
本次分析覆盖了 Flutter 客户端、ASP.NET Core 后端、AI 问诊/饮食识别链路、路由、数据存储、UI 结构、测试与工程配置。执行过的主要检查包括:
- `flutter analyze`:当前客户端有 162 条 analyzer/lint 问题,其中包含错误导入、未使用代码、异步上下文风险、废弃 API、调试输出等。
- `dotnet test`:后端测试未能真正跑完,原因是正在运行的 `Health.WebApi` 进程锁住了 `bin/Debug/net10.0` 下的 DLL导致构建复制失败。
- 重点阅读:`api_client.dart``chat_provider.dart``app_router.dart``data_providers.dart``local_database.dart``Program.cs``auth_endpoints.cs``ai_chat_endpoints.cs``file_endpoints.cs`、测试目录等。
整体判断:项目功能面铺得很广,已经具备“患者端健康管理 + AI 助手 + 饮食识别 + 用药/报告/日历/随访 + 医生/管理员”的雏形。但目前最大问题不是单个页面丑而是功能深度、数据安全、接口契约、状态管理、UI 体系和测试可信度还没有收拢。现在已经到了需要“先稳核心链路,再美化体验”的阶段。
## 2. 最需要优先处理的问题
| 优先级 | 问题 | 影响 | 建议 |
| --- | --- | --- | --- |
| P0 | 短信验证码接口返回 `devCode`,登录页还会自动填充 | 真实环境下等于绕过验证码安全 | 仅开发环境返回,生产环境绝不返回;前端删除自动填充逻辑 |
| P0 | SSE token 放在 query 中,后端用 `ReadJwtToken` 读取但没有验证签名 | 可被伪造用户 ID存在严重认证风险 | SSE 也必须走标准 JWT 验证,或使用一次性短票据 |
| P0 | AI 会话按 `conversationId` 查询后未确认归属用户 | 可能跨用户写入/读取会话 | 所有 conversation 查询都加 `UserId == currentUserId` |
| P1 | 文件上传前后端契约不一致 | 图片上传后前端拿不到 URLAI 图片消息可能只保存本地路径 | 后端返回可访问 URL或前端按后端返回结构处理 |
| P1 | token 和健康数据存在本地 SQLite未加密 | 手机丢失或被调试时有泄露风险 | 使用 secure storage 保存 token敏感健康数据考虑加密 |
| P1 | CORS 允许任意 Origin 且允许 Credentials | Web 场景下有跨站风险 | 按环境配置白名单 |
| P1 | 后端用 `EnsureCreatedAsync` 而不是 migrations | 数据库升级不可控 | 建立 EF migrations 流程 |
| P1 | UI 设计体系不统一 | 页面之间像不同产品拼接,后期维护难 | 建立颜色、间距、字体、组件规范 |
| P2 | Flutter 存在大量未使用代码、旧页面、调试输出 | 维护成本高,也容易藏 bug | 分模块清理,保留真实业务入口 |
| P2 | 测试依赖运行中的本地服务和不安全 dev 行为 | CI 不可靠,安全问题被测试固化 | 单元/集成测试分层,测试环境用隔离配置 |
## 3. 功能层面分析
### 3.1 功能广度够,但关键流程深度不够
目前功能入口很多AI 问诊、记数据、饮食拍照、用药、报告、运动、健康档案、复查随访、医生端、管理员端等。这个方向是对的,但现在许多功能更像“有入口、有页面、有部分数据”,还没有形成足够扎实的闭环。
建议优先把以下闭环做深:
1. 健康数据闭环:记录数据、展示趋势、异常提示、医生/AI 解读、复查建议。
2. 饮食闭环:图片识别、用户修正、营养统计、长期趋势、与血糖/体重关联。
3. 用药闭环:药品计划、提醒、服药打卡、漏服记录、医生可见。
4. 报告闭环上传报告、AI 解析、结构化指标、异常项追踪、历史对比。
现在的问题是入口比闭环多。用户第一次点进去可能觉得丰富,但长期使用时会发现很多地方缺少持续价值。
### 3.2 健康仪表盘需要从“展示数值”升级到“解释状态”
血压、心率、血糖、血氧、体重这些指标是同等级核心指标UI 上横向平铺是合理的。但产品上还需要补足:
- 每个指标显示采集时间,避免用户误以为是最新状态。
- 显示单位和正常范围。
- 显示趋势,例如较上次升高/下降。
- 异常时给出明确状态,而不是只换颜色。
- 区分数据来源:手动录入、蓝牙设备、报告解析、医生录入。
医疗健康类应用不能只好看,还要让用户理解“现在是否安全、下一步做什么”。
### 3.3 AI 功能需要更强的边界
AI 问诊、饮食分析、报告解读是项目亮点,但要注意:
- AI 建议不能替代医生诊断,需要在关键场景给出边界提示。
- AI 生成结果要允许用户修正,尤其是饮食热量、报告指标、药品信息。
- AI 使用了用户健康上下文,应有授权说明、数据范围说明、删除机制。
- AI 工具调用失败时,前端需要展示可理解的失败状态,而不是静默失败。
## 4. UI/UX 分析
### 4.1 当前最大 UI 问题:没有稳定设计系统
项目里已经有 `AppColors``AppTheme`,也有多处页面自己的渐变、阴影、圆角、卡片样式。最近的页面修改又加入了更多独立渐变。这样短期能调好某个页面,但长期会导致页面之间不统一。
建议建立一套稳定规则:
- 主色:用于导航、主要按钮、健康仪表盘重点区域。
- 功能色:饮食、用药、报告、运动、问诊等可以不同,但要同一明度和饱和度等级。
- 状态色:正常、警告、危险、完成、禁用必须固定。
- 卡片规则:圆角、阴影、边框、内边距统一。
- 图标规则:同一模块内图标线宽、尺寸、背景形状统一。
现在用户已经多次指出“颜色太花”“图标不一致”“侧边栏不好看”,本质就是设计 token 没有统一。
### 4.2 侧边栏应该是高频操作中心,不是杂物入口
侧边栏现在承担了个人信息、仪表盘、功能入口、设置等很多内容。建议侧边栏只保留高频且有明确层级的内容:
- 顶部:用户身份和健康状态摘要。
- 中部:核心健康指标,横向一屏看完。
- 功能入口:报告管理、饮食记录、用药管理、健康日历、复查随访、运动计划,两行三列。
- 底部:健康档案、设置。
个人信息区域不一定要卡片包起来,可以用更轻的排版。健康仪表盘可以做成视觉重点,但功能入口不应该抢它的层级。
### 4.3 页面质感不均衡
部分页面已经开始有精致的渐变和卡片,但另一些页面仍像占位页或默认列表页。尤其是:
- 个人信息页:信息架构需要重做,当前不够像一个正式健康档案/账号资料页。
- 设置页:应按账号、安全、通知、设备、隐私、关于分组,而不是堆按钮。
- 饮食分析页餐次选择、识别结果、热量展示、AI 建议这几个区域需要更统一的卡片层级。
- 医生端/管理员端:如果后续要真实使用,需要比患者端更重视密度、筛选、表格和状态。
### 4.4 可访问性风险
当前大量使用渐变、浅色图标、小号文字和颜色区分状态。健康类应用的用户可能包含中老年人,建议:
- 核心数字字号足够大。
- 不只靠颜色表达异常,还要有文字。
- 保证按钮文字和图标对比度。
- 支持系统字体缩放。
- 重要按钮触控面积至少 44x44。
## 5. 前端工程分析
### 5.1 API 配置不适合真实移动端
`health_app/lib/core/api_client.dart``baseUrl` 默认是 `http://localhost:5000`。这在 Android/iOS 真机上通常不可用,也不适合测试/生产环境切换。
建议:
- 使用 `--dart-define=API_BASE_URL=...`
- 区分 dev/staging/prod。
- 本地 Android 模拟器使用 `10.0.2.2` 或局域网地址。
### 5.2 Token 存储不安全
当前 token 存在本地 SQLite key-value 中,例如 `access_token``refresh_token`。这对健康类应用风险偏高。
建议:
- token 改用 `flutter_secure_storage` 或平台安全存储。
- SQLite 中的敏感健康数据考虑加密。
- 退出登录时确认清理 token、用户缓存、会话缓存。
### 5.3 上传接口前后端不一致
前端 `uploadFile` 期望后端返回:
- `url`
-`data.url`
但后端 `file_endpoints.cs` 返回的是文件列表,每项包含:
- `id`
- `name`
- `size`
这会导致 `ChatNotifier.sendImage` 中的 `uploadedUrl` 很可能是 null最终消息只保存本地路径跨设备、重启、后端 AI 处理都会出问题。
建议统一契约:
- 后端返回 `{ id, name, size, url, contentType }`
- 前端保存 `remoteUrl`,本地路径只做临时预览。
- 上传失败要有明确 UI 反馈。
### 5.4 路由可靠性不足
`app_router.dart` 使用字符串 switch 和 `params['id']!`。如果参数缺失会直接崩溃。
建议:
- 至少对参数做空值保护。
- 核心页面可以逐步迁移到 typed route。
- 路由表按模块拆分,避免一个文件不断膨胀。
### 5.5 状态管理有隐患
`chat_provider.dart` 中有一些状态直接修改对象字段的写法,例如修改 `ChatMessage``content``type``metadata``confirmed`。这容易造成 Riverpod rebuild 不稳定、历史消息状态串联、难以调试。
建议:
- 消息对象尽量不可变。
- 更新消息时使用 copy/update list。
- loading、streaming、error 状态显式建模。
### 5.6 错误处理过于安静
一些 provider 会 catch 异常后返回 fallback 数据,例如医生列表、运动计划。这个方式能让页面不崩,但会掩盖真实后端错误。
建议:
- demo 数据和真实数据明确分离。
- 网络失败时展示“加载失败/重试”,不要假装成功。
- 对关键接口增加日志和错误上报。
### 5.7 当前 Flutter analyzer 需要清理
本次 `flutter analyze` 返回 162 条问题。较重要的包括:
- `settings_pages.dart``data_providers.dart` 导入 `apiClientProvider`,但 provider 实际不在该文件中,属于当前明显错误。
- 多处 `use_build_context_synchronously`,异步后使用 `context` 前没有判断 mounted。
- BLE 使用废弃的 `BluetoothDevice.localName`
- 大量 `avoid_print`可能泄露请求、token、健康数据。
- 多个未使用方法、变量、页面,说明旧代码堆积严重。
建议先定一个目标:把 analyzer 从 162 条降到 0 或只剩明确允许的少量规则。
## 6. 后端工程与安全分析
### 6.1 短信验证码存在严重安全问题
`auth_endpoints.cs` 中发送短信验证码后会返回 `devCode`,前端登录页还会自动填充。这个行为如果进入真实环境,会直接破坏验证码意义。
另外还存在:
- 管理员手机号 `12345678910`
- 固定验证码 `000000`
- 缺少短信发送频率限制。
- 缺少验证码尝试次数限制。
- 验证码在部分失败流程中可能提前被标记已使用。
建议:
- 只有开发环境允许返回验证码。
- 生产环境必须接入真实短信服务。
- 加入 IP/手机号频率限制。
- 管理员登录改为独立安全流程。
### 6.2 SSE 认证方式有严重漏洞
AI SSE 接口允许从 query string 读取 token而且后端使用 `ReadJwtToken` 读取用户 ID。`ReadJwtToken` 只解析 token不验证签名、不验证过期、不验证 issuer/audience。
这意味着攻击者可能构造一个看似 JWT 的字符串,放入任意用户 ID claim后端就可能当成有效用户。
建议:
- 禁止直接信任 query token。
- SSE 鉴权也必须经过 `JwtBearer` 验证。
- 如果浏览器 EventSource 不方便加 header可以先用标准授权接口换一个短期一次性 stream token服务端存储并校验。
### 6.3 会话归属校验不足
AI 聊天接口中根据 `conversationId` 查询会话后,需要确认该会话属于当前用户。否则只要知道或猜到 conversationId就有跨用户写入/读取风险。
建议:
```csharp
var conversation = await db.Conversations
.FirstOrDefaultAsync(c => c.Id == convId && c.UserId == currentUserId);
```
所有报告、健康档案、饮食、聊天记录等用户资源都应遵循这个模式。
### 6.4 CORS 配置过宽
`Program.cs` 中 CORS 允许任意 origin同时允许 credentials。这在 Web 客户端场景下风险很大。
建议:
- dev 环境允许 localhost。
- staging/prod 使用固定域名白名单。
- 不要在任意 origin 下允许 credentials。
### 6.5 数据库初始化方式不适合长期维护
后端使用 `EnsureCreatedAsync()`。这适合原型阶段,不适合真实项目迭代。后续字段变更、索引变更、数据迁移都会困难。
建议:
- 建立 EF Core migrations。
- 启动时只在开发环境自动迁移,生产环境由部署流程控制。
- 所有 schema 变更进入版本管理。
### 6.6 文件上传风险
`file_endpoints.cs` 当前只保存上传文件,没有看到严格的大小、类型、内容校验。
建议:
- 限制文件大小。
- 限制 MIME 类型和扩展名。
- 图片重新编码或扫描。
- 不直接信任用户文件名。
- 返回可访问 URL并控制访问权限。
### 6.7 System.Drawing 跨平台风险
后端 AI 图片压缩使用 `System.Drawing` 相关 APIanalyzer 给出了 CA1416 警告。这些 API 在非 Windows 环境不可靠。如果部署到 Linux 容器,可能出问题。
建议换成:
- ImageSharp
- SkiaSharp
- 或云端对象存储/图片处理服务
## 7. AI 与隐私合规分析
项目会把用户健康档案、健康记录、饮食图片、报告等数据送入 AI。健康数据属于高敏感数据需要明确处理策略。
建议补齐:
- 用户授权:哪些数据会发送给 AI。
- 数据最小化:只传当前任务必要字段。
- 日志脱敏不要记录完整模型响应、token、报告原文、图片隐私信息。
- 删除机制用户删除账号后AI 会话、上传文件、日志也要清理。
- 医疗免责声明AI 只做健康建议,不替代诊断。
- 审计日志:医生/管理员访问患者数据需要留痕。
当前 `vlm_log_*.txt` 会记录模型响应,可能包含敏感结果,建议尽快调整为脱敏日志或仅开发环境启用。
## 8. 测试与工程流程
### 8.1 后端测试当前不可靠
`dotnet test` 未跑完,因为正在运行的 WebApi 进程锁住了构建输出 DLL。这说明本地开发/测试流程还不稳定。
建议:
- 测试使用独立输出目录或先停止运行中的服务。
- CI 中从干净环境执行。
- 单元测试不要依赖手动启动的 localhost 服务。
### 8.2 测试内容还偏浅
目前测试更像验证部分服务逻辑和开发流程,没有覆盖高风险业务:
- 验证码频控和错误次数。
- JWT 过期、刷新、伪造 token。
- 用户 A 不能访问用户 B 的会话/报告/健康数据。
- 文件上传大小/类型限制。
- AI SSE 中断、重试、失败展示。
- 饮食识别后用户修正和保存。
建议先补安全边界测试,再补 UI golden/screenshot 测试。
## 9. 具体 bug 与风险点清单
| 文件 | 问题 | 建议 |
| --- | --- | --- |
| `health_app/lib/pages/settings/settings_pages.dart` | `apiClientProvider` 导入来源错误analyzer 已报错 | 从正确 provider 文件导入,或统一 provider 暴露位置 |
| `health_app/lib/core/api_client.dart` | `baseUrl` 写死 localhost | 使用环境配置 |
| `health_app/lib/core/api_client.dart` | 上传返回结构与后端不匹配 | 统一上传响应 |
| `health_app/lib/core/api_client.dart` | `LogInterceptor` 打印请求/响应 body | 生产关闭,敏感字段脱敏 |
| `health_app/lib/core/local_database.dart` | token 存 SQLite | 改 secure storage |
| `health_app/lib/providers/chat_provider.dart` | 图片消息上传 URL 可能为空 | 修复上传契约和失败 UI |
| `health_app/lib/providers/chat_provider.dart` | 静默 catch | 展示错误状态并记录日志 |
| `health_app/lib/core/app_router.dart` | `params['id']!` 可能崩溃 | 参数校验和 fallback 页面 |
| `backend/src/Health.WebApi/Endpoints/auth_endpoints.cs` | 返回 `devCode` | 仅 dev 环境启用 |
| `backend/src/Health.WebApi/Endpoints/auth_endpoints.cs` | 固定管理员验证码 | 改正式认证流程 |
| `backend/src/Health.WebApi/Endpoints/ai_chat_endpoints.cs` | query token 未验证签名 | 改标准 JWT 鉴权 |
| `backend/src/Health.WebApi/Endpoints/ai_chat_endpoints.cs` | conversation 归属校验不足 | 查询时加入 UserId |
| `backend/src/Health.WebApi/Endpoints/file_endpoints.cs` | 文件类型/大小校验不足 | 加白名单和限制 |
| `backend/src/Health.WebApi/Program.cs` | CORS 过宽 | 按环境配置白名单 |
| `backend/src/Health.WebApi/Program.cs` | `EnsureCreatedAsync` | 改 migrations |
## 10. 建议整改路线
### 10.1 0 到 3 天:先堵住安全和明显 bug
1. 修复 SSE token 验证和 conversation 用户归属校验。
2. 删除生产环境 `devCode` 返回和前端自动填充验证码。
3. 修复文件上传返回结构。
4. 修复 `settings_pages.dart` 的错误导入。
5. 关闭生产环境请求/响应 body 日志。
6. 把 Flutter analyzer 里的真正错误先清零。
### 10.2 1 到 2 周:收拢核心体验
1. 建立统一设计 token颜色、渐变、按钮、卡片、图标。
2. 重做侧边栏、个人信息页、设置页、饮食分析页的信息层级。
3. 健康仪表盘增加趋势、时间、单位、状态解释。
4. 清理 `remaining_pages.dart` 中旧页面和无入口页面。
5. 前端 API baseUrl 改成环境配置。
6. token 改安全存储。
### 10.3 1 个月:提升产品完整度
1. 建立 EF migrations 和 CI。
2. 增加安全测试验证码、JWT、跨用户访问、上传。
3. 增加 AI 结果修正、置信度、失败重试。
4. 补齐隐私授权、数据删除、访问审计。
5. 医生端做成真正可用的工作台:患者筛选、风险排序、随访提醒。
6. 报告、饮食、用药、运动做长期趋势关联。
## 11. 总体建议
这个项目最有价值的方向是“围绕患者长期健康数据做 AI 辅助管理”,不是简单堆功能入口。接下来建议把项目重心从“页面多”转为“核心闭环扎实”:
- 患者每天愿意记录。
- 数据能被看懂。
- 异常能被发现。
- AI 建议能被修正和追踪。
- 医生能看到有价值的摘要。
- 安全和隐私经得起真实使用。
UI 上不要继续单页单独调色,应该先统一设计体系,再逐步替换页面。工程上先修安全和接口契约,再做大面积美化。这样项目会从“原型功能很多”变成“真正像一个可信赖的健康产品”。