把活层退役旧品牌「造梦AI」统一改为现行「绘境AI」,brand-invariant 门红线归零。构成: ~412 Java @author 署名 + game-studio/index.html 浏览器标题 + game-runtime/package.json 描述 + game-admin/.env VITE_APP_TITLE 运营后台标题 + contracts API title/@Schema 用户协议示例/events 描述 + docs-design mockup 品牌位 + 各模块注释。全是注释/显示/元数据,零逻辑改动。 zaomeng 拼音持久化标识符按 2026-06-24 评审 GR-05 不动(347 处保留)。 白名单(docs/ip 法律备案 / _archive / 带日期留痕)与 AGENTS.md 门定义自身不动。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
408 lines
20 KiB
YAML
408 lines
20 KiB
YAML
openapi: 3.0.3
|
||
# 契约 #1 API | 模块:compliance(game-module-compliance,Wave3 合规域「锁风门 Gate」)| owner:Wave3 compliance 子 agent 主笔,全员 review
|
||
# 职责(架构 Doc B + D2 范围铁律):只做 Gate——发布前合规扫描(聚合风格/IP 原子→verdict)+ 内容分级 + 封禁台账。
|
||
# 【明确不做】审核状态机:审核状态机权威归 project(game_review_record),compliance 绝不重写(D2)。
|
||
# seam(R1):compliance 只交付 ComplianceGateApi.evaluate 供 project.submitPublish 同进程注入(block→admitted=false 不抛异常);
|
||
# 不自改 submitPublish、不自登记 publish-blocked 错误码(那条文案由 project 侧 GateResultVO.code 携带)。
|
||
# 封禁(R3 状态分支):写 game_user_ban 台账=主操作恒执行;下架联动仅当游戏==PUBLISHED 时才调 project 状态机;
|
||
# 本波 ProjectApi 暂无 reviewProject seam,下架联动标 TODO 留 Phase C 主 agent 收口(只写台账、不裸调不存在的方法)。
|
||
# 降权(R5):降权出流屏蔽 P1 本波不生效(不建 FeedDownweightApi 孤儿 seam、不调 feed)。
|
||
# IP(D5):ip 不独立建模块,仅在 compliance 内留 IpComplianceSeam 扩展点(默认 pass 桩),Wave4 接 ip 只换实现。
|
||
# U4 R-ACC(2026-06-18 扩):政策正文页(富文本 + 版本,app 只读最新 / admin 发布多版本)+ 申诉回路(app 本人提交/查询 + admin 处理状态机,可选关联封禁台账)。归属 compliance(已有 rating/ban/gate 合规语义),薄 CRUD。
|
||
# 端:/rpc-api(project.publish 同进程 Feign 注入)/ /admin-api(管理端 game-admin,RBAC 封禁+政策发布+申诉处理)/ /app-api(产品端只读分级+政策最新+本人申诉);前缀由 huijing 框架按 controller 包名/RpcConstants 自动添加
|
||
# 错误码段:compliance = 1-109-***-***(本模块独占,禁止与他模块重叠:100 project/101 aigc/102 runtime/103 feed/104 telemetry/106 trade/111 ad/112 studio)
|
||
# 子段:001 锁风门 / 002 封禁 / 003 分级 / 004 政策正文(U4)/ 005 申诉(U4)。publish-blocked 不在本模块登记(R1:block→admitted=false 不抛异常)。
|
||
# 响应统一 Huijing CommonResult 信封:{ code, data, msg };code=0 成功
|
||
info:
|
||
title: 绘境AI compliance 模块 API
|
||
version: 1.0.0
|
||
description: >-
|
||
合规锁风门 Gate("做得出"安全闸门)。project.publish 发布前同步调 evaluate → 聚合风格/IP 合规原子产出 verdict
|
||
(pass/review/block)+ 落锁风门台账 + 落内容分级;block 则 project 置 admitted=false(不抛异常)。
|
||
封禁台账供 admin 处置游戏/用户;下架联动按 project 状态分支(本波 TODO 留 Phase C)。MVP 合规原子全 mock 桩(默认 pass)。
|
||
|
||
servers:
|
||
- url: http://localhost:48080
|
||
description: 本地(Swagger/Knife4j http://localhost:48080/doc.html)
|
||
|
||
paths:
|
||
# ===========================================================================
|
||
# RPC 端 /rpc-api(project.publish 同进程注入,唯一 seam,R1)
|
||
# ===========================================================================
|
||
/rpc-api/compliance/evaluate:
|
||
post:
|
||
tags: [rpc-compliance]
|
||
summary: 锁风门评估(project.publish 注入用,R1 唯一形态)
|
||
description: >-
|
||
project.submitPublish 发布前同步调;聚合风格/IP 合规原子产出 verdict = max(各原子)(block>review>pass),
|
||
落 game_compliance_gate_result 审计台账 + upsert game_content_rating 分级。
|
||
block 仍正常返回 verdict(不抛异常),由 project 侧据此置 admitted=false。
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/ComplianceGateReqDTO' }
|
||
responses:
|
||
'200':
|
||
description: 聚合裁决
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultGateVerdict' }
|
||
|
||
# ===========================================================================
|
||
# 管理端 /admin-api(封禁台账,RBAC,R3 状态分支)
|
||
# ===========================================================================
|
||
/admin-api/compliance/ban/create:
|
||
post:
|
||
tags: [admin-compliance]
|
||
summary: 创建封禁(写台账=主操作恒执行;游戏下架联动按 project 状态分支)
|
||
description: >-
|
||
落 game_user_ban(主操作恒执行,同目标生效中封禁查重 uk_target_active)。
|
||
R3 下架联动:targetType=游戏 且 game.status==PUBLISHED 时才调 project reviewProject(decision=3);
|
||
非 PUBLISHED 只记封禁、不调状态机、不抛异常。【本波】ProjectApi 暂无 reviewProject seam,下架联动 TODO 留 Phase C。
|
||
R5 降权出流屏蔽 P1 本波不生效(不调 feed)。
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/BanCreateReqVO' }
|
||
responses:
|
||
'200':
|
||
description: 新建封禁台账 ID
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultLong' }
|
||
/admin-api/compliance/ban/cancel:
|
||
post:
|
||
tags: [admin-compliance]
|
||
summary: 解封(status 1→0)
|
||
description: 按 banId 解封;记录不存在或已解封报 COMPLIANCE_BAN_NOT_EXISTS。
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/BanCancelReqVO' }
|
||
responses:
|
||
'200':
|
||
description: 是否成功
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultBoolean' }
|
||
/admin-api/compliance/ban/page:
|
||
get:
|
||
tags: [admin-compliance]
|
||
summary: 封禁台账分页(admin RBAC)
|
||
parameters:
|
||
- { name: pageNo, in: query, required: true, schema: { type: integer, default: 1 } }
|
||
- { name: pageSize, in: query, required: true, schema: { type: integer, default: 10 } }
|
||
- { name: targetType, in: query, required: false, schema: { type: integer }, description: '目标类型过滤:1 游戏/2 用户' }
|
||
- { name: status, in: query, required: false, schema: { type: integer }, description: '状态过滤:1 生效/0 已解封' }
|
||
responses:
|
||
'200':
|
||
description: 分页结果
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultPageUserBan' }
|
||
|
||
# ===========================================================================
|
||
# 产品端 /app-api(内容分级只读,用户/匿名 Token)
|
||
# ===========================================================================
|
||
/app-api/compliance/rating/get:
|
||
get:
|
||
tags: [app-compliance]
|
||
summary: 取内容分级(只读)
|
||
description: 按游戏+版本读分级(all/8+/12+/16+);无记录报 COMPLIANCE_RATING_NOT_FOUND。分级写入仅由 Gate evaluate + admin 复核产生。
|
||
parameters:
|
||
- { name: gameId, in: query, required: true, schema: { type: integer, format: int64 } }
|
||
- { name: versionId, in: query, required: false, schema: { type: integer, format: int64 }, description: '无版本传 0' }
|
||
responses:
|
||
'200':
|
||
description: 内容分级
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultContentRating' }
|
||
|
||
# ===========================================================================
|
||
# U4 R-ACC 政策正文(app 只读取最新 / admin 发布富文本多版本)
|
||
# 设计:政策正文 = 薄 CRUD(富文本 + 版本);app 端取某政策类型「最新已发布」一版(无登录依赖、匿名可读,仿 rating)。
|
||
# ===========================================================================
|
||
/app-api/compliance/policy/latest:
|
||
get:
|
||
tags: [app-compliance]
|
||
summary: 取某政策正文最新已发布版(只读,匿名可读)
|
||
description: 按政策类型取「最新已发布(status=1)+最大 version」一版;无记录报 COMPLIANCE_POLICY_NOT_FOUND。
|
||
parameters:
|
||
- { name: policyType, in: query, required: true, schema: { type: string }, description: '政策类型:user-agreement/privacy/community-guideline/minor-protection' }
|
||
responses:
|
||
'200':
|
||
description: 政策正文
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultPolicyDocument' }
|
||
/admin-api/compliance/policy/publish:
|
||
post:
|
||
tags: [admin-compliance]
|
||
summary: 发布政策正文新版(admin RBAC)
|
||
description: 新增一版政策正文(富文本 + version);version 须比同类型现有最大版本大,否则报 COMPLIANCE_POLICY_VERSION_CONFLICT。
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/PolicyPublishReqVO' }
|
||
responses:
|
||
'200':
|
||
description: 新政策正文记录 ID
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultLong' }
|
||
/admin-api/compliance/policy/page:
|
||
get:
|
||
tags: [admin-compliance]
|
||
summary: 政策正文历史分页(admin RBAC)
|
||
parameters:
|
||
- { name: pageNo, in: query, required: true, schema: { type: integer, default: 1 } }
|
||
- { name: pageSize, in: query, required: true, schema: { type: integer, default: 10 } }
|
||
- { name: policyType, in: query, required: false, schema: { type: string }, description: '政策类型过滤' }
|
||
responses:
|
||
'200':
|
||
description: 分页结果
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultPagePolicyDocument' }
|
||
|
||
# ===========================================================================
|
||
# U4 R-ACC 申诉(app 本人提交/查询 / admin 处理状态机)
|
||
# 设计:申诉 = 薄 CRUD + 状态机(提交→admin 处理→结果);可选关联 game_user_ban 台账(banId)。
|
||
# 归属隔离:本人 userId 取自 token(getLoginUserId()),Mapper 强制 WHERE 谓词(可信边界,非前端入参)。
|
||
# 状态机 status:0 待处理 → 1 已通过 / 2 已驳回(admin 处理;重复提交守卫=同用户+同 banId 存在待处理则拒)。
|
||
# ===========================================================================
|
||
/app-api/compliance/appeal/submit:
|
||
post:
|
||
tags: [app-compliance]
|
||
summary: 提交申诉(本人 Token)
|
||
description: 提交申诉;可选关联 banId。重复提交守卫=同用户同 banId 已有待处理申诉则报 COMPLIANCE_APPEAL_DUPLICATE。
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/AppealSubmitReqVO' }
|
||
responses:
|
||
'200':
|
||
description: 新申诉记录 ID
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultLong' }
|
||
/app-api/compliance/appeal/my-page:
|
||
get:
|
||
tags: [app-compliance]
|
||
summary: 我的申诉分页(本人 Token,归属隔离)
|
||
parameters:
|
||
- { name: pageNo, in: query, required: true, schema: { type: integer, default: 1 } }
|
||
- { name: pageSize, in: query, required: true, schema: { type: integer, default: 10 } }
|
||
- { name: status, in: query, required: false, schema: { type: integer }, description: '状态过滤:0 待处理/1 已通过/2 已驳回' }
|
||
responses:
|
||
'200':
|
||
description: 分页结果
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultPageAppeal' }
|
||
/admin-api/compliance/appeal/handle:
|
||
post:
|
||
tags: [admin-compliance]
|
||
summary: 处理申诉(admin RBAC,状态机流转)
|
||
description: 待处理(0)→已通过(1)/已驳回(2);记录不存在或非待处理报 COMPLIANCE_APPEAL_CANNOT_HANDLE。
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/AppealHandleReqVO' }
|
||
responses:
|
||
'200':
|
||
description: 处理成功
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultBoolean' }
|
||
/admin-api/compliance/appeal/page:
|
||
get:
|
||
tags: [admin-compliance]
|
||
summary: 申诉台账分页(admin RBAC)
|
||
parameters:
|
||
- { name: pageNo, in: query, required: true, schema: { type: integer, default: 1 } }
|
||
- { name: pageSize, in: query, required: true, schema: { type: integer, default: 10 } }
|
||
- { name: status, in: query, required: false, schema: { type: integer }, description: '状态过滤:0 待处理/1 已通过/2 已驳回' }
|
||
responses:
|
||
'200':
|
||
description: 分页结果
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CommonResultPageAppeal' }
|
||
|
||
components:
|
||
schemas:
|
||
# ===== 锁风门 Gate(RPC seam,R1 唯一形态)=====
|
||
ComplianceGateReqDTO:
|
||
type: object
|
||
required: [gameId, versionId]
|
||
properties:
|
||
gameId: { type: integer, format: int64, description: '游戏项目 ID(锁风门定位锚点)' }
|
||
versionId: { type: integer, format: int64, description: '待发布版本 ID' }
|
||
title: { type: string, description: '标题(风格原子参考,可空)' }
|
||
summary: { type: string, description: '摘要(风格原子参考,可空)' }
|
||
ageRating: { type: string, description: '适龄分级建议:all/8+/12+/16+' }
|
||
promptHash: { type: string, description: '生成 Prompt 摘要(合规溯源,可空)' }
|
||
GateVerdict: # = 草案 ComplianceGateRespDTO,R1 命名对齐
|
||
type: object
|
||
required: [verdict]
|
||
properties:
|
||
verdict: { type: string, enum: [pass, review, block], description: '聚合裁决 = max(各原子),block>review>pass' }
|
||
rating: { type: string, description: '本次评估落定的内容分级' }
|
||
detail: { type: array, items: { $ref: '#/components/schemas/ComplianceGateItemDTO' } }
|
||
ComplianceGateItemDTO:
|
||
type: object
|
||
properties:
|
||
atom: { type: string, description: '原子标识:textContent/imageContent/ip-reserved' }
|
||
verdict: { type: string, enum: [pass, review, block] }
|
||
reason: { type: string, description: '裁决原因(pass 可空)' }
|
||
|
||
# ===== 封禁(admin,R3 状态分支)=====
|
||
BanCreateReqVO:
|
||
type: object
|
||
required: [targetType, targetId]
|
||
properties:
|
||
targetType: { type: integer, description: '封禁目标类型:1 游戏 / 2 用户' }
|
||
targetId: { type: integer, format: int64, description: '封禁目标 ID(游戏=game_id / 用户=user_id)' }
|
||
banType: { type: integer, description: '处置类型:1 封禁 / 2 降权(P1 本波不生效)' }
|
||
reason: { type: string, description: '封禁/降权原因' }
|
||
BanCancelReqVO:
|
||
type: object
|
||
required: [banId]
|
||
properties:
|
||
banId: { type: integer, format: int64, description: '封禁台账记录 ID' }
|
||
UserBanRespVO:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, format: int64 }
|
||
targetType: { type: integer, description: '1 游戏 / 2 用户' }
|
||
targetId: { type: integer, format: int64 }
|
||
banType: { type: integer, description: '1 封禁 / 2 降权' }
|
||
status: { type: integer, description: '1 生效 / 0 已解封' }
|
||
reason: { type: string }
|
||
createTime: { type: string, format: date-time }
|
||
|
||
# ===== 分级(app 只读)=====
|
||
ContentRatingRespVO:
|
||
type: object
|
||
properties:
|
||
rating: { type: string, description: 'all/8+/12+/16+' }
|
||
ratedBy: { type: string, description: 'gate 锁风门自动 / admin 人工复核' }
|
||
updateTime: { type: string, format: date-time }
|
||
|
||
# ===== U4 政策正文(app 只读最新 / admin 发布多版本)=====
|
||
PolicyPublishReqVO:
|
||
type: object
|
||
required: [policyType, version, title, content]
|
||
properties:
|
||
policyType: { type: string, description: '政策类型:user-agreement/privacy/community-guideline/minor-protection' }
|
||
version: { type: integer, description: '版本号(须比同类型现有最大版本大)' }
|
||
title: { type: string, description: '政策标题' }
|
||
content: { type: string, description: '政策正文(富文本 HTML,可大文本)' }
|
||
PolicyDocumentRespVO:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, format: int64 }
|
||
policyType: { type: string, description: '政策类型' }
|
||
version: { type: integer, description: '版本号' }
|
||
title: { type: string }
|
||
content: { type: string, description: '政策正文(富文本)' }
|
||
status: { type: integer, description: '状态:1 已发布/0 草稿(本波只发布态)' }
|
||
updateTime: { type: string, format: date-time }
|
||
|
||
# ===== U4 申诉(app 本人提交/查询 / admin 处理状态机)=====
|
||
AppealSubmitReqVO:
|
||
type: object
|
||
required: [appealType, reason]
|
||
properties:
|
||
appealType: { type: integer, description: '申诉类型:1 封禁申诉 / 2 审核申诉 / 3 其它' }
|
||
banId: { type: integer, format: int64, description: '可选关联封禁台账 ID(封禁申诉时填)' }
|
||
reason: { type: string, description: '申诉理由' }
|
||
AppealHandleReqVO:
|
||
type: object
|
||
required: [appealId, decision]
|
||
properties:
|
||
appealId: { type: integer, format: int64, description: '申诉记录 ID' }
|
||
decision: { type: integer, description: '处理决定:1 通过 / 2 驳回' }
|
||
handleResult: { type: string, description: '处理结果说明(可空)' }
|
||
AppealRespVO:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, format: int64 }
|
||
appealType: { type: integer, description: '1 封禁申诉/2 审核申诉/3 其它' }
|
||
banId: { type: integer, format: int64, description: '关联封禁台账 ID(可空)' }
|
||
reason: { type: string }
|
||
status: { type: integer, description: '0 待处理/1 已通过/2 已驳回' }
|
||
handleResult: { type: string, description: '处理结果说明' }
|
||
createTime: { type: string, format: date-time }
|
||
updateTime: { type: string, format: date-time }
|
||
|
||
# ===== CommonResult 信封 =====
|
||
CommonResultGateVerdict:
|
||
type: object
|
||
properties:
|
||
code: { type: integer }
|
||
data: { $ref: '#/components/schemas/GateVerdict' }
|
||
msg: { type: string }
|
||
CommonResultContentRating:
|
||
type: object
|
||
properties:
|
||
code: { type: integer }
|
||
data: { $ref: '#/components/schemas/ContentRatingRespVO' }
|
||
msg: { type: string }
|
||
CommonResultPageUserBan:
|
||
type: object
|
||
properties:
|
||
code: { type: integer }
|
||
data:
|
||
type: object
|
||
properties:
|
||
list: { type: array, items: { $ref: '#/components/schemas/UserBanRespVO' } }
|
||
total: { type: integer, format: int64 }
|
||
msg: { type: string }
|
||
CommonResultLong:
|
||
type: object
|
||
properties:
|
||
code: { type: integer }
|
||
data: { type: integer, format: int64 }
|
||
msg: { type: string }
|
||
CommonResultBoolean:
|
||
type: object
|
||
properties:
|
||
code: { type: integer }
|
||
data: { type: boolean }
|
||
msg: { type: string }
|
||
CommonResultPolicyDocument:
|
||
type: object
|
||
properties:
|
||
code: { type: integer }
|
||
data: { $ref: '#/components/schemas/PolicyDocumentRespVO' }
|
||
msg: { type: string }
|
||
CommonResultPagePolicyDocument:
|
||
type: object
|
||
properties:
|
||
code: { type: integer }
|
||
data:
|
||
type: object
|
||
properties:
|
||
list: { type: array, items: { $ref: '#/components/schemas/PolicyDocumentRespVO' } }
|
||
total: { type: integer, format: int64 }
|
||
msg: { type: string }
|
||
CommonResultPageAppeal:
|
||
type: object
|
||
properties:
|
||
code: { type: integer }
|
||
data:
|
||
type: object
|
||
properties:
|
||
list: { type: array, items: { $ref: '#/components/schemas/AppealRespVO' } }
|
||
total: { type: integer, format: int64 }
|
||
msg: { type: string }
|