hyapp-server/docs/my-page-overview-api.md
2026-05-08 18:48:29 +08:00

11 KiB
Raw Blame History

My Page Overview API

本文定义 App 底部 我的 页首屏聚合接口。该接口只返回首屏渲染需要的轻量摘要:用户资料、我的邀请码、核心资产余额、身份开关、消息红点和入口显隐。流水、成员列表、背包完整列表、工资明细、邀请列表和团队统计必须放到二级页接口。

Goals

  • 我的 页首屏一次请求拿到稳定摘要,减少 App 冷启动后的接口数量。
  • 聚合已有轻量能力:/users/me/wallet/me/balances/users/me/host-identity/messages/tabs
  • 避免实时 COUNT(*)、扫流水、扫成员、扫背包、现算工资。
  • 后端控制入口显隐App 不硬编码复杂身份组合。
  • 所有数据按 app_code 和当前 JWT user_id 隔离。

Endpoint

GET /api/v1/users/me/overview
Authorization: Bearer <access_token>

响应仍使用 gateway /api/v1 envelope

{
  "code": "OK",
  "message": "ok",
  "request_id": "req_01",
  "data": {
    "profile": {},
    "wallet": {},
    "invite": {},
    "roles": {},
    "badges": {},
    "entries": [],
    "server_time_ms": 1777996800000
  }
}

Response Shape

{
  "profile": {
    "user_id": "10001",
    "display_user_id": "163000",
    "default_display_user_id": "163000",
    "display_user_id_kind": "default",
    "display_user_id_expires_at_ms": 0,
    "username": "Alice",
    "avatar": "https://cdn.example.com/avatar.png",
    "gender": "female",
    "birth": "2000-01-01",
    "country": "US",
    "country_id": 1,
    "country_name": "United States",
    "country_display_name": "United States",
    "region_id": 10,
    "region_code": "north_america",
    "region_name": "North America",
    "language": "en",
    "profile_completed": true,
    "onboarding_status": "completed"
  },
  "wallet": {
    "balances": [
      {
        "asset_type": "COIN",
        "available_amount": 12000,
        "frozen_amount": 0,
        "version": 8
      },
      {
        "asset_type": "DIAMOND",
        "available_amount": 300,
        "frozen_amount": 0,
        "version": 3
      },
      {
        "asset_type": "USD_BALANCE",
        "available_amount": 2500,
        "frozen_amount": 500,
        "version": 2
      }
    ],
    "recharge_enabled": true,
    "diamond_exchange_enabled": true,
    "withdraw_enabled": true
  },
  "invite": {
    "my_invite_code": "A1B2C3",
    "invite_enabled": true,
    "invite_count": 12,
    "valid_invite_count": 3,
    "valid_invite_threshold_coin": 80000
  },
  "roles": {
    "is_host": true,
    "is_agent": false,
    "is_bd": false,
    "is_bd_leader": false,
    "is_coin_seller": false
  },
  "badges": {
    "unread_system_messages": 2,
    "unread_activity_messages": 1,
    "pending_role_invitations": 0
  },
  "entries": [
    {
      "key": "wallet",
      "title": "Wallet",
      "visible": true,
      "badge_count": 0
    },
    {
      "key": "host_center",
      "title": "Host Center",
      "visible": true,
      "badge_count": 0
    },
    {
      "key": "coin_seller_center",
      "title": "Coin Seller",
      "visible": false,
      "badge_count": 0
    },
    {
      "key": "backpack",
      "title": "Backpack",
      "visible": true,
      "badge_count": 0
    },
    {
      "key": "settings",
      "title": "Settings",
      "visible": true,
      "badge_count": 0
    }
  ],
  "server_time_ms": 1777996800000
}

Field Sources

Field Source Query Pattern
profile user-service.GetUser single row by (app_code, user_id)
wallet.balances wallet-service.GetBalances point read for COINDIAMONDUSD_BALANCE
invite.my_invite_code user-service invite code module point read active primary code by (app_code, user_id)
invite.invite_count invite read model users that successfully filled this invite code; without read model return 0 or omit
invite.valid_invite_count invite read model invited users whose cumulative eligible recharge reaches the configured threshold
invite.valid_invite_threshold_coin invite validity policy current configured threshold, default 80000 COIN
roles user-service host identity module point read role facts or future role summary read model
badges.unread_* message inbox owner counter/read model, not message list scan
entries gateway composition rules computed from roles and feature flags
server_time_ms gateway current server clock

当前实现已有 /users/me/wallet/me/balances/users/me/host-identity/messages/tabs/users/me/overview 可以先在 gateway-service 聚合这些能力;后续如果角色判断的三次 not-found RPC 变慢,再在 user-service 增加 GetUserRoleSummary 内部 RPC。

Asset Rules

首屏只返回三类资产:

Asset Show Rule
COIN 所有用户展示
DIAMOND 所有用户展示,但文案不能暗示可直接消费
USD_BALANCE 有余额、冻结金额、host/agent/bd/coin_seller 身份时展示

不要返回 GIFT_POINT。积分是后台工资/活动计算输入,不是普通用户钱包可直接操作资产。

Entry Rules

入口显隐由后端返回App 只负责渲染。

Entry Key Visible Rule
wallet always true
host_center roles.is_host == true
apply_host roles.is_host == false
agency_center roles.is_agent == true
bd_center roles.is_bd == true
bd_leader_center roles.is_bd_leader == true
coin_seller_center roles.is_coin_seller == true
backpack always true
settings always true
support always true

同一个用户可能同时是 BD 和 host。不要用互斥枚举表达角色必须使用 bool flags。

Expensive Fields To Exclude

不要在 overview 中实时查询这些字段:

Field Reason Replacement
邀请用户列表 需要分页,可能扫 user_invite_relations 二级页 GET /api/v1/invites/users
实时邀请人数 COUNT(*) 高活跃邀请人会让首页变慢 read model counter 或返回 0
邀请奖励流水 属于钱包/活动明细 二级页分页

这些字段不要放进首屏 overview

Field Reason Replacement
period_mic_minutes 需要统计聚合,可能扫 stats Host Center 二级页
period_gift_points 需要统计聚合,可能跨日汇总 Host Center 二级页
estimated_earning_usd_minor 不能首屏现算工资 后台工资 read model 或收益页
agency_member_count 容易 COUNT(*) members Agency Center 二级页或 summary table
bd_host_count 团队规模统计昂贵 BD Center 二级页或 summary table
pending_withdrawals 扫提现/流水表 wallet badge counter
recharge_count 扫充值记录 wallet 二级页
resource_count 扫背包权益表 backpack 二级页
latest_transactions 扫交易流水 wallet 二级页
inbox_items 扫消息列表 messages 二级页

首屏接口禁止为了红点实时扫大表。需要红点就维护 counter/read model没有 counter 时先不展示该红点。

Performance Budget

目标:

  • P95 backend latency: < 120ms in normal region deployment.
  • Gateway fanout RPC count: max 4.
  • No list scan.
  • No transaction history query.
  • No member COUNT(*).
  • No resource entitlement list.
  • No salary calculation.

推荐并行 fanout

sequenceDiagram
  participant C as Client
  participant G as gateway-service
  participant U as user-service
  participant W as wallet-service
  participant M as message inbox owner

  C->>G: GET /api/v1/users/me/overview
  par profile and roles
    G->>U: GetUser(user_id)
    G->>U: GetUserRoleSummary(user_id)
  and wallet
    G->>W: GetBalances(COIN, DIAMOND, USD_BALANCE)
  and badges
    G->>M: ListMessageTabs(user_id)
  end
  G->>G: compose entries and feature flags
  G-->>C: overview

MVP 可以复用已有 GetHostProfileGetBDProfileGetCoinSellerProfile 聚合角色;优化版应增加单个 GetUserRoleSummary,减少 not-found RPC 和错误映射成本。

Degraded Responses

首屏接口可以部分降级,但必须清楚标记。

Upstream Failure Response Rule
user-service.GetUser fail 整体失败,资料是首屏主数据
wallet-service.GetBalances fail 返回空 balances并加 wallet.unavailable=true
role summary fail 返回 all false并加 roles.unavailable=true,不要误展示特权入口
message tabs fail unread 置 0并加 badges.unavailable=true

如果某个上游超时gateway 不应无限等待。overview 是首屏接口,应该有比普通操作接口更短的聚合超时预算。

HTTP Handler Shape

新增路由:

mux.Handle(apiV1Prefix+"/users/me/overview", h.profileAPIHandler(jwtVerifier, h.getMyOverview))

handler 只做协议聚合:

  1. 从 JWT context 取 user_idapp_code
  2. 并行请求 profile、balances、roles、message tabs。
  3. 把资产补齐为固定三类,缺失资产返回 0。
  4. 根据 roles 和 feature flags 生成 entries。
  5. 返回 envelope data。

不要在 gateway 写 SQL也不要在 gateway 做工资、成员、资源统计。

Verification Matrix

Scenario Expected
普通用户打开我的页 返回 profile、COIN/DIAMOND/USD_BALANCE、普通入口
host 打开我的页 roles.is_host=true,展示 host_center
BD Leader 打开我的页 is_bd=trueis_bd_leader=true,展示 leader 入口
币商打开我的页 is_coin_seller=true,展示 coin seller 入口
钱包没有账户行 三类资产都返回 0 投影
消息服务失败 我的页仍可展示,消息红点降级为 0
用户资料服务失败 overview 整体失败
大量成员/流水存在 overview 延迟不受影响,因为不查成员和流水

Implementation Order

  1. 新增本文档,确认字段边界和慢查询排除规则。
  2. gateway-service 增加 GET /api/v1/users/me/overview handler。
  3. 复用现有 GetUserGetBalancesGetHostProfile/GetBDProfile/GetCoinSellerProfileListMessageTabs
  4. 增加 handler 单元测试覆盖普通用户、host、BD Leader、币商、钱包缺失、消息降级。
  5. 如果角色 RPC 成本偏高,再在 user-service 增加 GetUserRoleSummary
  6. 如果红点需要更多类型,先补 counter/read model再把 badge 加进 overview。

Critical Rules

  • 我的 页 overview 是轻聚合接口,不是用户全量详情接口。
  • 首屏不做 COUNT(*)、不扫流水、不扫成员、不查完整背包、不现算工资。
  • 钱包余额以 wallet-service 为准。
  • 用户资料以 user-service 为准。
  • 角色入口以服务端返回的 rolesentries 为准。
  • 消息红点以 message inbox counter/read model 为准,用户私聊未读仍以腾讯云 IM SDK 为准。