hyapp-server/docs/App入口状态机.md

14 KiB
Raw Permalink Blame History

App Entry State Machine

本文定义用户从打开 App 到进入主界面的完整状态机。它只描述 App 入口流程、接口调用顺序、跳转条件和异常恢复边界;登录注册细节见 Login And Registration Technical Design,邀请码细节见 Registration Invite Code Architecture,房间重连细节见 Room Entry Reconnect Development Requirements

Goals

  • 客户端启动时用确定的状态机决定去登录页、资料补全页、主界面或维护/升级页。
  • 未完成资料的用户不能进入房间、IM、RTC、钱包和付费流程。
  • access token 过期时优先 refreshrefresh 失败才回登录页。
  • 主界面首屏只调用轻量一级接口:房间、消息、我的。
  • 腾讯云 IM 登录必须在 profile_completed=true 后发生,避免未完成资料用户进入实时系统。
  • 房间恢复必须独立于房间列表,不能靠列表猜测用户是否还在某个房间。

Current Interface Inventory

Capability Endpoint Status Rule
三方登录即注册 POST /api/v1/auth/third-party/login DONE 返回 is_new_user/profile_completed/onboarding_status
refresh token POST /api/v1/auth/token/refresh DONE 成功后轮换 refresh token
资料补全 POST /api/v1/users/me/onboarding/complete DONE 成功后返回新的 access token不轮换 refresh token可选提交 invite_code
注册国家 GET /api/v1/countries DONE 登录前可用
我的页首屏 GET /api/v1/users/me/overview DONE 主界面轻聚合
房间列表 GET /api/v1/rooms?tab=hot/new DONE 需要 completed profile
消息 tab GET /api/v1/messages/tabs DONE 需要 completed profile
腾讯 IM UserSig GET /api/v1/im/usersig DONE 需要 completed profile
App 启动配置 GET /api/v1/app/bootstrap DONE 版本、维护、feature flags、配置版本
当前房间恢复 GET /api/v1/rooms/current DONE 判断是否有可恢复房间
推送 token 绑定 POST /api/v1/devices/push-token / DELETE /api/v1/devices/push-token DONE 离线消息触达

Top Level State Machine

stateDiagram-v2
  [*] --> Launch
  Launch --> Bootstrap
  Bootstrap --> ForceUpgrade
  Bootstrap --> Maintenance
  Bootstrap --> TokenCheck

  TokenCheck --> LoginRequired: no local token
  TokenCheck --> AuthenticatedProbe: access token exists

  AuthenticatedProbe --> MainReady: overview ok and profile completed
  AuthenticatedProbe --> Refreshing: access token expired or 401
  AuthenticatedProbe --> ProfileRequired: PROFILE_REQUIRED or token says profile incomplete

  Refreshing --> AuthenticatedProbe: refresh ok
  Refreshing --> LoginRequired: refresh failed

  LoginRequired --> LoginOrRegister
  LoginOrRegister --> ProfileRequired: login ok but profile incomplete
  LoginOrRegister --> MainReady: login ok and profile completed

  ProfileRequired --> CompleteOnboarding
  CompleteOnboarding --> MainReady: success with replacement access token

  MainReady --> MainTabs
  MainTabs --> IMLogin
  MainTabs --> RoomRestoreProbe

Launch Sequence

启动顺序:

  1. App 启动,生成或读取 stable device_id
  2. GET /api/v1/app/bootstrap,以 bootstrap 返回的版本、维护、feature flags 和配置版本作为入口决策事实。
  3. 如果 bootstrap 返回强更,进入强更页。
  4. 如果 bootstrap 返回维护中,进入维护页。
  5. 检查本地是否有 access token。
  6. 没有 token进入登录页。
  7. 有 token调用 GET /api/v1/users/me/overview 做认证探测和首屏数据读取。

不要只靠本地缓存判断是否进入主界面。用户可能被禁用、token 可能过期、资料完成状态可能已经变化。

Bootstrap Contract

当前接口:

GET /api/v1/app/bootstrap

登录前也可调用。请求必须携带 App 解析头:

Header Meaning
X-App-Code / X-HY-App-Code 已知内部 app_code
X-App-Package / X-Package-Name 包名或 Bundle ID
X-App-Platform / X-Platform android or ios
X-App-Version 客户端版本
X-Build-Number 构建号

响应字段:

{
  "app_code": "lalu",
  "server_time_ms": 1777996800000,
  "force_upgrade": false,
  "maintenance": false,
  "minimum_version": "1.0.0",
  "latest_version": "1.2.0",
  "feature_flags": {
    "wallet_recharge": true,
    "wallet_withdraw": true,
    "diamond_exchange": true,
    "message_tab": true,
    "host_center": true,
    "room_create": true
  },
  "bottom_tabs": [
    {"key": "rooms", "title": "房间", "enabled": true},
    {"key": "messages", "title": "消息", "enabled": true},
    {"key": "me", "title": "我的", "enabled": true}
  ],
  "config_versions": {
    "countries": "v1",
    "banners": "v1",
    "h5_links": "v1",
    "resources": "v1",
    "gifts": "v1"
  }
}

bootstrap 只返回配置摘要和版本号,不返回完整礼物、背包资源或 banner 列表。客户端发现版本变化后再拉对应配置接口。

Authentication Probe

有 access token 时,首选调用:

GET /api/v1/users/me/overview

结果处理:

Result Client Action
200 OK 使用 overview 进入主界面
401 AUTH_REQUIRED / token expired 调 refresh
403 PROFILE_REQUIRED 进入资料补全页
403 USER_DISABLED/BANNED 进入账号异常页
5xx/502 展示重试页,不清 token

overview 失败时不要直接清空登录态。只有 refresh 明确失败、session revoked 或用户主动 logout 才清本地 token。

Refresh State

POST /api/v1/auth/token/refresh

请求必须带:

  • refresh_token
  • device_id

处理规则:

Result Client Action
refresh ok 替换 access token 和 refresh token重试 overview
SESSION_EXPIRED 清 token进登录页
SESSION_REVOKED 清 token进登录页
AUTH_FAILED 清 token进登录页
network/5xx 不清 token展示重试

refresh 成功会轮换 refresh token。客户端必须原子保存新 access token 和新 refresh token避免只保存一半导致下次启动失效。

Login State

三方登录:

POST /api/v1/auth/third-party/login

状态跳转:

Response Client Action
is_new_user=true 进入资料补全页
profile_completed=false 进入资料补全页
profile_completed=true 进入主界面

服务端不会返回 NOT_REGISTERED。三方身份不存在时,该接口原子创建用户、三方绑定、默认短号和 session。

Profile Required State

资料补全页需要先拉:

GET /api/v1/countries

提交:

POST /api/v1/users/me/onboarding/complete

请求体包含 username/avatar/gender/country,可以选填 invite_code。如果用户填写邀请码但服务端无法解析到有效邀请人,返回 INVALID_INVITE_CODE,客户端停留在资料补全页让用户修改或清空邀请码。

成功后:

  • 替换响应里的新 access token。
  • 保留原 refresh token该接口不轮换 refresh token。
  • 重新调用 GET /api/v1/users/me/overview
  • overview 成功后进入主界面。

未完成资料的 access token 会在 gateway profile gate 被拒绝。客户端不能绕过资料补全去请求房间、IM、RTC、钱包和付费接口。

Main Tabs Entry

进入主界面后,底部三个一级页使用这些接口:

Tab Primary Endpoint Notes
房间 GET /api/v1/rooms?tab=hot&limit=20 默认 hotnew 用同一接口
消息 GET /api/v1/messages/tabs 用户私聊列表走腾讯云 IM SDK
我的 GET /api/v1/users/me/overview 轻聚合,不查流水、成员、工资

主界面首屏可以并行:

sequenceDiagram
  participant C as Client
  participant G as gateway-service
  participant TIM as Tencent IM

  par room tab
    C->>G: GET /api/v1/rooms?tab=hot
  and message tab
    C->>G: GET /api/v1/messages/tabs
  and me tab
    C->>G: GET /api/v1/users/me/overview
  and IM
    C->>G: GET /api/v1/im/usersig
    C->>TIM: SDK login
  end

如果当前默认落在“房间” tab可以优先请求房间列表消息和我的延后或并行低优先级请求。

IM Login State

腾讯云 IM 登录必须发生在 profile_completed=true 后。

GET /api/v1/im/usersig

规则:

  • UserSig 只用于腾讯云 IM SDK 登录。
  • 用户私聊会话列表由 SDK 拉取。
  • 系统/活动消息由 /api/v1/messages/tabs/api/v1/messages 拉取。
  • UserSig 过期时重新调用该接口,不使用 refresh token。

未完成资料用户请求 /api/v1/im/usersig 必须返回 PROFILE_REQUIRED

Room Restore State

当前接口:

GET /api/v1/rooms/current

用途App 从后台回前台、进程重启、网络恢复时,判断是否有需要恢复的房间。不能通过房间列表猜测当前房间,因为列表是发现页,不表达当前用户 presence。

响应字段:

{
  "has_current_room": true,
  "room_id": "lalu_room_01",
  "room_version": 12,
  "role": "audience",
  "mic_session_id": "",
  "publish_state": "",
  "need_join_im_group": true,
  "need_rtc_token": false,
  "server_time_ms": 1777996800000
}

恢复规则:

State Client Action
has_current_room=false 不展示恢复入口
audience 重新登录 IM 并 join group不申请 RTC token
on mic pending/publishing /api/v1/rtc/token,恢复 RTC随后按麦位状态确认发流
room closed / kicked / banned 清本地房间态,展示原因或静默回房间列表

rooms/current 由 room-service 的用户 presence 读模型和 Room Cell 快照二次校验共同决定。该接口只做恢复探测,不写命令日志、不刷新心跳、不隐式 JoinRoom。

Push Token State

当前接口:

POST /api/v1/devices/push-token
DELETE /api/v1/devices/push-token

绑定时机:

  • 资料完成后。
  • 用户允许系统通知后。
  • token 变化、App 重装、语言/时区变化时重新上报。

该能力服务系统/活动消息离线触达,不影响 App 能否进入主界面。

Error Handling Rules

Error Meaning Client Action
AUTH_REQUIRED access token 缺失或无效 有 refresh 则 refresh否则登录
SESSION_EXPIRED refresh session 过期 清 token登录
SESSION_REVOKED refresh session 已吊销 清 token登录
PROFILE_REQUIRED 已登录但资料未完成 资料补全
INVALID_INVITE_CODE 注册页邀请码无效 停留资料补全页,提示修改或清空邀请码
USER_DISABLED 用户被禁用 账号异常页
USER_BANNED 用户被封禁 账号异常页
UPSTREAM_ERROR 上游不可用 重试,不清 token
network timeout 网络异常 重试,不清 token

不要因为普通 5xx、网络失败或 bootstrap 失败清空登录态。

Client Local State

客户端本地至少保存:

  • access_token
  • refresh_token
  • session_id
  • user_id
  • app_code
  • profile_completed
  • onboarding_status
  • device_id
  • last_room_id,只做恢复提示,不能作为 presence 事实
  • config version cache

服务端事实优先级高于本地缓存。只要服务端返回 profile required、disabled、banned、session revoked客户端必须更新本地状态。

Implementation Status

  1. 服务端已固定 App 入口状态机文档,客户端入口必须按本文状态转移。
  2. gateway 已实现 GET /api/v1/app/bootstrap返回版本、维护、feature flags、bottom tabs 和配置版本。
  3. gateway 已实现 GET /api/v1/rooms/current,只用 token user_id 做当前用户房间恢复探测,不修改房间状态。
  4. user-service 已实现 push token 绑定/解绑 RPCgateway 已暴露 POST/DELETE /api/v1/devices/push-token
  5. App 端下一步按本文状态机接入bootstrap -> token probe -> refresh/login/onboarding -> main tabs -> IM login -> room restore。
  6. 端到端 smoke 必须覆盖新用户注册、老用户启动、access token 过期 refresh、profile required、IM login、房间恢复。

Verification Matrix

Scenario Expected
首次安装无 token bootstrap 后进入登录页
新用户三方登录 创建用户,进入资料补全页
新用户资料补全填写有效邀请码 注册完成,邀请关系绑定到邀请码 owner
新用户资料补全填写无效邀请码 返回 INVALID_INVITE_CODE,仍在资料补全页
资料补全成功 替换 access token进入主界面
access token 过期 refresh 成功后重试 overview
refresh token 过期 清 token进入登录页
未完成资料请求房间列表 返回 PROFILE_REQUIRED
未完成资料请求 IM UserSig 返回 PROFILE_REQUIRED
主界面打开房间 tab GET /api/v1/rooms?tab=hot
主界面打开消息 tab GET /api/v1/messages/tabs,用户私聊走 IM SDK
主界面打开我的 tab GET /api/v1/users/me/overview
App 回前台且有房间 presence rooms/current 返回恢复信息
普通 5xx 或网络失败 展示重试,不清本地 token

Critical Rules

  • 资料未完成不能进入实时系统、房间、钱包和付费流程。
  • request_id 只做链路追踪,不做幂等键。
  • 登录和 refresh 响应里的 token 必须原子保存。
  • CompleteOnboarding 只替换 access token不轮换 refresh token。
  • IM 登录在主资料完成之后,用户私聊状态以腾讯云 IM SDK 为准。
  • 房间恢复用 rooms/current,不要用房间列表代替。
  • bootstrap 只返回配置摘要和版本,不返回大列表。