18 KiB
Raw Blame History

设计文档:从正式系统恢复源码

概述

本设计文档描述了如何从正式系统的 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 命令

    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

    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. 文件对比工具

功能: 对比本地源码和容器源码的差异

实现:

# 获取容器内文件列表
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. 部署工具

功能: 将恢复的源码部署到影子系统

使用:

.\deploy-local-build.ps1 -Target shadow

该脚本应该:

  1. 构建 Docker 镜像
  2. 停止旧的影子系统容器
  3. 启动新的影子系统容器
  4. 验证容器状态

数据模型

文件差异报告

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[];     // 本地多余的文件
}

功能验证清单

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 字段直接访问,无需特殊处理

数据库字段说明

// 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. 路径兼容性测试: 确保新老素材都能正常下载