7.9 KiB
线上业务接入边界方案
文档版本:v1.0 最后更新:2026-04-02
1. 目的
本文档定义小程序接入线上业务 API 时的架构边界,确保以下原则始终成立:
- 游戏玩法仍然完全由配置驱动
- 线上 API 只负责业务编排,不负责定义或污染玩法
- 地图引擎和规则运行时可以继续独立于业务系统运行
- 本地 demo、离线配置、线上赛事三种入口可以共存
本文档适用于以下接入范围:
- 用户管理
- 登录与鉴权
- 首页卡片
- 赛事详情
- 地图详情
- Event 详情
- 报名
- launch 启动
- 后续 session 上报与查询
2. 核心结论
线上接入后,系统仍保持两层结构:
- 业务层:决定“用户是谁、能进什么、当前启动什么”
- 游戏层:决定“地图怎么画、规则怎么跑、控制点怎么判定、体验怎么表现”
两层之间只允许通过一个明确的启动模型通信,不允许业务 API 对游戏规则对象做直接写入。
一句话定义:
API 负责发放启动上下文,配置负责定义游戏本身。
3. 分层原则
3.1 业务层职责
业务层负责:
- 登录与 token 管理
- 用户资料与身体数据
- 卡片、赛事、地图、Event 列表与详情
- 报名资格校验
- launch 启动资格与 session 凭证发放
- 后续成绩、轨迹、历史记录上传与查询
业务层可以决定:
- 是否允许用户启动
- 当前应启动哪个 Event
- 当前应加载哪份配置或 manifest
- 当前启动绑定的
session_id、session_token
业务层不可以决定:
- 控制点布局
- 游戏规则
- 打卡判定
- 跳点规则
- 引导、音效、表现策略
- 游戏内内容卡的结构和行为定义
3.2 游戏层职责
游戏层负责:
- 地图资源加载
- KML / course / 配置解析
GameDefinition构建- 规则插件运行
- 传感器接入
- HUD、反馈、结果页、本地统计
- 游戏内 session 生命周期
游戏层只认配置和本地运行态,不认业务 API 对象。
游戏层不应该直接出现以下业务字段:
competition_idregistration_statusaccess_tokenrefresh_tokenAuthorizationuser_id
业务字段可以存在于页面壳层或业务服务层,但不进入规则层。
4. 唯一允许的层间模型
业务层和游戏层之间,统一通过 GameLaunchEnvelope 通信。
建议结构如下:
interface GameLaunchEnvelope {
config: {
configUrl: string
configLabel: string
configChecksumSha256?: string | null
releaseId?: string | null
routeCode?: string | null
}
business: {
source: 'demo' | 'competition' | 'direct-event' | 'custom'
competitionId?: string | null
eventId?: string | null
launchRequestId?: string | null
participantId?: string | null
sessionId?: string | null
sessionToken?: string | null
sessionTokenExpiresAt?: string | null
realtimeEndpoint?: string | null
realtimeToken?: string | null
} | null
}
解释:
config是游戏层真正消费的输入business是业务壳保留的上下文- 地图页可以同时拿到两者,但地图引擎只读取
config
5. 推荐启动链路
5.1 Demo 启动
适用于本地调试、离线测试、玩法验证。
流程:
- 页面构建 demo
GameLaunchEnvelope config.configUrl指向 demo 配置business.source = 'demo'- 跳转地图页
- 地图页加载配置并启动引擎
特点:
- 不依赖业务 API
- 不依赖登录
- 不依赖 session
5.2 线上赛事启动
适用于正式业务入口。
流程:
- 业务页请求赛事 / Event 详情
- 用户在业务页完成登录、资格校验、报名确认
- 用户点击开始,业务页调用
launch - 后端返回
session_id、session_token、release_id、manifest_url、route_code - 业务层把上述信息转换为
GameLaunchEnvelope - 地图页只根据
config载入配置 - 业务壳层保存
business上下文供后续上报使用
注意:
launch是业务启动,不等于规则层startSession- 规则层本地开始游戏,仍由引擎按配置驱动
5.3 线上直入地图启动
适用于地图详情或 Event 直入。
流程与赛事入口基本一致,区别仅在于:
- 入口页不同
- 资格校验更轻
business.source = 'direct-event'
6. manifest 的角色
后端提供的 manifest_url 不应直接变成规则层对象。
推荐做法:
- 业务层或适配层下载 manifest
- 将 manifest 解析并映射到当前配置体系
- 输出为当前引擎已支持的配置入口
manifest 是“线上发布描述”,不是“规则运行对象”。
建议把 manifest 适配理解为一个编译过程:
- 输入:后端发布描述
- 输出:当前配置驱动引擎可识别的配置资源
7. 目录建议
建议按三层组织代码:
miniprogram/
services/
http.ts
client-api.ts
auth.ts
business/
launch/
launchBuilder.ts
launchStore.ts
manifestAdapter.ts
utils/
gameLaunch.ts
pages/
login/
home/
competition-detail/
event-detail/
map/
说明:
services只处理 API 通信business/launch只做业务到配置的适配utils/gameLaunch.ts定义启动模型和页面跳转协议pages/map只做配置加载和游戏承载
8. 代码边界约束
8.1 允许进入地图页的内容
允许进入地图页:
GameLaunchEnvelopeconfigUrlconfigLabelreleaseIdrouteCodesessionToken
但地图页内部还要继续区分:
- 引擎可读:
config - 业务壳可读:
business
8.2 不允许进入引擎的内容
以下内容禁止进入 MapEngine、GameRuntime、GameDefinition:
- 用户信息
- 登录态 token
- 报名状态
- 业务接口返回原始对象
- 赛事详情原始 JSON
- Event 详情原始 JSON
8.3 上报也走旁路
后续若接 punches、finish、session-uploads,建议流程如下:
- 游戏层产生本地事件
- 页面壳层或业务 service 订阅这些事件
- 由业务层决定是否调用 API
不要在规则层里直接 wx.request。
9. 当前项目的落地点
当前项目已具备以下基础:
- 地图页是配置驱动入口
remoteMapConfig.ts负责远程配置加载MapEngine负责本地规则与表现运行- 已新增
utils/gameLaunch.ts作为启动边界模型
当前建议继续保持:
MapEngine只接RemoteMapConfig- 地图页只从
GameLaunchEnvelope.config获取配置入口 - 业务上下文保留在地图页外层或页面壳层
10. 分阶段落地建议
阶段一:边界固化
目标:
- 地图页彻底改为只接
GameLaunchEnvelope - demo 启动与线上启动走同一套入口协议
验收标准:
- 不再依赖页面内硬编码 URL 作为唯一启动方式
- 业务字段不进入引擎
阶段二:业务壳接入
目标:
- 接入登录、首页卡片、赛事详情、Event 详情、报名、launch
验收标准:
- 能从业务页成功进入地图页
- 地图仍由配置驱动启动
阶段三:manifest 适配
目标:
- 将后端
manifest_url适配为当前配置体系可消费的输入
验收标准:
- 同一个 Event 的线上发布内容可稳定映射为游戏配置入口
阶段四:session 下游联通
目标:
- 补充上报、完成、结果、历史查询
验收标准:
- 业务链路打通
- 规则层仍不直接依赖业务 API
11. 必须长期坚持的规则
- 业务 API 不定义玩法
- 配置文件不承载用户态
- 引擎不依赖登录状态
- 引擎不依赖报名状态
- 业务页不直接修改
GameDefinition - 规则层不直接请求业务 API
如果后续出现需求需要绕过这几条规则,应视为架构变更,不应当作普通功能迭代处理。
12. 一句话总结
线上系统负责“把用户送进正确的一局游戏”,配置系统负责“定义这局游戏是什么”。