509 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.

# 设计文档:从正式系统恢复源码
## 概述
本设计文档描述了如何从正式系统的 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. **路径兼容性测试**: 确保新老素材都能正常下载