Files
cmr-mini/doc/gameplay/多赛道Variant前后端最小契约.md

295 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 多赛道 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` 成为贯穿一局的稳定事实。**