社区社交后端四子能力(game-module-community),克隆通知底座/feed互动幂等范式: - 评论 Comments:CRUD + 举报转 compliance。删除按 userId 归属强校验(防越权删他人评论), 举报落本端举报态幂等 + 事务提交后 afterCommit 接缝(compliance 无受理 -api,留桩 OPEN ITEM)。 - 关注 Follow:active 软开关幂等切换(不删行,范本=feed FeedInteractLog),不能关注自己, 并发双插由 DB 唯一键 DuplicateKeyException CAS 收敛;粉丝数/关注数 countActive。 - 排行 Ranking:Redis ZSET + ZSET↔DB 一致性窗口。DB=真相、ZSET=缓存索引: 写穿透双写(DB 原子累加 + ZSET incrementScore)、ZSET 缺失/启动从 DB 回填重建、最终一致; 维度白名单 RankDimensionEnum(game_hot/creator_hot)。 - 弹幕 Danmaku:WebSocket 单机最小实(LocalWebSocketMessageSender),自维护房间 gameId→sessionId 注册表做房间维度广播(框架仅按用户维度推送),断连懒清理;多实例需切 sender-type=redis(MQ future-state 未部署)。 契约/库表: - Flyway V23.0.0(U3 独占 V23.x):game_community_comment/follow/rank/danmaku 四表 + 幂等唯一键(follow uk(user_id,target_user_id,deleted,tenant_id)、rank uk(dimension,target_id,...)), 同步 huijing-server/db/migration + contracts/db-schemas。 - community.yaml additive 加 8 个 app 端点 + 5 个 schema(既有冻结)。 - 错误码段 1-107-004 评论 / 005 关注 / 006 排行 / 007 弹幕。 验证:mvn -pl game-module-community/game-module-community-server -am test -o 全绿 (57 tests:新增 U3 35 + 既有 22;CommentService 9 / FollowService 8 / RankService 8 / Danmaku 10)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
578 lines
32 KiB
YAML
578 lines
32 KiB
YAML
openapi: 3.0.3
|
||
# 契约 #8 API | 模块:community(通知底座:站内信 + 创作者等级 + 新人奖励触发)| owner:WS5,全员 review
|
||
# 设计依据:docs/agent-specs/2026-06-11-Wave4-community-biz-execution.md §4.3/§4.4(D-B 通知底座最小集,覆盖 5/5 P0)。
|
||
# 端:/app-api(产品端 game-studio:我的站内信中心 / 未读角标 / 我的等级 / 我的奖励,用户 Token + Mapper 强制 getLoginUserId() 归属谓词)
|
||
# /rpc-api(CommunityNotifyApi 四方法,供上游 aigc/project/trade 同进程 @Primary 调用,非对外业务路由)
|
||
# /admin-api(staging only:四类投递 mock-trigger,上游未接通前独立验收)
|
||
# 前缀由 huijing 框架按 controller.app/admin 包名自动添加;本文件 path 直接写含前缀的完整对外路径。
|
||
# 错误码段(落 game 业务段 1-107-***-***,模块归属决定,contracts/README.md §四 已在册):
|
||
# 1-107-001-*** = 站内信(消息不存在/非本人消息/已读状态非法…)
|
||
# 1-107-002-*** = 创作者等级(等级记录不存在/计数累加异常…)
|
||
# 1-107-003-*** = 新人奖励(里程碑重复触发被幂等拦截…)
|
||
# 响应统一 Huijing CommonResult 信封:{ code, data, msg };code=0 成功。
|
||
# 触达机制(评审版 §3.3 定型):aigc 生成完成 / compliance·project 审核出结果 / trade 收益变动后,
|
||
# 各自 service 在本地事务【提交后】同进程调用 community 暴露的 CommunityNotifyApi(复用 @Primary 本地实现)写站内信;
|
||
# 不新建 MQ、不动 events.schema.json。CommunityNotifyApiImpl 入口注入系统身份 LoginUser(id=0) + finally clearContext。
|
||
# 幂等:站内信以 (userId,type,bizRef) 去重(重复投递不重复落库);里程碑以 (creator_user_id,milestone) 唯一键幂等。
|
||
# 归属隔离(R-medium PII 红线):客户侧端点必须在 Mapper 查询里强制以登录态 user_id 作谓词 enforce(可信边界,非 @DataPermission),
|
||
# 前端不够;用户只见自己站内信/等级/奖励,不得读他人 PII。
|
||
# 边界 OUT:SOC/GRW 域(关系图谱/排行/成就/扇出/邮件,全 P1/P2)仅留接口桩、本波不实现;
|
||
# reward 真实记账/到账(记入钱包/流量包)留 M4,本波只写自有 reward 触发记录表。
|
||
info:
|
||
title: 绘境AI community 模块 API
|
||
version: 1.0.0
|
||
description: >-
|
||
通知底座最小集:站内消息中心(系统/公告/审核/收益四类聚合 + 未读角标 + 标记已读)+
|
||
创作者等级(published_count 计数权威源 = project 发布成功同进程 notify 累加,新人里程碑触发)+
|
||
新人奖励触发记录(里程碑幂等触发,真实发放留 M4)。
|
||
上游 aigc/project/trade 经 CommunityNotifyApi(@Primary 本地实现)在本地事务提交后同进程投递站内信。
|
||
覆盖产品功能 P-NTF-01/02/03/05(通知触达)+ P-INC-01(创作者成长激励计数)。
|
||
前端据此 vite-plugin-mock 自动生成 mock。
|
||
|
||
servers:
|
||
- url: http://localhost:48080
|
||
description: 本地(Swagger/Knife4j http://localhost:48080/doc.html)
|
||
|
||
paths:
|
||
# ===========================================================================
|
||
# app 端(产品端 game-studio):我的站内信中心 / 未读角标 / 我的等级 / 我的奖励
|
||
# 全部用户 Token,Mapper 强制 getLoginUserId() 归属谓词,用户只见自己数据。
|
||
# ===========================================================================
|
||
/app-api/community/messages:
|
||
get:
|
||
tags: [app-community]
|
||
summary: 站内信分页列表(P-NTF-01)
|
||
description: >-
|
||
我的消息中心列表,按已读态 + 创建时间倒序。
|
||
归属隔离:Mapper 强制 user_id = getLoginUserId() 谓词(可信边界),用户只见自己消息。
|
||
parameters:
|
||
- { name: type, in: query, required: false, schema: { type: integer, enum: [1, 2, 3, 4] }, description: '消息类型:1系统 2公告 3审核 4收益(可选,不传查全部)' }
|
||
- { name: readStatus, in: query, required: false, schema: { type: integer, enum: [0, 1] }, description: '已读状态:0未读 1已读(可选)' }
|
||
- { name: cursor, in: query, required: false, schema: { type: integer, format: int64 }, description: '游标分页:上一页末条 id(可选,首页不传)' }
|
||
- { name: size, in: query, required: false, schema: { type: integer, default: 20 }, description: '每页条数(默认 20)' }
|
||
responses:
|
||
'200':
|
||
description: 站内信分页结果(CommonResult 信封)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data:
|
||
type: object
|
||
properties:
|
||
list: { type: array, items: { $ref: '#/components/schemas/CommunityMessageRespVO' } }
|
||
nextCursor: { type: integer, format: int64, nullable: true, description: '下一页游标,null 表示无更多' }
|
||
msg: { type: string, example: '' }
|
||
|
||
/app-api/community/messages/{id}/read:
|
||
post:
|
||
tags: [app-community]
|
||
summary: 标记单条已读(P-NTF-01)
|
||
description: >-
|
||
标记单条站内信已读,落 read_status=1 + read_time。
|
||
归属隔离:service 校验该消息 user_id == getLoginUserId(),非本人消息拒绝(1-107-001-***)。
|
||
parameters:
|
||
- { name: id, in: path, required: true, schema: { type: integer, format: int64 }, description: '消息 ID' }
|
||
responses:
|
||
'200':
|
||
description: 标记结果(CommonResult<Boolean>)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { type: boolean, example: true }
|
||
msg: { type: string, example: '' }
|
||
|
||
/app-api/community/messages/unread-count:
|
||
get:
|
||
tags: [app-community]
|
||
summary: 未读数角标(P-NTF-01)
|
||
description: 未读消息数角标,按 type 分组计数 + 总未读数。归属隔离同上。
|
||
responses:
|
||
'200':
|
||
description: 未读计数(CommonResult)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data:
|
||
type: object
|
||
properties:
|
||
total: { type: integer, description: '总未读数' }
|
||
byType:
|
||
type: object
|
||
description: '按四类分组未读数(key=type 1/2/3/4,value=count)'
|
||
additionalProperties: { type: integer }
|
||
msg: { type: string, example: '' }
|
||
|
||
/app-api/community/level:
|
||
get:
|
||
tags: [app-community]
|
||
summary: 当前创作者等级 + published_count + 下一里程碑进度(P-INC-01)
|
||
description: >-
|
||
当前登录创作者的等级记录:level + published_count + 距下一新人里程碑进度(如 2/3)。
|
||
published_count 权威源 = project 发布成功后同进程 notify 原子累加。
|
||
归属隔离:creator_user_id = getLoginUserId()。无记录时返回初始化默认(level=1/count=0)。
|
||
responses:
|
||
'200':
|
||
description: 创作者等级(CommonResult)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { $ref: '#/components/schemas/CommunityLevelRespVO' }
|
||
msg: { type: string, example: '' }
|
||
|
||
/app-api/community/rewards:
|
||
get:
|
||
tags: [app-community]
|
||
summary: 我的奖励触发记录列表(P-INC-01)
|
||
description: >-
|
||
我的新人奖励触发记录列表,status 触发态(0已触发待发放)/发放态(1已发放,M4 回写)均可见。
|
||
归属隔离:creator_user_id = getLoginUserId()。
|
||
responses:
|
||
'200':
|
||
description: 奖励触发记录列表(CommonResult)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { type: array, items: { $ref: '#/components/schemas/CommunityRewardRespVO' } }
|
||
msg: { type: string, example: '' }
|
||
|
||
# ===========================================================================
|
||
# app 端(U3 R-SOC 社区社交):评论 / 关注 / 排行 / 弹幕(additive,2026-06-18 plan002 U3)
|
||
# 错误码段:评论 1-107-004 / 关注 1-107-005 / 排行 1-107-006 / 弹幕 1-107-007。
|
||
# 写端点(发评论/删评论/举报/关注/取关/发弹幕)需用户 Token,归属/发起方一律 getLoginUserId()(非前端入参)。
|
||
# 公开读:评论列表/计数、排行 TopN、弹幕回放无需登录。举报转 compliance:落本端举报态 + 事务提交后接缝(compliance 受理 -api 待提供,OPEN ITEM)。
|
||
# 弹幕实时接收走 WebSocket(type="danmaku",本契约仅描述 HTTP;WS 路径见后端 huijing.websocket.path),HTTP 发送为兜底入口。
|
||
# ===========================================================================
|
||
/app-api/community/comments:
|
||
post:
|
||
tags: [app-community]
|
||
summary: 发表评论(R-SOC)
|
||
description: 需登录;作者 = 当前登录用户(token 解析,非前端入参)。内容非空。
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [targetType, targetId, content]
|
||
properties:
|
||
targetType: { type: integer, enum: [1], default: 1, description: '评论目标类型:1游戏' }
|
||
targetId: { type: integer, format: int64, description: '评论目标 ID(gameId)' }
|
||
content: { type: string, maxLength: 1024, description: '评论正文' }
|
||
parentId: { type: integer, format: int64, default: 0, description: '父评论 ID(0=一级,MVP 不展开树)' }
|
||
responses:
|
||
'200':
|
||
description: 新评论 ID(CommonResult<Long>)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { type: integer, format: int64, example: 1 }
|
||
msg: { type: string, example: '' }
|
||
get:
|
||
tags: [app-community]
|
||
summary: 评论分页列表(R-SOC)
|
||
description: 公开读;按 target_type+target_id 维度,id 倒序。
|
||
parameters:
|
||
- { name: targetType, in: query, required: false, schema: { type: integer, enum: [1], default: 1 }, description: '目标类型:1游戏' }
|
||
- { name: targetId, in: query, required: true, schema: { type: integer, format: int64 }, description: '目标 ID(gameId)' }
|
||
- { name: pageNo, in: query, required: false, schema: { type: integer, default: 1 }, description: '页码,从 1 开始' }
|
||
- { name: pageSize, in: query, required: false, schema: { type: integer, default: 10 }, description: '每页条数(最大 200)' }
|
||
responses:
|
||
'200':
|
||
description: 评论分页结果(CommonResult)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data:
|
||
type: object
|
||
properties:
|
||
list: { type: array, items: { $ref: '#/components/schemas/CommunityCommentRespVO' } }
|
||
total: { type: integer, format: int64, example: 100 }
|
||
msg: { type: string, example: '' }
|
||
/app-api/community/comments/{id}:
|
||
delete:
|
||
tags: [app-community]
|
||
summary: 删除评论(R-SOC)
|
||
description: 需登录;先校验归属当前登录用户,防越权删他人评论(数据边界红线)。
|
||
parameters:
|
||
- { name: id, in: path, required: true, schema: { type: integer, format: int64 }, description: '评论 ID' }
|
||
responses:
|
||
'200':
|
||
description: CommonResult<Boolean>
|
||
content: { application/json: { schema: { $ref: '#/components/schemas/CommonResultBoolean' } } }
|
||
/app-api/community/comments/count:
|
||
get:
|
||
tags: [app-community]
|
||
summary: 评论数(R-SOC)
|
||
description: 某目标的评论总数(公开计数)。
|
||
parameters:
|
||
- { name: targetType, in: query, required: false, schema: { type: integer, enum: [1], default: 1 } }
|
||
- { name: targetId, in: query, required: true, schema: { type: integer, format: int64 }, description: '目标 ID(gameId)' }
|
||
responses:
|
||
'200':
|
||
description: CommonResult<Long>
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { type: integer, format: int64, example: 42 }
|
||
msg: { type: string, example: '' }
|
||
/app-api/community/comments/{id}/report:
|
||
post:
|
||
tags: [app-community]
|
||
summary: 举报评论(R-SOC)
|
||
description: >-
|
||
需登录;理由必填;落本端举报态(report_status=1)幂等 + 事务提交后转 compliance 受理。
|
||
OPEN ITEM:compliance 当前无举报受理 -api,本波仅留接缝桩,接通后经 -api 调用 + 幂等 + 补偿。
|
||
parameters:
|
||
- { name: id, in: path, required: true, schema: { type: integer, format: int64 }, description: '被举报评论 ID' }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [reason]
|
||
properties:
|
||
reason: { type: string, maxLength: 200, description: '举报理由(必填)' }
|
||
responses:
|
||
'200':
|
||
description: CommonResult<Boolean>
|
||
content: { application/json: { schema: { $ref: '#/components/schemas/CommonResultBoolean' } } }
|
||
|
||
/app-api/community/follow/{targetUserId}:
|
||
post:
|
||
tags: [app-community]
|
||
summary: 关注(R-SOC)
|
||
description: 需登录;发起方 = 当前登录用户;幂等(重复关注同态不写);不能关注自己;并发由 DB 唯一键 CAS 收敛。
|
||
parameters:
|
||
- { name: targetUserId, in: path, required: true, schema: { type: integer, format: int64 }, description: '被关注方用户 ID' }
|
||
responses:
|
||
'200':
|
||
description: 关注结果(CommonResult)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { $ref: '#/components/schemas/CommunityFollowResultRespVO' }
|
||
msg: { type: string, example: '' }
|
||
delete:
|
||
tags: [app-community]
|
||
summary: 取关(R-SOC)
|
||
description: 需登录;幂等(反激活 active=0,不删行)。
|
||
parameters:
|
||
- { name: targetUserId, in: path, required: true, schema: { type: integer, format: int64 }, description: '被关注方用户 ID' }
|
||
responses:
|
||
'200':
|
||
description: 取关结果(CommonResult)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { $ref: '#/components/schemas/CommunityFollowResultRespVO' }
|
||
msg: { type: string, example: '' }
|
||
/app-api/community/follow/stat/{userId}:
|
||
get:
|
||
tags: [app-community]
|
||
summary: 关注统计(R-SOC)
|
||
description: 某用户粉丝数/关注数 + 当前登录者是否已关注 ta(未登录则 followedByMe=false)。
|
||
parameters:
|
||
- { name: userId, in: path, required: true, schema: { type: integer, format: int64 }, description: '查询的用户 ID' }
|
||
responses:
|
||
'200':
|
||
description: 关注统计(CommonResult)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { $ref: '#/components/schemas/CommunityFollowStatRespVO' }
|
||
msg: { type: string, example: '' }
|
||
|
||
/app-api/community/rank:
|
||
get:
|
||
tags: [app-community]
|
||
summary: 排行榜单 TopN(R-SOC)
|
||
description: >-
|
||
公开读;维度须为已定义维度(game_hot 游戏热度 / creator_hot 创作者热度)。
|
||
优先读 Redis ZSET(快路径),ZSET 缺失自动从 DB 权威源回填重建(读路径不空窗,最终一致)。
|
||
parameters:
|
||
- { name: dimension, in: query, required: true, schema: { type: string, enum: [game_hot, creator_hot] }, description: '排行维度' }
|
||
- { name: topN, in: query, required: false, schema: { type: integer, default: 10 }, description: '取前 N 名' }
|
||
responses:
|
||
'200':
|
||
description: 榜单(CommonResult)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { type: array, items: { $ref: '#/components/schemas/CommunityRankItemRespVO' } }
|
||
msg: { type: string, example: '' }
|
||
|
||
/app-api/community/danmaku:
|
||
post:
|
||
tags: [app-community]
|
||
summary: 发送弹幕(R-SOC)
|
||
description: >-
|
||
需登录;落库(可回放)+ 触发 WebSocket 房间(gameId)广播给在线观众;发送者 = 当前登录用户。
|
||
实时接收走 WebSocket(type="danmaku");本 HTTP 发送为不开 WS 客户端的兜底入口。
|
||
单实例边界:多实例需切 huijing.websocket.sender-type=redis(MQ future-state 未部署)。
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [gameId, content]
|
||
properties:
|
||
gameId: { type: integer, format: int64, description: '游戏 ID(弹幕房间)' }
|
||
content: { type: string, maxLength: 255, description: '弹幕正文' }
|
||
playTime: { type: integer, default: 0, description: '播放进度(秒,MVP 可为 0)' }
|
||
responses:
|
||
'200':
|
||
description: 已落库弹幕(CommonResult,同时是 WS 广播载荷)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { $ref: '#/components/schemas/CommunityDanmakuRespVO' }
|
||
msg: { type: string, example: '' }
|
||
/app-api/community/danmaku/recent:
|
||
get:
|
||
tags: [app-community]
|
||
summary: 最近弹幕回放(R-SOC)
|
||
description: 公开读;某游戏最近 N 条弹幕(进房补帧),按时间正序。
|
||
parameters:
|
||
- { name: gameId, in: query, required: true, schema: { type: integer, format: int64 }, description: '游戏 ID(房间)' }
|
||
- { name: limit, in: query, required: false, schema: { type: integer, default: 50 }, description: '取近 N 条' }
|
||
responses:
|
||
'200':
|
||
description: 弹幕列表(CommonResult)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { type: array, items: { $ref: '#/components/schemas/CommunityDanmakuRespVO' } }
|
||
msg: { type: string, example: '' }
|
||
|
||
# ===========================================================================
|
||
# RPC 端(/rpc-api/community/*):CommunityNotifyApi 四方法
|
||
# 供上游 aigc/project/trade 同进程 @Primary 调用,非对外业务路由(@FeignClient(name="community-server"))。
|
||
# 实现入口注入系统身份 LoginUser(id=0) + finally clearContext;统一 CommonResult 信封。
|
||
# ===========================================================================
|
||
/rpc-api/community/notify/generate-done:
|
||
post:
|
||
tags: [rpc-community]
|
||
summary: '[RPC] P-NTF-02 生成完成通知'
|
||
description: >-
|
||
aigc 在 DifyCallbackServiceImpl.handleCallback 提交后调;触发判定 = 提交后回查任务为 SUCCEEDED 终态且 versionId 已回填
|
||
(非 result==TRUE);三实参均取自回查的 AigcTaskDO(creatorUserId/gameId/versionId)。落 type=1 系统消息。
|
||
parameters:
|
||
- { name: creatorUserId, in: query, required: true, schema: { type: integer, format: int64 }, description: '创作者用户 ID(取自回查任务)' }
|
||
- { name: gameId, in: query, required: true, schema: { type: integer, format: int64 }, description: '游戏 ID(取自回查任务)' }
|
||
- { name: versionId, in: query, required: true, schema: { type: integer, format: int64 }, description: '版本 ID(取自回查任务)' }
|
||
responses:
|
||
'200':
|
||
description: CommonResult<Boolean>
|
||
content: { application/json: { schema: { $ref: '#/components/schemas/CommonResultBoolean' } } }
|
||
|
||
/rpc-api/community/notify/review-result:
|
||
post:
|
||
tags: [rpc-community]
|
||
summary: '[RPC] P-NTF-03 审核结果通知'
|
||
description: >-
|
||
project 在 reviewProject 提交后调;decision 三态(1通过/2拒绝/3下架,对齐 ReviewDecisionEnum)——
|
||
本波仅对 1/2 发通知(caller 侧以 decision∈{1,2} 守门),reject(2) 须带 reason。落 type=3 审核消息。
|
||
parameters:
|
||
- { name: creatorUserId, in: query, required: true, schema: { type: integer, format: int64 }, description: '创作者用户 ID' }
|
||
- { name: gameId, in: query, required: true, schema: { type: integer, format: int64 }, description: '游戏 ID' }
|
||
- { name: decision, in: query, required: true, schema: { type: integer, enum: [1, 2] }, description: '审核决定:1通过 2拒绝(3下架本波不发)' }
|
||
- { name: reason, in: query, required: false, schema: { type: string }, description: '拒绝原因(decision=2 必带)' }
|
||
responses:
|
||
'200':
|
||
description: CommonResult<Boolean>
|
||
content: { application/json: { schema: { $ref: '#/components/schemas/CommonResultBoolean' } } }
|
||
|
||
/rpc-api/community/notify/income-changed:
|
||
post:
|
||
tags: [rpc-community]
|
||
summary: '[RPC] P-NTF-05 收益变动通知'
|
||
description: >-
|
||
trade 在 SettlementServiceImpl.settle 入账成功后调(仅 firstRecord 首次真实入账才通知,幂等复跑不重发);
|
||
netAmount=创作者实得净额(分)。落 type=4 收益消息。
|
||
parameters:
|
||
- { name: creatorUserId, in: query, required: true, schema: { type: integer, format: int64 }, description: '创作者用户 ID' }
|
||
- { name: source, in: query, required: true, schema: { type: integer }, description: '收益来源(对齐 trade 来源枚举)' }
|
||
- { name: sourceRef, in: query, required: true, schema: { type: string }, description: '来源业务键(settleId 等)' }
|
||
- { name: netAmount, in: query, required: true, schema: { type: integer, format: int64 }, description: '创作者实得净额(分)' }
|
||
responses:
|
||
'200':
|
||
description: CommonResult<Boolean>
|
||
content: { application/json: { schema: { $ref: '#/components/schemas/CommonResultBoolean' } } }
|
||
|
||
/rpc-api/community/notify/project-published:
|
||
post:
|
||
tags: [rpc-community]
|
||
summary: '[RPC] P-INC-01 发布计数(方案a)'
|
||
description: >-
|
||
project 发布成功后同进程 notify(与 notifyReviewResult 合并在同一 caller,isApprove 时多调一次);
|
||
累加 published_count 并触发新人里程碑(幂等)。落 type=1 系统消息(里程碑达成时)。
|
||
parameters:
|
||
- { name: creatorUserId, in: query, required: true, schema: { type: integer, format: int64 }, description: '创作者用户 ID' }
|
||
- { name: gameId, in: query, required: true, schema: { type: integer, format: int64 }, description: '游戏 ID' }
|
||
responses:
|
||
'200':
|
||
description: CommonResult<Boolean>
|
||
content: { application/json: { schema: { $ref: '#/components/schemas/CommonResultBoolean' } } }
|
||
|
||
# ===========================================================================
|
||
# admin 端(staging only):四类投递 mock-trigger
|
||
# 上游未接通前独立验收四类投递,仅 dev/staging 生效(@ConditionalOnProperty(name="community.mock-trigger.enabled",
|
||
# havingValue="true") 与现有灰度开关风格一致;或 @Profile({"dev","staging"}),二选一钉死),生产关闭。
|
||
# ===========================================================================
|
||
/admin-api/community/notifications/{type}/mock-trigger:
|
||
post:
|
||
tags: [admin-community]
|
||
summary: '[staging only] 四类投递 mock-trigger'
|
||
description: >-
|
||
上游未接通前独立验收四类站内信投递,仅 dev/staging 生效,生产关闭。
|
||
实查全 game-module 无 @Profile 先例(现有差异化手段是 @ConditionalOnProperty 灰度开关),建设时二选一钉死。
|
||
parameters:
|
||
- { name: type, in: path, required: true, schema: { type: integer, enum: [1, 2, 3, 4] }, description: '投递类型:1系统 2公告 3审核 4收益' }
|
||
requestBody:
|
||
required: false
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
userId: { type: integer, format: int64, description: '目标收件人 user_id(mock 指定)' }
|
||
title: { type: string, description: '消息标题' }
|
||
content: { type: string, description: '消息正文' }
|
||
bizRef: { type: string, description: '业务关联键' }
|
||
responses:
|
||
'200':
|
||
description: CommonResult<Boolean>
|
||
content: { application/json: { schema: { $ref: '#/components/schemas/CommonResultBoolean' } } }
|
||
|
||
components:
|
||
schemas:
|
||
CommonResultBoolean:
|
||
type: object
|
||
description: Huijing 统一响应信封(Boolean 数据)
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { type: boolean, example: true }
|
||
msg: { type: string, example: '' }
|
||
CommunityMessageRespVO:
|
||
type: object
|
||
description: 站内消息(我的消息中心列表项)
|
||
properties:
|
||
id: { type: integer, format: int64, description: '消息 ID' }
|
||
type: { type: integer, description: '消息类型:1系统 2公告 3审核 4收益' }
|
||
bizRef: { type: string, description: '业务关联键(供前端跳转)' }
|
||
title: { type: string, description: '消息标题' }
|
||
content: { type: string, description: '消息正文(审核拒绝含原因)' }
|
||
readStatus: { type: integer, description: '已读状态:0未读 1已读' }
|
||
readTime: { type: string, format: date-time, nullable: true, description: '已读时间' }
|
||
createTime: { type: string, format: date-time, description: '创建时间' }
|
||
CommunityLevelRespVO:
|
||
type: object
|
||
description: 创作者等级 + 计数 + 下一里程碑进度
|
||
properties:
|
||
level: { type: integer, description: '创作者等级:1小白(MVP)' }
|
||
publishedCount: { type: integer, description: '已发布作品数(计数权威源)' }
|
||
lastMilestone: { type: string, description: '末次已触发里程碑键(如 publish_3)' }
|
||
nextMilestone: { type: string, nullable: true, description: '下一里程碑键(null 表示已达顶)' }
|
||
nextMilestoneTarget: { type: integer, nullable: true, description: '下一里程碑目标作品数(如 3)' }
|
||
CommunityRewardRespVO:
|
||
type: object
|
||
description: 新人奖励触发记录
|
||
properties:
|
||
id: { type: integer, format: int64, description: '奖励触发记录 ID' }
|
||
milestone: { type: string, description: '里程碑键(如 publish_3)' }
|
||
rewardType: { type: integer, description: '奖励类型:1流量包 2现金' }
|
||
rewardAmount: { type: integer, format: int64, description: '奖励额度(流量包=曝光量;现金=分)' }
|
||
status: { type: integer, description: '发放状态:0已触发待发放(本波终态) 1已发放(M4)' }
|
||
grantedRef: { type: string, description: 'M4 发放回执(本波空)' }
|
||
createTime: { type: string, format: date-time, description: '触发时间' }
|
||
|
||
# ====================== U3 R-SOC 社区社交(additive) ======================
|
||
CommunityCommentRespVO:
|
||
type: object
|
||
description: 社区评论(列表项)
|
||
properties:
|
||
id: { type: integer, format: int64, description: '评论 ID' }
|
||
targetType: { type: integer, description: '评论目标类型:1游戏' }
|
||
targetId: { type: integer, format: int64, description: '评论目标 ID(gameId)' }
|
||
userId: { type: integer, format: int64, description: '评论作者用户 ID' }
|
||
content: { type: string, description: '评论正文' }
|
||
parentId: { type: integer, format: int64, description: '父评论 ID(0=一级评论)' }
|
||
reportStatus: { type: integer, description: '举报态:0正常 1被举报' }
|
||
createTime: { type: string, format: date-time, description: '创建时间' }
|
||
CommunityFollowResultRespVO:
|
||
type: object
|
||
description: 关注/取关结果(回显切换后关注态 + 被关注方最新粉丝数)
|
||
properties:
|
||
targetUserId: { type: integer, format: int64, description: '被关注方用户 ID' }
|
||
following: { type: boolean, description: '切换后是否已关注:true=已关注 false=已取关' }
|
||
followerCount: { type: integer, format: int64, description: '被关注方最新粉丝数' }
|
||
CommunityFollowStatRespVO:
|
||
type: object
|
||
description: 关注统计(粉丝数 + 关注数 + 当前登录者是否已关注 ta)
|
||
properties:
|
||
userId: { type: integer, format: int64, description: '查询的用户 ID' }
|
||
followerCount: { type: integer, format: int64, description: '粉丝数(被多少 active 用户关注)' }
|
||
followingCount: { type: integer, format: int64, description: '关注数(active 关注了多少人)' }
|
||
followedByMe: { type: boolean, description: '当前登录者是否已关注 ta(未登录则恒 false)' }
|
||
CommunityRankItemRespVO:
|
||
type: object
|
||
description: 排行榜单项
|
||
properties:
|
||
rank: { type: integer, description: '名次(从 1 开始)' }
|
||
targetId: { type: integer, format: int64, description: '排行对象 ID(game_hot=gameId / creator_hot=creatorUserId)' }
|
||
score: { type: integer, format: int64, description: '排行分值' }
|
||
CommunityDanmakuRespVO:
|
||
type: object
|
||
description: 弹幕(回放列表项 + WebSocket 广播载荷,type="danmaku" 的 content)
|
||
properties:
|
||
id: { type: integer, format: int64, description: '弹幕 ID' }
|
||
gameId: { type: integer, format: int64, description: '游戏 ID(房间)' }
|
||
userId: { type: integer, format: int64, description: '发送者用户 ID' }
|
||
content: { type: string, description: '弹幕正文' }
|
||
playTime: { type: integer, description: '播放进度(秒)' }
|
||
createTime: { type: string, format: date-time, description: '发送时间' }
|