Files

345 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AI 交互接口文档 —— 禅道 AI SOP 改造(二期)
> **版本**:v1.0 | **日期**:2026-08-06 | **关联改动**:CHG-039 ~ CHG-070(鉴权落地 CHG-061)
> **验证状态**:✅ 已验证(全部字段/分支/错误文案均取自运行代码实证,非推测)
> **证据位置**:见文末「证据映射表」;单测 24 绿、8086 三×三鉴权矩阵实测通过(dev_log CHG-061)
> **适用范围**:AI 框架通道(demand-assessor / pmassist / tgassist 等技能脚本)与 zentao 后端的全部交互接口
---
## 1. 通用约定
### 1.1 Base URL
| 环境 | Base URL | 说明 |
|---|---|---|
| 本地测试 | `http://127.0.0.1:8085/zentao` | 框架脚本(submit_assessment.py / upload_md.py)默认地址(CHG-061 拍板"别用正线的 url") |
| 测试库直连验证 | `192.168.1.161:3306/zentao_dev` | DB 回读校验用,非接口地址 |
| 生产 | `http://192.168.1.105:8015/zentao` | ⚠️ [ASSUMPTION] 端口 8015 见 dev_log CHG-070"发布 8015 即可生效";主机地址以部署实为准 |
- 所有路径均含上下文根 `/zentao`(部署于域名根路径)。
- 字符集 UTF-8;JSON 接口 `produces = application/json; charset=UTF-8`。
### 1.2 鉴权(CHG-061 落地)
- 请求头:**`Authorization: {token}`**(JWT,由 `JwtAuthenticationFilter` 解析,写入 `RiskUserThreadLocal`)。
- token 获取(人工/调试用):
```
POST /zentao/zt-user/login
Content-Type: application/json
{"account":"admin","password":"<md5(密码)>"}
→ 响应 data 即 token
```
- **AI 通道使用 ai 账户永久 token**(生成于 `.claude/ai_token.txt`,框架两脚本自动携带,无需手工管理)。
- token 缺失或无效:过滤器直接返回 `{"code":-1,"message":"请登录"}`,不进入业务层。
**接口级权限矩阵**:
| 接口 | 权限要求 | 越权响应 |
|---|---|---|
| `/zt-story-expand/saveOrUpdate` | **仅 ai 账户 token** | `code:-1` "该接口仅AI框架通道可用(需ai账户token)" |
| `/zt-task/aiBatchAdd` | **仅 ai 账户 token** | `code:-1` "aiBatchAdd仅AI框架通道可用(需ai账户token)" |
| `/common/uploadBind` | **任意登录态**(AI 带 ai token;UI 带用户 token) | `code:-1` "请登录(上传需携带有效token)" |
### 1.3 统一响应结构
```json
{ "code": 0, "message": "成功", "data": { } }
```
| code | 含义 | 触发 |
|---|---|---|
| `0` | 成功 | 正常返回(data 可为 null) |
| `-1` | 失败 | 业务校验失败(BusinessException,message 为具体原因);文件为空;未登录 |
| `-2` | 重复添加 | 框架保留码,本三接口未使用 |
| `401` | 请登录 | 框架保留码;实际未登录返回 `-1` + "请登录"(过滤器写死) |
### 1.4 AI 框架典型调用时序
```mermaid
sequenceDiagram
participant Skill as AI 技能脚本<br/>(demand-assessor/tgassist)
participant ZT as zentao 后端
participant DB as MySQL (zt_*)
Note over Skill: .claude/ai_token.txt<br/>自动读 ai 永久 token
Skill->>ZT: ① POST /zt-story-expand/saveOrUpdate<br/>(W 指标 + 验收标准 MD)
ZT->>DB: upsert zt_story_expand(按 story_id)
Skill->>ZT: ② POST /zt-task/aiBatchAdd<br/>(拆分 devel/test 任务)
ZT->>DB: insert zt_task × N(跳过重复)<br/>+ zt_action 留痕(任务级+需求级)
Skill->>ZT: ③ POST /common/uploadBind<br/>(PRD/审查报告/日志等 MD 文件)
ZT->>DB: 刷新主表 url 字段 → 插 zt_file<br/>+ zt_action 动态
ZT-->>Skill: {"code":0,"data":zt_file 记录}
```
---
## 2. 接口一览
| # | 接口 | 方法 | 路径 | Content-Type | 鉴权 | 用途 | 关联 FR |
|---|---|---|---|---|---|---|---|
| 1 | AI 评估指标与验收标准提交 | POST | `/zentao/zt-story-expand/saveOrUpdate` | application/json | 仅 ai token | 七步评估结果(S/B/F(T)/G(A)/W)+ 验收标准 MD 落库 | FR-004 |
| 2 | AI 批量拆分任务 | POST | `/zentao/zt-task/aiBatchAdd` | application/json | 仅 ai token | 按任务清单批量建 devel/test 任务,防重跳过 | FR-006 |
| 3 | 文件上传并绑定业务对象 | POST | `/zentao/common/uploadBind` | multipart/form-data | 任意登录态 | 上传 MD 等文件,同步刷新主表 url 字段 | FR-002/005/008/010/011 |
---
## 3. 接口 1:AI 评估指标与验收标准提交
```
POST /zentao/zt-story-expand/saveOrUpdate
Content-Type: application/json
Authorization: {ai token}
```
**用途**:demand-assessor 七步评估完成后,将工作量指标与 AI 框架验收标准写入 `zt_story_expand`(按 `story_id` upsert)。生产侧由 `submit_assessment.py` 调用。
### 3.1 请求体字段(ZtStoryExpand)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `storyId` | Integer | ✅ | 需求 ID(zt_story.id)。**为空时服务端静默返回成功、不处理**(见 3.2 分支②) |
| `numberUnits` | Integer | 评估时✅ | 单元数量 S |
| `unitBusinessComplexity` | String | 评估时✅ | 单元业务复杂度 B(如 `"2.2"`) |
| `technicalComplexityCoefficient` | String | 评估时✅ | 技术复杂度系数 F(T)(如 `"1.4"`) |
| `aiEfficiencyCoefficient` | String | 评估时✅ | AI 效率系数 G(A)(如 `"0.55"`) |
| `evaluationTime` | BigDecimal | 评估时✅ | 评估工时 W(人日,如 `5.1`) |
| `workloadIndex` | String | 否 | 工作量指数(finished 结算时优先取库内已有值) |
| `aiParticipationRate` | String | 否 | AI 参与率(只存不算,口径待定) |
| `requirementStatus` | String | 否 | `inProgress`(默认)/ `finished`;**finished 触发月度工作量结算** |
| `requirementCompletionDegree` | String | 否 | 需求完成度 `"0"~"100"`;finished 时被强制置 `"100"` |
| `acceptanceCriteria` | String | 否 | AI 框架验收指标(Given/When/Then,MD 文本)。与老验收标准 `zt_storyspec.verify` 互不干扰(CHG-022) |
| `productPerson` / `developPerson` / `testPerson` | String | 否 | 产品/开发/测试人员(中文名) |
| `id` / `createTime` / `updateTime` / `createUser` / `updateUser` | — | 无需传 | 服务端维护(id 自增,时间戳自动写) |
| `storyTitle` / `createUserNickname` / `month` / `monthEvaluationTime` | — | 无需传 | 非数据库字段(查询展示/内部结算用) |
### 3.2 业务规则与分支
| # | 分支 | 行为 |
|---|---|---|
| ① | token 非 ai 账户 | 拒绝:`-1` "该接口仅AI框架通道可用(需ai账户token)" |
| ② | `storyId` 为空 | **静默返回 `code:0`**,不建不改(注意:不等于参数报错) |
| ③ | 该 storyId 无记录 | insert;`requirementStatus` 未传时默认 `inProgress`;create/updateTime=now |
| ④ | 已有记录且其状态为 `finished` | **拒绝**:"该需求已完成,不可再修改"(守卫:定稿后不可覆写) |
| ⑤ | 已有记录(非 finished) | update by id,updateTime=now |
| ⑥ | 本次提交 `requirementStatus=finished` | 强制完成度 `"100"`;写当月 `zt_story_month_workload`:增量 = 100 − 历史最高完成度;折算工时 = 工作量指数 × 增量 ÷ 100(2 位小数 HALF_UP);增量 ≤ 0 记 0 |
| ⑦ | 幂等性 | 同 storyId 重复提交 = 覆盖更新,不产生重复行 |
### 3.3 报文示例
```json
{
"storyId": 9130,
"numberUnits": 3,
"unitBusinessComplexity": "2.2",
"technicalComplexityCoefficient": "1.4",
"aiEfficiencyCoefficient": "0.55",
"evaluationTime": 5.1,
"workloadIndex": "5.1",
"developPerson": "魏冬霞",
"testPerson": "罗勇",
"acceptanceCriteria": "## AC-001\n- Given ...\n- When ...\n- Then ..."
}
```
### 3.4 响应
```json
{ "code": 0, "message": "成功", "data": null }
```
失败:`{ "code": -1, "message": "该接口仅AI框架通道可用(需ai账户token)" }` / `{ "code": -1, "message": "该需求已完成,不可再修改" }`
---
## 4. 接口 2:AI 批量拆分任务
```
POST /zentao/zt-task/aiBatchAdd
Content-Type: application/json
Authorization: {ai token}
```
**用途**:按任务清单为指定需求批量创建研发/测试任务;同需求下重名同类型任务自动跳过。生产侧由任务拆分流程(tasks.md → zentao)调用。
### 4.1 请求体字段(ZtTaskAiBatchDTO)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `storyId` | Integer | ✅ | 需求 ID;不存在则整批拒绝 |
| `tasks` | Array | ✅ 非空 | 任务项列表 |
| `tasks[].name` | String | ✅ | 任务名称(空则整批拒绝) |
| `tasks[].type` | String | ✅ | 仅 `devel`(开发)/ `test`(测试);其他值**整批拒绝** |
| `tasks[].assignedTo` | String | 否 | 指派人账号(zt_user.account);留痕时转中文昵称显示 |
| `tasks[].aiEvaluationTime` | Float | 否 | AI 评估工时 → 同时写入 `estimate` 与 `left`,`consumed=0` |
| `tasks[].planStartDate` | String | 否 | 预计开始 `yyyy-MM-dd` → `estStarted` |
| `tasks[].deadline` | String | 否 | 预计完成 `yyyy-MM-dd` → `deadline`,并写 `deadlineTime`(秒级时间戳) |
### 4.2 业务规则与分支
| # | 分支 | 行为 |
|---|---|---|
| ① | token 非 ai 账户 | 拒绝:`-1` "aiBatchAdd仅AI框架通道可用(需ai账户token)" |
| ② | `storyId` 空 / 需求不存在 / `tasks` 空 / 任一 name 空 / 任一 type 非 devel\|test / 日期格式错 | **整批拒绝**(BusinessException,事务回滚,一个都不建) |
| ③ | 防重 | 同需求下已存在 `name#type`(未删除)→ 跳过并记入 `skipped`;**批内重复同样防重**(建过的 key 即时入集合) |
| ④ | 创建字段 | `status=wait`、`openedby=ai`(token 身份)、`openeddate=now`、`estimate=left=aiEvaluationTime` |
| ⑤ | 留痕(CHG-059/060/062) | 任务级:`zt_action`(RW+XJ)每任务一条,与手工建任务同形状;需求级:**一批合并一条**(XQ+BJ),文案含个数、序号、各任务名称/类型/工时/指派中文名、跳过数 |
| ⑥ | 日期格式 | 非法日期整批拒绝:"日期格式错误,应为yyyy-MM-dd:{任务名}" |
### 4.3 报文示例
```json
{
"storyId": 9130,
"tasks": [
{"name": "二期 DDL×3 + 自测", "type": "devel", "assignedTo": "guoqibing",
"aiEvaluationTime": 8, "planStartDate": "2026-08-10", "deadline": "2026-08-11"},
{"name": "后端接口测试:uploadBind/aiBatchAdd", "type": "test", "assignedTo": "zhangfubin",
"aiEvaluationTime": 8, "planStartDate": "2026-08-12", "deadline": "2026-08-12"}
]
}
```
### 4.4 响应
```json
{
"code": 0,
"message": "成功",
"data": {
"created": 2,
"taskIds": [18565, 18566],
"skipped": ["二期 DDL×3 + 自测"]
}
}
```
- `created`:本次实际新建数;`taskIds`:新建任务 ID 列表;`skipped`:因重名同类型跳过的任务名列表。
- 全部重复时:`created:0`、`taskIds:[]`、`skipped` 全量 —— 仍返回 `code:0`(跳过不算失败)。
---
## 5. 接口 3:文件上传并绑定业务对象
```
POST /zentao/common/uploadBind
Content-Type: multipart/form-data
Authorization: {任意登录态 token}
```
**用途**:上传文件(AI 框架场景为 MD 文档)并一步绑定到业务对象:写磁盘 + 插 `zt_file` + **按 objectType 刷新主表访问链接字段** + 写动态留痕。生产侧由 `upload_md.py` 调用(默认本地 8085、自动带 ai token)。
### 5.1 表单字段(UploadDTO)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `file` | File | ✅ | 上传文件(空文件拒绝);服务端仅保留原扩展名,文件名为 `yyyyMMddHHmmss + UUID` |
| `objectType` | String | ✅ | 业务对象类型,**白名单 9 类**(见 5.2);不在白名单整体拒绝 |
| `objectId` | Integer | ✅ | 主表记录 ID(需求/会议);记录不存在则拒绝 |
| `title` | String | 否 | 文件标题;缺省取原始文件名(中文标题落库正确,CHG-061 已验证) |
| `reviewResult` | String | 否 | **仅 `objectType=aiCodeReview` 有效**:`pass` / `reject`,非空时同步写 `zt_story.code_review_status` |
### 5.2 objectType → 主表字段刷新映射(白名单)
| objectType | 含义 | 刷新主表字段 | 动态留痕 |
|---|---|---|---|
| `story` | PRD/需求文档 | `zt_story.prd_url` | XQ+BJ |
| `aiCodeReview` | 代码审查报告 | `zt_story.code_review_url`(+`code_review_status`,若传 reviewResult) | XQ+BJ |
| `aiWorkLog` | 工作日志 | `zt_story.work_log_url` | XQ+BJ |
| `aiDocUpdate` | AI 项目文档更新记录 | `zt_story.ai_doc_update_url` | XQ+BJ |
| `testCase` | 测试用例 | `zt_story.test_case_url` | XQ+BJ |
| `testReport` | 测试报告模版 | `zt_story.test_report_download_url` | XQ+BJ |
| `testReportSubmit` | 测试报告提交 | `zt_story.test_report_submit_url` | XQ+BJ |
| `testOther` | 其他测试文档 | `zt_story.test_other_url` | XQ+BJ |
| `meeting` | 会议纪要 | `zt_meeting.url` | MEET+BJ |
> FileTypes 枚举另有 task/bug/userStory 等 6 个 code,但 **uploadBind 不支持**——传入会拒绝:"uploadBind不支持的objectType:{type}"。
### 5.3 业务规则与分支
| # | 分支 | 行为 |
|---|---|---|
| ① | 无登录态 | `-1` "请登录(上传需携带有效token)" |
| ② | file 为空 | `-1` "失败" |
| ③ | objectType/objectId 为空 | `-1` "objectType/objectId不能为空" |
| ④ | objectType 非枚举值 | "不支持的objectType:{type}";是枚举但非白名单 → "uploadBind不支持的objectType:{type}" |
| ⑤ | objectId 记录不存在 | "需求不存在:{id}" / "会议不存在:{id}" |
| ⑥ | 执行顺序(事务) | **先校验并刷新主表 → 失败整体回滚不落盘**;再写磁盘 → 插 `zt_file` → 写 `zt_action`(文案含完整可访问 URL) |
| ⑦ | 落库字段 | `zt_file.addedby` = token 身份;`pathname`/`url` = 相对路径 `/zentao/img/{文件名}`(经前端源/代理可达,规避跨域);`size` 字节数;`extension` 原扩展名 |
| ⑧ | 多文件 | 同一 (objectType, objectId) 可多次上传,形成多份列表;主表 url 字段记录**最新一份**,前端列表取 `zt_file` 全集 |
### 5.4 调用示例
```bash
curl -X POST "http://127.0.0.1:8085/zentao/common/uploadBind" \
-H "Authorization: {ai token}" \
-F "file=@代码审查报告.md" \
-F "objectType=aiCodeReview" \
-F "objectId=9130" \
-F "title=代码审查报告-v1" \
-F "reviewResult=pass"
```
### 5.5 响应
```json
{
"code": 0,
"message": "成功",
"data": {
"id": 1234,
"title": "代码审查报告-v1",
"extension": ".md",
"size": 5321,
"pathname": "/zentao/img/20260806170215a1b2c3....md",
"url": "/zentao/img/20260806170215a1b2c3....md",
"objecttype": "aiCodeReview",
"objectid": 9130,
"addedby": "ai",
"addeddate": "2026-08-06 17:02:15",
"deleted": "0"
}
}
```
---
## 6. 失败分支汇总(排障速查)
| 现象 | code | message | 排查 |
|---|---|---|---|
| 未带 token / token 失效 | -1 | 请登录 | 检查 `Authorization` 头;ai token 见 `.claude/ai_token.txt` |
| 用人工 token 调 saveOrUpdate / aiBatchAdd | -1 | 仅AI框架通道可用(需ai账户token) | 换 ai token;这是设计守卫,非缺陷 |
| 需求已 finished 再提交指标 | -1 | 该需求已完成,不可再修改 | 生产 itsm 已有 finished 记录被此守卫拒绝(summary 2026-08-06),属按设计拦截 |
| saveOrUpdate 返回 0 但库里没数据 | 0 | 成功 | 检查是否漏传 `storyId`(分支 3.2② 静默成功) |
| aiBatchAdd 一个任务都没建 | -1 | (任一校验消息) | 整批拒绝机制:任一任务非法全部回滚;先修非法项 |
| aiBatchAdd 成功但 created=0 | 0 | 成功 | 全部命中防重,看 `skipped` |
| uploadBind 报类型不支持 | -1 | (uploadBind)不支持的objectType | 对照 5.2 白名单(9 类) |
| uploadBind 成功但页面看不到 | 0 | 成功 | 前端列表读 `zt_file`;检查 objectType/objectId 是否传对、前端是否按类型渲染 |
---
## 7. 证据映射表
| 章节 | 关键结论 | 证据来源 |
|---|---|---|
| 1.2 鉴权 | Authorization 头 JWT 解析、越权文案 | [CODE:codes/zentao/src/main/java/com/sa/zentao/conf/JwtAuthenticationFilter.java:41-66] [CODE:ZtStoryExpandServiceImpl.java:41-45] [CODE:ZtTaskServiceImpl.java:1360-1364] [CODE:CommonsController.java:129-132] |
| 1.3 响应结构 | Result/Code 枚举值 | [CODE:codes/zentao/src/main/java/com/sa/zentao/dao/Result.java] [CODE:codes/zentao/src/main/java/com/sa/zentao/dao/Code.java] [CODE:conf/GlobalExceptionHandler.java:28-32] |
| 3. 接口1 | 字段集/upsert/finished 守卫与结算 | [CODE:entity/ZtStoryExpand.java] [CODE:ZtStoryExpandServiceImpl.java:40-79,120-150] |
| 4. 接口2 | 字段/整批拒绝/防重/留痕形状 | [CODE:dao/ZtTaskAiBatchDTO.java] [CODE:ZtTaskServiceImpl.java:1357-1470] |
| 5. 接口3 | 白名单映射/事务顺序/落库字段 | [CODE:CommonsController.java:120-187] [CODE:ZtFileServiceImpl.java:74-154] [CODE:enums/FileTypes.java] [CODE:dao/UploadDTO.java] |
| 1.1/运行实证 | 8085 默认地址、token 自动携带、中文标题正确 | [RUNTIME:dev_log CHG-061 闭环记录] [RUNTIME:summary.md 2026-08-06] |
## 8. 假设与缺口
| 项 | 状态 | 说明 |
|---|---|---|
| 生产 Base URL | ⚠️ [ASSUMPTION] | 8015 端口见于 dev_log CHG-070;生产主机/域名以部署实为准,发布时确认 |
| `evaluationTime` 单位 | ✅ 已确认 | 人日(demand-assessor W 定义,summary 附录口径一致) |
| `deadlineTime` 精度 | ✅ 已验证 | 秒级时间戳(ZtTaskServiceImpl.java:1425) |
| ai 永久 token 过期策略 | ✅ 已确认 | 永久 token(CHG-061 决策,存 `.claude/ai_token.txt`) |
---
> 下一步(Check):本文档与 `outputs/dev_plan.md`、`06_test_docs/test_cases.md` §0 环境约定一致;如发现不一致以运行代码为准修正本文档(Runtime 事实优先)。