hyapp-server/docs/经理中心资源赠送架构.md
2026-05-11 19:26:01 +08:00

14 KiB
Raw Blame History

Manager Center Resource Grant Architecture

本文定义后台资源列表的“赠送权限”开关、H5 经理中心资源赠送、以及可复用用户查询接口的服务边界。资源 catalog、用户资源权益和赠送事实仍按 Resource And Resource Group Architecture 归属 wallet-service经理、Agency、BD 等业务身份仍按 Host, Agency And BD App Architecture 归属 user-service

Goals

  • 后台资源列表增加“赠送权限” switch新建资源默认打开关闭后资源仍可存在、可用于其他业务但不能出现在经理中心赠送列表也不能被经理中心赠送。
  • server/admin 和后台前端支持读取、创建、编辑和切换该字段,但不成为资源配置事实 owner。
  • H5 经理中心提供资源赠送列表、赠送给用户接口和通用用户查询入口。
  • 经理身份必须由服务端校验,客户端不能自报 is_manager
  • 用户查询接口按业务场景复用首个场景是经理中心赠送后续代理中心、申请成为主播、BD 中心可以复用同一个 user-service 查询能力,但必须传入明确 scene 并执行各自权限和字段裁剪。

Non-Goals

  • 不新增独立 manager-serviceresource-service
  • 不把用户资源余额、背包、赠送记录写入 server/admin 数据库。
  • 不允许 H5 客户端提交资源价格、金币数量、权益有效期或赠送策略。
  • 不支持经理中心赠送资源组;资源组仍只允许后台或明确的系统命令赠送。
  • 不在 room-service 中校验经理身份或资源赠送权限。
  • 不把通用用户查询做成无权限全局搜索;所有查询必须带 scene且返回字段按 scene 收敛。

Service Ownership

Service Owns Does Not Own
wallet-service resources.manager_grant_enabled、资源赠送白名单判断、资源赠送事务、钱包入账、用户资源权益、resource outbox 用户是否经理、用户资料搜索、后台账号权限
user-service 用户主数据、短号解析、通用用户查询、经理/Agency/BD/主播/币商等业务身份能力判定 资源 catalog、钱包余额、用户资源权益
gateway-service H5 HTTP /api/v1 envelope、App 鉴权、scene 参数、调用 user-service 校验能力和目标用户、调用 wallet-service 赠送命令 资源事实、用户身份事实、钱包/背包落账
server/admin 后台鉴权、资源列表/编辑表单、操作审计、调用 wallet-service 管理 RPC 资源事实、H5 经理身份、用户资源背包
H5 经理中心 展示资源列表、选择目标用户、提交赠送命令 权限判断、目标用户真实性、赠送数量和有效期计算

Core Concepts

Concept Meaning
manager_grant_enabled 资源是否允许由经理中心赠送。它不是后台能否赠送的开关;后台仍使用现有 grantable 和后台权限控制。
manager_center App H5 业务入口,由 gateway 鉴权后进入。首版经理身份映射为 active Agency owner后续如果引入 Agency manager 表,只扩展 user-service 能力判定。
business user lookup 通用用户查询能力。调用方必须传 sceneuser-service 按 scene 校验 actor 能力并裁剪返回字段。
manager resource grant 经理中心发起的单资源赠送命令。落库仍是 resource_grantsgrant_source=manager_centeroperator_user_id=actor_user_id

Admin Resource Switch

resources 增加字段:

ALTER TABLE resources
  ADD COLUMN manager_grant_enabled BOOLEAN NOT NULL DEFAULT TRUE,
  ADD KEY idx_resources_manager_grant (app_code, manager_grant_enabled, status, sort_order);

字段语义:

  • 默认值为 TRUE,满足“后台资源列表赠送权限 switch 默认打开”。
  • 关闭 switch 只影响经理中心赠送列表和经理中心赠送命令。
  • status=disabled 的资源即使 manager_grant_enabled=TRUE,也不能出现在 H5 赠送列表。
  • grantable=FALSE 的资源即使 manager_grant_enabled=TRUE,也不能被任何赠送命令发放。
  • 历史已经赠送出去的权益不受该字段变更影响。

后台接口保持当前 server/admin -> wallet-service 边界:

GET  /api/v1/admin/resources
POST /api/v1/admin/resources
PUT  /api/v1/admin/resources/{resource_id}
POST /api/v1/admin/resources/{resource_id}/enable
POST /api/v1/admin/resources/{resource_id}/disable

DTO/RPC 需要补充:

  • wallet.v1.Resource.manager_grant_enabled
  • CreateResourceRequest.manager_grant_enabled
  • UpdateResourceRequest.manager_grant_enabled
  • ListResourcesRequest.manager_grant_only

server/admin 只做字段透传和操作审计。新增或编辑资源时,如果请求体不传 managerGrantEnabledadmin-server 必须向 wallet-service 传 true,避免前端漏字段导致默认关闭。

Manager Capability Boundary

首版经理身份定义为:

  • 当前用户拥有 active Agency,且 agencies.owner_user_id = actor_user_id
  • Agency.status=active
  • 该能力由 user-service host domain 判断gateway 不能只读 access token 或客户端传参。

建议在 user-service 增加通用能力接口:

message CheckBusinessCapabilityRequest {
  RequestMeta meta = 1;
  int64 actor_user_id = 2;
  string capability = 3;
}

message CheckBusinessCapabilityResponse {
  bool allowed = 1;
  string reason = 2;
}

首版 capability

Capability Allowed When
manager_center active Agency owner
manager_resource_grant active Agency owner

后续如果出现 Agency 授权管理员,不改 gateway 和 wallet-service只在 user-service host domain 增加 agency_managers 或对应 read model并扩展 capability 判定。

H5 App APIs

所有接口走 gateway /api/v1 envelope。access token 解析、RequestMeta.request_idapp_codeclient_ipuser_agent 由 gateway 透传到内部 gRPC。

赠送列表

GET /api/v1/manager-center/resource-grants/resources?resource_type=badge&page=1&page_size=20

处理规则:

  1. gateway 从 token 取 actor_user_id
  2. gateway 调 user-service CheckBusinessCapability(capability=manager_resource_grant)
  3. gateway 调 wallet-service ListResources(active_only=true, manager_grant_only=true, resource_type, page, page_size)
  4. wallet-service 只返回 status=active AND grantable=TRUE AND manager_grant_enabled=TRUE 的资源。

响应字段只返回 H5 展示和提交所需字段:

{
  "items": [
    {
      "resource_id": "101",
      "resource_type": "badge",
      "name": "VIP Badge",
      "asset_url": "https://...",
      "preview_url": "https://...",
      "wallet_asset_type": "",
      "wallet_asset_amount": 0,
      "sort_order": 10
    }
  ],
  "total": 1,
  "page": 1,
  "page_size": 20
}

H5 不能从该接口获得后台审计字段、created_by_user_idupdated_by_user_id 或完整 metadata_json。如果某类资源需要额外展示配置,必须在 wallet-service 先定义稳定的展示 DTO不能把原始后台 metadata 透出。

赠送给用户

POST /api/v1/manager-center/resource-grants

请求:

{
  "command_id": "mgr-grant-20260511-0001",
  "target_user_id": "900001",
  "resource_id": "101",
  "reason": "manager_center"
}

处理规则:

  1. gateway 校验当前用户拥有 manager_resource_grant capability。
  2. gateway 调 user-service GetUser(target_user_id),确认目标用户属于同一 app_code、存在、未禁用、未封禁。
  3. gateway 不接受客户端提交 quantityduration_mswallet_asset_amount
  4. gateway 调 wallet-service GrantResource
    • grant_source=manager_center
    • operator_user_id=actor_user_id
    • target_user_id=resolved target
    • quantity=1
    • duration_ms=0
    • reason=manager_center
  5. wallet-service 在同一事务中校验资源 status=activegrantable=TRUEmanager_grant_enabled=TRUE,再按现有资源策略落 resource_grantsresource_grant_items、钱包账本或用户资源权益。

wallet-service 不能只依赖赠送列表过滤。GrantResource 必须在写事务内根据 grant_source=manager_center 重新锁定资源并校验 manager_grant_enabled,防止客户端绕过列表直接提交资源 ID。

幂等规则沿用现有 resource_grants.command_id

  • 同一 app_code + command_id、同一 payload 重试返回原 grant。
  • 同一 command_id 换目标用户或资源返回冲突。
  • request_id 只做链路追踪,不能当幂等键。

Common User Lookup

通用用户查询不要挂在经理中心专属模块里。建议 gateway 暴露统一入口:

GET /api/v1/business/users/lookup?scene=manager_resource_grant&keyword=123456&page_size=20

user-service 新增或扩展查询 RPC

message BusinessUserLookupRequest {
  RequestMeta meta = 1;
  int64 actor_user_id = 2;
  string scene = 3;
  string keyword = 4;
  int32 page_size = 5;
}

message BusinessUserLookupItem {
  int64 user_id = 1;
  string display_user_id = 2;
  string username = 3;
  string avatar = 4;
  UserStatus status = 5;
  int64 region_id = 6;
  string region_code = 7;
  string region_name = 8;
}

message BusinessUserLookupResponse {
  repeated BusinessUserLookupItem users = 1;
}

scene 权限矩阵:

Scene Actor Requirement Query Scope
manager_resource_grant manager_resource_grant capability active users in same app_code
agency_application logged-in active user active agencies or agency owner candidates,按后续申请流程定义
bd_invite_agency active BD or BD Leader same-region active users,不能已有 active Agency owner
bd_invite_bd active BD Leader same-region active users,不能已有 active BD

首版只实现 manager_resource_grant。未实现 scene 必须返回 INVALID_ARGUMENT,不能默认降级成全局用户搜索。

查询安全规则:

  • keyword 必须是短号、用户 ID 或至少 2 个字符的昵称片段。
  • 数字 keyword 优先按 current display_user_id 精确匹配,再按 user_id 精确匹配。
  • page_size 最大 20。
  • 只返回必要展示字段,不返回手机号、登录方式、设备、邀请码绑定、钱包余额或三方身份。
  • 被禁用、封禁、跨 app_code 用户不返回。
  • gateway 对 lookup 和 grant 都要做限流lookup 不能成为撞库枚举入口。

Sequence

sequenceDiagram
  participant H5 as H5 Manager Center
  participant G as gateway-service
  participant U as user-service
  participant W as wallet-service

  H5->>G: GET /manager-center/resource-grants/resources
  G->>U: CheckBusinessCapability(actor, manager_resource_grant)
  U-->>G: allowed
  G->>W: ListResources(active_only, manager_grant_only)
  W-->>G: grantable resources
  G-->>H5: resources

  H5->>G: GET /business/users/lookup?scene=manager_resource_grant
  G->>U: BusinessUserLookup(actor, scene, keyword)
  U-->>G: minimal users
  G-->>H5: users

  H5->>G: POST /manager-center/resource-grants
  G->>U: CheckBusinessCapability(actor, manager_resource_grant)
  U-->>G: allowed
  G->>U: GetUser(target_user_id)
  U-->>G: active target
  G->>W: GrantResource(source=manager_center)
  W-->>G: resource grant
  G-->>H5: grant result

Validation Rules

Rule Owner Error
actor is not active manager user-service PERMISSION_DENIED
lookup scene unknown user-service INVALID_ARGUMENT
target user not found, disabled, banned, or different app user-service/gateway NOT_FOUND or PERMISSION_DENIED
resource disabled wallet-service CONFLICT
resource grantable=FALSE wallet-service CONFLICT
resource manager_grant_enabled=FALSE and source is manager_center wallet-service PERMISSION_DENIED
H5 submits quantity or duration gateway ignore or reject;首版建议 reject INVALID_ARGUMENT
duplicate command_id with changed payload wallet-service LEDGER_CONFLICT

Event And Audit

  • 后台切换 manager_grant_enabled 产出 ResourceChanged outbox便于 H5 资源列表缓存刷新。
  • 经理中心赠送成功产出 ResourceGranted 和必要的 UserResourceChanged/WalletBalanceChanged 事件。
  • resource_grants.grant_source='manager_center' 是 App 赠送审计来源。
  • operator_user_id 记录发起赠送的经理用户 ID不记录后台 admin 用户。
  • gateway 应在结构化日志记录 request_idactor_user_idtarget_user_idresource_idgrant_id 和错误 reason。

Implementation Order

  1. api/proto/wallet/v1/wallet.proto 增加 manager_grant_enabledmanager_grant_only,运行 make proto
  2. wallet-service MySQL 初始化脚本增加 resources.manager_grant_enabledrepository list/create/update/status/GrantResource 路径全部带字段和校验。
  3. server/admin resource DTO/request 增加 managerGrantEnabled;后台资源列表 switch 默认打开,编辑时透传。
  4. user-service 增加 CheckBusinessCapabilityBusinessUserLookup,首版只开放 manager_resource_grant scene。
  5. gateway-service 增加 H5 经理中心三个入口:赠送资源列表、通用用户查询、赠送资源。
  6. 补 OpenAPI、前端生成代码和 H5 页面联调。
  7. 补测试wallet manager switch、admin 透传、user lookup 权限、gateway H5 流程和幂等冲突。

Acceptance Criteria

  • 新建资源不传 managerGrantEnabled 时,后台列表 switch 显示打开。
  • 后台关闭某资源赠送权限后H5 经理中心赠送列表不返回该资源。
  • H5 绕过列表直接提交关闭权限的 resource_idwallet-service 拒绝赠送。
  • 非经理用户调用赠送列表、用户查询或赠送接口均返回权限错误。
  • 经理用户可以查询目标用户并完成单资源赠送,resource_grants.grant_source=manager_centeroperator_user_id 为经理用户 ID。
  • 同一 command_id 重试不重复发放;换目标或资源返回冲突。