# 部署架构升级 V2：前后端合一容器 + MySQL 需求文档

> **文档版本**: v1.0
> **创建日期**: 2026-07-28
> **文档状态**: 初稿待评审
> **负责人**: czj
> **目标服务器**: 192.168.5.60 / Ubuntu 26.04 LTS
> **部署目录**: `/data/third_party/plat-auto-test/`

---

## 目录

1. [背景与问题](#一背景与问题)
2. [需求目标](#二需求目标)
3. [架构设计](#三架构设计)
4. [详细需求](#四详细需求)
5. [非功能需求](#五非功能需求)
6. [验收标准](#六验收标准)
7. [风险评估](#七风险评估)
8. [附录](#八附录)

---

## 一、背景与问题

### 1.1 当前部署现状（V1）

当前系统已通过 Docker 容器化部署在 `192.168.5.60`，架构为：

```
┌──────────────┐    ┌──────────────┐    ┌──────────┐
│  Frontend    │    │   Backend    │    │  SQLite  │
│  Nginx 容器  │───▶│  uvicorn     │───▶│  文件    │
│  :80         │    │  :8001       │    │          │
│  静态文件    │    │  Playwright  │    │ volume   │
└──────────────┘    └──────────────┘    └──────────┘
    3 个容器独立运行        代码 COPY 进镜像
```

### 1.2 存在的问题

| 问题 | 详细描述 | 影响程度 |
|------|---------|---------|
| **1. 前端独立容器冗余** | 前端是 Vue 构建的纯静态文件，Nginx 容器仅 serve 静态文件，增加资源占用和管理复杂度 | ⭐⭐⭐ |
| **2. 代码更新需重建镜像** | 代码 COPY 进镜像，每次修改代码必须 `docker compose build`（3-5 分钟），开发迭代效率低 | ⭐⭐⭐ |
| **3. 前端更新需重启容器** | 修改前端后需重建镜像并重启 Nginx 容器，无法热更新 | ⭐⭐ |
| **4. SQLite 并发瓶颈** | SQLite 不支持高并发写入，多用户/批量执行时容易 `database is locked` | ⭐⭐⭐ |
| **5. 项目目录与另一服务共用** | 当前在 `~/ubains-module-test/` git 目录下，与 8088 端口维护平台共用仓库，存在分支冲突风险 | ⭐⭐ |
| **6. 数据无独立备份方案** | SQLite 文件数据库难以增量备份，迁移困难 | ⭐⭐ |

### 1.3 目标

1. **前后端合一容器**：前端静态文件由 FastAPI 直接 serve，去掉独立 Nginx 容器
2. **前端热更新**：前端构建产物通过 volume 挂载，替换文件直接生效，无需重启容器
3. **后端 volume 挂载**：后端代码通过 volume 挂载，修改后重启容器（秒级）即可生效，无需重建镜像
4. **MySQL 替代 SQLite**：数据库升级为 MySQL 8.0，独立容器运行，数据持久化，支持并发写入
5. **独立部署目录**：迁移到 `/data/third_party/plat-auto-test/`，与另一服务完全隔离
6. **数据独立存储**：MySQL 数据文件单独 volume 持久化，便于备份和迁移

---

## 二、需求目标

### 2.1 业务需求

| 需求 ID | 需求描述 | 优先级 |
|---------|---------|--------|
| REQ-01 | 前后端合并为同一容器运行，减少容器数量 | P0 |
| REQ-02 | 前端代码更新后实现热替换，无需重启容器 | P0 |
| REQ-03 | 后端代码更新后只需重启容器（秒级），无需重建镜像 | P0 |
| REQ-04 | 数据库从 SQLite 迁移至 MySQL 8.0，支持并发写入 | P0 |
| REQ-05 | 项目部署到独立目录 `/data/third_party/plat-auto-test/`，与另一服务隔离 | P0 |
| REQ-06 | MySQL 数据独立 volume 持久化，支持备份和恢复 | P1 |
| REQ-07 | 保留 SQLite 兼容性，本地开发环境仍可用 SQLite | P1 |
| REQ-08 | 现有 283 个用例数据完整迁移到 MySQL | P0 |

### 2.2 架构对比

| 维度 | V1（当前） | V2（目标） |
|------|-----------|-----------|
| **容器数量** | 3 个（前端 Nginx + 后端 + SQLite 文件） | **2 个（合一应用 + MySQL 8.0）** |
| **前端运行方式** | 独立 Nginx 容器 serve 静态文件 | **FastAPI StaticFiles 直接 serve** |
| **前端更新** | 重建镜像 + 重启容器（3-5 分钟） | **替换 dist/ 文件，热生效（无需重启）** |
| **后端更新** | 重建镜像 + 重启容器（3-5 分钟） | **重启容器（5-10 秒，无需重建）** |
| **数据库** | SQLite 文件（volume 挂载） | **MySQL 8.0 独立容器（volume 持久化）** |
| **部署目录** | `~/ubains-module-test/`（与另一服务共用） | **`/data/third_party/plat-auto-test/`（独立）** |
| **代码与镜像关系** | 代码 COPY 进镜像 | **代码 volume 挂载，镜像只装环境** |
| **数据备份** | 手动复制 .db 文件 | **mysqldump 标准备份流程** |

---

## 三、架构设计

### 3.1 整体架构图

```
                   用户浏览器
                        │
                        ▼
        ┌───────────────────────────────────────┐
        │      服务器 192.168.5.60 (Ubuntu)       │
        │                                         │
        │   ┌─────────────────────────────────┐  │
        │   │  Docker Compose 网络              │  │
        │   │  (plat-auto-test-net)              │  │
        │   │                                   │  │
        │   │  ┌────────────────────┐  ┌──────┐│  │
        │   │  │    app 容器        │  │mysql ││  │
        │   │  │    (合一)          │◀─│ 容器 ││  │
        │   │  │                    │  │      ││  │
        │   │  │  ┌──────────────┐ │  │:3306 ││  │
        │   │  │  │ FastAPI       │ │  └──────┘│  │
        │   │  │  │ ├─ API 路由   │ │          │  │
        │   │  │  │ ├─ StaticFiles│ │          │  │
        │   │  │  │ ├─ Playwright │ │          │  │
        │   │  │  │ └─ WebSocket  │ │          │  │
        │   │  │  └──────────────┘ │          │  │
        │   │  │  Port: 80         │          │  │
        │   │  └────────┬─────────┘  └────┬───┘  │
        │   │           │                  │      │
        │   │      Volume 挂载         Volume     │
        │   │           │                  │      │
        │   └───────────┼──────────────────┼──────┘
        │               │                  │
        │   ┌───────────▼──────────────────▼──────┐
        │   │  /data/third_party/plat-auto-test/   │
        │   │  ├── backend/       (源码 volume)    │
        │   │  ├── frontend/dist/ (构建产物 volume)│
        │   │  ├── data/          (截图/报告)      │
        │   │  ├── mysql/data/    (MySQL 数据)     │
        │   │  └── logs/          (日志)           │
        │   └──────────────────────────────────────┘
        │                                           │
        │   另一维护平台 (8088) ← 独立，不受影响      │
        └───────────────────────────────────────────┘
```

### 3.2 容器职责

| 容器 | 数量 | 职责 | 端口 | 镜像 |
|------|------|------|------|------|
| **app** | 1 | FastAPI（API + 前端静态文件 + Playwright + WebSocket） | 80 | 自构建（python:3.10-slim） |
| **mysql** | 1 | MySQL 8.0 数据库 | 3306（仅容器内，宿主机映射 3307） | mysql:8.0 |

### 3.3 关键设计决策

**决策 1：前后端合一 — 为什么去掉独立 Nginx？**

| 理由 | 说明 |
|------|------|
| 前端是静态文件 | Vue 构建产物是纯静态 HTML/JS/CSS，FastAPI 的 `StaticFiles` 可直接 serve |
| 同源访问 | 前端 API 请求走 `/api/*` 相对路径，无需跨域配置 |
| 减少资源 | 从 3 个容器减到 2 个，降低内存和运维复杂度 |
| 热更新 | FastAPI 静态文件服务实时读取文件系统，替换 dist/ 立即生效 |

**决策 2：MySQL 独立容器 — 为什么不是宿主机直装？**

| 理由 | 说明 |
|------|------|
| 环境隔离 | 数据库版本、配置与宿主机解耦，不影响其他服务 |
| 易于备份 | `mysqldump` 标准备份，Docker volume 持久化 |
| 易于迁移 | 容器化数据库可整体迁移到其他 Docker 主机 |
| 版本管理 | 可独立升级 MySQL 版本，不影响应用 |

**决策 3：代码 volume 挂载 — 为什么代码不 COPY 进镜像？**

| 理由 | 说明 |
|------|------|
| 更新速度快 | 改后端代码只需重启容器（5-10s），无需重建镜像（3-5min） |
| 前端热更新 | 替换 dist/ 文件即时生效，完全不需重启 |
| 镜像体积小 | 镜像只包含 Python 环境 + Playwright + pip 依赖，约 1.2GB（不含业务代码） |
| 版本回退快 | 保留旧代码目录即可快速回退 |

---

## 四、详细需求

### 4.1 服务器目录结构

```
/data/third_party/plat-auto-test/          ← 项目根目录（独立，无 git 仓库）
├── deploy/                                ← 部署配置文件
│   ├── docker-compose.yml                 ← 服务编排（app + mysql）
│   ├── Dockerfile                         ← 合一应用镜像
│   ├── init.sql                           ← MySQL 初始化脚本
│   ├── nginx.conf                         ← Nginx 配置（可选，未来 HTTPS 用）
│   ├── .env                               ← 环境变量（敏感信息，不提交 git）
│   └── deploy.sh                          ← 一键部署脚本
├── backend/                               ← 后端源码（volume 挂载到容器 /app）
│   ├── app/
│   │   ├── main.py                        ← 改造：新增 StaticFiles 挂载前端
│   │   ├── config.py                      ← 改造：DATABASE_URL 支持 MySQL
│   │   ├── database.py                    ← 无需改动（已有条件判断）
│   │   ├── models/
│   │   ├── routers/
│   │   ├── services/
│   │   ├── executors/
│   │   └── websocket/
│   ├── scripts/
│   ├── requirements.txt                   ← 改造：新增 aiomysql + cryptography
│   └── ...
├── frontend/
│   └── dist/                              ← 前端构建产物（volume 挂载）
│       ├── index.html
│       ├── assets/
│       └── ...
├── data/                                  ← 应用数据（volume 挂载到 /app/data）
│   ├── screenshots/                       ← 执行截图
│   └── reports/                           ← 测试报告
├── mysql/
│   └── data/                              ← MySQL 数据持久化（volume 挂载）
└── logs/                                  ← 应用日志（volume 挂载到 /app/logs）
```

### 4.2 目录权限要求

| 目录 | 容器内路径 | 宿主机权限 | 容器内 UID | 说明 |
|------|-----------|-----------|-----------|------|
| `backend/` | `/app` | 755 / ubains:ubains | 1000 | 后端源码 |
| `frontend/dist/` | `/app/frontend/dist` | 755 / ubains:ubains | 1000 | 前端构建产物 |
| `data/` | `/app/data` | 777 | 1000 | 截图/报告（需写入） |
| `mysql/data/` | `/var/lib/mysql` | 999:999 (mysql) | 999 | MySQL 数据 |
| `logs/` | `/app/logs` | 777 | 1000 | 日志 |

### 4.3 Dockerfile 需求

**文件**: `deploy/Dockerfile`

```dockerfile
FROM python:3.10-slim

WORKDIR /app

# 安装系统依赖（Playwright 需要）
RUN apt-get update && apt-get install -y --no-install-recommends \
    wget gnupg curl \
    libnss3 libnspr4 libatk1.0-0t64 libatk-bridge2.0-0t64 \
    libcups2t64 libdrm2 libdbus-1-3 libxkbcommon0 \
    libxcomposite1 libxdamage1 libxfixes3 libxrandr2 \
    libgbm1 libpango-1.0-0 libcairo2 libasound2t64 \
    && rm -rf /var/lib/apt/lists/*

# 安装 Python 依赖（使用国内镜像源）
COPY requirements.txt .
RUN pip install --no-cache-dir \
    -i https://pypi.tuna.tsinghua.edu.cn/simple \
    --trusted-host pypi.tuna.tsinghua.edu.cn \
    --retries 5 --timeout 120 -r requirements.txt

# 安装 Playwright Chromium
RUN playwright install chromium

# 创建必要目录
RUN mkdir -p /app/data/screenshots /app/data/reports \
    /app/frontend/dist /app/logs

# ⚠️ 以下内容通过 volume 挂载，不 COPY 进镜像：
# - backend/ 源码 → /app
# - frontend/dist/ → /app/frontend/dist
# - data/ → /app/data
# - logs/ → /app/logs

EXPOSE 80

# 启动 uvicorn，监听 80 端口（同时提供 API + 前端静态文件）
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
```

**关键要求**：
- 镜像只装环境（Python + Playwright + pip 依赖），**不打包业务代码**
- 首次构建后，后续更新代码**无需重建镜像**
- 使用国内镜像源加速构建

### 4.4 requirements.txt 改造

```diff
  fastapi==0.110.0
  uvicorn[standard]==0.27.0
  sqlalchemy==2.0.25
  aiosqlite==0.19.0      # 保留，本地开发仍用 SQLite
+ aiomysql==0.2.0        # 新增，MySQL 异步驱动
+ cryptography==42.0.0   # 新增，MySQL 认证需要
  pydantic==2.5.3
  ...
```

### 4.5 main.py 改造（前端静态文件服务）

在 `main.py` 末尾添加前端静态文件挂载：

```python
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from pathlib import Path

# ==================== 前端静态文件服务 ====================
FRONTEND_DIST = Path(__file__).parent.parent / "frontend" / "dist"

if FRONTEND_DIST.exists():
    # 挂载静态资源目录
    app.mount("/assets", StaticFiles(directory=FRONTEND_DIST / "assets"), name="assets")

    # SPA 路由：所有非 /api 路径回退到 index.html
    @app.get("/{full_path:path}")
    async def serve_spa(full_path: str):
        """前端 SPA 入口，所有非 API 路径返回 index.html"""
        file_path = FRONTEND_DIST / full_path
        if file_path.exists() and file_path.is_file():
            return FileResponse(str(file_path))
        return FileResponse(str(FRONTEND_DIST / "index.html"))
```

**关键要求**：
- 仅在 `frontend/dist/` 存在时才挂载（本地开发时不干扰）
- SPA 路由回退：所有非 `/api` 路径返回 `index.html`
- 前端热更新：FastAPI 实时读取文件系统，替换 dist/ 文件后立即生效

### 4.6 Docker Compose 编排

**文件**: `deploy/docker-compose.yml`

```yaml
version: "3.8"

services:
  mysql:
    image: mysql:8.0
    container_name: plat-auto-test-mysql
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE:-plat_auto_test}
      MYSQL_USER: ${MYSQL_USER:-platapp}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      TZ: Asia/Shanghai
    volumes:
      - /data/third_party/plat-auto-test/mysql/data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    ports:
      - "3307:3306"   # 宿主机 3307，避免与本地 MySQL 冲突
    networks:
      - plat-auto-test-net
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 10
      start_period: 30s
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
      - --default-authentication-plugin=mysql_native_password
      - --max_connections=200

  app:
    build:
      context: ../backend
      dockerfile: ../deploy/Dockerfile
    container_name: plat-auto-test-app
    restart: unless-stopped
    depends_on:
      mysql:
        condition: service_healthy
    environment:
      - DATABASE_URL=mysql+aiomysql://${MYSQL_USER}:${MYSQL_PASSWORD}@mysql:3306/${MYSQL_DATABASE}?charset=utf8mb4
      - PLAYWRIGHT_HEADLESS=true
      - PLAYWRIGHT_TIMEOUT=30000
      - LOG_LEVEL=INFO
      - TZ=Asia/Shanghai
    volumes:
      - /data/third_party/plat-auto-test/backend:/app
      - /data/third_party/plat-auto-test/frontend/dist:/app/frontend/dist
      - /data/third_party/plat-auto-test/data:/app/data
      - /data/third_party/plat-auto-test/logs:/app/logs
    ports:
      - "80:80"
    networks:
      - plat-auto-test-net
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:80/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

networks:
  plat-auto-test-net:
    driver: bridge
```

**关键设计**：
- `mysql` 先启动并通过健康检查后，`app` 才启动（`depends_on` + `condition: service_healthy`）
- `app` 的 `DATABASE_URL` 用容器服务名 `mysql` 作为主机名（Docker 内部 DNS）
- MySQL 宿主机映射 `3307` 端口（避免与服务器本地 3306 冲突）
- 全部代码和数据通过 volume 挂载

### 4.7 MySQL 初始化脚本

**文件**: `deploy/init.sql`

```sql
-- 确保字符集
ALTER DATABASE plat_auto_test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 授予权限
GRANT ALL PRIVILEGES ON plat_auto_test.* TO 'platapp'@'%';
FLUSH PRIVILEGES;

-- 时区设置
SET GLOBAL time_zone = '+08:00';
SET SESSION time_zone = '+08:00';
```

### 4.8 环境变量配置

**文件**: `deploy/.env`

```bash
# ==================== MySQL 配置 ====================
MYSQL_ROOT_PASSWORD=Ubains@13579
MYSQL_DATABASE=plat_auto_test
MYSQL_USER=platapp
MYSQL_PASSWORD=PlatApp@2026

# ==================== 应用配置 ====================
PLAYWRIGHT_HEADLESS=true
PLAYWRIGHT_TIMEOUT=30000
LOG_LEVEL=INFO
```

> ⚠️ **安全提示**：生产环境请修改 `MYSQL_ROOT_PASSWORD` 和 `MYSQL_PASSWORD` 为强密码。
> `.env` 文件不要提交到 git。

### 4.9 数据迁移方案

#### 4.9.1 表结构迁移

应用首次启动时，`main.py` 的 `lifespan` 调用 `init_db()` → `Base.metadata.create_all()`，根据 SQLAlchemy 模型自动在 MySQL 中创建所有表。

#### 4.9.2 数据迁移

需要编写迁移脚本 `backend/scripts/migrate_sqlite_to_mysql.py`，将本地 SQLite 数据迁移到 MySQL：

| 表名 | 行数 | 说明 |
|------|------|------|
| `modules` | ~28 | 测试模块 |
| `test_cases` | ~283 | 测试用例 |
| `executions` | 若干 | 执行记录 |
| `case_results` | 若干 | 用例结果 |
| `case_dependencies` | 若干 | 用例依赖 |
| `security_configs` | 若干 | 安全测试配置 |
| `vulnerability_results` | 若干 | 漏洞结果 |

### 4.10 更新流程

#### 场景 1：更新前端（热更新，无需重启）

```bash
# 本地构建
cd frontend && npm run build

# 上传 dist/ 到服务器（直接覆盖）
scp -r dist/* ubains@192.168.5.60:/data/third_party/plat-auto-test/frontend/dist/
```

✅ **效果**：替换文件后，刷新浏览器即刻生效，**无需重启容器**。

#### 场景 2：更新后端（需重启容器，秒级）

```bash
# 上传修改后的代码
scp -r backend/app ubains@192.168.5.60:/data/third_party/plat-auto-test/backend/

# 重启容器（5-10 秒）
ssh ubains@192.168.5.60
cd /data/third_party/plat-auto-test/deploy
docker compose restart app
```

#### 场景 3：更新依赖（需重建镜像）

仅在 `requirements.txt` 发生变更时才需要：

```bash
cd /data/third_party/plat-auto-test/deploy
docker compose build app
docker compose up -d app
```

---

## 五、非功能需求

### 5.1 性能要求

| 指标 | 要求 |
|------|------|
| 应用容器启动时间 | < 15 秒（等待 MySQL 健康检查后） |
| API 健康检查响应 | < 100ms |
| 后端重启时间 | < 10 秒 |
| 前端首屏加载 | < 3 秒 |
| 数据库连接池 | 最大 200 连接 |

### 5.2 安全要求

| 要求 | 说明 |
|------|------|
| MySQL 密码 | 生产环境使用强密码，`.env` 不提交 git |
| 端口暴露 | 宿主机只暴露 80（前端）和 3307（MySQL 调试），3306 仅在容器内 |
| 文件权限 | `data/` 和 `logs/` 目录容器内可写 |
| 容器隔离 | 应用容器与数据库容器网络隔离，仅通过内部网络通信 |

### 5.3 兼容性要求

| 场景 | 数据库 | 说明 |
|------|--------|------|
| 生产环境（服务器） | MySQL 8.0 | 通过 `DATABASE_URL` 环境变量配置 |
| 本地开发（Windows） | SQLite | 保留 `aiosqlite` 依赖，默认使用 SQLite |
| 本地测试 | SQLite | 无需额外配置 |

### 5.4 数据持久化要求

| 数据 | 存储方式 | 备份方式 |
|------|---------|---------|
| MySQL 数据库 | Volume 挂载到 `mysql/data/` | `mysqldump` 每日备份 |
| 执行截图 | Volume 挂载到 `data/screenshots/` | 定期清理 30 天前的 |
| 测试报告 | Volume 挂载到 `data/reports/` | 定期清理 30 天前的 |
| 应用日志 | Volume 挂载到 `logs/` | 日志轮转 |

---

## 六、验收标准

### 6.1 功能验收

| 验收项 | 操作 | 期望结果 |
|--------|------|---------|
| 目录独立 | 检查 `/data/third_party/plat-auto-test/` | 文件结构完整，与 `/opt/troubleshoot/` 独立 |
| 容器运行 | `docker compose ps` | app + mysql 状态 running/healthy |
| API 健康 | `curl http://localhost/health` | 返回 `{"status":"healthy"}` |
| 前端访问 | 浏览器打开 `http://192.168.5.60` | 显示登录页或首页 |
| 数据库连接 | 查看应用日志 | 无 MySQL 连接错误，表自动创建 |
| 数据完整 | 查询用例数 | 283 个用例完整迁移 |
| 前端热更新 | 替换 dist/ 后刷新浏览器 | 新版本生效，无需重启容器 |
| 后端更新 | 重启 app 容器后调用 API | 新代码生效 |
| 已有服务 | 访问 8088 端口 | 另一维护平台正常 |
| 本地开发 | 本地 `uvicorn` 启动 | 使用 SQLite 正常运行 |

### 6.2 性能验收

| 验收项 | 标准 |
|--------|------|
| 容器启动时间 | 总部署时间 < 5 分钟 |
| 后端重启时间 | < 10 秒 |
| 前端热更新 | 替换文件后，浏览器刷新即生效，无需等待 |
| 批量执行 | 同时执行 10 个用例，无 `database is locked` |

### 6.3 数据迁移验收

| 验收项 | 操作 | 期望结果 |
|--------|------|---------|
| 模块数据 | `curl /api/modules?case_type=ui` | 返回 16 个 UI 模块 |
| 用例数据 | `curl /api/cases?limit=500` | 返回 283 个用例 |
| 执行记录 | 查看执行历史 | 历史执行记录可查询 |

---

## 七、风险评估

| 风险 | 概率 | 影响 | 缓解措施 |
|------|------|------|---------|
| MySQL 连接失败 | 低 | 高 | 健康检查依赖确保启动顺序 |
| 数据迁移丢失 | 低 | 高 | 迁移前备份 SQLite，迁移后对比行数 |
| 容器内路径不一致 | 中 | 高 | 确保 WORKDIR 和 volume 路径严格匹配 |
| 旧容器端口冲突 | 低 | 中 | 先停旧容器再启动新容器 |
| Playwright 执行异常 | 低 | 中 | 容器内已安装所有系统依赖 |
| 前端热更新不生效 | 低 | 低 | 浏览器缓存问题，强制刷新解决 |
| 代码 volume 挂载性能 | 低 | 低 | 绑定挂载性能接近原生 |

---

## 八、附录

### 8.1 相关文档

| 文档 | 路径 | 说明 |
|------|------|------|
| V1 部署方案 | `Docs/部署方案/Linux服务器部署方案.md` | 原始部署方案 |
| V1 执行计划 | `Docs/部署方案/Linux容器化部署_执行计划.md` | 原始部署执行计划 |
| V2 设计方案 | `Docs/部署方案/Linux容器化部署方案_v2.md` | V2 实施方案初稿 |
| Volume 优化 PRD | `Docs/PRD/需求文档/部署运维/_PRD_需求文档_容器化部署Volume挂载优化.md` | 前置需求文档 |
| Volume 优化计划 | `Docs/PRD/需求文档/部署运维/_执行计划_容器化部署Volume挂载优化.md` | 前置计划文档 |
| UI 自动化交接 | `HANDOFF_UI自动化.md` | 项目交接 |
| 项目指南 | `CLAUDE.md` | 项目指导 |

### 8.2 服务器信息

| 项目 | 值 |
|------|-----|
| 服务器 IP | 192.168.5.60 |
| SSH 用户 | ubains |
| 操作系统 | Ubuntu 26.04 LTS |
| 已有服务 | 8088 端口（`/opt/troubleshoot/`） |
| 部署目录 | `/data/third_party/plat-auto-test/` |
| 前端地址 | http://192.168.5.60 |
| API 文档 | http://192.168.5.60/docs |
| MySQL 外部访问 | 192.168.5.60:3307（仅调试用） |

### 8.3 部署架构演进路线

| 阶段 | 架构 | 状态 |
|------|------|------|
| V1 | 前端 Nginx + 后端 + SQLite（代码 COPY 进镜像） | ✅ 已部署 |
| **V2** | **合一应用 + MySQL 8.0（代码 volume 挂载）** | 📋 **本需求文档** |
| V3（远期） | 应用 + MySQL + Redis + HTTPS + 监控告警 | 🔮 规划中 |

### 8.4 涉及改造的文件清单

| 文件 | 操作 | 说明 |
|------|------|------|
| `deploy/Dockerfile` | 🆕 新建 | 合一应用镜像（替代原 backend + frontend 两个 Dockerfile） |
| `deploy/docker-compose.yml` | 🔄 重写 | 从 3 服务改为 2 服务（app + mysql） |
| `deploy/init.sql` | 🆕 新建 | MySQL 初始化 |
| `deploy/.env.example` | 🔄 更新 | 新增 MySQL 配置项 |
| `deploy/deploy.sh` | 🔄 重写 | 适配新目录和新架构 |
| `backend/app/main.py` | 🔄 改造 | 新增 StaticFiles 挂载前端静态文件 |
| `backend/requirements.txt` | 🔄 改造 | 新增 aiomysql + cryptography |
| `backend/scripts/migrate_sqlite_to_mysql.py` | 🆕 新建 | 数据迁移脚本 |

---

*本文档由 Claude Code 编写，供评审后进入 prd-plan 阶段生成执行计划。*