# PRD — 压测字段唯一性配置

> **版本**: v1.0
> **日期**: 2026-08-19
> **状态**: 待实现
> **关联 PRD**: `_PRD_bodyTemplate动态变量替换与响应捕获.md`

---

## 1. 背景与问题

### 1.1 当前痛点

性能测试中，部分 API 的请求体字段要求**业务唯一性**（如 `templateName`、`messageName`、`topicName` 等），同一值不可重复提交。当前系统的 bodyTemplate 机制虽支持 `{__RANDOM_NAME_8__}` 等占位符，但存在以下问题：

1. **并发模式下所有请求解析出相同值**：`{__RANDOM_NAME_8__}` 在模板解析时一次性替换，所有并发请求获得相同随机值 → 第一个请求成功，后续请求因唯一性约束失败
2. **无结构化配置**：用户无法在任务中声明"哪些字段需要唯一"，只能手动在 bodyTemplate 中写占位符，但占位符不支持按请求序号递增
3. **curl 导入后无唯一性标记**：从 curl 导入任务时，系统不知道哪些字段有唯一性约束，用户需手动编辑 bodyTemplate

### 1.2 用户需求

> 用户原话：*"新建任务弹窗这里没办法设置哪些字段需要保持唯一性"*

在新建/编辑性能测试任务时，能够**声明请求体中哪些字段需要按请求自动唯一化**，执行时系统自动为每个请求生成该字段的唯一值，确保并发压测不会因字段重复而失败。

### 1.3 适用场景

| 场景 | 示例字段 | 说明 |
|------|---------|------|
| 新建会议 | `messageName` | 会议名称不可重复 |
| 新建模板 | `templateName` | 模板名称不可重复 |
| 新建话题 | `topicList[].topicName` | 话题名称不可重复 |
| 其他唯一性字段 | 任意 JSON Path 定位的字段 | 业务自定义 |

---

## 2. 需求范围

### 2.1 核心功能

1. **任务级 `unique_fields` 配置**：新建/编辑任务时，可配置一个或多个需要唯一化的字段
2. **每个字段可指定唯一化策略**：
   - `suffix`（默认）：追加 `_req_{request_index}` 或 `_{random_8}` 后缀
   - `template`：使用自定义模板替换（如 `{__RANDOM_NAME_8__}`）
3. **执行时自动唯一化**：在 bodyTemplate 解析**之后**，对已配置的字段按请求序号生成唯一值
4. **curl 导入时推断**：导入 curl 后，用户可手动标记需要唯一化的字段

### 2.2 非功能性需求

- 唯一化在 bodyTemplate 解析后执行，不修改 bodyTemplate 本身
- 兼容 `body`（静态 body）和 `body_template`（动态模板）两种模式
- 不影响已有的 bodyTemplate 占位符替换逻辑
- 唯一化字段支持 JSON Path 表达式（如 `$.templateName`、`$[0].topicList[0].topicName`）

### 2.3 不在此范围

- 不涉及数据库唯一约束校验
- 不涉及 API 返回的重复字段错误自动识别
- 不涉及跨任务唯一性（同一任务内唯一即可）

---

## 3. 设计方案

### 3.1 数据模型

```python
class UniqueFieldRule(BaseModel):
    """唯一性字段规则"""
    field: str           # JSON Path 定位字段，如 "$.templateName" 或 "templateName"
    strategy: str = "suffix"  # 唯一化策略: "suffix" | "template"
    template: Optional[str] = None  # 当 strategy="template" 时使用
```

### 3.2 字段变更

**PerformanceTask 模型**（新增字段）：

| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `unique_fields` | JSON | `[]` | 唯一性字段规则列表 |

**PerformanceTaskCreate / Update / Response**（同步新增）：

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `unique_fields` | `Optional[List[UniqueFieldRule]]` | 否 | 唯一性字段配置 |

### 3.3 执行器唯一化逻辑

在 `performance_executor.py` 的 `_send_request()` 或 `_worker()` 中，在 bodyTemplate 解析完成后、签名之前，插入唯一化步骤：

```
bodyTemplate 解析 → 得到 resolved_body
    ↓
对 resolved_body 中每个 unique_field 做唯一化处理
    ↓
用处理后的 body 做签名 → 发送请求
```

**唯一化策略**：

| 策略 | 行为 | 示例（request_index=5） |
|------|------|------------------------|
| `suffix` | 原值 + `_req_{index}` | `"测试模板"` → `"测试模板_req_005"` |
| `template` | 用 `{__RANDOM_NAME_8__}` 等替换 | `"测试模板"` → `"xYzAbCdE"` |

### 3.4 唯一化时机

```
_send_request() 内部流程（修改后）：
1. _resolve_body(task_dict, body, ...)  → 解析 bodyTemplate 占位符
2. 对 resolved_body 应用 unique_fields 唯一化  ← 新增步骤
3. _build_headers(..., body_for_sign=resolved_body)  → 签名
4. 发送 HTTP 请求
5. _capture_response(...)  → 捕获响应
```

### 3.5 前端交互

**新建/编辑任务弹窗** → 新增「唯一性字段」配置区域：

```
┌─ 唯一性字段（可选）─────────────────────────────────────┐
│  [+ 添加字段]                                           │
│  ┌─ 字段1 ───────────────────────────────────────────┐ │
│  │  JSON Path: [templateName          ] ▼ 策略: [suffix]│ │
│  │  (支持 $.templateName 或直接字段名)                  │ │
│  └────────────────────────────────────────────────────┘ │
│  ┌─ 字段2 ───────────────────────────────────────────┐ │
│  │  JSON Path: [topicList[0].topicName] ▼ 策略: [suffix]│ │
│  └────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
```

**curl 导入后**：解析 body 中所有字符串字段，推荐用户标记唯一性。

---

## 4. 边界情况

| 场景 | 行为 |
|------|------|
| `unique_fields` 为空数组 | 不执行唯一化，行为与当前一致 |
| 字段在 body 中不存在 | 静默跳过，不报错 |
| 字段值本身已包含 `_req_` 后缀 | 追加新后缀（`xxx_req_1` → `xxx_req_1_req_005`）— 用户需注意 |
| 并发模式 + suffix 策略 | 每个请求独立调用 `_apply_unique()`，request_index 递增 |
| body 为数组 `[{...}]` | JSON Path 支持 `$[0].fieldName` 定位数组元素 |
| 使用 `template` 策略但 template 为空 | 回退使用 `suffix` 策略 |

---

## 5. 验收标准

1. ✅ 新建任务时可添加多个唯一性字段
2. ✅ 编辑任务时可修改/删除唯一性字段
3. ✅ curl 导入后 body 字段可被标记为唯一性字段
4. ✅ 执行时每个请求的指定字段值不同（用 `suffix` 策略验证）
5. ✅ 结合 bodyTemplate 的 `{__RANDOM_NAME_8__}` 仍正常工作
6. ✅ 后端兼容旧任务（`unique_fields` 为空，行为不变）
7. ✅ 前端 `npm run build` 无类型错误
8. ✅ 端到端验证：curl 导入 → 标记唯一字段 → 执行 → 全部成功

---

## 6. 相关文档

- `_PRD_bodyTemplate动态变量替换与响应捕获.md` — bodyTemplate 基础机制
- `_PRD_从curl自动生成压测任务.md` — curl 导入机制
- `HANDOFF_性能测试.md` — 当前进度

---

*本文档由 Claude Code 生成，遵循 PRD → 计划执行 → 代码的工作流。*