Files
soft/上线规划文档.md
MingNian d5f167167a feat: replace Redis with PostgreSQL for caching, rate limiting, SMS codes, and token blacklist
- Add 4 PG entities: VerificationCode, RateLimitEntry, TokenBlacklistEntry, CacheEntry
- Add 4 services: VerificationService, RateLimitService, TokenBlacklistService, CacheService
- Add CleanupBackgroundService for periodic expired data cleanup
- Add MigrationHelper for safe schema migration without data loss
- Update AuthController: real SMS code generation, rate limiting, logout endpoint with JWT blacklist
- Update JwtProvider: add JTI claim for token revocation
- Update Program.cs: register new services, JWT blacklist validation, DB migration
- Remove StackExchange.Redis NuGet package and all Redis config references
- Update start-dev.bat: 6→5 services, remove Redis startup
- Update docs: remove Redis references from all documentation
- Fix: logout button spacing on profile page
- Fix: .gitignore data/→/data/ to not ignore Infrastructure/Data/
2026-05-26 13:48:53 +08:00

553 lines
14 KiB
Markdown
Raw Permalink 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.

# 上线全流程规划文档
> 当前项目是一个跑在本地的 Demo。本文档说明要成为一个**真正可上线运营的产品**,还需要做哪些工作。
---
## 目录
1. [文件上传与存储](#1-文件上传与存储)
2. [医生端查看与解读](#2-医生端查看与解读)
3. [历史记录与数据持久化](#3-历史记录与数据持久化)
4. [页面过渡动画](#4-页面过渡动画)
5. [联网与 App 化](#5-联网与-app-化)
6. [安全与鉴权](#6-安全与鉴权)
7. [消息推送](#7-消息推送)
8. [运维与监控](#8-运维与监控)
9. [开发流程规范化](#9-开发流程规范化)
10. [完整上线检查清单](#10-完整上线检查清单)
---
## 1. 文件上传与存储
### 现状
- 患者点"上传报告",选了文件但**没有真正存到服务器**
- 后端只记录了空的 `imageUrls: []`
- 没有文件存储服务对接
### 需要做的事
#### 1.1 MinIO 对接(已在本地装了,没接代码)
MinIO 是一个兼容 AWS S3 的对象存储服务适合存图片、PDF 等文件。
**后端需要新增:**
```
backend/src/HealthManager.Infrastructure/Services/FileStorageService.cs ← 新建
```
核心功能:
- `UploadAsync(Stream fileStream, string fileName)` → 上传到 MinIO返回文件 URL
- `GetFileUrl(string objectKey)` → 获取文件访问地址
- `DeleteAsync(string objectKey)` → 删除文件
**流程:**
```
患者选图片 → 前端调 POST /api/files/upload → 后端接收文件流
→ 上传到 MinIO → 得到 URL → 报告保存时把 URL 存入 imageUrls
→ 医生点查看 → 前端直接通过 URL 加载图片
```
#### 1.2 新增文件上传接口
```
POST /api/files/upload ← 上传单个文件,返回 { url, key }
POST /api/files/upload-multiple ← 上传多个文件
GET /api/files/{key} ← 下载/预览文件
DELETE /api/files/{key} ← 删除文件
```
#### 1.3 前端改造
```
ReportUploadPage.tsx:
选文件 → 调上传接口 → 拿到 URL 数组
→ 调创建报告接口 { title, category, imageUrls: ["url1", "url2"] }
→ 显示上传进度条
```
#### 1.4 文件大小和类型限制
| 限制项 | 建议值 |
|--------|--------|
| 单文件最大 | 10MB |
| 允许格式 | jpg, png, pdf |
| 每人每天上限 | 20 个文件 |
---
## 2. 医生端查看与解读
### 现状
- 医生能看到报告标题和状态
- 但看不到图片(因为根本没存图)
- 解读功能比较简陋
### 需要做的事
#### 2.1 图片查看器
医生点报告后,应该能看到所有上传的图片:
```
ReportDetailPage.tsx:
- 图片缩略图列表(来自 imageUrls
- 点击放大查看
- 支持左右翻页
```
#### 2.2 报告解读界面增强
```
当前:只有一个文本框,写一句话
需要:
- 逐项填写检查结果(血压、血糖、血脂...
- 异常项自动标红
- 风险等级(正常/关注/异常)
- 建议措施的富文本编辑器
- 解读完成后自动通知患者
```
#### 2.3 报告历史
医生端需要:
- 按患者查看历史报告列表
- 按时间/类型筛选
- 对比不同时间点的报告变化趋势
---
## 3. 历史记录与数据持久化
### 现状
- 数据存在本地 PostgreSQL
- 没有定期备份
- 健康数据会无限增长
### 需要做的事
#### 3.1 数据库备份
```bash
# 自动备份脚本Linux 服务器上跑)
pg_dump HealthManager > /backup/health_$(date +%Y%m%d).sql
# 每天凌晨 3 点自动执行crontab
0 3 * * * /opt/scripts/backup-db.sh
# 保留最近 30 天,旧自动删除
```
#### 3.2 历史数据归档
健康记录表会越来越大,需要归档策略:
- 1 年以上的健康数据 → 移到归档表或压缩存储
- 3 年以上的 → 可选择性清理
- 报告和相关文件 → 永久保留
#### 3.3 数据导出
患者应该能导出自己的数据:
```
GET /api/health-records/export?format=csv
GET /api/health-records/export?format=pdf
```
---
## 4. 页面过渡动画
### 现状
- 有 CSS 动画定义但未完全启用
- 页面切换比较生硬
### 需要做的事
#### 4.1 路由过渡动画
使用 `framer-motion`(已安装)实现:
```tsx
// 页面进入:从右滑入 + 淡入
// 页面离开:向左滑出 + 淡出
// 返回时:从左滑入
<AnimatePresence mode="wait">
<motion.div
key={location.pathname}
initial={{ opacity: 0, x: 50 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -50 }}
transition={{ duration: 0.25 }}
>
<Outlet />
</motion.div>
</AnimatePresence>
```
#### 4.2 组件级动画
| 场景 | 动画 |
|------|------|
| 列表加载 | 骨架屏Skeleton闪烁数据来到后列表项依次弹出 |
| 卡片点击 | 缩放+阴影变化,给"按下去"的反馈 |
| 数字变化 | 健康数据变化时数字滚动动画 |
| 按钮点击 | 涟漪效果ripple effect |
| 消息发送 | 气泡从输入框弹入对话区 |
| 下拉刷新 | 顶部旋转加载指示器 |
| Toast 提示 | 从顶部滑入2.5 秒后滑出 |
#### 4.3 页面切换保留状态
当前切换到别的 Tab 再回来,数据会重新加载。需要:
- 首页数据缓存 30 秒,切回来直接用
- 列表页记住滚动位置
---
## 5. 联网与 App 化
### 现状
- 前端 `npm run dev` 跑在本地
- 后端 `dotnet run` 跑在本地
- 只能用 `localhost` 访问
### 需要做的事
#### 5.1 部署到服务器
**最简单方案:一台 Linux 云服务器(阿里云/腾讯云)**
```
服务器配置建议:
- 2核 CPU
- 4GB 内存
- 40GB SSD
- Ubuntu 22.04
```
需要安装的东西和本地一样:
- PostgreSQL 18
- MinIO
- .NET 10 Runtime
- Nginx作为反代和静态文件服务
#### 5.2 Nginx 配置
```
把所有服务统一到一个域名下:
https://api.chatmed.online → 后端 API (5000端口)
https://patient.chatmed.online → 患者前端 (打包成静态文件)
https://doctor.chatmed.online → 医生前端 (打包成静态文件)
https://files.chatmed.online → MinIO (9000端口)
```
#### 5.3 前端打包部署
现在跑的是开发模式Vite dev server上线要用生产模式
```bash
# 患者端
cd frontend-patient
npm run build # 生成 dist/ 文件夹
# 把 dist/ 里的文件放到 Nginx 的目录下
# 医生端同理
cd frontend-doctor
npm run build
```
#### 5.4 打包成手机 App
如果要在手机上像 App 一样用(不是浏览器打开),两种方案:
**方案 APWA推荐最简单**
在网页基础上加个配置文件,用户浏览器打开后可以"添加到主屏幕",就像真的 App
```json
// public/manifest.json
{
"name": "健康管家",
"short_name": "健康管家",
"start_url": "/",
"display": "standalone", // 全屏,没有浏览器地址栏
"background_color": "#F2F5FA",
"theme_color": "#1E6BFF",
"icons": [
{ "src": "/icon-192.png", "sizes": "192x192" },
{ "src": "/icon-512.png", "sizes": "512x512" }
]
}
```
再加一个 Service Worker 实现**离线缓存**——没网也能看历史数据。
**方案 B套壳 App推荐给小白用户**
用 Capacitor 把网页包成一个真实的 APK/IPA
```bash
npm install @capacitor/core @capacitor/cli
npx cap init
npx cap add android # 生成 Android 项目
npx cap add ios # 生成 iOS 项目
npx cap sync # 把前端代码同步进去
```
然后分别在 Android Studio 和 Xcode 里打包成 `.apk``.ipa`,可以上传到应用商店。
| 对比 | PWA | Capacitor 套壳 |
|------|-----|---------------|
| 开发成本 | 低(只需配置) | 中(需原生打包环境) |
| 用户安装方式 | 网页上点"添加到桌面" | 应用商店下载 |
| 离线支持 | 有 | 有 |
| 推送通知 | iOS 支持有限 | 完整支持 |
| 应用商店上架 | 不能 | 能 |
| **建议** | **先做这个,快速验证** | **验证完再做这个** |
---
## 6. 安全与鉴权
### 现状
- JWT 登录30 分钟过期
- 密码是 SHA256Demo 够用,上线不够)
- 没有 HTTPS
- 没有接口限流
- 手机验证码是假的(不验证)
### 需要做的事
#### 6.1 HTTPS + 域名
```bash
# 用 Let's Encrypt 免费申请 SSL 证书
# 所有请求强制走 HTTPS
# 后端、前端、MinIO 全部 HTTPS
```
#### 6.2 密码安全
```
当前方案SHA256(password)
上线方案bcrypt 或 Argon2加盐哈希防彩虹表攻击
```
#### 6.3 真实短信验证码
接腾讯云短信 / 阿里云短信:
```
POST /api/auth/send-sms → 调短信平台API → 用户手机收到验证码
验证码 5 分钟过期
同一号码 60 秒内不能重复发送
```
#### 6.4 接口安全
| 措施 | 说明 |
|------|------|
| 限流 | 同一 IP 每分钟最多 60 次请求 |
| 登录限流 | 同一手机号 5 次失败后锁定 15 分钟 |
| 敏感操作二次验证 | 修改手机号、删除数据需要再输入验证码 |
| SQL 注入防护 | EF Core 已自带参数化查询 |
| XSS 防护 | 前端 React 已自带转义 |
| CORS | 只允许自己域名 |
#### 6.5 数据脱敏
```
日志里不能记录手机号、密码、真实姓名
显示时手机号中间四位打星号138****8000
```
---
## 7. 消息推送
### 现状
- 通知存在数据库里,前端轮询拉取
- 用户不打开 App 就看不到新消息
### 需要做的事
#### 7.1 WebSocket 实时推送
当前已有 SignalR`/hubs/chat`),需要扩展到:
- 新消息实时弹窗
- 医生解读完成 → 患者立即收到通知
- 用药提醒时间到了 → 推送通知
#### 7.2 App 推送(离线也能收到)
| 平台 | 推送服务 |
|------|---------|
| Android | Firebase Cloud Messaging (FCM) |
| iOS | Apple Push Notification Service (APNs) |
| 国内 Android | 华为/小米/OPPO 推送(不用 FCM |
后端需要新增一个 PushService统一处理各类推送。
---
## 8. 运维与监控
### 需要做的事
#### 8.1 日志系统
```
当前:控制台输出
需要Serilog 写入文件 + 集中收集
├── 请求日志(谁、什么时候、调了什么接口)
├── 错误日志(哪出错了、堆栈信息)
└── 慢查询日志(哪些 SQL 耗时超过 500ms
```
#### 8.2 健康检查
```
GET /health → 检查数据库连接、MinIO连接
返回 { status: "healthy", db: "ok", minio: "ok" }
```
自动化监控:每 30 秒检查一次,挂了自动发短信/邮件报警。
#### 8.3 性能监控
```
.NET: Application Insights 或 Prometheus
PostgreSQL: pg_stat_statements 插件
前端: Web Vitals (LCP, FID, CLS)
```
#### 8.4 自动部署
```bash
# 当 git push 到 main 分支时,服务器自动:
1. git pull 拉取最新代码
2. dotnet build 编译后端
3. npm run build 编译前端
4. 重启服务
```
用 GitHub Actions 或 Jenkins 实现。
---
## 9. 开发流程规范化
### 当前
- 直接在 main 分支上改代码
- 没有测试
- 没有代码审查
### 需要建立
#### 9.1 分支管理
```
main ← 生产环境,只有经过测试的代码才合并进来
develop ← 开发环境
feature/* ← 每个新功能一个分支(如 feature/file-upload
bugfix/* ← 修 Bug 的分支
release/* ← 准备上线的版本
```
#### 9.2 提交规范
```
feat: 文件上传功能
fix: 修复医生看不到报告的bug
docs: 更新使用手册
style: 调整首页配色
refactor: 重构健康数据服务
test: 添加登录接口测试
```
#### 9.3 自动化测试
```
单元测试:关键业务逻辑(如风险等级计算)
集成测试API 接口(用 xUnit + WebApplicationFactory
E2E 测试:核心用户流程(用 Playwright
```
#### 9.4 代码审查
每个 PR 至少一个人 Review 后才能合并。
---
## 10. 完整上线检查清单
### 阶段一Demo 完善(当前 → 2周内
- [x] 后端 API 全功能
- [x] 患者前端全功能
- [x] 医生前端全功能
- [ ] 文件上传到 MinIO
- [ ] 医生端图片查看
- [ ] 页面过渡动画
- [ ] 上报 Bug 修复
### 阶段二内部测试2-4周
- [ ] 部署到测试服务器
- [ ] 配置 HTTPS + 域名
- [ ] 手机号验证码真实对接
- [ ] 密码改用 bcrypt
- [ ] 接口限流
- [ ] 3-5 个真实用户测试
- [ ] 收集反馈,修复问题
### 阶段三上线准备4-6周
- [ ] 部署到生产服务器2核4G起步
- [ ] 数据库自动备份
- [ ] 日志和监控就位
- [ ] PWA 配置(可添加到手机桌面)
- [ ] 性能压测(模拟 100 个用户同时用)
- [ ] 隐私协议 + 用户协议页面
- [ ] 操作手册终稿
### 阶段四正式运营6-8周+
- [ ] 上线运营
- [ ] 用户反馈渠道
- [ ] 定期数据备份验证
- [ ] 根据数据做功能迭代
- [ ] 考虑 App 应用商店上架Capacitor 打包)
- [ ] 如果需要,接微信小程序
---
## 总结Demo vs 上线 差异一览
| 维度 | 当前 Demo | 上线产品 |
|------|----------|---------|
| 文件存储 | 没存imageUrls 为空 | MinIO 存储,返回真实 URL |
| 网络 | localhost | 域名 + HTTPS |
| 鉴权 | JWT + SHA256 密码 | JWT + bcrypt + 短信验证码 |
| 推送 | 前端轮询 | SignalR 实时 + App 离线推送 |
| 前端 | Vite dev server | Nginx 静态文件 / PWA / App |
| 数据库 | 本地 PostgreSQL | 服务器 PostgreSQL + 每日备份 |
| 日志 | 控制台 | 文件 + 集中收集 |
| 测试 | 无 | 单元 + 集成 + E2E |
| 部署 | 手动 dotnet run | 自动化 CI/CD |
| 监控 | 无 | 健康检查 + 性能 + 报警 |
| 动画 | 基础 CSS | framer-motion 全页面动画 |
| 安全 | CORS | 限流 + HTTPS + 脱敏 + 审计 |
**最优先要做的三件事**:① 文件上传存 MinIO → ② 部署到服务器 → ③ HTTPS + 真实短信