完善后端联调链路与模拟器多通道支持
This commit is contained in:
@@ -12,9 +12,10 @@
|
||||
3. [API 清单](D:/dev/cmr-mini/backend/docs/接口清单.md)
|
||||
4. [数据模型](D:/dev/cmr-mini/backend/docs/数据模型.md)
|
||||
5. [配置管理方案](D:/dev/cmr-mini/backend/docs/配置管理方案.md)
|
||||
6. [前后端联调清单](D:/dev/cmr-mini/backend/docs/前后端联调清单.md)
|
||||
7. [TodoList](D:/dev/cmr-mini/backend/docs/todolist.md)
|
||||
8. [开发说明](D:/dev/cmr-mini/backend/docs/开发说明.md)
|
||||
6. [资源对象与目录方案](D:/dev/cmr-mini/backend/docs/资源对象与目录方案.md)
|
||||
7. [前后端联调清单](D:/dev/cmr-mini/backend/docs/前后端联调清单.md)
|
||||
8. [TodoList](D:/dev/cmr-mini/backend/docs/todolist.md)
|
||||
9. [开发说明](D:/dev/cmr-mini/backend/docs/开发说明.md)
|
||||
|
||||
## 当前系统范围
|
||||
|
||||
@@ -34,6 +35,7 @@
|
||||
下一阶段建议重点:
|
||||
|
||||
- 可伸缩配置管理
|
||||
- 共享资源对象化
|
||||
- source/build/release 分层
|
||||
- 配置构建器
|
||||
- 发布资产清单
|
||||
|
||||
@@ -30,9 +30,29 @@
|
||||
|
||||
所以 backend 现在最重要的不是再扩散接口,而是把当前契约和语义收稳。
|
||||
|
||||
当前已确认不再阻塞主链的事项:
|
||||
|
||||
- `evt_demo_001` 的 release manifest 现已可正常加载
|
||||
- 小程序已能进入地图
|
||||
- 模拟定位 / 调试日志问题已回到小程序与模拟器侧,不再属于 backend 当前阻塞
|
||||
|
||||
前端当前需要配合的事项:
|
||||
|
||||
- 正式联调时始终以 `launch.resolvedRelease.manifestUrl` 为准,不再回退到本地样例配置路径
|
||||
- 如果再出现配置加载失败,反馈完整上下文:
|
||||
- `eventPublicID`
|
||||
- `releaseId`
|
||||
- `manifestUrl`
|
||||
- 页面报错文案
|
||||
- 控制台 / 网络日志
|
||||
- 当前 demo 联调建议统一使用:
|
||||
- `eventPublicID = evt_demo_001`
|
||||
- `channelCode = mini-demo`
|
||||
- `channelType = wechat_mini`
|
||||
|
||||
## 3. P0 必做
|
||||
|
||||
## 3.1 固定 session 状态语义
|
||||
## 3.0 固定 session 状态语义
|
||||
|
||||
需要 backend 明确并固定:
|
||||
|
||||
@@ -51,7 +71,7 @@
|
||||
- 小程序现在已经按这个方向接
|
||||
- 如果 backend 想改这 3 个状态语义,需要先讨论,不要单边改
|
||||
|
||||
## 3.2 明确“放弃恢复”的后端处理
|
||||
## 3.1 明确“放弃恢复”的后端处理
|
||||
|
||||
这是当前最值得后端配合确认的一点。
|
||||
|
||||
@@ -87,7 +107,7 @@ backend 需要确认的目标语义是:
|
||||
|
||||
- 如果 backend 认可这套语义,小程序侧下一步就可以把“点击放弃恢复”改成同步调用 `finish(cancelled)`。
|
||||
|
||||
## 3.3 保证 start / finish 幂等与重复调用安全
|
||||
## 3.2 保证 start / finish 幂等与重复调用安全
|
||||
|
||||
联调和真实环境里,以下情况很常见:
|
||||
|
||||
@@ -110,7 +130,7 @@ backend 需要确认:
|
||||
|
||||
- 不把客户端补偿逻辑变成一堆冲突分支
|
||||
|
||||
## 3.4 固定 `launch` 返回契约,不随意漂移
|
||||
## 3.3 固定 `launch` 返回契约,不随意漂移
|
||||
|
||||
当前客户端已经按下面这些字段接入:
|
||||
|
||||
@@ -130,9 +150,38 @@ backend 现在需要做的是:
|
||||
- 先保持这些字段名稳定
|
||||
- 如果要调整命名或层级,先沟通
|
||||
|
||||
前端当前需要做的是:
|
||||
|
||||
- 只消费当前已约定字段
|
||||
- 不额外推断 release URL
|
||||
- 不把本地样例配置路径混进正式 launch 流程
|
||||
- 如果字段缺失或命名变化,直接在联调清单里标阻塞
|
||||
|
||||
## 4. P1 应尽快做
|
||||
|
||||
## 4.1 增加用户身体资料读取接口
|
||||
## 4.1 给首页 / play / result 的 ongoing 语义再做一次回归确认
|
||||
|
||||
当前前端已经开始走:
|
||||
|
||||
- 首页聚合
|
||||
- `event play`
|
||||
- `launch`
|
||||
- `session start / finish`
|
||||
- 本地故障恢复
|
||||
|
||||
backend 建议再回归确认这几个接口对“进行中 session”的口径一致:
|
||||
|
||||
- `/me/entry-home`
|
||||
- `/events/{eventPublicID}/play`
|
||||
- `/sessions/{sessionPublicID}/result`
|
||||
|
||||
重点确认:
|
||||
|
||||
1. `cancelled` 后不再继续出现在 ongoing 入口
|
||||
2. `failed` 后不再继续出现在 ongoing 入口
|
||||
3. `finished` 后结果页与首页摘要字段一致
|
||||
|
||||
## 4.2 增加用户身体资料读取接口
|
||||
|
||||
小程序侧已经有:
|
||||
|
||||
@@ -152,7 +201,7 @@ backend 下一步建议提供:
|
||||
|
||||
这样后面心率页和消耗估算就能真实接业务数据。
|
||||
|
||||
## 4.2 给 `session result` 补一点稳定摘要字段校验
|
||||
## 4.3 给 `session result` 补一点稳定摘要字段校验
|
||||
|
||||
客户端现在会上报:
|
||||
|
||||
@@ -170,7 +219,7 @@ backend 建议补两件事:
|
||||
|
||||
不要因为某个可选字段缺失就整局 finish 失败。
|
||||
|
||||
## 4.3 dev workbench 增加一组“恢复 / 取消恢复”场景按钮
|
||||
## 4.4 dev workbench 增加一组“恢复 / 取消恢复”场景按钮
|
||||
|
||||
当前 workbench 已经很好用了。
|
||||
|
||||
@@ -182,6 +231,17 @@ backend 建议补两件事:
|
||||
|
||||
这会很适合配合小程序故障恢复联调。
|
||||
|
||||
## 4.5 前端预埋“放弃恢复”调用位
|
||||
|
||||
这项先预埋,不要先自行定语义。
|
||||
|
||||
前端建议准备好:
|
||||
|
||||
- 在“放弃恢复”按钮点击后,预留调用 `finish(cancelled)` 的位置
|
||||
- 但是否正式启用,要等 backend 把 `cancelled` 语义确认完
|
||||
|
||||
这样一旦 backend 确认语义,小程序就能快速切过去,不需要再改一轮页面流程。
|
||||
|
||||
## 5. P2 下一阶段
|
||||
|
||||
## 5.1 配置后台 source / build / release 真正开始做
|
||||
@@ -205,6 +265,23 @@ backend 建议补两件事:
|
||||
|
||||
这部分不是当前联调阻塞项,但后面会成为业务壳的重要组成。
|
||||
|
||||
## 5.3 兼顾未来 APP 的统一后端约束
|
||||
|
||||
backend 后续建设需要继续坚持:
|
||||
|
||||
- 不做“小程序专用后端”
|
||||
- 用户模型保持平台级
|
||||
- `event / release / session / result` 不按终端拆两套
|
||||
- 终端差异只通过上下文字段和运行时适配处理
|
||||
|
||||
建议优先保持:
|
||||
|
||||
- 业务接口统一
|
||||
- 配置发布结构统一
|
||||
- 结果沉淀结构统一
|
||||
|
||||
这样后面 APP 接入时不会推翻现有 backend 结构。
|
||||
|
||||
## 6. 需要先讨论再动的边界
|
||||
|
||||
这些事项 backend 不建议自己先拍板:
|
||||
@@ -252,4 +329,4 @@ backend 现在最值得先做的,不是扩接口,而是先确认下面 3 条
|
||||
|
||||
当前 backend 最重要的任务不是“再加更多接口”,而是:
|
||||
|
||||
> 先把 session 运行态语义和故障恢复放弃语义定稳,再继续扩后台配置系统。
|
||||
> 先把 session 运行态语义、放弃恢复语义和 ongoing session 口径定稳,再继续扩后台配置系统。
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
- `WECHAT_MINI_DEV_PREFIX`
|
||||
- `LOCAL_EVENT_DIR`
|
||||
- `ASSET_BASE_URL`
|
||||
- `ASSET_PUBLIC_BASE_URL`
|
||||
- `ASSET_BUCKET_ROOT`
|
||||
- `OSSUTIL_PATH`
|
||||
- `OSSUTIL_CONFIG_FILE`
|
||||
|
||||
## 2. 本地启动
|
||||
|
||||
@@ -86,6 +90,9 @@ Redis 后面只在需要性能优化、限流或短期票据缓存时再接。
|
||||
|
||||
- `LOCAL_EVENT_DIR` 决定本地 source config 从哪里读
|
||||
- `ASSET_BASE_URL` 决定 preview build 时如何把相对资源路径归一化成可运行 URL
|
||||
- `ASSET_PUBLIC_BASE_URL` 决定 publish 时如何把公开 URL 映射到 OSS 对象 key
|
||||
- `ASSET_BUCKET_ROOT` 决定发布对象上传到哪个 bucket 根路径
|
||||
- `OSSUTIL_PATH` 和 `OSSUTIL_CONFIG_FILE` 决定 backend 发布 manifest 时使用哪个 OSS 客户端
|
||||
|
||||
## 4. Migration
|
||||
|
||||
@@ -125,6 +132,11 @@ Redis 后面只在需要性能优化、限流或短期票据缓存时再接。
|
||||
- result
|
||||
- profile
|
||||
|
||||
补充说明:
|
||||
|
||||
- `publish build` 现在会真实上传 `manifest.json` 和 `asset-index.json` 到 OSS
|
||||
- 如果上传失败,接口会直接报错,不再出现“数据库里已有 release,但 OSS 上没有对象”的假成功
|
||||
|
||||
并且支持:
|
||||
|
||||
- quick flow
|
||||
|
||||
@@ -14,6 +14,11 @@ flowchart LR
|
||||
H --> I["Result / History"]
|
||||
```
|
||||
|
||||
补充说明:
|
||||
|
||||
- 这条主流程既服务当前小程序,也要服务未来 APP
|
||||
- 终端差异主要体现在登录方式、设备能力和运行时 UI,不应拆成两套业务流程
|
||||
|
||||
## 2. 入口解析
|
||||
|
||||
入口层先解决:
|
||||
@@ -39,6 +44,10 @@ APP 当前主链是手机号验证码:
|
||||
2. `POST /auth/login/sms`
|
||||
3. 返回 `access_token + refresh_token`
|
||||
|
||||
说明:
|
||||
|
||||
- APP 是未来更强接入端,后端设计必须预留身体资料、设备绑定、遥测摘要等扩展空间
|
||||
|
||||
### 3.2 微信小程序
|
||||
|
||||
微信小程序当前主链是:
|
||||
@@ -134,6 +143,11 @@ APP 当前主链是手机号验证码:
|
||||
- `launch.business.sessionId`
|
||||
- `launch.business.sessionToken`
|
||||
|
||||
补充约束:
|
||||
|
||||
- `launch` 是统一业务启动入口,不应因为 APP / 小程序差异复制两套接口
|
||||
- 终端差异通过 `clientType`、`deviceKey`、后续能力声明字段处理
|
||||
|
||||
### 6.3 客户端应如何使用
|
||||
|
||||
客户端进入游戏前,应以返回中的这几项为准:
|
||||
@@ -202,3 +216,13 @@ APP 当前主链是手机号验证码:
|
||||
不要退回成:
|
||||
|
||||
`event -> launch -> game`
|
||||
|
||||
也不要走成:
|
||||
|
||||
`mini event -> mini launch -> mini game`
|
||||
|
||||
或:
|
||||
|
||||
`app event -> app launch -> app game`
|
||||
|
||||
业务接口必须保持统一,终端差异只进入上下文,不进入对象模型分叉。
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
- 运行时解析复杂地图规则
|
||||
- 直接下发数据库编辑态对象给客户端
|
||||
|
||||
补充约束:
|
||||
|
||||
- 这套 backend 必须服务未来 APP,不是“小程序专用后端”
|
||||
- 登录方式可以按终端区分,但业务对象和业务接口不能按端分裂成两套
|
||||
|
||||
## 2. 分层
|
||||
|
||||
### 2.1 平台层
|
||||
@@ -35,6 +40,12 @@
|
||||
|
||||
这层是整个平台共用能力。
|
||||
|
||||
它必须同时支撑:
|
||||
|
||||
- APP
|
||||
- 微信小程序
|
||||
- 后续公众号 / H5 / 其他渠道
|
||||
|
||||
### 2.2 业务层
|
||||
|
||||
业务层统一处理:
|
||||
@@ -58,6 +69,12 @@
|
||||
|
||||
这层是“客户端真正进入游戏时要消费的运行配置入口”。
|
||||
|
||||
这里的发布结构应保持终端中立:
|
||||
|
||||
- 不写死为小程序专用结构
|
||||
- 不直接依赖某个端的页面实现
|
||||
- 允许 APP 和小程序共用同一份 release / manifest
|
||||
|
||||
### 2.4 运行层
|
||||
|
||||
运行层统一处理:
|
||||
@@ -126,6 +143,12 @@
|
||||
- `GET /sessions/{id}` 会返回 `resolvedRelease`
|
||||
- `GET /sessions/{id}/result` 能追溯到当时的 release
|
||||
|
||||
补充约束:
|
||||
|
||||
- release / manifest 只描述运行配置,不承载某个端的页面状态
|
||||
- 玩家设置、设备能力差异、运行时 UI 编译由客户端自行处理
|
||||
- 后端负责“发布可运行配置”,不是“替某个端生成最终运行时 profile”
|
||||
|
||||
## 5. 代码分层
|
||||
|
||||
### 5.1 入口层
|
||||
@@ -189,6 +212,16 @@
|
||||
- 驱动地图和玩法
|
||||
- 产生过程数据和结束摘要
|
||||
|
||||
适用范围:
|
||||
|
||||
- 微信小程序客户端
|
||||
- 未来 APP 客户端
|
||||
|
||||
也就是说:
|
||||
|
||||
- 后端按统一业务模型输出
|
||||
- 终端差异放在客户端运行时适配层,不放在后端业务接口层
|
||||
|
||||
### 6.3 后续网关该怎么接
|
||||
|
||||
后面如果接实时网关,建议仍然走:
|
||||
|
||||
589
backend/docs/资源对象与目录方案.md
Normal file
589
backend/docs/资源对象与目录方案.md
Normal file
@@ -0,0 +1,589 @@
|
||||
# 资源对象与目录方案
|
||||
|
||||
本文档用于把“地图复用、KML 复用、内容资源复用、配置发布”统一收成一套后端可执行方案。
|
||||
|
||||
目标:
|
||||
|
||||
- 不再把所有资源都塞进单个 `event/*.json`
|
||||
- 让地图、KML、内容模板、主题资源都能独立复用
|
||||
- 让 `event` 只负责“组合与覆盖”,不拥有底层资源本体
|
||||
- 让 `release` 能稳定追溯当时到底用了哪一份地图、哪一份 KML、哪一套资源包
|
||||
- 让同一套资源对象既能服务小程序,也能服务未来 APP
|
||||
|
||||
---
|
||||
|
||||
## 1. 设计结论
|
||||
|
||||
后端后续不要按“一个活动一个完整资源目录”来设计,而要按“资源对象库 + Event 组合 + Release 固化”来设计。
|
||||
|
||||
建议统一拆成这 5 类对象:
|
||||
|
||||
1. `Map`
|
||||
2. `Playfield`
|
||||
3. `GameMode`
|
||||
4. `ResourcePack`
|
||||
5. `Event`
|
||||
|
||||
它们的关系是:
|
||||
|
||||
- `Map`:地图底座
|
||||
- `Playfield`:空间对象 / KML / 控制点集
|
||||
- `GameMode`:玩法默认规则
|
||||
- `ResourcePack`:内容、主题、音频等资源档
|
||||
- `Event`:业务活动对象,只做引用与少量覆盖
|
||||
|
||||
最终客户端吃的仍然不是这些编辑态对象,而是:
|
||||
|
||||
- `Release`
|
||||
- `manifest.json`
|
||||
|
||||
补充约束:
|
||||
|
||||
- manifest 必须保持终端中立
|
||||
- 不要在资源对象层把目录或字段设计成“小程序专用资源包”
|
||||
- APP 与小程序应共享同一套资源对象和 release 记录
|
||||
|
||||
---
|
||||
|
||||
## 2. 为什么必须这么拆
|
||||
|
||||
你现在遇到的核心问题不是“目录怎么摆”,而是“哪些资源会复用”。
|
||||
|
||||
当前最典型的复用场景:
|
||||
|
||||
- 同一张地图会被多个活动复用
|
||||
- 同一份 KML / 控制点集会被多个活动复用
|
||||
- 同一套 H5 内容模板会被多个活动复用
|
||||
- 同一套主题和音频资源会被多个活动复用
|
||||
|
||||
如果继续按 `event -> 自己拥有所有文件` 设计,后面会出现:
|
||||
|
||||
- 地图重复拷贝
|
||||
- KML 重复上传
|
||||
- 同一资源多个活动版本不一致
|
||||
- 一次资源修复需要改很多 event
|
||||
- 历史 session 无法明确追溯当时使用的是哪一版资源
|
||||
|
||||
所以正确做法不是“每个 event 一套全量文件”,而是:
|
||||
|
||||
`共享资源对象 -> event 引用 -> release 固化版本`
|
||||
|
||||
---
|
||||
|
||||
## 3. 五类核心对象
|
||||
|
||||
## 3.1 Map
|
||||
|
||||
作用:
|
||||
|
||||
- 表示一张可复用地图底座
|
||||
|
||||
最少应包含:
|
||||
|
||||
- `code`
|
||||
- `name`
|
||||
- `status`
|
||||
- `tiles root`
|
||||
- `mapmeta`
|
||||
- 可选边界、缩放、投影信息
|
||||
|
||||
典型场景:
|
||||
|
||||
- 一个公园底图
|
||||
- 一张校园底图
|
||||
- 一张城区底图
|
||||
|
||||
注意:
|
||||
|
||||
- `Map` 不等于某场活动
|
||||
- `Map` 是共享资产
|
||||
|
||||
## 3.2 Playfield
|
||||
|
||||
作用:
|
||||
|
||||
- 表示一份可复用场地对象数据
|
||||
|
||||
最常见的承载就是:
|
||||
|
||||
- `KML`
|
||||
- `GeoJSON`
|
||||
- 控制点集
|
||||
|
||||
最少应包含:
|
||||
|
||||
- `code`
|
||||
- `name`
|
||||
- `kind`
|
||||
- `sourceType`
|
||||
- `sourceFile`
|
||||
- 可选提取元数据
|
||||
- 控制点数量
|
||||
- 边界范围
|
||||
- 是否包含起终点
|
||||
|
||||
注意:
|
||||
|
||||
- `Playfield` 是共享对象,不属于某个 event 私有
|
||||
- 同一份 KML 可以被多个 event 复用
|
||||
|
||||
## 3.3 GameMode
|
||||
|
||||
作用:
|
||||
|
||||
- 表示一种玩法模式的默认规则对象
|
||||
|
||||
例如:
|
||||
|
||||
- `classic-sequential`
|
||||
- `score-o`
|
||||
|
||||
最少应包含:
|
||||
|
||||
- `code`
|
||||
- `mode`
|
||||
- `defaults json`
|
||||
|
||||
注意:
|
||||
|
||||
- 它不是最终 event 配置
|
||||
- 只是玩法默认值来源之一
|
||||
|
||||
## 3.4 ResourcePack
|
||||
|
||||
作用:
|
||||
|
||||
- 表示一套可复用资源档
|
||||
|
||||
当前最适合放进来的有:
|
||||
|
||||
- `audioProfile`
|
||||
- `contentProfile`
|
||||
- `themeProfile`
|
||||
|
||||
一个资源包内部可以包含:
|
||||
|
||||
- 内容模板
|
||||
- H5 页面
|
||||
- 图片
|
||||
- 图标
|
||||
- 音效
|
||||
- 主题色与主题变量
|
||||
|
||||
## 3.5 Event
|
||||
|
||||
作用:
|
||||
|
||||
- 表示一个业务活动实例
|
||||
|
||||
它应该只负责:
|
||||
|
||||
- 引用哪个 `Map`
|
||||
- 引用哪个 `Playfield`
|
||||
- 引用哪个 `GameMode`
|
||||
- 引用哪个 `ResourcePack`
|
||||
- 叠加少量 `Event Overrides`
|
||||
|
||||
不要让 `Event` 负责:
|
||||
|
||||
- 保存整份地图资源
|
||||
- 保存 KML 原件
|
||||
- 承担所有玩法默认规则
|
||||
- 拷贝整套资源包
|
||||
|
||||
---
|
||||
|
||||
## 4. 推荐目录结构
|
||||
|
||||
仓库内建议把“源资源”和“活动源配置”拆开。
|
||||
|
||||
推荐结构:
|
||||
|
||||
```text
|
||||
resources/
|
||||
maps/
|
||||
lxcb-001/
|
||||
v2026-03-30/
|
||||
mapmeta.json
|
||||
tiles/
|
||||
playfields/
|
||||
c01/
|
||||
v2026-03-30/
|
||||
course.kml
|
||||
meta.json
|
||||
resource-packs/
|
||||
default-race/
|
||||
v2026-03-30/
|
||||
content/
|
||||
content.html
|
||||
audio/
|
||||
theme/
|
||||
|
||||
game-modes/
|
||||
classic-sequential/
|
||||
v1/
|
||||
mode.json
|
||||
score-o/
|
||||
v1/
|
||||
mode.json
|
||||
|
||||
events/
|
||||
evt-demo-001/
|
||||
source.json
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `resources/` 放共享对象的源资源
|
||||
- `game-modes/` 放玩法默认规则对象
|
||||
- `events/` 只放活动级 source config
|
||||
|
||||
当前根目录 [event](D:/dev/cmr-mini/event) 可以继续保留作为过渡区,但后面建议逐步迁到:
|
||||
|
||||
- `events/`
|
||||
- `resources/`
|
||||
- `game-modes/`
|
||||
|
||||
---
|
||||
|
||||
## 5. Event Source 应该怎么写
|
||||
|
||||
后续 `event source` 不建议继续直接写死地图路径和 KML 路径,而应该引用对象版本。
|
||||
|
||||
推荐形态:
|
||||
|
||||
```json
|
||||
{
|
||||
"schemaVersion": "1",
|
||||
"version": "2026.04.01",
|
||||
"app": {
|
||||
"id": "evt-demo-001",
|
||||
"title": "积分赛示例"
|
||||
},
|
||||
"refs": {
|
||||
"map": {
|
||||
"code": "lxcb-001",
|
||||
"version": "v2026-03-30"
|
||||
},
|
||||
"playfield": {
|
||||
"code": "c01",
|
||||
"version": "v2026-03-30"
|
||||
},
|
||||
"gameMode": {
|
||||
"code": "score-o",
|
||||
"version": "v1"
|
||||
},
|
||||
"resourcePack": {
|
||||
"code": "default-race",
|
||||
"version": "v2026-03-30"
|
||||
}
|
||||
},
|
||||
"overrides": {
|
||||
"game": {
|
||||
"session": {
|
||||
"maxDurationSec": 5400
|
||||
},
|
||||
"punch": {
|
||||
"radiusMeters": 5
|
||||
}
|
||||
},
|
||||
"playfield": {
|
||||
"metadata": {
|
||||
"title": "示例路线",
|
||||
"code": "demo-001"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这样 `Event` 管的是:
|
||||
|
||||
- 引用
|
||||
- 覆盖
|
||||
|
||||
不是:
|
||||
|
||||
- 全量资源路径
|
||||
- 全量运行时配置
|
||||
|
||||
---
|
||||
|
||||
## 6. Manifest 生成规则
|
||||
|
||||
build / publish 时,Go 中间层应做装配:
|
||||
|
||||
`Map + Playfield + GameMode + ResourcePack + Event Overrides -> manifest.json`
|
||||
|
||||
最终生成给客户端的 manifest 可以保持现在的运行结构,例如:
|
||||
|
||||
```json
|
||||
{
|
||||
"schemaVersion": "1",
|
||||
"releaseId": "rel_xxx",
|
||||
"version": "2026.04.01",
|
||||
"app": {
|
||||
"id": "evt-demo-001",
|
||||
"title": "积分赛示例"
|
||||
},
|
||||
"map": {
|
||||
"tiles": "https://.../maps/lxcb-001/v2026-03-30/tiles/",
|
||||
"mapmeta": "https://.../maps/lxcb-001/v2026-03-30/mapmeta.json"
|
||||
},
|
||||
"playfield": {
|
||||
"kind": "control-set",
|
||||
"source": {
|
||||
"type": "kml",
|
||||
"url": "https://.../playfields/c01/v2026-03-30/course.kml"
|
||||
}
|
||||
},
|
||||
"game": {
|
||||
"mode": "score-o"
|
||||
},
|
||||
"resources": {
|
||||
"audioProfile": "default",
|
||||
"contentProfile": "default",
|
||||
"themeProfile": "default-race"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这层才是客户端真正消费的配置。
|
||||
|
||||
重要边界:
|
||||
|
||||
- 后端负责对象装配和发布
|
||||
- 前端继续负责运行时 profile 编译
|
||||
- 不把玩家设置和运行时状态写回发布配置
|
||||
|
||||
再补一条:
|
||||
|
||||
- 不把 APP 专属页面状态或小程序专属页面状态写进 manifest
|
||||
- 如需终端能力差异,后续通过能力声明或运行时适配层处理
|
||||
|
||||
---
|
||||
|
||||
## 7. OSS / CDN 目录建议
|
||||
|
||||
线上目录不要再继续以:
|
||||
|
||||
- `gotomars/event/classic-sequential.json`
|
||||
- `gotomars/event/score-o.json`
|
||||
|
||||
这种“玩法文件名”方式长期演进。
|
||||
|
||||
建议改成版本化结构:
|
||||
|
||||
```text
|
||||
gotomars/maps/{mapCode}/{version}/...
|
||||
gotomars/playfields/{playfieldCode}/{version}/...
|
||||
gotomars/resource-packs/{packCode}/{version}/...
|
||||
gotomars/game-modes/{modeCode}/{version}/mode.json
|
||||
gotomars/event-releases/{eventPublicID}/{releasePublicID}/manifest.json
|
||||
gotomars/event-releases/{eventPublicID}/{releasePublicID}/asset-index.json
|
||||
```
|
||||
|
||||
好处:
|
||||
|
||||
- 共享资源独立版本化
|
||||
- event release 只固化引用
|
||||
- 历史 session 可以回溯
|
||||
- 同一个 map / KML 修复时不会污染所有旧 release
|
||||
- APP 与小程序可共用相同资源版本,不必重复发两套发布目录
|
||||
|
||||
---
|
||||
|
||||
## 8. 数据库建模建议
|
||||
|
||||
推荐按“主表 + version 表”建模。
|
||||
|
||||
建议对象:
|
||||
|
||||
- `maps`
|
||||
- `map_versions`
|
||||
- `playfields`
|
||||
- `playfield_versions`
|
||||
- `game_modes`
|
||||
- `game_mode_versions`
|
||||
- `resource_packs`
|
||||
- `resource_pack_versions`
|
||||
- `events`
|
||||
- `event_versions`
|
||||
- `event_releases`
|
||||
|
||||
其中:
|
||||
|
||||
- 主表存稳定元信息
|
||||
- version 表存 `jsonb` 内容和具体资源引用
|
||||
|
||||
例如:
|
||||
|
||||
### `maps`
|
||||
|
||||
- `id`
|
||||
- `code`
|
||||
- `name`
|
||||
- `status`
|
||||
- `current_version_id`
|
||||
|
||||
### `map_versions`
|
||||
|
||||
- `id`
|
||||
- `map_id`
|
||||
- `version_code`
|
||||
- `content_jsonb`
|
||||
- `published_asset_root`
|
||||
- `status`
|
||||
|
||||
### `playfields`
|
||||
|
||||
- `id`
|
||||
- `code`
|
||||
- `name`
|
||||
- `kind`
|
||||
- `status`
|
||||
- `current_version_id`
|
||||
|
||||
### `playfield_versions`
|
||||
|
||||
- `id`
|
||||
- `playfield_id`
|
||||
- `version_code`
|
||||
- `source_type`
|
||||
- `content_jsonb`
|
||||
- `asset_root`
|
||||
- `status`
|
||||
|
||||
### `resource_packs`
|
||||
|
||||
- `id`
|
||||
- `code`
|
||||
- `name`
|
||||
- `status`
|
||||
- `current_version_id`
|
||||
|
||||
### `resource_pack_versions`
|
||||
|
||||
- `id`
|
||||
- `resource_pack_id`
|
||||
- `version_code`
|
||||
- `content_jsonb`
|
||||
- `asset_root`
|
||||
- `status`
|
||||
|
||||
### `game_modes`
|
||||
|
||||
- `id`
|
||||
- `code`
|
||||
- `name`
|
||||
- `status`
|
||||
- `current_version_id`
|
||||
|
||||
### `game_mode_versions`
|
||||
|
||||
- `id`
|
||||
- `game_mode_id`
|
||||
- `version_code`
|
||||
- `content_jsonb`
|
||||
- `status`
|
||||
|
||||
### `event_versions`
|
||||
|
||||
- `id`
|
||||
- `event_id`
|
||||
- `version_code`
|
||||
- `map_version_id`
|
||||
- `playfield_version_id`
|
||||
- `game_mode_version_id`
|
||||
- `resource_pack_version_id`
|
||||
- `overrides_jsonb`
|
||||
- `status`
|
||||
|
||||
核心点:
|
||||
|
||||
- `Event` 不直接指向文件 URL
|
||||
- `EventVersion` 指向对象版本
|
||||
- `Release` 固化当时装配结果
|
||||
|
||||
---
|
||||
|
||||
## 9. 后端职责边界
|
||||
|
||||
后端应强管理:
|
||||
|
||||
- 对象关系
|
||||
- 版本关系
|
||||
- 引用有效性
|
||||
- 发布装配
|
||||
- 发布记录
|
||||
|
||||
后端不应强管理:
|
||||
|
||||
- 每个玩法的所有细字段解释
|
||||
- 所有 HUD / 动画 / 实验细项的强结构化列
|
||||
- 玩家运行时设置
|
||||
- 玩家实时状态
|
||||
|
||||
同样不应做:
|
||||
|
||||
- 为 APP 和小程序各维护一套资源目录规范
|
||||
- 为 APP 和小程序各发布一套不同语义的 event 配置
|
||||
|
||||
适合继续走 `jsonb` 的内容:
|
||||
|
||||
- `game.sequence.*`
|
||||
- `game.guidance.*`
|
||||
- `game.presentation.*`
|
||||
- `playfield.controlOverrides.*`
|
||||
- 各类实验性字段
|
||||
|
||||
---
|
||||
|
||||
## 10. 推荐实施顺序
|
||||
|
||||
建议不要一次重构到底,按下面顺序推进:
|
||||
|
||||
1. 先把概念定住
|
||||
- `Map`
|
||||
- `Playfield`
|
||||
- `GameMode`
|
||||
- `ResourcePack`
|
||||
- `Event`
|
||||
|
||||
2. 先做文档和目录规范
|
||||
|
||||
3. 后端先补对象模型和 version 表草案
|
||||
|
||||
4. 配置构建器改成“按引用装配”
|
||||
|
||||
5. 发布器改成“版本化共享资源 + event release manifest”
|
||||
|
||||
6. 最后再做正式后台 UI
|
||||
|
||||
---
|
||||
|
||||
## 11. 当前阶段的务实建议
|
||||
|
||||
在完全切换到对象化模型前,当前仓库可以先这样过渡:
|
||||
|
||||
- 继续保留 [event](D:/dev/cmr-mini/event) 作为最小样例区
|
||||
- 继续保留现有 `import-local -> preview -> publish`
|
||||
- 但新的 source 设计和目录设计先按本文档收口
|
||||
|
||||
也就是说:
|
||||
|
||||
- 短期不推翻现有链路
|
||||
- 中期把资源引用模型补进来
|
||||
- 长期把单文件 `event/*.json` 迁到对象化配置系统
|
||||
|
||||
---
|
||||
|
||||
## 12. 一句话结论
|
||||
|
||||
后端资源管理的正确方向不是“每个活动一堆文件”,而是:
|
||||
|
||||
`共享资源对象库 + Event 引用装配 + Release 固化发布`
|
||||
|
||||
只有这样,地图复用、KML 复用、资源包复用、多活动发布才能长期稳定。
|
||||
|
||||
并且这套模型必须从一开始就兼顾未来 APP,而不是做成“小程序跑通后再重构”的临时结构。
|
||||
Reference in New Issue
Block a user