feat: 问题数据迁移到数据库;学员详情页URL导航改造;侧边栏统一
- 问题从文件系统迁移到数据库 problems 表 - 移除 PROBLEMS_DIR 配置和文件读取逻辑 - student.html 完整重写:编辑/添加/删除问题,生成方案进度显示 - 学员详情页支持独立URL访问 (/student/<id>) - 统一侧边栏到 base.html - 更新文档:DEPLOYMENT_SOP, MODELS, STRUCTURE, FRONTEND_ARCH - 部署到生产环境 v1.2.0
This commit is contained in:
+60
-44
@@ -1,7 +1,7 @@
|
||||
# 钢琴练习方案系统 - 部署 SOP
|
||||
|
||||
> 版本:v1.1
|
||||
> 日期:2026-04-21
|
||||
> 版本:v1.2
|
||||
> 日期:2026-04-23
|
||||
> 核心原则:**不删除,只备份后新增/替换**
|
||||
|
||||
---
|
||||
@@ -46,11 +46,12 @@
|
||||
|
||||
| 类型 | 源 | 容器内 | 说明 |
|
||||
|------|-----|--------|------|
|
||||
| Bind Mount | `/opt/piano-plan/个性化方案` | `/app/个性化方案` | 问题文件(15个md) |
|
||||
| Volume | `piano-plan-data` | `/app/data` | SQLite 数据库 |
|
||||
| Volume | `piano-plan-output` | `/app/output` | PDF 输出 |
|
||||
| Bind Mount | `/opt/piano-plan/config` | `/app/config` | API 配置 |
|
||||
|
||||
> ⚠️ **已移除**:`/opt/piano-plan/个性化方案` 挂载点(问题文件已迁移到数据库 `problems` 表)
|
||||
|
||||
---
|
||||
|
||||
## 三、部署步骤
|
||||
@@ -81,22 +82,18 @@ docker save piano-plan:latest -o piano-plan.tar
|
||||
scp -i ~/.ssh/id_rsa piano-plan.tar root@47.106.65.108:/opt/piano-plan/
|
||||
```
|
||||
|
||||
### 3.3 服务器部署(使用脚本!)
|
||||
### 3.3 服务器部署
|
||||
|
||||
```bash
|
||||
# 7. SSH 到服务器
|
||||
ssh -i ~/.ssh/id_rsa root@47.106.65.108
|
||||
|
||||
# 8. 使用自动化部署脚本(会自动完成所有步骤并验证)
|
||||
bash /path/to/deploy.sh /opt/piano-plan/piano-plan.tar
|
||||
# 8. 创建带时间戳的备份目录
|
||||
mkdir -p /opt/piano-plan/backups/backup_$(date +%Y%m%d)
|
||||
|
||||
# 或者手动部署(不推荐):
|
||||
# 8a. 确认当前容器挂载配置
|
||||
docker inspect piano-plan --format '{{json .Mounts}}'
|
||||
|
||||
# 9. 创建备份
|
||||
mkdir -p /opt/piano-plan/backups
|
||||
docker cp piano-plan:/app/data/piano_plans.db /opt/piano-plan/backups/piano_plans.db.bak
|
||||
# 9. 备份当前数据库和配置
|
||||
docker cp piano-plan:/app/data/piano_plans.db /opt/piano-plan/backups/backup_$(date +%Y%m%d)/
|
||||
cp /opt/piano-plan/config/api_config.json /opt/piano-plan/backups/backup_$(date +%Y%m%d)/
|
||||
|
||||
# 10. 停止旧容器
|
||||
docker stop piano-plan
|
||||
@@ -105,38 +102,52 @@ docker rm piano-plan
|
||||
# 11. 加载新镜像
|
||||
docker load -i /opt/piano-plan/piano-plan.tar
|
||||
|
||||
# 12. 启动新容器(挂载配置必须完全正确!)
|
||||
# 12. 启动新容器(无个性化方案挂载!)
|
||||
docker run -d \
|
||||
--name piano-plan \
|
||||
-p 5001:5001 \
|
||||
--restart unless-stopped \
|
||||
-e FLASK_ENV=production \
|
||||
-v /opt/piano-plan/个性化方案:/app/个性化方案 \
|
||||
-v piano-plan-data:/app/data \
|
||||
-v piano-plan-output:/app/output \
|
||||
-v /opt/piano-plan/config:/app/config \
|
||||
piano-plan:latest
|
||||
```
|
||||
|
||||
### 3.4 验证
|
||||
### 3.4 数据同步(特殊情况下从开发环境覆盖生产数据库)
|
||||
|
||||
> ⚠️ **警告**:这是**特殊处理**,仅在开发环境和生产环境数据结构需要统一时执行。正常部署不应覆盖生产数据库。
|
||||
|
||||
```bash
|
||||
# 13. 检查容器状态
|
||||
# 13. 停止容器
|
||||
docker stop piano-plan
|
||||
|
||||
# 14. 上传开发环境数据库到服务器(在本地执行)
|
||||
scp -i ~/.ssh/id_rsa data/piano_plans.db root@47.106.65.108:/opt/piano-plan/backups/
|
||||
|
||||
# 15. 覆盖生产数据库
|
||||
docker cp /opt/piano-plan/backups/piano_plans.db piano-plan:/app/data/piano_plans.db
|
||||
|
||||
# 16. 重启容器
|
||||
docker start piano-plan
|
||||
```
|
||||
|
||||
### 3.5 验证
|
||||
|
||||
```bash
|
||||
# 17. 检查容器状态
|
||||
docker ps --filter name=piano-plan
|
||||
|
||||
# 14. 检查日志
|
||||
# 18. 检查日志
|
||||
docker logs piano-plan --tail 20
|
||||
|
||||
# 15. 验证服务
|
||||
# 19. 验证服务
|
||||
curl -I http://localhost:5001/
|
||||
|
||||
# 16. 验证问题文件(应该看到15个md文件)
|
||||
docker exec piano-plan ls /app/个性化方案/
|
||||
# 20. 验证数据库表
|
||||
docker exec piano-plan ls /app/data/
|
||||
|
||||
# 17. 验证数据库(应该看到 templates 表)
|
||||
docker exec piano-plan python -c "import sqlite3; conn=sqlite3.connect('/app/data/piano_plans.db'); print([r[0] for r in conn.execute('SELECT name FROM sqlite_master WHERE type=\"table\"')])"
|
||||
|
||||
# 18. 验证 API 配置
|
||||
# 21. 验证 API 配置
|
||||
docker exec piano-plan cat /app/config/api_config.json
|
||||
```
|
||||
|
||||
@@ -152,7 +163,7 @@ docker exec piano-plan cat /app/config/api_config.json
|
||||
| 学员数据 | piano-plan-data:/app/data | students, student_problems 表 |
|
||||
| 班级数据 | piano-plan-data:/app/data | classes 表 |
|
||||
| 练习方案 | piano-plan-data:/app/data | practice_plans 表 |
|
||||
| 问题文件 | /opt/piano-plan/个性化方案 | 15个md文件 |
|
||||
| 问题数据 | piano-plan-data:/app/data | problems 表(已从文件迁移到数据库) |
|
||||
|
||||
### 4.2 新增/更新的数据
|
||||
|
||||
@@ -221,32 +232,40 @@ ssh -i ~/.ssh/id_rsa root@47.106.65.108 "docker cp /tmp/update_templates.py pian
|
||||
|
||||
## 五、回滚流程
|
||||
|
||||
### 5.1 快速回滚(推荐)
|
||||
### 5.1 从备份恢复数据库
|
||||
|
||||
```bash
|
||||
# 停止当前容器
|
||||
# 停止容器
|
||||
docker stop piano-plan
|
||||
|
||||
# 从备份目录恢复(替换日期)
|
||||
docker cp /opt/piano-plan/backups/backup_20260423/piano_plans.db piano-plan:/app/data/piano_plans.db
|
||||
|
||||
# 重启容器
|
||||
docker start piano-plan
|
||||
```
|
||||
|
||||
### 5.2 完整回滚(恢复旧镜像+数据库)
|
||||
|
||||
```bash
|
||||
# 停止并删除当前容器
|
||||
docker stop piano-plan
|
||||
docker rm piano-plan
|
||||
|
||||
# 使用旧镜像重新启动(如果镜像还在)
|
||||
# 使用旧镜像重新启动(如果镜像还在本地)
|
||||
docker run -d \
|
||||
--name piano-plan \
|
||||
-p 5001:5001 \
|
||||
--restart unless-stopped \
|
||||
-e FLASK_ENV=production \
|
||||
-v /opt/piano-plan/个性化方案:/app/个性化方案 \
|
||||
-v piano-plan-data:/app/data \
|
||||
-v piano-plan-output:/app/output \
|
||||
-v /opt/piano-plan/config:/app/config \
|
||||
piano-plan:latest
|
||||
```
|
||||
|
||||
### 5.2 从备份恢复
|
||||
|
||||
```bash
|
||||
# 恢复数据库
|
||||
# 从备份恢复数据库
|
||||
docker stop piano-plan
|
||||
cp /opt/piano-plan/backups/piano_plans.db.bak /var/lib/docker/volumes/piano-plan-data/_data/piano_plans.db
|
||||
docker cp /opt/piano-plan/backups/backup_YYYYMMDD/piano_plans.db piano-plan:/app/data/piano_plans.db
|
||||
docker start piano-plan
|
||||
```
|
||||
|
||||
@@ -275,9 +294,10 @@ docker start piano-plan
|
||||
|
||||
| 源 | 容器内路径 | 说明 |
|
||||
|-----|------------|------|
|
||||
| /opt/piano-plan/个性化方案 | /app/个性化方案 | 问题文件 |
|
||||
| /opt/piano-plan/config | /app/config | API 配置 |
|
||||
|
||||
> ⚠️ **已移除**:`/opt/piano-plan/个性化方案` 挂载(问题文件已迁移到数据库)
|
||||
|
||||
---
|
||||
|
||||
## 七、API 配置说明
|
||||
@@ -300,9 +320,6 @@ docker start piano-plan
|
||||
|
||||
## 八、常见问题
|
||||
|
||||
### Q: 部署后问题文件看不到?
|
||||
A: 检查挂载 `/opt/piano-plan/个性化方案:/app/个性化方案` 是否正确
|
||||
|
||||
### Q: 数据库是空的?
|
||||
A: 检查 volume `piano-plan-data` 是否被错误覆盖,尝试从备份恢复
|
||||
|
||||
@@ -335,8 +352,7 @@ location /api/generate-plan {
|
||||
```
|
||||
[ ] 容器状态:running
|
||||
[ ] 服务响应:HTTP 200/302
|
||||
[ ] 问题文件数量:15个 md 文件
|
||||
[ ] 数据库记录:users, students, classes, student_problems, practice_plans 完整
|
||||
[ ] 数据库记录:users, students, classes, student_problems, practice_plans, problems 完整
|
||||
[ ] templates 表存在且包含 AI提示词模板、报告导出模板
|
||||
[ ] API 配置:provider, model, api_key 正确
|
||||
[ ] 功能验证:能生成练习方案
|
||||
@@ -344,5 +360,5 @@ location /api/generate-plan {
|
||||
|
||||
---
|
||||
|
||||
> **最后更新**:2026-04-21
|
||||
> **更新原因**:更新部署流程,添加数据保护规范,明确挂载点配置;添加 SSE 问题排查
|
||||
> **最后更新**:2026-04-23
|
||||
> **更新原因**:v1.2 部署更新;移除个性化方案挂载(问题已迁移到数据库);更新备份和回滚流程
|
||||
|
||||
+18
-7
@@ -79,15 +79,15 @@ piano-plan/
|
||||
### 发布流程
|
||||
|
||||
1. **开发完成** → 本地测试通过
|
||||
2. **构建镜像** → `docker build -t piano-plan:v1.2.0 .`
|
||||
2. **构建镜像** → `docker build -t piano-plan:latest .`
|
||||
3. **打包部署文件** → 创建 `releases/v1.2.0/` 目录,放入:
|
||||
- `piano-plan-v1.2.0.tar.gz` - Docker镜像
|
||||
- `piano-nginx.conf` - Nginx配置(从服务器获取最新)
|
||||
- `docker-compose.yml` - 部署编排
|
||||
4. **上传** → 传到服务器 load 镜像
|
||||
5. **部署** → docker-compose up -d
|
||||
- `piano-plan.tar` - Docker镜像
|
||||
4. **上传** → scp 到服务器 `/opt/piano-plan/`
|
||||
5. **部署** → 按照 DEPLOYMENT_SOP.md 执行
|
||||
6. **清理** → 本地 tar 包可删除(git已管理版本)
|
||||
|
||||
> ⚠️ Nginx 配置在服务器上:`/srv/nginx/conf/conf.d/piano.yoin.fun.conf`
|
||||
|
||||
### 版本化部署包命名
|
||||
|
||||
```
|
||||
@@ -143,4 +143,15 @@ deploy: v1.2.0 生产环境部署
|
||||
|
||||
---
|
||||
|
||||
*最后更新:2026-04-21*
|
||||
## 版本历史
|
||||
|
||||
| 版本 | 日期 | 说明 |
|
||||
|------|------|------|
|
||||
| V1.0 | 2026-04-17 | 初始版本:学员管理、问题记录、方案生成 |
|
||||
| V1.1 | 2026-04-17 | 添加用户登录认证系统 |
|
||||
| V1.2 | 2026-04-18 | 添加用户管理、角色权限、班级管理 |
|
||||
| V1.2.0 | 2026-04-23 | 问题迁移到数据库;URL导航改造;侧边栏统一 |
|
||||
|
||||
---
|
||||
|
||||
*最后更新:2026-04-23*
|
||||
|
||||
+20
-2
@@ -11,6 +11,9 @@
|
||||
```
|
||||
base.html (基础模板)
|
||||
├── index.html (学员管理)
|
||||
├── home.html (默认首页)
|
||||
├── student.html (学员详情)
|
||||
├── plan_edit.html (方案编辑)
|
||||
├── settings.html (问题配置)
|
||||
├── classes.html (班级管理)
|
||||
├── users.html (用户管理)
|
||||
@@ -218,8 +221,11 @@ base.html 已包含修改密码弹窗 HTML 和 JS。各页面不需要重复定
|
||||
|
||||
```
|
||||
app/templates/
|
||||
├── base.html # 基础模板(核心)
|
||||
├── base.html # 基础模板(核心,统一侧边栏)
|
||||
├── index.html # 学员管理
|
||||
├── home.html # 默认首页(统计信息)
|
||||
├── student.html # 学员详情(URL导航)
|
||||
├── plan_edit.html # 方案编辑(URL导航)
|
||||
├── settings.html # 问题配置
|
||||
├── classes.html # 班级管理
|
||||
├── users.html # 用户管理
|
||||
@@ -232,8 +238,20 @@ app/templates/
|
||||
|
||||
> 注意:`login.html`、`setup.html`、`wechat_card.html` 是独立页面,不继承 base.html。
|
||||
|
||||
## 7. 更新日志
|
||||
## 7. URL 导航模式
|
||||
|
||||
系统支持两种导航模式:
|
||||
|
||||
| 模式 | 说明 | 示例 |
|
||||
|------|------|------|
|
||||
| SPA 模式 | 点击学员卡片弹窗查看详情 | 原 index.html 模式 |
|
||||
| URL 模式 | 通过 URL 直接访问 | `/student/<id>`, `/plan/<id>/edit` |
|
||||
|
||||
推荐使用 URL 模式,便于分享和书签。
|
||||
|
||||
## 8. 更新日志
|
||||
|
||||
| 日期 | 版本 | 变更内容 |
|
||||
|------|------|----------|
|
||||
| 2026-04-21 | v1.0 | 初始文档,定义 base.html 模板继承模式 |
|
||||
| 2026-04-23 | v1.1 | 添加 URL 导航模式说明;新增 home.html, student.html, plan_edit.html |
|
||||
|
||||
+22
-6
@@ -10,6 +10,22 @@
|
||||
|
||||
## 数据表
|
||||
|
||||
### 0. Problem (问题定义)
|
||||
|
||||
系统预定义的15种常见钢琴学习问题。
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | Integer | 主键,自增 |
|
||||
| code | String(50) | 问题编号,如 "05_掌关节支撑差" |
|
||||
| name | String(100) | 问题名称,如 "掌关节支撑差" |
|
||||
| category | String(20) | 分类:技术类/认知类/节奏类/习惯类/综合类 |
|
||||
| created_at | DateTime | 创建时间 |
|
||||
|
||||
> ⚠️ 问题数据已从文件系统迁移到数据库。student_problems 表通过 `problem_id` 外键关联到此表。
|
||||
|
||||
---
|
||||
|
||||
### 1. User (用户)
|
||||
|
||||
系统用户,用于登录认证和权限管理。
|
||||
@@ -58,12 +74,13 @@
|
||||
|------|------|------|
|
||||
| id | Integer | 主键,自增 |
|
||||
| student_id | Integer | 外键,关联 Student |
|
||||
| problem_id | String(50) | 问题编号,如 "01_手小" |
|
||||
| problem_name | String(100) | 问题名称,如 "手小" |
|
||||
| problem_id | Integer | 外键,关联 Problem.id |
|
||||
| severity | String(10) | 严重程度:轻微/中等/严重 |
|
||||
| level | String(20) | 级别:启蒙/入门/进阶/熟练/精通 |
|
||||
| created_at | DateTime | 创建时间 |
|
||||
|
||||
> ⚠️ `problem_id` 现为数字外键,关联 `Problem.id`。通过 `student_problem.problem` 关系获取问题名称。
|
||||
|
||||
---
|
||||
|
||||
### 4. Class (班级)
|
||||
@@ -139,8 +156,7 @@
|
||||
├──────────────────┤ │
|
||||
│ id │ │
|
||||
│ student_id ─────┘ │
|
||||
│ problem_id │
|
||||
│ problem_name │
|
||||
│ problem_id │◄─┼──► Problem
|
||||
│ severity │
|
||||
│ level │
|
||||
│ created_at │
|
||||
@@ -173,8 +189,8 @@ print(user.role) # "admin" or "user"
|
||||
|
||||
```python
|
||||
student = Student.query.get(1)
|
||||
for problem in student.problems:
|
||||
print(problem.problem_name, problem.severity, problem.level)
|
||||
for sp in student.problems:
|
||||
print(sp.problem.name, sp.problem.code, sp.severity, sp.level)
|
||||
```
|
||||
|
||||
### 查询班级及其学员
|
||||
|
||||
+9
-10
@@ -28,8 +28,11 @@
|
||||
│ │ └── pdf_generator.py # PDF生成器
|
||||
│ │
|
||||
│ └── templates/ # 前端模板
|
||||
│ ├── base.html # 基础模板(所有页面继承)
|
||||
│ ├── base.html # 基础模板(所有页面继承,统一侧边栏)
|
||||
│ ├── index.html # 学员管理页面(继承base)
|
||||
│ ├── home.html # 默认首页(显示统计信息)
|
||||
│ ├── student.html # 学员详情页(URL导航)
|
||||
│ ├── plan_edit.html # 方案编辑页(URL导航)
|
||||
│ ├── settings.html # 问题配置页面(继承base)
|
||||
│ ├── login.html # 登录页面(独立)
|
||||
│ ├── setup.html # 初始设置页面(独立)
|
||||
@@ -47,12 +50,6 @@
|
||||
├── config/ # 配置目录(运行时创建)
|
||||
│ └── api_config.json # API配置文件
|
||||
│
|
||||
├── 个性化方案/ # 练习方案内容
|
||||
│ └── 针对性练习(拆分为单独文件)/
|
||||
│ ├── 01_手小.md
|
||||
│ ├── 02_识谱慢.md
|
||||
│ └── ...
|
||||
│
|
||||
├── run.py # 应用入口
|
||||
├── run.bat # 启动脚本
|
||||
├── requirements.txt # Python依赖
|
||||
@@ -96,8 +93,9 @@ def create_app():
|
||||
数据库模型定义:
|
||||
- `User` - 用户(登录认证、权限管理)
|
||||
- `Student` - 学员
|
||||
- `StudentProblem` - 问题记录
|
||||
- `Class` - 班级(新增)
|
||||
- `StudentProblem` - 问题记录(关联 Problem 表)
|
||||
- `Problem` - 问题定义(15种预定义问题,已从文件迁移到数据库)
|
||||
- `Class` - 班级
|
||||
- `PracticePlan` - 练习方案
|
||||
|
||||
---
|
||||
@@ -276,4 +274,5 @@ generate_pdf(plan_id, student_name, content, output_dir)
|
||||
|------|------|------|
|
||||
| V1.0 | 2026-04-17 | 初始版本:学员管理、问题记录、方案生成 |
|
||||
| V1.1 | 2026-04-17 | 添加用户登录认证系统 |
|
||||
| V1.2 | 2026-04-18 | 添加用户管理、角色权限、班级管理 |
|
||||
| V1.2 | 2026-04-18 | 添加用户管理、角色权限、班级管理 |
|
||||
| V1.2.0 | 2026-04-23 | 问题迁移到数据库;URL导航改造;侧边栏统一 |
|
||||
Reference in New Issue
Block a user