# HANDOFF — 自动化部署测试模块会话交接文档

> **生成时间**: 2026-08-12
> **当前分支**: `platform-auto-test`
> **最近提交**: `09346c8e` feat(element-mapping): 元素映射表扩展至v1.2 新增登录页+会议预约子页面共220元素
> **状态**: ✅ 自动化部署测试模块全部完成（后端服务 + SSH 执行器 + 19 条 API + WebSocket 实时日志 + 4 个前端页面 + 构建通过）

---

## ⚠️ 多窗口并行开发注意（自动化部署测试窗口）

本窗口是**自动化部署测试模块开发**，与可能的其他窗口并行开发。**必须遵守** `Docs/多窗口并行开发指南.md`：

| 项目 | 本窗口（自动化部署测试） | 其他窗口 |
|------|------------------------|----------|
| 后端端口 | 8001（或 8002） | 视情况 |
| 前端端口 | 3000（或 3001） | 视情况 |
| 开发模块 | 自动化部署测试 | 其他模块 |
| Git 提交 | 提交前先 `git pull` | 提交后 push |
| 数据库 | 错开写入时间 | 错开写入时间 |

---

## 一、本次任务（已完成）

### 任务：自动化部署测试模块

**核心能力**：
1. ✅ **服务器管理** — 在平台内维护 SSH 目标服务器列表（IP、端口、用户名、密码/密钥），支持连接测试
2. ✅ **脚本配置** — 配置远程部署脚本路径/命令，支持交互式应答规则（触发词 → 自动应答）
3. ✅ **一键执行部署** — 选择脚本 → 通过 SSH 在目标服务器上执行远程命令，自动处理交互提示
4. ✅ **实时日志** — WebSocket 流式推送执行日志，深色终端风格查看器，自动滚动
5. ✅ **历史回看** — 执行记录持久化，全量日志可回看、复制、刷新
6. ✅ **安全处理** — 密码加密存储（Fernet），敏感应答以 `******` 隐藏

### 关键设计决策

| 决策 | 结论 | 说明 |
|------|------|------|
| 交互输入处理 | 预设"触发词 → 应答"映射 | 脚本配置时定义每一步的触发文本和应答内容，按顺序匹配 |
| 脚本来源 | 脚本已存在于目标服务器 | 仅需配置远程路径/命令（如 `bash /opt/deploy/deploy.sh`） |
| SSH 库 | paramiko | 项目中已有 `deploy_to_560.py`、`claude_service.py` 在用 |
| 执行模式 | 专用 `threading.Thread` + `loop.run_in_executor` | 复用 `execution_service.py` 已固化的模式，避免 asyncio/greenlet 死锁 |
| 日志通道 | WebSocket 实时广播 + 数据库落库 | 双通道：实时 + 历史回看 |

---

## 二、已完成事项清单

### 2.1 后端新增文件

| 文件 | 说明 |
|------|------|
| `backend/app/models/deploy_server.py` | 服务器模型（`deploy_servers` 表）：name/host/port/username/password_encrypted/auth_type/private_key/status/description，密码用 Fernet 加密 |
| `backend/app/models/deploy_script.py` | 脚本模型（`deploy_scripts` 表）：name/description/server_id(FK)/remote_command/work_dir/timeout/expect_answers(JSON) |
| `backend/app/models/deploy_execution.py` | 执行记录模型（`deploy_executions` 表）：快照字段 + status/start_time/end_time/duration/exit_code/error_message/trigger_by |
| `backend/app/models/deploy_log.py` | 日志模型（`deploy_logs` 表）：execution_id(FK)/timestamp/level/message/is_sensitive |
| `backend/app/schemas/deploy.py` | Pydantic 校验层：DeployServer/Create/Update/Response、ExpectAnswer、DeployScript/Create/Update/Response、DeployExecution/Create/Response、DeployLog/Response |
| `backend/app/executors/deploy_executor.py` | **SSH 执行器核心**：paramiko SSHClient + invoke_shell PTY + 单线程轮询循环 + 交互应答匹配（contains/regex） + cancel() 强制关闭 |
| `backend/app/services/deploy_service.py` | 业务逻辑层：服务器 CRUD、脚本 CRUD、执行记录 CRUD、核心执行（专用线程池 + WebSocket 广播 + 日志落库） |
| `backend/app/routers/deploy.py` | 19 条 API 路由（含 WebSocket） |

### 2.2 后端修改文件

| 文件 | 修改内容 |
|------|---------|
| `backend/app/main.py` | 导入并注册 `deploy.router`，前缀 `/api/deploy` |
| `backend/app/models/__init__.py` | 导入 4 个新模型并加入 `__all__` |
| `backend/requirements.txt` | 追加 `paramiko==3.4.0` |

### 2.3 前端新增文件

| 文件 | 说明 |
|------|------|
| `frontend/src/types/deploy.ts` | TypeScript 类型：DeployServer/DeployServerCreate/ExpectAnswer/DeployScript/DeployScriptCreate/DeployExecution/DeployLog |
| `frontend/src/api/deploy.ts` | API 封装：listServers/createServer/updateServer/deleteServer/testServerConnection + listScripts/createScript/updateScript/deleteScript + listExecutions/createExecution/runExecution/cancelExecution/deleteExecution/getExecution/listExecutionLogs + createDeployLogStream(WebSocket) |
| `frontend/src/views/deploy/index.vue` | 父容器 `<router-view />` |
| `frontend/src/views/deploy/DeployServers.vue` | 服务器 CRUD 表格 + 新增/编辑弹窗（auth_type 切换密码/密钥、show-password、连接测试按钮） |
| `frontend/src/views/deploy/DeployScripts.vue` | 脚本 CRUD 表格 + 交互应答编辑器（动态行：trigger/triggerType/answer/timeout/sensitive/description，可增删行） |
| `frontend/src/views/deploy/DeployExecutions.vue` | 执行中心：脚本选择弹窗 → 执行 → WebSocket 实时日志查看器（深色终端风格、自动滚动、状态徽标、取消按钮） |
| `frontend/src/views/deploy/DeployExecutionDetail.vue` | 历史执行详情 + 全量日志回看（刷新、复制日志、敏感信息隐藏） |

### 2.4 前端修改文件

| 文件 | 修改内容 |
|------|---------|
| `frontend/src/App.vue` | 侧边栏新增"自动化部署测试"菜单（含 3 个子菜单：服务器管理/部署脚本/部署执行）、图标导入、路由映射 |
| `frontend/src/router/index.ts` | 新增 `/deploy` 父路由（含 4 个子路由：servers/scripts/executions/executions/:id），懒加载 |

### 2.5 文档

| 文件 | 说明 |
|------|------|
| `Docs/PRD/需求文档/部署运维/_PRD_需求文档_自动化部署测试模块.md` | 需求文档 |
| `Docs/PRD/需求文档/部署运维/_PRD_需求文档_自动化部署测试模块_计划执行.md` | 计划执行文档 |

---

## 三、API 参考

### 端点一览（共 19 条）

```
### 服务器管理
GET    /api/deploy/servers              → 列表（支持 limit/offset/status 筛选）
POST   /api/deploy/servers              → 新增
PUT    /api/deploy/servers/{server_id}  → 编辑
DELETE /api/deploy/servers/{server_id}  → 删除
POST   /api/deploy/servers/{server_id}/test  → 测试 SSH 连接

### 脚本管理
GET    /api/deploy/scripts              → 列表（支持 limit/offset/server_id 筛选）
POST   /api/deploy/scripts              → 新增
PUT    /api/deploy/scripts/{script_id}  → 编辑
DELETE /api/deploy/scripts/{script_id}  → 删除

### 执行管理
POST   /api/deploy/executions           → 创建执行记录
POST   /api/deploy/executions/{id}/run  → 触发执行
POST   /api/deploy/executions/{id}/cancel  → 取消执行
GET    /api/deploy/executions           → 列表（支持 limit/offset/status/script_id 筛选）
GET    /api/deploy/executions/{id}      → 详情
DELETE /api/deploy/executions/{id}      → 删除
GET    /api/deploy/executions/{id}/logs → 日志列表（支持 limit/offset/level 筛选）

### WebSocket 实时日志
WS     /api/deploy/ws/executions/{execution_id}  → 流式推送执行日志
```

### 消息类型（WebSocket）

| 类型 | 含义 | 关键字段 |
|------|------|---------|
| `deploy_start` | 部署开始 | `message` |
| `deploy_output` | 标准输出 | `message` |
| `deploy_stderr` | 错误输出 | `message` |
| `deploy_answer_sent` | 自动应答已发送 | `answer`（敏感时隐藏） |
| `deploy_complete` | 部署完成 | `exitCode`, `duration` |
| `deploy_error` | 部署失败/取消 | `error`/`message`, `exitCode`（-1 为取消） |

### 创建执行请求体

```json
{
  "script_id": "script_xxx"
}
```

### 执行记录响应

```json
{
  "id": "exec_xxx",
  "script_id": "script_xxx",
  "server_id": "srv_xxx",
  "script_name": "部署统一平台",
  "server_name": "560 部署服务器",
  "server_host": "192.168.5.60",
  "remote_command": "bash /opt/deploy/deploy.sh",
  "status": "running",
  "start_time": "2026-08-12T10:00:00",
  "end_time": null,
  "duration": null,
  "exit_code": null,
  "error_message": null,
  "trigger_by": "系统",
  "created_at": "2026-08-12T10:00:00"
}
```

---

## 四、架构与数据流

### 目录结构

```
backend/app/models/deploy_server.py     # 服务器 ORM 模型
backend/app/models/deploy_script.py     # 脚本 ORM 模型
backend/app/models/deploy_execution.py  # 执行记录 ORM 模型
backend/app/models/deploy_log.py        # 日志 ORM 模型
backend/app/schemas/deploy.py           # Pydantic 校验
backend/app/executors/deploy_executor.py  # SSH 执行器核心
backend/app/services/deploy_service.py  # 业务逻辑层
backend/app/routers/deploy.py           # API 路由层

frontend/src/types/deploy.ts            # 类型定义
frontend/src/api/deploy.ts              # API 封装
frontend/src/views/deploy/              # 4 个视图页面
```

### 执行数据流

```
用户点击【执行部署】
  → 前端 POST /api/deploy/executions → 创建执行记录（pending）
  → 前端 POST /api/deploy/executions/{id}/run
  → deploy_service.run_execution():
      1. 创建专用 threading.Thread
      2. 线程内打开 WebSocket 连接 → 广播 deploy_start
      3. 构造 DeployExecutor（paramiko SSHClient + invoke_shell）
      4. 轮询循环：
         - channel.recv(4096) → 累积 buffer
         - asyncio.run_coroutine_threadsafe(broadcast) → 实时推送日志
         - 遍历 expect_answers → 匹配 → channel.send(answer + "\n")
         - 匹配成功 → 广播 deploy_answer_sent
         - 每条日志同步落库 DeployLog
      5. 完成 → channel.recv_exit_status() → 广播 deploy_complete
      6. 异常/取消 → 广播 deploy_error
  → 前端 WebSocket 实时显示日志
  → 用户可随时关闭弹窗，历史日志在详情页回看
```

### 交互式应答规则结构

```json
[
  {
    "trigger": "password:",
    "triggerType": "contains",
    "answer": "my_password",
    "timeout": 30,
    "order": 0,
    "sensitive": true,
    "description": "输入 sudo 密码"
  },
  {
    "trigger": "继续.*[Y/n]",
    "triggerType": "regex",
    "answer": "Y",
    "timeout": 60,
    "order": 1,
    "sensitive": false,
    "description": "确认继续部署"
  }
]
```

### 关键复用点

| 复用组件 | 来源 | 用途 |
|---------|------|------|
| `ConnectionManager.manager.broadcast()` | `websocket/manager.py` | WebSocket 分组广播 |
| 专用线程 + `loop.run_in_executor` 模式 | `services/execution_service.py` | 避免 asyncio 死锁 |
| `generate_id(prefix)` | `utils/id_generator.py` | ID 生成（srv_/script_/exec_/log_） |
| Fernet 加解密 | `services/device_sim_service.py` | 密码加密存储 |
| `WebSocketClient` | `utils/websocket.ts` | 前端 WebSocket 连接 |
| Axios 封装 | `utils/request.ts` | HTTP 请求（timeout 300s） |

---

## 五、核心实现细节

### 5.1 SSH 执行器（deploy_executor.py）

- **连接**：`paramiko.SSHClient` + `AutoAddPolicy` + 密码/密钥认证
- **PTY**：`channel.invoke_shell(term='xterm', get_pty=True)` — 脚本依赖 `isatty()` 时必需
- **轮询**：单线程循环，`channel.recv(4096)` 累积 buffer，`time.sleep(0.05)` 防忙等
- **应答匹配**：按 `order` 排序遍历未匹配规则，`contains` 或 `re.search` 匹配 buffer，命中后 `channel.send(answer + "\n")`
- **完成检测**：`channel.exit_status_ready()` → `recv_exit_status()`（主）；命令 timeout 为 fallback
- **取消**：`cancel()` 置 `_cancelled=True` 并 `channel.close()` 强制退出
- **清理**：`close()` 关闭 channel + transport

### 5.2 密码安全

- 密码在数据库中以 `password_encrypted` 字段存储（Fernet 加密）
- 前端编辑时密码字段留空表示不修改
- 敏感应答在日志中以 `******` 显示（`is_sensitive=True`）
- 前端编辑器中敏感应答使用 `type="password" show-password`

### 5.3 执行状态流转

```
pending → running → completed
                  → failed
                  → cancelled
```

---

## 六、当前数据状态

| 内容 | 状态 | 备注 |
|------|------|------|
| 后端 SSH 执行器 | ✅ 完成 | paramiko + PTY + 交互应答 + cancel |
| 后端业务服务 | ✅ 完成 | CRUD + 执行编排 + WebSocket 广播 |
| 后端 API 路由 | ✅ 19 条 | 全部注册到 main.py，含 WebSocket |
| 后端数据模型 | ✅ 4 个表 | deploy_servers/scripts/executions/logs |
| 前端 API 封装 | ✅ 完成 | deploy.ts 中 18 个方法 |
| 前端 4 个页面 | ✅ 完成 | Servers/Scripts/Executions/ExecutionDetail |
| 前端侧边栏菜单 | ✅ 完成 | 3 个子菜单项 |
| 前端路由 | ✅ 完成 | 4 个子路由，懒加载 |
| 前端 TypeScript | ✅ 通过 | vue-tsc --noEmit 无错误 |
| 前端构建 | ✅ 通过 | npm run build 37s，无报错 |
| 后端导入 | ✅ 通过 | 所有模块可正常 import |
| 需求文档 | ✅ 2 个 | PRD + 计划执行 |

---

## 七、下次会话建议

### 待办（按优先级）

| 优先级 | 待办 | 说明 |
|--------|------|------|
| **P0** | 后端启动验证 | 启动后端服务，检查 `/docs` 出现所有 19 条 deploy 路由，DB 自动建表 |
| **P0** | 端到端冒烟测试 | 新增服务器 → 测试连接 → 创建脚本（含 2-3 条应答规则）→ 执行部署 → 观察实时日志 → 完成状态 |
| **P1** | 边界场景测试 | 连接失败（错误凭据）、脚本超时、未匹配提示（等 timeout 后继续）、非零退出码、执行中取消 |
| **P1** | 多服务器扩缩容 | 当前脚本关联单服务器，未来可扩展为多目标批量部署 |
| **P2** | 部署模板 | 预置常用部署脚本模板（如 Nginx 部署、Jar 包部署、Docker 部署） |
| **P2** | 执行计划 | 支持定时执行、依赖链执行（脚本 A 成功后才执行脚本 B） |
| **P3** | 部署历史统计 | 成功率趋势图、平均耗时统计、失败原因分析 |

### 踩坑记录

| # | 现象 | 根因 | 正确做法 |
|---|------|------|---------|
| D1 | `form.expectAnswers` 可能 undefined 导致 TS18048 | `DeployScriptCreate.expectAnswers` 是可选字段 | `form` 类型用 `Required<Pick<DeployScriptCreate, ...>>` 使 expectAnswers 必选 |
| D2 | `{ id: string }` 不能赋值给 `DeployExecution` | `openDetail({ id })` 只传了 id 但类型需 15+ 字段 | 单独创建 `openDetailById(id: string)` 函数 |
| D3 | `formatTime` 参数类型不匹配 | `execution.startTime` 是 `string\|null` 但 `formatTime` 期望 `string` | 参数类型改为 `string \| null \| undefined` |
| D4 | `filename` 声明但未使用 | `FunctionalReport.vue` 中 `getReportFileName` 赋值后未使用 | 移除未使用变量，直接内联调用 |

---

## 八、启动与验证

```bash
# 后端
cd backend
pip install -r requirements.txt
uvicorn app.main:app --reload --port 8001

# 前端
cd frontend
npm run dev

# 访问
# 前端: http://localhost:3000/deploy/servers
# API 文档: http://localhost:8001/docs（搜 deploy 标签）
# 健康检查: http://localhost:8001/health

# 端到端冒烟测试步骤
# 1. 新增 SSH 服务器（如 192.168.5.60 ubains/Ubains@123）
# 2. 点击"测试连接"验证连通性
# 3. 新建脚本指向目标服务器（如 `bash /opt/deploy/test.sh`），配置 2-3 条 expect_answers
# 4. 点击【执行部署】→ 观察实时日志流、自动应答发送、完成状态
# 5. 验证边界：连接失败、超时、非零退出码、执行中取消
```

---

## 九、文件完整清单

### 后端新增（8 个文件）

```
backend/app/models/deploy_server.py
backend/app/models/deploy_script.py
backend/app/models/deploy_execution.py
backend/app/models/deploy_log.py
backend/app/schemas/deploy.py
backend/app/executors/deploy_executor.py
backend/app/services/deploy_service.py
backend/app/routers/deploy.py
```

### 后端修改（3 个文件）

```
backend/app/main.py              — 注册 deploy 路由
backend/app/models/__init__.py   — 导入 4 个新模型
backend/requirements.txt         — 新增 paramiko==3.4.0
```

### 前端新增（7 个文件）

```
frontend/src/types/deploy.ts
frontend/src/api/deploy.ts
frontend/src/views/deploy/index.vue
frontend/src/views/deploy/DeployServers.vue
frontend/src/views/deploy/DeployScripts.vue
frontend/src/views/deploy/DeployExecutions.vue
frontend/src/views/deploy/DeployExecutionDetail.vue
```

### 前端修改（2 个文件）

```
frontend/src/App.vue              — 侧边栏新增"自动化部署测试"菜单
frontend/src/router/index.ts      — 新增 /deploy 路由组
```

### 文档（2 个文件）

```
Docs/PRD/需求文档/部署运维/_PRD_需求文档_自动化部署测试模块.md
Docs/PRD/需求文档/部署运维/_PRD_需求文档_自动化部署测试模块_计划执行.md
```

---

*本文档由自动化部署测试开发窗口生成，供下一次会话快速恢复上下文。其他窗口的交接见 `HANDOFF.md`（主文档）、`HANDOFF_功能测试报告.md`、`HANDOFF_安全测试.md`、`HANDOFF_设备模拟.md` 等。*