完善多赛道联调与全局产品架构

This commit is contained in:
2026-04-02 18:11:43 +08:00
parent 6964e26ec9
commit 0e28f70bad
45 changed files with 4819 additions and 282 deletions

View File

@@ -0,0 +1,324 @@
# APP全局产品架构草案
> 文档版本v1.0
> 最后更新2026-04-02 18:10:04
本文档用于整理当前 APP 级产品逻辑的整体设想,作为后续页面架构、后端对象模型、联调边界和默认流程设计的上层基线。
---
## 1. 总体判断
当前产品不应再简单理解为“地图游戏程序”,更准确的定位应当是:
**以地图为资源底座、以活动为对外核心、以对局为过程、以用户资产为沉淀的运动游戏系统。**
这意味着:
- 地图是场地资产和体验载体
- 活动是运营层、展示层、商业层和用户入口
- Session 是一次真实对局过程
- 历史、成就、奖励、资料等属于用户长期资产
---
## 2. 一级模块建议
建议 APP 长期按 5 个一级模块组织。
### 2.1 首页 / 发现
负责:
- 地区浏览
- 地图列表
- 推荐活动
- 默认体验入口
- 宣传入口
适用对象:
- 游客
- 初次进入的新用户
- 以地图体验为目标的训练型用户
### 2.2 活动 / 赛事
这是系统核心模块。
负责:
- 活动卡片列表
- 活动详情
- 报名
- 签到
- 开局
- 公告
- 排行榜
- 社交或分享入口
- 多地图活动聚合
说明:
- 活动页本质上是系统的对外展示壳和运营壳
- 不同客户的活动页、排行榜、宣传页都可能是定制化的
- 这里适合长期采用“原生模板 + 原生 DSL + H5 增强”的分层方案
### 2.3 地图体验
负责:
- 地图默认体验活动
- 地图自由体验
- 训练入口
- 正式进入地图游戏过程
- 游戏过程中的内容、规则、结算
说明:
- 地图体验层是运行层,不是对外运营主入口
- 游客主要通过这一层进入体验
### 2.4 我的
负责:
- 历史记录
- 成绩详情
- 报名信息
- 全局头像与昵称
- 成就
- 奖励展示
- 收藏与长期资产
说明:
- 历史、成就、奖励不应分散在不同页面里,建议统一收口在用户资产中心
### 2.5 系统
负责:
- 设置
- 帮助
- 使用说明
- 反馈
- 关于
- 调试入口
---
## 3. 核心对象模型
建议长期围绕 4 个核心对象组织前后端模型。
### 3.1 Map
含义:
- 地图资源
- 场地资产
- 瓦片与底图
- 点位、图层、默认体验挂载位置
### 3.2 Event
含义:
- 活动
- 赛事
- 运营包装壳
- 报名、签到、排行榜、宣传、社交等活动级能力
说明:
- 一个 Event 可以挂一个地图,也可以挂多个地图
- 一个地图也可以承载多个 Event
### 3.3 Session
含义:
- 一次具体开局记录
- 一次真实游戏过程
- 与规则、成绩、恢复、结果页直接相关
### 3.4 User Asset
含义:
- 历史记录
- 成就
- 奖励
- 头像昵称
- 报名资料快照
- 收藏与长期沉淀
---
## 4. 用户主流程建议
### 4.1 游客主流程
1. 打开程序
2. 浏览地区和地图
3. 进入地图默认体验活动
4. 进行单局游戏
5. 结果和历史先本地保存
6. 登录后再触发同步或迁移
设计结论:
- 游客以地图体验链为主
- 游客不应直接进入正式活动能力
### 4.2 注册用户主流程
1. 打开程序
2. 浏览活动 / 赛事
3. 进入活动详情
4. 报名 / 签到 / 开局
5. 进入正式对局
6. 成绩回写历史、排行榜、奖励、成就
设计结论:
- 注册用户以活动运营链为主
- 活动是主要用户入口
---
## 5. 当前设想的逐项落点
### 5.1 地图列表
保留,但定位建议明确为:
- 自由体验入口
- 游客入口
- 训练入口
### 5.2 活动卡片列表
必须升格为核心模块。
活动系统长期需要支持:
- 标准模板活动
- 默认体验活动
- 客户定制活动
### 5.3 历史记录
建议归入“我的”模块统一管理,至少分成:
- 最近活动
- 全部记录
- 成绩详情
### 5.4 游客模式
建议正式规则为:
- 游客只可进入地图默认体验活动
- 游客数据先本地存储
- 登录后触发数据迁移或合并
### 5.5 全局资料与活动内资料
建议分两层模型:
- 全局用户资料
- 活动报名资料快照
因为活动内昵称、头像、队伍信息可能与全局资料不同。
### 5.6 帮助页面
建议未来拆成:
- 新手引导
- 使用帮助
- 常见问题
### 5.7 反馈功能
建议反馈最少自动带上:
- 当前活动
- 当前地图
- 当前 session
- 设备信息
- 程序版本
### 5.8 成就展示
当前可以先不做奖励系统,但架构上建议预留:
- 成就
- 奖章
- 奖励
- 收藏品
---
## 6. 产品主线建议
当前最适合正式确定的一条主线是:
### 游客态
- 以地图和默认体验为主
### 登录态
- 以活动和赛事为主
这个分流非常重要,因为它会影响:
- 首页结构
- 登录前后导航
- 活动和地图的权重关系
- 默认入口设计
---
## 7. 与当前工程结构的关系
对照当前代码与文档体系,可以理解为:
- `MapEngine`、渲染层、传感器层:地图资源与运行骨架
- 规则层、Telemetry、FeedbackSession 过程层
- 活动页、准备页、结果页、首页聚合Event 与 User Asset 的上层壳
- 配置系统与文档体系:把 Map / Event / Session 的差异转为可配置运行态
因此,后续开发不应再只围绕“地图页”扩功能,而应正式开始:
- 活动系统设计
- 结果与历史沉淀设计
- 游客链与登录链分流
---
## 8. 当前阶段建议
当前建议优先做这三件事:
1. 正式梳理活动系统页面骨架
2. 打磨顺序赛 / 积分赛的默认规则、默认样式、默认流程
3. 明确游客模式与登录模式的数据迁移规则
不建议当前阶段做的事:
- 过早铺开复杂社交体系
- 在奖励系统未定前做大而全的成就结构
- 让地图页承担过多对外展示职责
---
## 9. 一句话结论
当前 APP 最合理的全局方案是:
**地图是资源底座活动是对外核心Session 是游戏过程,历史与成就是用户资产。**
后续页面、后端模型、联调策略和配置体系,都应围绕这四个对象继续收口。

View File

@@ -0,0 +1,383 @@
# 多赛道 Variant 五层设计草案
> 文档版本v0.1
> 最后更新2026-04-02 18:24:00
本文档用于定义“一个活动对应多版 KML / 多条赛道”时的推荐架构。
目标:
- 不从页面交互倒推系统结构
- 先把多赛道能力按平台层次拆清
- 让前端、后端、后台、恢复、结果页都围绕同一套事实工作
- 为后续“手动选择 / 随机指定 / 后端指定”留出统一伸缩空间
说明:
- 本文档是设计草案,不是最终接口契约
- 本文档优先定义分层、边界、事实和约束
- 具体页面表现、后台表单细节、字段命名可在后续实现阶段微调
---
## 1. 背景与核心判断
当前项目里,一场活动后续可能不止一版 KML。
常见需求包括:
- 同一活动下有 A / B / C 多条赛道
- 准备阶段允许玩家手动选择
- 准备阶段由系统随机分配
- 后续可能由后台或裁判端直接指定
这里最关键的判断是:
**赛道版本不是页面临时状态,而是 session 级事实。**
也就是说,一旦某局比赛绑定了某个赛道版本,这个事实必须贯穿:
- 准备阶段
- launch
- session start / finish
- 故障恢复
- result
- ongoing session
- 历史结果
如果这一点不先定住,后面多端、多页面、多恢复链会很快乱掉。
---
## 2. 总体原则
多赛道能力建议固定遵守下面 6 条原则:
1. 一局比赛只绑定一个赛道版本
2. 前端可以参与选择,但最终绑定以后端 session 为准
3. 客户端不应各自实现不同的随机分配规则
4. 恢复链必须记住赛道版本
5. 结果页、历史结果和 ongoing 摘要必须可追溯赛道版本
6. 扩展新分配模式时,不破坏现有分层
一句话总结:
**前端负责交互后端负责最终绑定session 负责真实落账。**
---
## 3. 五层模型
多赛道能力建议拆成 5 层。
### 3.1 资源层
职责:
- 只定义赛道素材本身
- 不讨论谁来选,不讨论 session
典型内容:
- KML 文件
- 赛道元数据
- 可选地图资源
- 可选赛道封面、说明图
这一层回答的是:
- 这个赛道版本本身是什么
- 它的原始素材和元信息是什么
建议约束:
- 每个赛道版本都应有稳定的 `variantId`
- 每个赛道版本都应能独立定位到自己的 KML / manifest 入口
- 资源层不应混入“本局随机到谁”这种运行时逻辑
### 3.2 活动编排层
职责:
- 定义一个活动下有哪些赛道版本可用
- 定义这些版本如何被分配
典型内容:
- `assignmentMode`
- `courseVariants[]`
- 权重
- 可选分组规则
- 可选活动级覆盖
这一层回答的是:
- 当前活动允许哪些赛道版本
- 当前活动按什么模式分配赛道
推荐至少支持 3 种模式:
1. `manual`
- 用户手选
2. `random`
- 系统随机指定
3. `server-assigned`
- 后端预先指定,前端只展示
后续可扩展模式:
- 按分组分配
- 按批次轮换
- 团队共用赛道
- 避免重复赛道
### 3.3 会话绑定层
职责:
- 真正决定“这局比赛到底绑定哪条赛道”
- 作为跨端、跨页面、跨恢复的一致事实
这一层回答的是:
- 当前 session 最终绑定的是哪个 `variantId`
- 这个绑定是手选、随机还是后端直接指定
这一层必须落账的最小事实建议包括:
- `sessionId`
- `eventId`
- `variantId`
- `assignmentMode`
- `assignedAt`
- 可选的 `assignmentSource`
核心约束:
- `variantId` 一旦绑定,不应在本局内漂移
- launch、恢复、结果、排行榜都要引用同一 `variantId`
- 客户端本地恢复快照必须保存 `variantId`
### 3.4 客户端呈现层
职责:
- 负责向玩家展示可选项或绑定结果
- 负责发起用户选择
- 负责消费最终绑定后的赛道配置
这一层回答的是:
- 准备页要不要展示赛道列表
- 是否允许点击手选
- 是否显示“本局随机分配结果”
- 地图页加载哪一个 manifest
推荐规则:
- `manual`:准备页展示赛道列表,允许选择
- `random`:准备页展示“随机分配”结果,不允许随意更改
- `server-assigned`:准备页只展示最终结果,不提供选择
强约束:
- 客户端不能把“页面选择结果”当成最终事实
- 客户端必须以后端返回的 `variantId` 为准
- 地图页只消费最终绑定后的 manifest / runtime profile
### 3.5 后台运营层
职责:
- 管理赛道版本
- 管理活动编排
- 管理发布与审计
这一层回答的是:
- 活动有哪些赛道版本
- 每个版本的素材、说明和发布状态是什么
- 当前活动采用哪种分配策略
- 某局最终是怎么绑定出来的
后台层建议逐步承担:
- 赛道版本管理
- 活动绑定多个 variant
- 权重配置
- 发布检查
- 历史审计
---
## 4. 多端协作边界
多赛道能力一旦牵涉多端,最容易出问题的地方是边界不清。
建议固定边界如下:
### 4.1 前端负责
- 展示赛道选择或展示赛道结果
- 发起选择请求或发起随机请求
- 消费 launch 返回的赛道绑定结果
- 在地图、恢复、结果页中显示当前 `variantId` 或赛道名
### 4.2 后端负责
- 最终确认本局绑定哪个 `variantId`
-`variantId` 写入 session
- 确保 launch 返回的 release / manifest 与 `variantId` 对应
- 确保 result / ongoing / recovery 均能反查 `variantId`
### 4.3 后台负责
- 管理活动可用的 variants
- 管理 assignment mode
- 管理发布、上下线和审计
约束:
- 不允许前端自己定义“随机分配算法”后直接当成最终结果
- 不允许某端私自改 `variantId` 但不落 session
- 不允许恢复链丢失 `variantId`
---
## 5. 配置与发布建议
多赛道不是只改一个 `kmlUrl`
它建议进入活动编排配置,而不是页面临时字段。
推荐抽象:
- 活动级:
- `assignmentMode`
- `courseVariants[]`
- variant 级:
- `id`
- `name`
- `kmlUrl`
- `weight`
- `overrides`
如果某些版本不仅 KML 不同,连分值、样式、规则也不同,推荐允许 variant 带局部覆盖。
推荐覆盖顺序:
`系统默认值 -> 玩法默认值 -> 活动默认值 -> variant 覆盖 -> 单点覆盖`
这样未来不会因为多赛道把既有继承体系打乱。
---
## 6. 恢复、结果与摘要约束
### 6.1 故障恢复
恢复快照中必须加入:
- `variantId`
- 可选 `variantName`
恢复原则:
- 恢复的是这局绑定的赛道事实
- 不重新随机
- 不重新询问选择
### 6.2 结果页
结果页建议至少展示:
- 活动名
- 赛道版本名或 `variantId`
- 本局结果摘要
### 6.3 ongoing / recent / 历史成绩
这些摘要建议都能反映:
- 本局属于哪个赛道版本
否则后续:
- 用户无法判断自己玩的哪版
- 运营无法解释同活动下不同赛道差异
- 排名、复盘、申诉都困难
---
## 7. 推荐实施顺序
这块不建议一上来就做全套复杂功能。
推荐分三期:
### 第一期:架构定型
目标:
- 定义 `courseVariants`
- 定义 `assignmentMode`
- 定义 session 绑定 `variantId`
- 明确恢复、结果、launch 必须带上 `variantId`
### 第二期:前后端最小闭环
目标:
- 支持 `manual`
- 支持 `random`
- 准备页可展示赛道选择或随机结果
- launch 能消费最终绑定结果
### 第三期:运营扩展
目标:
- 接后台编排
- 增加 `server-assigned`
- 扩展更多分配模式
- 做更完整的审计、排行榜和统计
---
## 8. 六层检查在多赛道能力中的应用
后续只要多赛道相关配置或契约有变更,建议继续执行当前约定的六层检查:
1. 文档
2. 配置源
3. 解析层
4. 编译层
5. 消费层
6. 发布与联调层
具体到多赛道能力,检查点通常包括:
- 文档是否同步 `assignmentMode / variants / variantId`
- 配置源是否新增或调整 variant 结构
- 解析层是否能读取多赛道结构
- 编译层是否能生成最终绑定后的 runtime profile
- 地图、结果页、恢复链是否都消费了 `variantId`
- launch / release / manifest 是否和最终 variant 绑定一致
---
## 9. 当前建议结论
当前阶段,建议把“多 KML / 多赛道”先当成**平台能力设计**,而不是页面功能。
当前最重要的不是先做某个选择 UI而是先定住以下 4 个事实:
1. 一个活动可以有多个 variants
2. 一个 session 只能绑定一个 `variantId`
3. 最终绑定以后端 session 为准
4. 恢复、结果、ongoing、历史结果都必须能追溯该 `variantId`
---
## 10. 一句话总结
**多赛道能力建议固定采用“资源层、活动编排层、会话绑定层、客户端呈现层、后台运营层”五层模型,先把 `variantId` 做成 session 级事实,再去实现准备页手选、随机分配和后台指定等具体交互。**

View 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` 成为贯穿一局的稳定事实。**

View File

@@ -1,6 +1,6 @@
# 游戏规则架构
> 文档版本v1.0
> 最后更新2026-04-02 08:28:05
> 最后更新2026-04-02 18:33:00
本文档用于说明当前项目中“游戏规则”在文档、配置文件、样例 JSON、解析代码和运行时规则引擎之间的实际组织方式。
@@ -68,6 +68,8 @@
- [程序默认规则基线](D:/dev/cmr-mini/doc/gameplay/程序默认规则基线.md)
- [运行时编译层总表](D:/dev/cmr-mini/doc/gameplay/运行时编译层总表.md)
- [多赛道 Variant 五层设计草案](D:/dev/cmr-mini/doc/gameplay/多赛道Variant五层设计草案.md)
- [多赛道 Variant 前后端最小契约](D:/dev/cmr-mini/doc/gameplay/多赛道Variant前后端最小契约.md)
- [玩法设计文档模板](D:/dev/cmr-mini/doc/gameplay/玩法设计文档模板.md)
- [玩法构想方案](D:/dev/cmr-mini/doc/gameplay/玩法构想方案.md)
- `doc/games/<游戏名称>/规则说明文档.md`

View File

@@ -1,6 +1,6 @@
# 文档索引
> 文档版本v1.0
> 最后更新2026-04-02 08:28:05
> 最后更新2026-04-02 18:10:04
维护约定:
@@ -41,7 +41,10 @@
- [玩法构想方案](/D:/dev/cmr-mini/doc/gameplay/玩法构想方案.md)
- [程序默认规则基线](/D:/dev/cmr-mini/doc/gameplay/程序默认规则基线.md)
- [游戏规则架构](/D:/dev/cmr-mini/doc/gameplay/游戏规则架构.md)
- [多赛道 Variant 五层设计草案](/D:/dev/cmr-mini/doc/gameplay/多赛道Variant五层设计草案.md)
- [多赛道 Variant 前后端最小契约](/D:/dev/cmr-mini/doc/gameplay/多赛道Variant前后端最小契约.md)
- [多线程联调协作方式](/D:/dev/cmr-mini/doc/gameplay/多线程联调协作方式.md)
- [APP全局产品架构草案](/D:/dev/cmr-mini/doc/gameplay/APP全局产品架构草案.md)
- [故障恢复机制](/D:/dev/cmr-mini/doc/gameplay/故障恢复机制.md)
- [运行时编译层总表](/D:/dev/cmr-mini/doc/gameplay/运行时编译层总表.md)
- [玩法设计文档模板](/D:/dev/cmr-mini/doc/gameplay/玩法设计文档模板.md)