zizi 096020fa0a feat(wave3-phaseA): project 侧跨主线收口(publish 唯一化+ProjectApi seam+GAP-4+治理+V6V7 G0)
Phase A 串行收口(主 agent 独占改黄金模块,11 单测绿),为 Phase B 并行建模块铺底:
- R1 publish 唯一化:submitPublish void→ProjectPublishRespVO{admitted,gates};门禁收集不抛、
  block→admitted=false 不改状态机;compliance gate 留 Phase C 接入 seam(TODO,不 import)
- R2 ProjectApi seam 单点定稿:+getCurrentVersionId(GAP-3)/+createProject(写类RPC 显式 creatorUserId)
- GAP-4:events.schema.json 信封 envelope/user 由 snake→camelCase(与 telemetry/前端 SDK 对齐,破坏性窗口收敛)
- R4 治理:登记 studio=112/Flyway V8(README §4/§1/§2 + CLAUDE.md;与前端仓 game-studio 区分)
- R6 G0:V6/V7 集中复制到 yudao-server/db/migration(diff-identical)
- project.yaml publish 响应同步结构化;D2 锚点 reviewProject/game_review_record 未动

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 01:37:06 +00:00

229 lines
9.1 KiB
YAML
Raw 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.

openapi: 3.0.3
# 契约 #1 API | 模块:project(黄金模板)| owner:WS1 lead 主笔,全员 review
# 端:/app-api(产品端 game-studio,用户 Token+DataPermission) /admin-api(管理端 game-admin,RBAC);前缀由 yudao 框架按 controller.app/admin 包名自动添加
# 错误码段:project = 1-100-***-***
# 响应统一 Yudao CommonResult 信封:{ code, data, msg };code=0 成功
info:
title: 绘境AI project 模块 API
version: 1.0.0
description: 游戏项目 CRUD / 状态机 / 版本 / 草稿 / 发布编排 / 审核 / 专区。前端据此 vite-plugin-mock 自动生成 mock。
servers:
- url: http://localhost:48080
description: 本地(Swagger/Knife4j http://localhost:48080/doc.html)
paths:
/app-api/project/my:
get:
tags: [app-project]
summary: 我的项目列表(创作者只见自己数据)
parameters:
- { name: status, in: query, required: false, schema: { type: integer }, description: 按状态机筛选 }
- { name: pageNo, in: query, required: false, schema: { type: integer, default: 1 } }
- { name: pageSize, in: query, required: false, schema: { type: integer, default: 10 } }
responses:
'200':
description: 成功
content:
application/json:
schema: { $ref: '#/components/schemas/CommonResultProjectPage' }
/app-api/project:
post:
tags: [app-project]
summary: 创建项目(初始 status=0 草稿)
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/ProjectCreateReqVO' }
responses:
'200':
description: 返回新建项目 ID
content:
application/json:
schema: { $ref: '#/components/schemas/CommonResultLong' }
/app-api/project/{id}:
get:
tags: [app-project]
summary: 项目详情
parameters:
- { name: id, in: path, required: true, schema: { type: integer, format: int64 } }
responses:
'200':
description: 成功
content:
application/json:
schema: { $ref: '#/components/schemas/CommonResultProject' }
/app-api/project/{id}/draft:
put:
tags: [app-project]
summary: 保存草稿(仅 status=0 可改;标题/简介/封面/标签/适龄)
parameters:
- { name: id, in: path, required: true, schema: { type: integer, format: int64 } }
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/ProjectDraftReqVO' }
responses:
'200':
description: 成功
content:
application/json:
schema: { $ref: '#/components/schemas/CommonResultBoolean' }
/app-api/project/{id}/publish:
post:
tags: [app-project]
summary: 提交发布(发布前门禁聚合 → 进审核 BPM;统一发布编排 compliance→runtime→feed 失败回滚 ←G6)
description: >-
归属/草稿态为安全前置,失败抛异常(code≠0)。发布前门禁聚合为 gates:全部通过则 admitted=true 并置 status=1 审核中;
任一拦截则 admitted=false 且不改状态机(无副作用),创作者据 gates 修复后重提。
parameters:
- { name: id, in: path, required: true, schema: { type: integer, format: int64 } }
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/ProjectPublishReqVO' }
responses:
'200':
description: 成功(含发布前门禁聚合结果 admitted + gates)
content:
application/json:
schema: { $ref: '#/components/schemas/CommonResultProjectPublish' }
/admin-api/project/review/page:
get:
tags: [admin-project]
summary: 审核队列(管理端 RBAC)
parameters:
- { name: status, in: query, required: false, schema: { type: integer }, description: 默认取 status=1 审核中 }
- { name: pageNo, in: query, required: false, schema: { type: integer, default: 1 } }
- { name: pageSize, in: query, required: false, schema: { type: integer, default: 10 } }
responses:
'200':
description: 成功
content:
application/json:
schema: { $ref: '#/components/schemas/CommonResultProjectPage' }
/admin-api/project/review:
post:
tags: [admin-project]
summary: 审核决策(通过/拒绝/下架;锁风门 Gate 二态聚合)
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/ReviewReqVO' }
responses:
'200':
description: 成功
content:
application/json:
schema: { $ref: '#/components/schemas/CommonResultBoolean' }
components:
schemas:
# ---- Yudao CommonResult 信封 ----
CommonResultBoolean:
type: object
properties:
code: { type: integer, description: '0=成功,非0=错误码 1-100-***-***' }
data: { type: boolean }
msg: { type: string }
CommonResultLong:
type: object
properties:
code: { type: integer }
data: { type: integer, format: int64, description: 新建项目 ID }
msg: { type: string }
CommonResultProject:
type: object
properties:
code: { type: integer }
data: { $ref: '#/components/schemas/ProjectRespVO' }
msg: { type: string }
CommonResultProjectPublish:
type: object
properties:
code: { type: integer }
data: { $ref: '#/components/schemas/ProjectPublishRespVO' }
msg: { type: string }
CommonResultProjectPage:
type: object
properties:
code: { type: integer }
data:
type: object
properties:
list: { type: array, items: { $ref: '#/components/schemas/ProjectRespVO' } }
total: { type: integer, format: int64 }
msg: { type: string }
# ---- 请求/响应 VO ----
ProjectCreateReqVO:
type: object
required: [title, templateId]
properties:
title: { type: string, maxLength: 60, description: 标题 }
templateId: { type: string, description: 玩法模板 ID }
ProjectDraftReqVO:
type: object
properties:
title: { type: string, maxLength: 60 }
summary: { type: string, maxLength: 500 }
coverUrl: { type: string }
tags: { type: array, items: { type: string }, maxItems: 10 }
ageRating: { type: string, enum: [all, '8+', '12+', '16+'] }
ProjectPublishReqVO:
type: object
required: [versionId, launchZoneId]
properties:
versionId: { type: integer, format: int64, description: 发布的版本 ID }
launchZoneId: { type: integer, format: int64, description: 发布去向专区(launchZone ←G1) }
GateResultVO:
type: object
required: [key, pass]
properties:
key: { type: string, description: '门禁键(稳定标识,如 age;Phase C 增 compliance)' }
label: { type: string, description: 门禁中文标签(展示用) }
pass: { type: boolean, description: 是否通过 }
code: { type: string, description: '拦截时错误码字符串(pass=true 时为 null;复用对应模块错误码段,不新增)' }
message: { type: string, description: 拦截时提示文案(pass=true 时为 null) }
ProjectPublishRespVO:
type: object
required: [admitted, gates]
properties:
admitted: { type: boolean, description: '是否准入(全部门禁通过=true;任一拦截=false 且不改状态机)' }
gates: { type: array, items: { $ref: '#/components/schemas/GateResultVO' }, description: 发布前门禁逐项结果 }
ReviewReqVO:
type: object
required: [gameId, versionId, decision]
properties:
gameId: { type: integer, format: int64 }
versionId: { type: integer, format: int64 }
decision: { type: integer, enum: [1, 2, 3], description: '1通过 2拒绝 3下架' }
reason: { type: string, maxLength: 500, description: 拒绝/下架理由(回填创作者) }
ProjectRespVO:
type: object
properties:
id: { type: integer, format: int64 }
title: { type: string }
summary: { type: string }
coverUrl: { type: string }
tags: { type: array, items: { type: string } }
templateId: { type: string }
ageRating: { type: string }
status: { type: integer, description: '0草稿 1审核中 2已通过 3已拒绝 4已发布 5已下架 6已封禁' }
currentVersionId: { type: integer, format: int64 }
launchZoneId: { type: integer, format: int64 }
featured: { type: boolean }
playCount: { type: integer, format: int64 }
likeCount: { type: integer, format: int64 }
createTime: { type: string, format: date-time }