# 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":""} → 响应 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 技能脚本
(demand-assessor/tgassist) participant ZT as zentao 后端 participant DB as MySQL (zt_*) Note over Skill: .claude/ai_token.txt
自动读 ai 永久 token Skill->>ZT: ① POST /zt-story-expand/saveOrUpdate
(W 指标 + 验收标准 MD) ZT->>DB: upsert zt_story_expand(按 story_id) Skill->>ZT: ② POST /zt-task/aiBatchAdd
(拆分 devel/test 任务) ZT->>DB: insert zt_task × N(跳过重复)
+ zt_action 留痕(任务级+需求级) Skill->>ZT: ③ POST /common/uploadBind
(PRD/审查报告/日志等 MD 文件) ZT->>DB: 刷新主表 url 字段 → 插 zt_file
+ 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 事实优先)。