完善多赛道联调与全局产品架构
This commit is contained in:
294
doc/gameplay/多赛道Variant前后端最小契约.md
Normal file
294
doc/gameplay/多赛道Variant前后端最小契约.md
Normal file
@@ -0,0 +1,294 @@
|
||||
# 多赛道 Variant 前后端最小契约
|
||||
> 文档版本:v0.1
|
||||
> 最后更新:2026-04-02 18:33:00
|
||||
|
||||
本文档用于定义“多 KML / 多赛道 variant”第一阶段联调所需的最小前后端契约。
|
||||
|
||||
目标:
|
||||
|
||||
- 先定最小可联调字段,不一开始追求大而全
|
||||
- 保证准备页、launch、地图、恢复、结果页能围绕同一 `variantId` 工作
|
||||
- 避免前端从页面交互反推后端字段
|
||||
|
||||
说明:
|
||||
|
||||
- 本文档只定义最小契约建议
|
||||
- 不等同于最终后台配置模型
|
||||
- 不等同于最终数据库模型
|
||||
- 本文档优先服务前后端第一阶段联调
|
||||
|
||||
---
|
||||
|
||||
## 1. 最小联调目标
|
||||
|
||||
第一阶段只解决下面 4 件事:
|
||||
|
||||
1. 一个活动可声明多个 `variant`
|
||||
2. 准备页能知道当前活动是否允许手选 / 随机 / 后端指定
|
||||
3. `launch` 能明确返回本局最终绑定的 `variantId`
|
||||
4. `result / ongoing / recovery` 能持续追溯同一个 `variantId`
|
||||
|
||||
一句话目标:
|
||||
|
||||
**让 `variantId` 成为贯穿一局的稳定事实。**
|
||||
|
||||
---
|
||||
|
||||
## 2. 契约原则
|
||||
|
||||
### 2.1 session 绑定优先
|
||||
|
||||
- 前端可参与选择
|
||||
- 最终绑定以后端 session 为准
|
||||
|
||||
### 2.2 launch 是最终真相
|
||||
|
||||
- 前端准备页即便做了手选或随机请求
|
||||
- 地图页真正消费的仍应是 `launch` 返回的最终绑定结果
|
||||
|
||||
### 2.3 恢复不重新分配
|
||||
|
||||
- 恢复链只恢复既有 `variantId`
|
||||
- 不重新随机
|
||||
- 不重新提示选择
|
||||
|
||||
### 2.4 结果必须可追溯
|
||||
|
||||
- 结果页
|
||||
- ongoing session
|
||||
- 历史成绩
|
||||
|
||||
都建议能反查:
|
||||
|
||||
- `variantId`
|
||||
- 可选 `variantName`
|
||||
|
||||
---
|
||||
|
||||
## 3. 活动级最小字段建议
|
||||
|
||||
建议活动可玩信息中增加一个最小赛道编排块,例如在 `play` 返回里体现:
|
||||
|
||||
### 3.1 assignmentMode
|
||||
|
||||
含义:
|
||||
|
||||
- 当前活动的赛道分配模式
|
||||
|
||||
建议最小取值:
|
||||
|
||||
- `manual`
|
||||
- `random`
|
||||
- `server-assigned`
|
||||
|
||||
### 3.2 courseVariants
|
||||
|
||||
含义:
|
||||
|
||||
- 当前活动可用赛道版本列表
|
||||
|
||||
建议最小字段:
|
||||
|
||||
- `id`
|
||||
- `name`
|
||||
- `description`
|
||||
- `routeCode`
|
||||
- `selectable`
|
||||
|
||||
备注:
|
||||
|
||||
- 第一阶段不一定要在 `play` 里返回所有复杂资源
|
||||
- 只要足够准备页展示选择即可
|
||||
|
||||
推荐最小形态示意:
|
||||
|
||||
```json
|
||||
{
|
||||
"play": {
|
||||
"assignmentMode": "manual",
|
||||
"courseVariants": [
|
||||
{
|
||||
"id": "variant_a",
|
||||
"name": "A 线",
|
||||
"description": "适合首次体验",
|
||||
"routeCode": "A",
|
||||
"selectable": true
|
||||
},
|
||||
{
|
||||
"id": "variant_b",
|
||||
"name": "B 线",
|
||||
"description": "稍长路线",
|
||||
"routeCode": "B",
|
||||
"selectable": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. launch 最小字段建议
|
||||
|
||||
launch 必须承担“最终绑定本局赛道”的责任。
|
||||
|
||||
建议在现有 `launch` 返回中增加一个明确的 variant 绑定块。
|
||||
|
||||
### 4.1 建议字段
|
||||
|
||||
- `launch.variant.id`
|
||||
- `launch.variant.name`
|
||||
- `launch.variant.routeCode`
|
||||
- `launch.variant.assignmentMode`
|
||||
|
||||
如需保守,也可挂到 `business` 下,但建议语义上单独成块,避免和 release/session 混淆。
|
||||
|
||||
### 4.2 前端输入建议
|
||||
|
||||
如果是手选模式,前端建议向 `launch` 传:
|
||||
|
||||
- `variantId`
|
||||
|
||||
如果是随机模式,前端可以:
|
||||
|
||||
- 不传,由后端分配
|
||||
- 或显式传一个 `assign=random` 请求意图
|
||||
|
||||
### 4.3 输出约束
|
||||
|
||||
无论前端是否传入 `variantId`,launch 返回都必须给出最终绑定结果。
|
||||
|
||||
因为地图页只应消费:
|
||||
|
||||
- 最终 `variantId`
|
||||
- 对应 manifest / config
|
||||
|
||||
不应再依赖准备页上的临时选择状态。
|
||||
|
||||
推荐最小形态示意:
|
||||
|
||||
```json
|
||||
{
|
||||
"launch": {
|
||||
"variant": {
|
||||
"id": "variant_b",
|
||||
"name": "B 线",
|
||||
"routeCode": "B",
|
||||
"assignmentMode": "manual"
|
||||
},
|
||||
"resolvedRelease": {
|
||||
"releaseId": "rel_xxx",
|
||||
"manifestUrl": "https://..."
|
||||
},
|
||||
"business": {
|
||||
"sessionId": "ses_xxx",
|
||||
"sessionToken": "..."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. session / result 最小字段建议
|
||||
|
||||
### 5.1 session 摘要
|
||||
|
||||
建议在以下位置都可见:
|
||||
|
||||
- `ongoingSession`
|
||||
- `recentSession`
|
||||
- `session detail`
|
||||
|
||||
最小补充:
|
||||
|
||||
- `variantId`
|
||||
- `variantName`
|
||||
- `routeCode`
|
||||
|
||||
### 5.2 result
|
||||
|
||||
建议 `GET /sessions/{sessionPublicID}/result` 至少返回:
|
||||
|
||||
- `result.session.variantId`
|
||||
- `result.session.variantName`
|
||||
- `result.session.routeCode`
|
||||
|
||||
这样前端单局结果页和历史结果页都能统一展示。
|
||||
|
||||
---
|
||||
|
||||
## 6. 前端第一阶段落点
|
||||
|
||||
前端第一阶段建议只做下面几件事:
|
||||
|
||||
### 6.1 准备页
|
||||
|
||||
- 读取 `assignmentMode`
|
||||
- 读取 `courseVariants[]`
|
||||
- 在 `manual` 下展示可选赛道列表
|
||||
- 在 `random` 下展示“随机分配”
|
||||
- 在 `server-assigned` 下只展示结果
|
||||
|
||||
### 6.2 launch 适配层
|
||||
|
||||
- 将 `launch.variant.*` 写入 `GameLaunchEnvelope`
|
||||
- 将 `variantId` 一起进入地图页和恢复快照
|
||||
|
||||
### 6.3 结果与历史页
|
||||
|
||||
- 显示本局 `variantName / routeCode`
|
||||
|
||||
### 6.4 故障恢复
|
||||
|
||||
- 快照中补 `variantId`
|
||||
- 恢复时继续使用既有 `variantId`
|
||||
|
||||
---
|
||||
|
||||
## 7. 第一阶段后端落点
|
||||
|
||||
后端第一阶段建议只做下面几件事:
|
||||
|
||||
### 7.1 play
|
||||
|
||||
- 返回 `assignmentMode`
|
||||
- 返回 `courseVariants[]`
|
||||
|
||||
### 7.2 launch
|
||||
|
||||
- 接收可选 `variantId`
|
||||
- 返回最终绑定后的 `variant` 信息
|
||||
|
||||
### 7.3 session / result
|
||||
|
||||
- 在 session 摘要和结果里带出 `variantId`
|
||||
|
||||
这样就足够完成第一阶段联调。
|
||||
|
||||
---
|
||||
|
||||
## 8. 和现有体系的关系
|
||||
|
||||
这份最小契约不替代现有六层检查,后续一旦开始实现,仍建议按六层检查推进:
|
||||
|
||||
1. 文档
|
||||
2. 配置源
|
||||
3. 解析层
|
||||
4. 编译层
|
||||
5. 消费层
|
||||
6. 发布与联调层
|
||||
|
||||
特别是:
|
||||
|
||||
- 配置层后续如果引入 `courseVariants`
|
||||
- 解析层如果开始读取多 variant 结构
|
||||
- 编译层如果开始按 `variantId` 产出 runtime profile
|
||||
|
||||
这三层都不能跳。
|
||||
|
||||
---
|
||||
|
||||
## 9. 一句话结论
|
||||
|
||||
**多赛道第一阶段联调只需要先定住 `assignmentMode`、`courseVariants[]`、`launch.variant.*`、`session/result.variant*` 这四组最小字段,让 `variantId` 成为贯穿一局的稳定事实。**
|
||||
Reference in New Issue
Block a user