# PRD：安全测试定时任务模块

> **版本**：v1.0  
> **创建日期**：2026-08-19  
> **状态**：初稿  
> **维护者**：czj · **所属模块**：安全测试  
> **关联文档**：`_PRD_安全测试定时任务模块_计划执行.md`

---

## 一、需求背景与目标

### 1.1 背景

当前安全测试模块支持以下流程：
- ✅ 安全测试执行（OWASP API Security Top 10）
- ✅ 安全测试报告生成（Markdown 7 章节）
- ✅ 报告上传 ERP（DOCX → HTML → 测试单/项目资料/协作文档）
- ✅ ERP 任务创建（指派跟踪 → 修复 → 回归验证闭环）

但安全测试只能**手动**发起执行（执行中心选择模块 → 选择配置 → 执行）。当需要周期性安全扫描（如每周对被测系统做一次全量安全测试、每天跑一次高危漏洞回归验证）时，必须人工到点操作，无法自动化、无人值守。

UI 自动化测试模块已实现定时任务功能（`scheduled_tasks` 表 + 后台 asyncio 调度循环 + 前端列表页），安全测试需参考该模式补充定时任务模块。

### 1.2 目标

在安全测试模块中新增**定时任务**功能，提供以下能力：

1. **设置定时任务**：选择安全测试模块、选择安全测试配置、设置执行周期（按间隔/每天定时/每周定时）
2. **自动触发执行**：后台调度引擎到期自动创建安全测试执行并运行
3. **自动生成报告**：执行完成后自动生成 Markdown 安全测试报告
4. **定时任务管理**：任务列表、创建/编辑、启停、立即执行、运行历史、删除

### 1.3 范围

| 范围 | 包含 | 不包含 |
|------|------|--------|
| 定时任务管理 | 创建/编辑/删除/启停 | 继承/复制定时任务 |
| 周期设置 | 按间隔/每天/每周 | cron 表达式高级周期 |
| 自动触发 | 到期自动执行安全测试 | 任务失败重试/告警通知 |
| 执行冲突 | 到点时有执行在跑 → 跳过本次 | 任务排队/顺延执行 |
| 报告生成 | 执行完成后自动生成报告 | 报告自动上传 ERP/创建 ERP 任务 |
| 运行历史 | 查看该任务触发的执行记录 | 运行历史导出 |

---

## 二、现状分析与复用基础

| 现状 | 结论 |
|------|------|
| UI 定时任务已有 `ScheduledTask` 模型 + `scheduled_tasks` 表 | 复用模型，新增 `case_type` 和 `config_id` 字段区分 UI/安全 |
| 调调度引擎 `scheduler_service.py` 已实现轮询 + 触发 | 扩展 `run_task_once` 按 `case_type` 分流 |
| `SecurityService.create_execution()` 已支持 `config_id` + `module_ids`/`case_ids` | 安全定时任务复用现成接口创建执行记录 |
| 安全测试执行 `SecurityService.run_execution()` 已实现 | 定时任务直接复用执行引擎 |
| 安全测试报告 `SecurityReportService` 已实现 Markdown 生成 | 定时任务完成后自动调用生成报告 |
| 前端 `ScheduledTasks.vue` 已实现 UI 定时任务列表页 | 可参考该页面实现安全版定时任务页 |

---

## 三、需求描述

### 3.1 菜单入口

安全测试父菜单下新增子菜单**「定时任务」**：

| 菜单项 | 路由 |
|--------|------|
| 定时任务 | `/security/scheduled-tasks` |

### 3.2 定时任务列表页

展示所有**安全测试**定时任务，表格列：

| 列 | 说明 |
|----|------|
| 任务名称 | 用户自定义 |
| 执行模块 | 该任务选择的模块名称列表（标签组展示） |
| 测试配置 | 使用的安全测试配置名称 |
| 周期 | 人类可读周期描述，如「每 30 分钟」「每天 22:00」「每周一 22:00」 |
| 状态 | 启用/停用 开关 |
| 上次执行 | 最近一次运行开始时间 |
| 下次执行 | 计算出的下次触发时间 |
| 执行次数 | 累计执行次数 |
| 操作 | 立即执行 / 编辑 / 删除 |

### 3.3 创建/编辑定时任务（对话框）

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| 任务名称 | 文本 | 是 | 唯一标识，执行记录的 `trigger_by` 取该值 |
| 执行模块 | 多选下拉 | 是 | 数据源 `/api/modules?case_type=security`（安全测试模块） |
| 测试配置 | 下拉选择 | 是 | 数据源 `/api/security/config` 安全测试配置列表 |
| 周期模式 | 单选 | 是 | `interval`（按间隔）/ `daily`（每天定时）/ `weekly`（每周定时） |
| 间隔值 | 数字 | 模式=interval | 如 30 |
| 间隔单位 | 单选 | 模式=interval | `minutes` / `hours` / `days` |
| 执行时间 | 时间选择器 HH:MM | 模式=daily | 每天该时刻执行 |
| 星期 + 执行时间 | 多选星期 + 时间 | 模式=weekly | 每周选中日的该时刻执行 |
| 自动生成报告 | 开关 | 否 | 默认开启；执行完成后自动生成 Markdown 报告 |

### 3.4 立即执行

点击「立即执行」→ 立即收集该任务选中模块的安全测试用例 + 使用任务的测试配置 → 创建安全测试执行记录并运行 → 完成后生成报告。与手动执行中心效果一致，执行记录标记 `trigger_type=scheduled`、`trigger_by=任务名`。

### 3.5 后台调度引擎

**复用现有** `scheduler_service.py` 的调度机制，在此基础上扩展：

| 原有行为（UI 定时任务） | 扩展行为（安全测试定时任务） |
|------------------------|---------------------------|
| `collect_module_cases` 筛选 `case_type="ui"` 的用例 | 新增 `case_type="security"` 的分支 |
| 通过 `ExecutionService.create_execution()` 创建执行记录 | 通过 `SecurityService.create_execution()` 创建执行记录，传入 `config_id` |
| `run_execution()` 走 UI 执行器（Playwright） | 走 `SecurityService.run_execution()` 执行 |
| 生成 HTML 报告 | 生成 Markdown 报告 |
| 使用 UI 全局执行锁 | 不共享 UI 执行锁（安全测试无浏览器冲突），但需防同一任务重复触发 |

### 3.6 触发流程

```
到期任务 → 收集模块用例（case_type="security"）
   → 查询 TestCase where module_id ∈ 任务.module_ids AND status='active' AND case_type='security'
   → 若用例数为 0 → 记日志，重算下次执行，跳过本次
   → 通过 SecurityService.create_execution(config_id, module_ids/收集到的case_ids) 创建执行记录
   → 通过 SecurityService.run_execution(exec_id) 执行
   → 执行完成后：若 auto_report=True → SecurityReportService 生成 Markdown 报告
   → 更新任务 last_run_at / run_count / next_run_at
```

**执行冲突策略**：安全测试执行无浏览器冲突（不共享 UI 执行锁），但为防止同一任务短时间内重复触发，仍使用 `_running_tasks` 集合防重。同时，若已有安全测试执行在运行，到点时**跳过本次**（避免过度并发，沿用 UI 定时任务的保守策略）。

### 3.7 运行历史

每个定时任务运行都会产生一条执行记录（`trigger_type=scheduled`、`trigger_by=任务名`，可在安全测试报告中心查看）。定时任务页提供「运行记录」查看入口（抽屉），列出该任务的历史执行：执行时间、状态、通过/失败数、耗时。

### 3.8 删除任务

删除定时任务仅删除任务定义，**不影响**已产生的执行记录与报告。

---

## 四、数据模型设计

### 4.1 复用 `scheduled_tasks` 表，新增字段

在现有 `ScheduledTask` 模型上新增两个字段：

| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `case_type` | String(20) | `"ui"` | 用例类型：`ui` / `security` |
| `config_id` | String(64) | nullable | 安全测试配置 ID（`case_type="security"` 时必填） |

**现有字段**（复用，无需改动）：

| 字段 | 说明 |
|------|------|
| `module_ids` | 选中模块 ID 列表（安全测试也复用此字段） |
| `schedule_type` / `interval_value` / `interval_unit` / `run_time` / `weekdays` | 周期设置 |
| `auto_report` / `enabled` / `last_run_at` / `next_run_at` / `run_count` | 运行状态 |
| `name` | 任务名称 |

### 4.2 不新增表

不新增独立数据表，所有定时任务统一存储在 `scheduled_tasks` 表中，通过 `case_type` 字段区分 UI 自动化与安全测试。

---

## 五、接口设计

### 5.1 安全测试定时任务管理 API（新增）

**路由文件**：`backend/app/routers/security_scheduled_tasks.py`  
**前缀**：`/api/security/scheduled-tasks`

| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/security/scheduled-tasks` | 获取安全测试定时任务列表（筛选 `case_type=security`） |
| POST | `/api/security/scheduled-tasks` | 创建安全测试定时任务（自动设 `case_type=security`） |
| PUT | `/api/security/scheduled-tasks/{id}` | 更新安全测试定时任务 |
| DELETE | `/api/security/scheduled-tasks/{id}` | 删除安全测试定时任务 |
| POST | `/api/security/scheduled-tasks/{id}/run` | 立即执行安全测试定时任务 |
| POST | `/api/security/scheduled-tasks/{id}/toggle` | 启用/停用 |
| GET | `/api/security/scheduled-tasks/{id}/runs` | 运行历史 |

### 5.2 调度引擎扩展

**文件**：`backend/app/services/scheduler_service.py`  
- `run_task_once()`：按 `case_type` 分流
  - `case_type="ui"`：现有逻辑（不变）
  - `case_type="security"`：走安全测试执行路径，使用 `SecurityService` + `SecurityReportService`
- `collect_module_cases()`：筛选条件改为 `case_type` 参数

### 5.3 后端注册

`backend/app/main.py`：注册 `security_scheduled_tasks` 路由，前缀 `/api/security/scheduled-tasks`

---

## 六、变更范围

| 层面 | 变更内容 | 涉及文件 |
|------|---------|---------|
| **后端模型** | ScheduledTask 新增 `case_type` / `config_id` 字段 | `backend/app/models/scheduled_task.py`（修改） |
| **后端 Schema** | 新增 `case_type` / `config_id` 字段 | `backend/app/schemas/scheduled_task.py`（修改） |
| **后端路由** | 安全测试定时任务 CRUD + 立即执行 + 运行历史 | `backend/app/routers/security_scheduled_tasks.py`（新建） |
| **后端路由** | 注册新路由 | `backend/app/main.py`（修改） |
| **后端服务** | 调度引擎扩展安全测试执行路径 | `backend/app/services/scheduler_service.py`（修改） |
| **后端数据库** | `_ensure_columns` 补齐 `case_type` / `config_id` 字段 | `backend/app/database.py`（修改） |
| **前端 API** | 安全测试定时任务 API 封装 | `frontend/src/api/securityScheduledTasks.ts`（新建） |
| **前端页面** | 安全测试定时任务列表页 | `frontend/src/views/security/ScheduledTasks.vue`（新建） |
| **前端路由** | 新增 `/security/scheduled-tasks` 路由 | `frontend/src/router/index.ts`（修改） |
| **前端菜单** | 安全测试父菜单新增「定时任务」子菜单 | `frontend/src/App.vue`（修改） |

---

## 七、验收标准

1. ✅ 侧边栏「安全测试」下显示「定时任务」子菜单，可进入列表页
2. ✅ 可创建安全测试定时任务：选择多个安全测试模块、选择测试配置、设置周期
3. ✅ 列表正确显示任务名、执行模块、测试配置、周期、状态、上次/下次执行时间
4. ✅ 启用任务后到点自动触发安全测试执行，执行记录 `trigger_type=scheduled`、`trigger_by=任务名`
5. ✅ 执行完成后自动生成 Markdown 报告，出现在安全测试报告中心
6. ✅ 立即执行按钮可手动触发一次，产生执行记录 + 报告
7. ✅ 运行历史列出该任务的历史执行（时间/状态/通过/失败/耗时）
8. ✅ 停用任务后不再触发；删除任务不影响已产生的执行记录与报告
9. ✅ 服务重启后，启用的定时任务自动恢复调度（读取 DB 中的 `next_run_at`）
10. ✅ UI 自动化定时任务不受影响（`case_type` 隔离，各自独立管理）

---

## 八、风险与注意事项

| 风险 | 说明 | 缓解 |
|------|------|------|
| `scheduled_tasks` 表新增字段在 MySQL 生产库自动建列 | `init_db` 的 `_ensure_columns` 会补齐字段 | 确保 `database.py` 的 `columns_to_add` 列表包含新增字段 |
| 安全测试执行耗时较长（全量 67 用例约 3-5s） | 异步执行，调度循环不阻塞 | 触发用 `asyncio.create_task` 异步，不阻塞 30s 轮询 |
| 安全测试与 UI 测试同时执行 | 两者执行器独立，不共享执行锁 | 无冲突风险，但需注意服务器资源消耗 |
| 同一任务短周期内重复触发 | 调度 30s 轮询粒度 + `_running_tasks` 防重集合 | 双保险，避免重复执行 |
| 无用户权限系统 | 定时任务创建/启停无鉴权 | 与现有平台一致，仅内网使用 |

---

## 九、后续规划（本次不实现）

- 定时任务失败通知（钉钉/邮件告警）
- cron 表达式高级周期
- 任务级超时控制
- 多次连续失败自动停用

---

*本文档由 Claude Code 生成，遵循项目 PRD 文档规范。*