hyapp-server/docs/CP关系服务端开发文档.md
2026-06-08 19:00:23 +08:00

12 KiB
Raw Blame History

CP关系服务端开发文档

本文定义当前 CP、兄弟、姐妹关系的服务端边界。关系事实归 user-service,送礼扣费归 wallet-service,房间送礼事实归 room-serviceCP 相关 IM 由 notice-service 消费 user_outbox 后补偿投递。

1. 关系规则

类型 编码 说明
CP cp CP 关系
兄弟 brother 兄弟关系
姐妹 sister 姐妹关系

规则:

  • CP 关系每个用户最多 1 个,不提供可调数量。
  • 兄弟和姐妹的每人 active 数量由后台 CP 配置控制。
  • A 和 B 同时只能存在一种 active 关系。
  • A 可以给 B 发送 cpbrothersister 多种 CP 礼物,形成多条 pending 申请。
  • B 接受其中一个申请后,同一对用户其他 pending 申请会被置为 blocked,不能再接受。
  • 申请默认 24 小时过期。
  • 不提供佩戴 CP 功能;资料卡如果要展示关系,直接展示用户当前 active 关系。

2. 服务归属

服务 负责内容
wallet-service 礼物配置、扣费、热度值、礼物 icon 和动画快照
room-service 送礼命令、房间热度、房间礼物 IM、RoomGiftSent outbox
user-service CP 申请、关系、亲密值、等级、等级奖励幂等、user_outbox
gateway-service App HTTP 接口、鉴权、request_id 透传
notice-service 申请、同意、拒绝、关系成立的 C2C/房间/区域 IM
cron-service 定时触发 user-service 过期申请处理

边界:

  • room-service 不保存 CP 关系状态。
  • user-service 不直连 wallet-serviceroom-servicenotice-service 数据库。
  • CP 申请和亲密值变化只能消费 RoomGiftSent MQ 事实,不能扫 room_outbox
  • 下游服务只能消费 owner service 发布到 RocketMQ 的 outbox。

3. CP礼物配置

礼物大类使用 gift_type_code=cp。CP 子类型使用发送时快照字段 cp_relation_type,值为 cpbrothersister

配置 说明
礼物类型 gift_type_code=cp,礼物面板展示为 CP 礼物 Tab
CP 子类型 cp_relation_type=cp/brother/sister,用于 CP Tab 二级分类
礼物 icon 来自绑定资源的 asset_url,发送事件保存快照
礼物价格和热度 继续由 wallet-service 结算,客户端不能传价格或热度

cp_relation_type 写入礼物 presentation_json

{
  "cp_relation_type": "cp",
  "cp_relation_label": "CP礼物"
}

4. RoomGiftSent字段

api/proto/events/room/v1/events.protoRoomGiftSent 必须带以下送礼快照:

字段 类型 说明
gift_type_code string CP 礼物为 cp
cp_relation_type string cpbrothersister;非 CP 礼物为空
gift_name string 礼物名称
gift_icon_url string 礼物 icon
gift_animation_url string 礼物动画,可为空

5. 送礼触发申请

sequenceDiagram
  participant F as Flutter
  participant G as gateway-service
  participant R as room-service
  participant W as wallet-service
  participant U as user-service
  participant N as notice-service
  participant IM as Tencent IM

  F->>G: POST /api/v1/rooms/gift/send
  G->>R: SendGift
  R->>W: DebitGift
  W-->>R: heat_value + gift_type_code + cp_relation_type + gift snapshot
  R->>R: update heat/rank/command log
  R-->>F: SendGiftResponse
  R-->>U: RoomGiftSent MQ
  U->>U: create or refresh CP application
  U-->>N: UserCPApplicationCreated MQ
  N->>IM: A -> B C2C cp_application_created
  N->>IM: room cp_application_created, recipient_user_id=B

处理规则:

  • 只有 gift_type_code=cpcp_relation_type 有效时创建申请。
  • 同一个 RoomGiftSent.event_id 只能消费一次。
  • A 给 B 发送同一类型 CP 礼物时,如果已有 pending 申请,刷新礼物快照和 expires_at_ms
  • A 给 B 发送不同类型 CP 礼物时,可以各有一条 pending 申请。
  • 如果任一方已经有 active 关系,申请可以存在,但接受时会被拒绝;已有关系双方互送礼物会增加亲密值。

6. 同意和拒绝

sequenceDiagram
  participant F as Flutter B
  participant G as gateway-service
  participant U as user-service
  participant N as notice-service
  participant IM as Tencent IM

  F->>G: POST /api/v1/cp/applications/{id}/accept
  G->>U: AcceptCPApplication
  U->>U: lock pair + lock both users + create relationship
  U-->>N: UserCPApplicationAccepted MQ
  U-->>N: UserCPRelationshipCreated MQ
  N->>IM: B -> A C2C cp_application_accepted
  N->>IM: A -> B C2C cp_application_accepted
  N->>IM: room cp_application_accepted, recipient_user_id=A
  N->>IM: region cp_relationship_created

处理规则:

  • 接受和拒绝都只能由申请目标用户 B 操作。
  • pending 申请过期后不能接受gateway envelope 返回 CONFLICT;内部 gRPC 语义是 FailedPrecondition。
  • 接受时同时校验 A 和 B 是否已经有任意 active 关系;任一方已有关系就返回 CONFLICT
  • 同意成功后写 active 关系,关闭同一对用户其他 pending 申请。
  • 同意会发两条 C2CB -> A 表示“我同意了你”,A -> B 表示“对方已同意你的申请”。
  • 同意和拒绝都会向 A 发送房间 IMrecipient_user_id=A 限定展示对象。
  • 拒绝仍只向 A 发送一条 C2C 和一条房间 IM。
  • 同意成功后额外发送区域 IM区域取申请来源房间的 visible_region_id

7. 亲密值和升级

任意礼物发送成功后,如果发送方和收礼方已经有 active 关系,则按本次礼物的 heat_value 增加亲密值。

规则:

  • 普通礼物按 100% 热度值增加亲密值。
  • 幸运礼物、超级幸运礼物直接使用钱包回执里的最终 heat_value,不重复计算比例。
  • 多目标送礼时按每个目标的账务回执分别增加对应关系亲密值。
  • 等级范围 1 到 5等级亲密值阈值和奖励资源组由后台 CP 配置维护。
  • 每个等级可绑定奖励资源组,升级时调用 wallet-service 给双方发放资源。
  • 奖励发放幂等键为 cp_level_reward:{relationship_id}:{level}:{user_id}
  • App 关系查询返回当前等级阈值、下一等级阈值、距离下一级和进度百分比。
  • 资料卡弹窗只能使用 /api/v1/cp/relationships 返回的阈值字段展示进度;客户端不能读取后台配置或硬编码等级表。

8. App HTTP接口

所有接口走 gateway-service,响应使用 {code,message,request_id,data}

方法 地址 说明
GET /api/v1/cp/applications 查询我的申请
POST /api/v1/cp/applications/{application_id}/accept 同意申请
POST /api/v1/cp/applications/{application_id}/reject 拒绝申请
GET /api/v1/cp/relationships 查询我的 active 关系

/api/v1/cp/relationships 的 relationship item 包含:

字段 说明
relationship_id 关系 ID
relation_type cpbrothersister
status 当前为 active
me 当前用户快照
partner 对方用户快照
intimacy_value 当前亲密值
level 当前等级
current_level_threshold 当前等级起始亲密值
next_level_threshold 下一等级所需亲密值;满级时为 0
needed_for_next_level 距离下一级还需要多少亲密值;满级时为 0
level_progress_percent 当前等级内进度百分比0 到 100
max_level 是否已经没有下一等级
formed_at_ms 关系形成时间
updated_at_ms 最近更新时间

这些字段由 user-service 从 user_cp_level_rules 计算gateway 只做透传。客户端资料卡不能根据本地表推算这些值。

申请列表参数:

参数 类型 必填 说明
direction string incomingoutgoing,默认 incoming
status string pendingacceptedrejectedexpiredblocked
page int32 默认 1
page_size int32 默认 20

关系列表参数:

参数 类型 必填 说明
relation_type string cpbrothersister;不传返回全部
page int32 默认 1
page_size int32 默认 20

拒绝请求体:

字段 类型 必填 说明
reason string 拒绝原因,只进入 IM/outbox payload

9. 数据表

表放在 user-service 库,所有表带 app_code,时间使用 UTC epoch milliseconds。

说明
user_cp_relation_configs CP/兄弟/姐妹数量与申请过期配置CP 数量服务端固定为 1兄弟/姐妹读取后台配置
user_cp_level_rules 等级阈值和奖励资源组
user_cp_gift_event_consumption RoomGiftSent 消费幂等
user_cp_applications CP 关系申请
user_cp_relationships 双人关系事实
user_cp_level_reward_grants 等级奖励发放幂等
user_outbox CP 事件事实

关键唯一约束:

  • active 关系按用户对唯一:(app_code, user_a_id, user_b_id, status='active')
  • CP active 关系按单用户唯一:任一用户已有 CP 关系就不能再接受新的 CP 关系。
  • 兄弟/姐妹 active 关系按后台配置做单用户数量上限校验。
  • pending 申请按用户对和类型唯一:(app_code, requester_user_id, target_user_id, relation_type, status='pending')

10. 相关IM

IM 通道 发送时机
cp_application_created C2C A 送 CP 礼物触发申请后A 发给 B
cp_application_created 房间群 A 送 CP 礼物触发申请后发到来源房间payload 带 recipient_user_id=B
cp_application_accepted C2C B 同意后B 发给 Apayload 带 c2c_notice_role=accepted_to_requestermessage_text=我同意了你
cp_application_accepted C2C B 同意后A 发给 Bpayload 带 c2c_notice_role=accepted_to_acceptormessage_text=对方已同意你的申请
cp_application_accepted 房间群 B 同意后发到来源房间payload 带 recipient_user_id=A
cp_application_rejected C2C B 拒绝后B 发给 A
cp_application_rejected 房间群 B 拒绝后发到来源房间payload 带 recipient_user_id=A
cp_relationship_created 区域群 关系建立后发送区域播报

C2C 使用腾讯云 IM From_Account 表达会话方向:申请为 A拒绝为 B同意会发 B -> AA -> B 两条。区域 IM 群 ID 使用 hy_<app_code>_bc_r_<region_id>,本地测试可通过 group_id_prefix 加前缀。

11. 错误码

场景 code 说明
申请不存在 NOT_FOUND application_id 不存在或不属于当前用户
申请已过期 CONFLICT 不能再同意;内部 gRPC 语义是 FailedPrecondition
已有关系 CONFLICT A/B 任一方已经有 active 关系
无权限处理 PERMISSION_DENIED 不是申请目标用户
幂等冲突 CONFLICT command_id 或事件消费 payload 不一致

12. 验证项

  • CP 礼物发送成功后,RoomGiftSentgift_type_code=cpcp_relation_type、礼物 icon 快照。
  • A 给 B 连发 cpbrothersister 三种礼物,会生成三条 pending 申请。
  • B 接受其中一条后,其他两条不能再接受。
  • A/B 建立关系后A 或 B 都不能再和第三人建立 active 关系。
  • pending 申请超过默认 24 小时后不能接受。
  • active 关系双方互送任意礼物,亲密值按 heat_value 增加。
  • 同意、拒绝、关系成立的 IM 都写入 notice_delivery_events,失败可重试。