509 lines
18 KiB
Markdown
509 lines
18 KiB
Markdown
# 设计文档:从正式系统恢复源码
|
||
|
||
## 概述
|
||
|
||
本设计文档描述了如何从正式系统的 Docker 容器中提取源码,对比本地差异,恢复缺失文件,并部署到影子系统进行测试验证的完整方案。
|
||
|
||
## 架构
|
||
|
||
### 系统组件
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ 源码恢复流程 │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ 步骤1: 连接正式系统容器 │
|
||
│ - SSH 到服务器 192.168.58.20 │
|
||
│ - 访问容器 youyidian-3d-material │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ 步骤2: 提取源码文件列表 │
|
||
│ - 列出容器内 /app 目录的所有文件 │
|
||
│ - 排除 node_modules, .next, uploads 等 │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ 步骤3: 对比本地源码 │
|
||
│ - 检查本地缺失的文件 │
|
||
│ - 检查内容不一致的文件 │
|
||
│ - 生成差异报告 │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ 步骤4: 复制缺失文件 │
|
||
│ - 使用 docker cp 或 scp 复制文件 │
|
||
│ - 保持目录结构 │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ 步骤5: 验证构建 │
|
||
│ - npm install │
|
||
│ - npm run build │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ 步骤6: 部署到影子系统 │
|
||
│ - 运行 deploy-local-build.ps1 -Target shadow │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ 步骤7: 功能测试 │
|
||
│ - 访问 http://192.168.58.20:5320 │
|
||
│ - 测试关键功能 │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
## 组件和接口
|
||
|
||
### 1. 源码提取工具
|
||
|
||
**功能**: 从 Docker 容器中提取源码文件
|
||
|
||
**方法**:
|
||
- 方法 A: 使用 `docker cp` 命令
|
||
```powershell
|
||
ssh root@192.168.58.20 "docker cp youyidian-3d-material:/app /tmp/source"
|
||
scp -r root@192.168.58.20:/tmp/source/* D:\gongxiangp2\
|
||
```
|
||
|
||
- 方法 B: 使用 `docker exec` + tar
|
||
```powershell
|
||
ssh root@192.168.58.20 "docker exec youyidian-3d-material tar czf /tmp/source.tar.gz -C /app ."
|
||
scp root@192.168.58.20:/tmp/source.tar.gz D:\gongxiangp2\
|
||
tar -xzf source.tar.gz
|
||
```
|
||
|
||
**推荐**: 方法 B,因为可以一次性打包,传输更快
|
||
|
||
### 2. 文件对比工具
|
||
|
||
**功能**: 对比本地源码和容器源码的差异
|
||
|
||
**实现**:
|
||
```powershell
|
||
# 获取容器内文件列表
|
||
ssh root@192.168.58.20 "docker exec youyidian-3d-material find /app -type f" > container-files.txt
|
||
|
||
# 获取本地文件列表
|
||
Get-ChildItem -Recurse -File | Select-Object FullName > local-files.txt
|
||
|
||
# 对比差异
|
||
Compare-Object (Get-Content container-files.txt) (Get-Content local-files.txt)
|
||
```
|
||
|
||
### 3. 构建验证工具
|
||
|
||
**功能**: 验证恢复后的源码能否正常构建
|
||
|
||
**步骤**:
|
||
1. 安装依赖: `npm install`
|
||
2. 构建项目: `npm run build`
|
||
3. 检查构建输出: `.next` 目录应该存在且包含构建文件
|
||
|
||
### 4. 部署工具
|
||
|
||
**功能**: 将恢复的源码部署到影子系统
|
||
|
||
**使用**:
|
||
```powershell
|
||
.\deploy-local-build.ps1 -Target shadow
|
||
```
|
||
|
||
**该脚本应该**:
|
||
1. 构建 Docker 镜像
|
||
2. 停止旧的影子系统容器
|
||
3. 启动新的影子系统容器
|
||
4. 验证容器状态
|
||
|
||
## 数据模型
|
||
|
||
### 文件差异报告
|
||
|
||
```typescript
|
||
interface FileDifference {
|
||
path: string; // 文件路径
|
||
status: 'missing' | 'different' | 'extra'; // 状态
|
||
importance: 'critical' | 'important' | 'optional'; // 重要性
|
||
category: 'api' | 'page' | 'component' | 'lib' | 'config' | 'other'; // 分类
|
||
}
|
||
|
||
interface DifferenceReport {
|
||
timestamp: Date; // 报告生成时间
|
||
totalFiles: number; // 总文件数
|
||
missingFiles: FileDifference[]; // 缺失的文件
|
||
differentFiles: FileDifference[]; // 内容不同的文件
|
||
extraFiles: FileDifference[]; // 本地多余的文件
|
||
}
|
||
```
|
||
|
||
### 功能验证清单
|
||
|
||
```typescript
|
||
interface FeatureTest {
|
||
name: string; // 功能名称
|
||
category: string; // 功能分类
|
||
tested: boolean; // 是否已测试
|
||
passed: boolean; // 是否通过
|
||
notes: string; // 备注
|
||
}
|
||
|
||
interface FeatureReport {
|
||
timestamp: Date; // 报告生成时间
|
||
totalFeatures: number; // 总功能数
|
||
testedFeatures: number; // 已测试功能数
|
||
passedFeatures: number; // 通过的功能数
|
||
features: FeatureTest[]; // 功能列表
|
||
}
|
||
```
|
||
|
||
## 正确性属性
|
||
|
||
*属性是一个特征或行为,应该在系统的所有有效执行中保持为真——本质上是关于系统应该做什么的正式陈述。属性作为人类可读规范和机器可验证正确性保证之间的桥梁。*
|
||
|
||
### 属性 1: 文件完整性
|
||
|
||
*对于任何*从容器提取的源码文件,该文件应该在本地存在且内容一致
|
||
|
||
**验证**: 需求 1.2, 1.3
|
||
|
||
### 属性 2: 目录结构一致性
|
||
|
||
*对于任何*容器中的目录结构,本地应该有相同的目录结构
|
||
|
||
**验证**: 需求 1.2
|
||
|
||
### 属性 3: 构建可重复性
|
||
|
||
*对于任何*恢复后的源码,执行 `npm run build` 应该成功生成 `.next` 目录
|
||
|
||
**验证**: 需求 5.2
|
||
|
||
### 属性 4: 功能等价性
|
||
|
||
*对于任何*正式系统中的功能,影子系统应该有相同的功能表现
|
||
|
||
**验证**: 需求 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7
|
||
|
||
## 错误处理
|
||
|
||
### 1. SSH 连接失败
|
||
- **错误**: 无法连接到服务器 192.168.58.20
|
||
- **处理**: 检查网络连接,确认 SSH 密钥配置正确
|
||
|
||
### 2. Docker 容器不存在
|
||
- **错误**: 容器 youyidian-3d-material 不存在
|
||
- **处理**: 检查容器名称,确认容器正在运行
|
||
|
||
### 3. 文件复制失败
|
||
- **错误**: 无法复制文件到本地
|
||
- **处理**: 检查磁盘空间,确认文件权限
|
||
|
||
### 4. 构建失败
|
||
- **错误**: npm run build 失败
|
||
- **处理**:
|
||
1. 检查 node_modules 是否完整
|
||
2. 检查 package.json 依赖版本
|
||
3. 查看构建错误日志
|
||
4. 检查环境变量配置
|
||
|
||
### 5. 部署失败
|
||
- **错误**: 部署脚本执行失败
|
||
- **处理**:
|
||
1. 检查 Docker 服务状态
|
||
2. 检查端口占用情况
|
||
3. 查看部署脚本日志
|
||
|
||
## 测试策略
|
||
|
||
### 单元测试
|
||
- 测试文件对比逻辑
|
||
- 测试文件复制功能
|
||
- 测试差异报告生成
|
||
|
||
### 集成测试
|
||
- 测试完整的源码提取流程
|
||
- 测试构建验证流程
|
||
- 测试部署流程
|
||
|
||
### 功能测试
|
||
- 在影子系统上测试所有关键功能
|
||
- 对比正式系统和影子系统的功能表现
|
||
- 记录测试结果
|
||
|
||
### 测试清单
|
||
|
||
#### 用户认证
|
||
- [ ] 钉钉登录
|
||
- [ ] 邮箱密码登录
|
||
- [ ] 用户注册
|
||
|
||
#### 素材管理
|
||
- [ ] 素材上传(所有类型)
|
||
- [ ] 素材浏览(瀑布流)
|
||
- [ ] 素材筛选(类型、店铺、场景、产品类别)
|
||
- [ ] 素材搜索(防抖处理)
|
||
- [ ] 素材详情
|
||
- [ ] 素材编辑
|
||
- [ ] 素材下载(包括模特类自动打包)
|
||
- [ ] 点赞功能
|
||
- [ ] 收藏功能
|
||
- [ ] 分享功能
|
||
|
||
#### 滚动位置保存
|
||
- [ ] 从详情页返回首页时保持滚动位置
|
||
- [ ] 筛选条件保存和恢复
|
||
|
||
#### 个人中心
|
||
- [ ] 我的素材
|
||
- [ ] 我的收藏
|
||
- [ ] 头像上传
|
||
- [ ] 个人信息修改
|
||
|
||
#### 管理员功能
|
||
- [ ] 用户管理
|
||
- [ ] 素材管理
|
||
- [ ] 分类管理(店铺、场景、平台、产品类别)
|
||
- [ ] 部门管理
|
||
- [ ] 系统设置
|
||
- [ ] 回收站
|
||
|
||
#### 辅助功能
|
||
- [ ] 排行榜
|
||
- [ ] AI 聊天
|
||
- [ ] 弹幕
|
||
- [ ] 网络诊断
|
||
- [ ] 更新日志
|
||
|
||
#### 视频处理
|
||
- [ ] 视频上传
|
||
- [ ] 视频转码
|
||
- [ ] 视频预览
|
||
|
||
## 实施步骤
|
||
|
||
### 阶段 1: 源码提取(预计 30 分钟)
|
||
1. 连接到服务器
|
||
2. 从容器打包源码
|
||
3. 下载到本地
|
||
4. 解压并检查
|
||
|
||
### 阶段 2: 差异分析(预计 20 分钟)
|
||
1. 生成文件列表
|
||
2. 对比差异
|
||
3. 生成差异报告
|
||
4. 标注重要文件
|
||
|
||
### 阶段 3: 文件恢复(预计 10 分钟)
|
||
1. 复制缺失文件
|
||
2. 更新不一致文件
|
||
3. 验证文件完整性
|
||
|
||
### 阶段 4: 构建验证(预计 15 分钟)
|
||
1. 安装依赖
|
||
2. 执行构建
|
||
3. 检查构建输出
|
||
4. 修复构建错误(如有)
|
||
|
||
### 阶段 5: 部署测试(预计 20 分钟)
|
||
1. 部署到影子系统
|
||
2. 验证容器状态
|
||
3. 访问影子系统
|
||
4. 初步功能测试
|
||
|
||
### 阶段 6: 功能验证(预计 60 分钟)
|
||
1. 测试用户认证
|
||
2. 测试素材管理
|
||
3. 测试筛选和搜索
|
||
4. 测试滚动位置保存
|
||
5. 测试管理员功能
|
||
6. 测试辅助功能
|
||
7. 记录测试结果
|
||
|
||
### 阶段 7: 文档更新(预计 15 分钟)
|
||
1. 更新功能恢复进度文档
|
||
2. 记录遇到的问题和解决方案
|
||
3. 更新部署文档
|
||
|
||
**总预计时间**: 约 2.5 小时
|
||
|
||
## 风险和缓解措施
|
||
|
||
### 风险 1: 源码提取不完整
|
||
- **影响**: 恢复的源码缺少关键文件
|
||
- **缓解**:
|
||
1. 提取前先列出所有文件
|
||
2. 提取后验证文件数量
|
||
3. 对比文件大小
|
||
|
||
### 风险 2: 构建失败
|
||
- **影响**: 无法生成可部署的镜像
|
||
- **缓解**:
|
||
1. 先在本地测试构建
|
||
2. 检查依赖版本
|
||
3. 查看构建日志
|
||
|
||
### 风险 3: 功能不一致
|
||
- **影响**: 影子系统功能与正式系统不一致
|
||
- **缓解**:
|
||
1. 详细的功能测试清单
|
||
2. 对比测试结果
|
||
3. 记录差异并修复
|
||
|
||
### 风险 4: 数据库不兼容
|
||
- **影响**: 影子系统无法连接数据库或数据结构不匹配
|
||
- **缓解**:
|
||
1. 检查数据库连接配置
|
||
2. 验证数据库 schema
|
||
3. 执行必要的迁移
|
||
|
||
## 生产系统问题分析(2025-12-20)
|
||
|
||
### 🔍 数据不一致问题调查结果
|
||
|
||
#### 数据库状态(正常)
|
||
- **生产数据库** (`lobechat` @ 192.168.58.20:5432):
|
||
- 总记录数: 1530条
|
||
- 未删除素材: 1524条
|
||
- 软删除素材: 6条
|
||
- **结论**: 数据库没有被覆盖,数据完整
|
||
|
||
- **影子数据库** (`lobechat_stage` @ 192.168.58.20:5432):
|
||
- 未删除素材: 1049条
|
||
- **结论**: 影子系统数据独立,没有混乱
|
||
|
||
#### 发现的BUG
|
||
|
||
##### BUG 1: 统计API包含软删除数据
|
||
- **API**: `/api/materials/stats`
|
||
- **问题**: 返回 `total: 1530`(包含6条软删除数据)
|
||
- **正确值**: 应该是 `1524`
|
||
- **影响**: "使用店铺"的"全部"按钮显示错误数字(1530)
|
||
- **修复**: 添加 `WHERE "deletedAt" IS NULL` 过滤条件
|
||
|
||
##### BUG 2: 分页API返回全部数据
|
||
- **API**: `/api/materials?page=X&pageSize=20`
|
||
- **问题**: 无论请求哪一页,都返回全部1524条数据
|
||
- **影响**:
|
||
- 前端性能严重下降(一次加载1524条数据)
|
||
- 用户看到的"瀑布流"实际上是全部数据
|
||
- 用户报告滚动到底部只显示1026个素材(可能是前端渲染限制)
|
||
- **修复**: 修复分页逻辑,确保正确使用 `skip` 和 `take`
|
||
|
||
##### BUG 3: 分类统计API未过滤软删除
|
||
- **API**: `/api/categories`
|
||
- **问题**: 统计每个分类的素材数量时未过滤软删除数据
|
||
- **影响**: 分类按钮显示的数字可能包含已删除素材
|
||
- **修复**: 添加 `WHERE "deletedAt" IS NULL` 过滤条件
|
||
|
||
#### 容器状态
|
||
- **正式系统容器**: 不在本地服务器上(在192.168.58.20服务器上运行)
|
||
- **端口4320**: 正常运行,可以访问
|
||
- **本地源码**: 与生产系统不一致,需要从生产容器恢复
|
||
|
||
### 📁 素材存储路径问题
|
||
|
||
#### 重要说明:新老素材存储位置不同
|
||
|
||
##### 老素材存储(2025-10-27之前)
|
||
- **预览图**: MinIO S3(老bucket配置)
|
||
- Endpoint: `https://s3.1080p.hk`
|
||
- Bucket: `jsxiangche`(老bucket,无路径前缀)
|
||
- URL格式: `https://s3.1080p.hk/jsxiangche/preview-{timestamp}-{hash}.webp`
|
||
- 示例: `https://s3.1080p.hk/jsxiangche/preview-1761537819211-edb4a190180c24f9.webp`
|
||
|
||
- **源文件(压缩包)**: 本地文件系统
|
||
- 路径: `uploads/material-{timestamp}-{hash}.zip`
|
||
- 相对路径格式(数据库存储)
|
||
- 示例: `uploads/material-1761537819728-8fb5090670b5b986.zip`
|
||
|
||
##### 新素材存储(2025-10-27之后)
|
||
- **预览图/视频缩略图**: MinIO S3(新路径配置)
|
||
- Endpoint: `https://s3.1080p.hk`
|
||
- Bucket: `jsxiangche`(同一bucket,但有路径前缀)
|
||
- 路径前缀: `由壹点AI/`
|
||
- URL格式: `https://s3.1080p.hk/jsxiangche/由壹点AI/video-thumb-{timestamp}-{hash}.jpg`
|
||
- 示例: `https://s3.1080p.hk/jsxiangche/由壹点AI/video-thumb-1766220802404-d6c20cf8f82c0c80.jpg`
|
||
|
||
- **源文件(压缩包/视频)**: 本地文件系统
|
||
- 路径: `uploads/video-{timestamp}-{hash}.mp4` 或 `uploads/material-{timestamp}-{hash}.zip`
|
||
- 相对路径格式(数据库存储)
|
||
- 示例: `uploads/video-1766220805356-02770716caf02d9c.mp4`
|
||
|
||
##### 处理策略
|
||
- ⚠️ **不要移动或修改老素材**
|
||
- 保持老素材在原位置,确保能正常访问和下载
|
||
- 老素材的路径信息已存储在数据库中
|
||
- 所有新上传的素材统一使用新位置(带 `由壹点AI/` 前缀)
|
||
|
||
##### 兼容性要求
|
||
- 下载功能已兼容新老路径(使用相同的 `./uploads` 目录)
|
||
- 根据数据库中的路径信息自动判断使用哪个存储位置
|
||
- 确保老素材和新素材都能正常下载
|
||
- S3 预览图通过 `previewUrl` 字段直接访问,无需特殊处理
|
||
|
||
#### 数据库字段说明
|
||
```typescript
|
||
// materials 表
|
||
{
|
||
zipFilePath: string; // 本地压缩包路径(可能是老路径或新路径)
|
||
previewUrl: string; // 预览图URL(S3或老存储)
|
||
// ... 其他字段
|
||
}
|
||
```
|
||
|
||
### 🎯 源码恢复优先级
|
||
|
||
#### 高优先级(必须恢复)
|
||
1. `/api/materials/route.ts` - 修复分页BUG
|
||
2. `/api/materials/stats/route.ts` - 修复统计BUG
|
||
3. `/api/categories/route.ts` - 修复分类统计BUG
|
||
4. `/api/materials/download/route.ts` - 确保支持新老路径
|
||
5. 所有素材上传相关代码 - 确保新素材使用新路径
|
||
|
||
#### 中优先级(建议恢复)
|
||
- 所有 `/api` 目录下的文件
|
||
- 所有 `/app` 目录下的页面文件
|
||
- 所有 `/components` 目录下的组件文件
|
||
|
||
#### 低优先级(可选)
|
||
- 配置文件(如果本地已正确配置)
|
||
- 文档文件
|
||
|
||
### ⚠️ 恢复注意事项
|
||
|
||
1. **不要直接修改生产系统**
|
||
- 只从生产系统读取和复制文件
|
||
- 所有修改先在本地测试
|
||
- 测试通过后部署到影子系统
|
||
- 影子系统验证通过后才部署到生产
|
||
|
||
2. **保护用户数据**
|
||
- `uploads` 目录不要删除或覆盖
|
||
- 老素材路径不要修改
|
||
- 数据库操作前必须备份
|
||
|
||
3. **环境隔离**
|
||
- 生产系统(4320): 数据库 `lobechat`, Redis 6379
|
||
- 影子系统(5320): 数据库 `lobechat_stage`, Redis 6380
|
||
- 确保环境变量正确配置
|
||
|
||
## 后续工作
|
||
|
||
1. **建立版本控制**: 恢复完成后立即初始化 Git 仓库
|
||
2. **设置 CI/CD**: 配置自动化构建和部署流程
|
||
3. **代码审查**: 审查恢复的代码,添加必要的注释
|
||
4. **性能优化**: 识别并优化性能瓶颈
|
||
5. **安全加固**: 检查安全漏洞,更新依赖包
|
||
6. **修复已知BUG**: 修复上述发现的3个BUG
|
||
7. **路径兼容性测试**: 确保新老素材都能正常下载
|