937 lines
27 KiB
Markdown
937 lines
27 KiB
Markdown
# 开发说明
|
||
> 文档版本:v1.45
|
||
> 最后更新:2026-04-07 18:15:01
|
||
|
||
|
||
## 1. 环境变量
|
||
|
||
参考 [`.env.example`](D:/dev/cmr-mini/backend/.env.example)。
|
||
|
||
当前最关键的变量:
|
||
|
||
- `APP_ENV`
|
||
- `HTTP_ADDR`
|
||
- `DATABASE_URL`
|
||
- `JWT_ACCESS_SECRET`
|
||
- `AUTH_SMS_PROVIDER`
|
||
- `AUTH_DEV_SMS_CODE`
|
||
- `WECHAT_MINI_APP_ID`
|
||
- `WECHAT_MINI_APP_SECRET`
|
||
- `WECHAT_MINI_DEV_PREFIX`
|
||
|
||
## 2. 运维后台当前结构
|
||
|
||
- 运维后台入口:`/admin/ops-workbench`
|
||
- 当前采用:
|
||
- 左侧:流程导航
|
||
- 中间:单主视图
|
||
- 右侧:状态 / 日志 / 最近对象
|
||
- 当前主流程导航:
|
||
- `资源总览`
|
||
- `地图 / 地点管理`
|
||
- `路线资源管理`
|
||
- `活动管理`
|
||
- `活动编排`
|
||
- `发布中心`
|
||
- `资源录入` 作为辅助入口保留
|
||
- `资源总览` 优先展示:
|
||
- 地点、地图、瓦片版本、受管资源
|
||
- 路线组、路线变体、运行绑定、配置源
|
||
- 活动数、默认体验活动、已发布活动、发布版本、展示定义、内容包、运维账号
|
||
- `地图 / 地点管理` 当前收成:
|
||
- 先看地图列表
|
||
- 右上角入口:`添加地图 / 添加地点`
|
||
- 点击地图进入详情弹出层
|
||
- 新增 / 编辑地图走独立弹出层
|
||
- 新增地点走独立弹出层
|
||
- 地点编辑区使用省/市两级选择,并回填到 `region`
|
||
- 地图详情只保留:
|
||
- 当前瓦片版本
|
||
- 默认体验活动概况
|
||
- 关联活动数量与摘要
|
||
- 关联活动详情统一去 `活动管理`
|
||
- 省市数据当前来自在线公开数据源:
|
||
- `uiwjs/province-city-china`
|
||
- backend 通过 `/ops/admin/region-options` 统一提供给运维台,页面本身不直连第三方源
|
||
- 当前选中活动的 `release / runtime / presentation / content bundle`
|
||
- 地图页当前只显示关联活动数量与摘要,不再平铺活动详情;活动详情和默认绑定统一放到 `活动管理 / 活动编排`。
|
||
- `地图 / 地点管理` 当前已支持:
|
||
- 地点列表
|
||
- 地图列表
|
||
- 地图关键字筛选
|
||
- 点列表项直接读取详情
|
||
- 选地点后自动带出该地点下地图
|
||
- 选地图后自动带出当前瓦片版本、默认活动概况和地图预览摘要
|
||
- `LOCAL_EVENT_DIR`
|
||
- `ASSET_BASE_URL`
|
||
- `ASSET_PUBLIC_BASE_URL`
|
||
- `ASSET_BUCKET_ROOT`
|
||
- `OSSUTIL_PATH`
|
||
- `OSSUTIL_CONFIG_FILE`
|
||
|
||
## 2. 本地启动
|
||
|
||
```powershell
|
||
cd D:\dev\cmr-mini\backend
|
||
.\start-backend.ps1
|
||
```
|
||
|
||
如果你想固定跑开发工作台常用端口 `18090`,直接执行:
|
||
|
||
```powershell
|
||
cd D:\dev\cmr-mini\backend
|
||
.\scripts\start-dev.ps1
|
||
```
|
||
|
||
开发环境补充:
|
||
|
||
- 运维后台入口:`/admin/ops-workbench`
|
||
- 运维接口前缀:`/ops/admin/*`
|
||
- 当 `APP_ENV != production` 时:
|
||
- 缺少 token 会直接进入 dev ops 上下文
|
||
- 残留旧 token、玩家 token、失效 token 也会自动回退到 dev ops 上下文
|
||
- 目的是避免开发联调时每次都要重新登录
|
||
|
||
## 3. Workbench 当前重点
|
||
|
||
- 推荐联调入口:
|
||
- `Bootstrap Demo(只准备数据)`
|
||
- `Bootstrap + 发布当前玩法`
|
||
- `Use Classic Demo / Use Score-O Demo / Use Manual Variant Demo`
|
||
- `整条链一键验收`
|
||
- `Bootstrap Demo(只准备数据)` 当前会直接准备三条标准 demo 的基础已发布态:
|
||
- `evt_demo_001`
|
||
- `evt_demo_score_o_001`
|
||
- `evt_demo_variant_manual_001`
|
||
- 这三条 demo 在 bootstrap 后都会直接带上:
|
||
- 当前 release
|
||
- runtime
|
||
- presentation
|
||
- content bundle
|
||
- 也就是说,frontend 当前从首页选择三种玩法时,不需要再额外先点一次发布按钮,已经能直接按“当前已发布 release”语义联调入口、详情和 `canLaunch`
|
||
- 当前玩法切换除了切 `event / release / source / build`,还会自动切换:
|
||
- `presentation schema`
|
||
|
||
## 4. 运维后台当前主流程
|
||
|
||
运维后台入口:
|
||
|
||
- [http://127.0.0.1:18090/admin/ops-workbench](http://127.0.0.1:18090/admin/ops-workbench)
|
||
|
||
当前不再把运维动作混在调试后台里,统一分成 3 条管理线:
|
||
|
||
1. 地图管理
|
||
- 先看地图列表
|
||
- 再做新建 / 编辑
|
||
- 然后看当前瓦片版本、默认活动和关联活动
|
||
|
||
2. KML / 赛道管理
|
||
- 围绕当前地图导入一组 KML
|
||
- 查看当前地图下赛道集
|
||
- 查看默认路线和路线摘要
|
||
|
||
3. 活动管理
|
||
- 先看活动列表
|
||
- 再做新建 / 修改 / 读取详情
|
||
- 然后管理默认 `runtime / presentation / content bundle`
|
||
- 最后进入发布中心
|
||
|
||
当前 UI 组织方式也已收口:
|
||
|
||
- 左侧:流程导航
|
||
- 中间:单主视图
|
||
- 右侧:状态 / 日志 / 最近对象
|
||
|
||
也就是说:
|
||
|
||
- 不再把所有运维功能平铺在一个长页面里
|
||
- 运维者一次只处理一个主任务块
|
||
- 主区已改成宽屏自适应,尽量利用大屏空间
|
||
|
||
当前新增的地图管理接口:
|
||
|
||
- `GET /admin/map-assets`
|
||
- `PUT /admin/map-assets/{mapAssetPublicID}`
|
||
- `GET /ops/admin/map-assets`
|
||
- `PUT /ops/admin/map-assets/{mapAssetPublicID}`
|
||
- `GET /ops/admin/course-sources`
|
||
- `GET /ops/admin/course-sources/{sourcePublicID}`
|
||
- `GET /ops/admin/course-sets/{courseSetPublicID}`
|
||
- `POST /ops/admin/events`
|
||
- `PUT /ops/admin/events/{eventPublicID}`
|
||
- `content manifest`
|
||
- `asset manifest`
|
||
- 这些 demo 资源现在由 backend 提供,避免继续在 workbench 里保留 `example.com` 占位地址:
|
||
- `GET /dev/demo-assets/manifests/{demoKey}`
|
||
- `GET /dev/demo-assets/presentations/{demoKey}`
|
||
- `GET /dev/demo-assets/content-manifests/{demoKey}`
|
||
- 如果 frontend 需要把页面侧调试日志直接打到 backend,优先使用:
|
||
- `POST /dev/client-logs`
|
||
- 然后在 workbench 的 `前端调试日志` 面板里查看
|
||
- 如果需要判断前端到底拿到了哪份配置,优先看 workbench 的:
|
||
- `当前 Launch 实际配置摘要`
|
||
- 这块会直接显示:
|
||
- `configUrl`
|
||
- `releaseId`
|
||
- `manifestUrl`
|
||
- `schemaVersion`
|
||
- `playfield.kind`
|
||
- `game.mode`
|
||
- 这组信息用于和前端地图页实际消费结果对口排查,避免只靠口头描述“像顺序赛/像积分赛”。
|
||
- 注意:
|
||
- 游客模式当前不走 `/dev/workbench` 一键链验证
|
||
- frontend 若要联调游客模式,请直接使用:
|
||
- `GET /public/experience-maps`
|
||
- `GET /public/experience-maps/{mapAssetPublicID}`
|
||
- `GET /public/events/{eventPublicID}`
|
||
- `GET /public/events/{eventPublicID}/play`
|
||
- `POST /public/events/{eventPublicID}/launch`
|
||
- 游客模式当前只允许默认体验活动进入,且仍然必须基于已发布 release。
|
||
- 这块摘要由 backend 代读 manifest,只用于 workbench 调试
|
||
- 这样做是为了避免浏览器直接读取 OSS 时受跨域影响
|
||
- 它不替代正式客户端加载逻辑
|
||
- 正式客户端仍必须直接消费 `launch.config.configUrl` 或 `launch.resolvedRelease.manifestUrl`
|
||
- `前端调试日志` 也是调试专用能力:
|
||
- backend 当前只在内存里保留最近 200 条
|
||
- 适合前端把关键事实直接打进来,避免只靠截图和口头描述
|
||
- 不替代正式生产日志体系
|
||
- `Bootstrap Demo` 准备出的联调文案也已换成中文样例:
|
||
- `领秀城公园顺序赛`
|
||
- `领秀城公园积分赛`
|
||
- `领秀城公园多赛道挑战`
|
||
- 当前“准备页地图预览 V1”已先接进只读查询接口:
|
||
- `GET /events/{eventPublicID}`
|
||
- `GET /events/{eventPublicID}/play`
|
||
- 当前 preview 字段最小结构为:
|
||
- `preview.mode`
|
||
- `preview.baseTiles.tileBaseUrl`
|
||
- `preview.baseTiles.zoom`
|
||
- `preview.baseTiles.tileSize`
|
||
- `preview.viewport.width / height`
|
||
- `preview.viewport.minLon / minLat / maxLon / maxLat`
|
||
- `preview.variants[].controls`
|
||
- `preview.variants[].legs`
|
||
- `preview.selectedVariantId`
|
||
- 当前实现边界:
|
||
- 只服务准备页只读预览
|
||
- 不进入正式 launch 主链
|
||
- demo 活动当前已自带预览元数据
|
||
- 非带预览元数据的活动允许返回空
|
||
- workbench 当前已增加固定卡片:
|
||
- `准备页地图预览状态`
|
||
- 当前会直接显示:
|
||
- `Preview Mode`
|
||
- `Tile Base URL`
|
||
- `Zoom`
|
||
- `Viewport`
|
||
- `Selected Variant`
|
||
- `Preview Variant Count`
|
||
- `First Variant Controls`
|
||
- `First Variant Legs`
|
||
- 点击:
|
||
- `Event Detail`
|
||
- `Event Play`
|
||
后都会刷新这张卡
|
||
- 当前运维入口第一期已迁移到独立运维工作台:
|
||
- `Import Tile Release`
|
||
- `Import KML Batch`
|
||
- 两条入口分别对应:
|
||
- `POST /admin/ops/tile-releases/import`
|
||
- `POST /admin/ops/course-sets/import-kml-batch`
|
||
- 推荐使用顺序:
|
||
1. 先录入瓦片版本
|
||
2. 再批量录入 KML 路线
|
||
3. 最后再继续组装 `runtime / event / release`
|
||
- 这两条入口当前只服务运维录入第一期,不替代正式后台 UI。
|
||
- 当前运维入口第二期已先落 backend 资源纳管接口:
|
||
- `GET /admin/assets`
|
||
- `POST /admin/assets/register-link`
|
||
- `POST /admin/assets/upload`
|
||
- `GET /admin/assets/{assetPublicID}`
|
||
- 当前用途:
|
||
- 运维不再必须自己管 OSS 目录细节
|
||
- 允许直接上传文件,由 backend 负责:
|
||
- 上传到 OSS
|
||
- 生成正式 URL
|
||
- 登记资源对象
|
||
- 也允许直接登记已有正式外链
|
||
- 当前已新增独立运维工作台:
|
||
- [http://127.0.0.1:18090/admin/ops-workbench](http://127.0.0.1:18090/admin/ops-workbench)
|
||
- 当前入口分工:
|
||
- `/dev/workbench`
|
||
- 调试工作台
|
||
- 一键回归、配置摘要、前端日志、联调排查
|
||
- 当前只保留运维入口说明与跳转,不再承载正式资源录入动作
|
||
- `/admin/ops-workbench`
|
||
- 运维工作台
|
||
- 资源上传、外链登记、地图瓦片导入、KML 批量导入
|
||
- 活动绑定
|
||
- 发布中心
|
||
- 当前运维后台鉴权也已经开始独立:
|
||
- 运维账号接口:
|
||
- `POST /ops/auth/sms/send`
|
||
- `POST /ops/auth/register`
|
||
- `POST /ops/auth/login/sms`
|
||
- `POST /ops/auth/refresh`
|
||
- `POST /ops/auth/logout`
|
||
- `GET /ops/me`
|
||
- 运维后台管理接口:
|
||
- `/ops/admin/*`
|
||
- 设计目标:
|
||
- 运维账号与前端玩家账号完全分离
|
||
- 生产环境走手机号验证码注册/登录
|
||
- 后续可扩角色分级、多租户
|
||
- 当前开发环境为了录资源和调发布方便,运维后台默认免登录:
|
||
- `/admin/ops-workbench` 可直接进入
|
||
- `/ops/admin/*` 在 non-production 下可直接调用
|
||
- 只有主动验证运维账号链路时,才需要真的走手机号验证码登录
|
||
- 当前运维工作台已收成 5 块:
|
||
- `资源总览`
|
||
- `地图资源管理`
|
||
- `资源录入`
|
||
- `赛道集管理`
|
||
- `活动绑定`
|
||
- `发布中心`
|
||
- 当前“地图资源管理”第一刀的最小目标是:
|
||
1. 读取地点列表
|
||
2. 新建地点
|
||
3. 读取地点详情
|
||
4. 新建地图资源
|
||
5. 读取地图详情
|
||
6. 在同一页面查看:
|
||
- 当前瓦片版本
|
||
- 当前瓦片地址
|
||
- 默认活动摘要
|
||
- 当前运维台对应入口:
|
||
- `GET /ops/admin/places`
|
||
- `POST /ops/admin/places`
|
||
- `GET /ops/admin/places/{placePublicID}`
|
||
- `POST /ops/admin/places/{placePublicID}/map-assets`
|
||
- `GET /ops/admin/map-assets/{mapAssetPublicID}`
|
||
- `POST /ops/admin/map-assets/{mapAssetPublicID}/tile-releases`
|
||
|
||
## 4. 活动卡片列表最小摘要
|
||
|
||
当前 backend 已为以下入口统一补齐活动卡片最小摘要字段:
|
||
|
||
- `/cards`
|
||
- `/home`
|
||
- `/me/entry-home`
|
||
|
||
当前字段集:
|
||
|
||
- `title`
|
||
- `subtitle`
|
||
- `summary`
|
||
- `status`
|
||
- `statusCode`
|
||
- `timeWindow`
|
||
- `ctaText`
|
||
- `coverUrl`
|
||
- `isDefaultExperience`
|
||
- `eventType`
|
||
- `currentPresentation`
|
||
- `currentContentBundle`
|
||
|
||
当前派生规则:
|
||
|
||
- `summary`
|
||
- 无值时回退为:`当前暂无活动摘要`
|
||
- `status`
|
||
- `running` -> `进行中`
|
||
- `upcoming` -> `即将开始`
|
||
- `ended` -> `已结束`
|
||
- 其余 -> `状态待确认`
|
||
- `timeWindow`
|
||
- 由 `cards.starts_at / ends_at` 派生
|
||
- 缺失时回退为:`时间待公布`
|
||
- `ctaText`
|
||
- 默认体验活动:`进入体验`
|
||
- 进行中:`进入活动`
|
||
- 已结束:`查看回顾`
|
||
- 其余:`查看详情`
|
||
- `currentPresentation / currentContentBundle`
|
||
- 当前继续表示已发布 release 实际绑定摘要
|
||
- 不是 event 草稿默认值
|
||
|
||
默认会设置:
|
||
|
||
- `APP_ENV=development`
|
||
- `HTTP_ADDR=:18090`
|
||
- `DATABASE_URL=postgres://postgres:asdf*123@192.168.100.77:5432/cmr20260401?sslmode=disable`
|
||
- `AUTH_SMS_PROVIDER=console`
|
||
- `WECHAT_MINI_DEV_PREFIX=dev-`
|
||
|
||
启动后可直接打开:
|
||
|
||
- [http://127.0.0.1:18090/dev/workbench](http://127.0.0.1:18090/dev/workbench)
|
||
|
||
当前 workbench 已覆盖两类调试链:
|
||
|
||
- 用户主链:`bootstrap -> auth -> entry/home -> event play/launch -> session -> result`
|
||
- 后台运营链:`maps/playfields/resource-packs -> admin event source -> build -> publish -> rollback`
|
||
- 第一阶段生产骨架联调台:`places -> map-assets -> tile-releases -> course-sources -> course-sets -> course-variants -> runtime-bindings`
|
||
- 第三刀最小接线验证:`runtimeBinding -> release -> launch.runtime`
|
||
- 第四刀发布闭环验证:`runtimeBinding -> publish(runtimeBindingId) -> release -> launch.runtime`
|
||
- 活动运营域第二阶段验证:`presentation -> content bundle -> publish(presentationId, contentBundleId, runtimeBindingId) -> release`
|
||
- 活动运营域第二阶段第二刀验证:`event detail / play / launch -> presentation + content bundle 摘要`
|
||
- 活动运营域第二阶段第三刀验证:`release 摘要闭环 + content bundle import`
|
||
- 活动运营域第二阶段第四刀验证:`presentation import -> event 默认 active 绑定 -> publish 空参继承`
|
||
- workbench 一键验证增强:`一键默认绑定发布` 与 `一键补齐 Runtime 并发布`
|
||
- `/dev/bootstrap-demo` 现在也会回填最小生产骨架:`place / map asset / tile release / course source / course set / course variant / runtime binding`
|
||
|
||
### 2.1 当前推荐验证方式
|
||
|
||
如果目标是验证“从测试数据准备到 release 继承是否完整”,优先使用 workbench 的一键流,而不是手工逐个点按钮。
|
||
|
||
当前推荐顺序:
|
||
|
||
1. `Bootstrap Demo(只准备数据)`
|
||
2. 选择一种玩法入口:
|
||
- `Use Classic Demo`
|
||
- `Use Score-O Demo`
|
||
- `Use Manual Variant Demo`
|
||
3. 如果只是想看发布过程,点 `Bootstrap + 发布当前玩法`
|
||
4. 如果想只测发布链,点 `一键补齐 Runtime 并发布`
|
||
5. 如果想直接验整条链,点 `一键标准回归`
|
||
|
||
当前这几个按钮的职责已经拆开:
|
||
|
||
- `Bootstrap Demo(只准备数据)`
|
||
- 只负责准备 demo event / source / build / release / runtime 等测试数据
|
||
- 不会基于当前玩法再额外重新发布一版
|
||
- `Bootstrap + 发布当前玩法`
|
||
- 会先执行一遍 `Bootstrap Demo`
|
||
- 然后对当前选中的玩法执行“发布活动配置(自动补 Runtime)”
|
||
- `一键补齐 Runtime 并发布`
|
||
- 不再隐式 bootstrap
|
||
- 只基于当前已选玩法和当前表单上下文执行发布链
|
||
|
||
当前这条一键链会自动完成:
|
||
|
||
- demo event / source / build / release 准备
|
||
- presentation 导入
|
||
- content bundle 导入
|
||
- event 默认 active 绑定保存
|
||
- 最小生产骨架准备:
|
||
- `place`
|
||
- `map asset`
|
||
- `tile release`
|
||
- `course source`
|
||
- `course set`
|
||
- `course variant`
|
||
- `runtime binding`
|
||
- publish
|
||
- release 回读校验
|
||
- `play / launch / result / history` 回归汇总
|
||
- demo 活动残留 ongoing session 清理:
|
||
- 会把 demo event 下历史遗留的 `launched / running` session 自动改成 `cancelled`
|
||
- 真实输入替换第一刀:
|
||
- `CourseSource.fileUrl` 当前已切到真实 KML:
|
||
- `https://oss-mbh5.colormaprun.com/gotomars/kml/lxcb-001/10/c01.kml`
|
||
- `https://oss-mbh5.colormaprun.com/gotomars/kml/lxcb-001/10/c02.kml`
|
||
- `TileRelease.tileBaseUrl / metaUrl` 当前已切到真实地图资源:
|
||
- `https://oss-mbh5.colormaprun.com/gotomars/map/lxcb-001/tiles/`
|
||
- `https://oss-mbh5.colormaprun.com/gotomars/map/lxcb-001/tiles/meta.json`
|
||
- manual 多赛道 demo 当前已使用两条真实赛道输入:
|
||
- `variant_a -> c01.kml`
|
||
- `variant_b -> c02.kml`
|
||
- 显式玩法测试入口:
|
||
- 顺序赛:`evt_demo_001 -> rel_demo_001 -> classic-sequential.json`
|
||
- 积分赛:`evt_demo_score_o_001 -> rel_demo_score_o_001 -> score-o.json`
|
||
- 多赛道:`evt_demo_variant_manual_001 -> rel_demo_variant_manual_001`
|
||
|
||
当前日志能力:
|
||
|
||
- 每一步都会写到“响应日志”
|
||
- 失败时会直接输出:
|
||
- 错误消息
|
||
- stack
|
||
- 最后一次 curl
|
||
- 成功时“预期结果”面板会直接给出:
|
||
- `Release ID`
|
||
- `Presentation`
|
||
- `Content Bundle`
|
||
- `Runtime Binding`
|
||
- `判定`
|
||
- 成功跑完标准回归后,“回归结果汇总”会直接给出:
|
||
- `发布链`
|
||
- `Play`
|
||
- `Launch`
|
||
- `Result`
|
||
- `History`
|
||
- `Session ID`
|
||
- `总判定`
|
||
- workbench 现在还支持查看 frontend 主动上报的调试日志:
|
||
- `拉取前端日志`
|
||
- `清空前端日志`
|
||
- 前端建议最少带:
|
||
- `eventId`
|
||
- `releaseId`
|
||
- `sessionId`
|
||
- `manifestUrl`
|
||
- `route`
|
||
- `game.mode`
|
||
- `playfield.kind`
|
||
- 当前页面阶段或动作名
|
||
|
||
### 2.2 前端调试日志最小约定
|
||
|
||
dev 环境下,frontend 可直接把关键调试事实发到 backend:
|
||
|
||
- `POST /dev/client-logs`
|
||
|
||
建议请求体最少包含:
|
||
|
||
```json
|
||
{
|
||
"source": "miniprogram",
|
||
"level": "info",
|
||
"category": "runtime",
|
||
"message": "map page loaded manifest",
|
||
"eventId": "evt_demo_score_o_001",
|
||
"releaseId": "rel_xxx",
|
||
"sessionId": "sess_xxx",
|
||
"manifestUrl": "https://oss-mbh5.colormaprun.com/...",
|
||
"route": "pages/map/map",
|
||
"occurredAt": "2026-04-03T16:16:38+08:00",
|
||
"details": {
|
||
"schemaVersion": "1",
|
||
"playfield.kind": "control-set",
|
||
"game.mode": "score-o",
|
||
"phase": "map-init"
|
||
}
|
||
}
|
||
```
|
||
|
||
当前说明:
|
||
|
||
- `source`:建议填终端来源,例如 `miniprogram`
|
||
- `level`:建议填 `info / warn / error`
|
||
- `category`:建议填 `launch / runtime / cache / network`
|
||
- `message`:一句话说明当前发生了什么
|
||
- `details`:放结构化调试细节,backend 原样收下
|
||
|
||
辅助接口:
|
||
|
||
- `GET /dev/client-logs?limit=50`
|
||
- `DELETE /dev/client-logs`
|
||
|
||
## 3. 当前开发约定
|
||
|
||
### 3.0 玩家进入规则
|
||
|
||
当前要明确一条玩家链路规则:
|
||
|
||
- 玩家进入游戏,必须基于“已发布 release”
|
||
- 不能基于:
|
||
- event 草稿默认绑定
|
||
- 未发布 presentation
|
||
- 未发布 content bundle
|
||
- 未发布 runtime
|
||
|
||
当前接口中的:
|
||
|
||
- `currentPresentation`
|
||
- `currentContentBundle`
|
||
|
||
在玩家链路里表示的是:
|
||
|
||
- 当前已发布 release 上实际绑定的展示版本摘要
|
||
- 当前已发布 release 上实际绑定的内容包摘要
|
||
|
||
不是:
|
||
|
||
- event 草稿默认值摘要
|
||
|
||
所以如果当前 release 还没绑定这些对象,玩家页看到空值是正常行为。前端页面应优先:
|
||
|
||
- 用 `play.canLaunch` 判定是否允许进入
|
||
- 把空值解释成“当前未发布或当前发布未绑定”
|
||
|
||
当前 `canLaunch` 已按正式进入规则收紧:
|
||
|
||
- 只有当当前 event 满足以下条件时,`play.canLaunch = true`
|
||
- event `status = active`
|
||
- 已存在当前发布 release
|
||
- 当前发布 release 有 `manifest`
|
||
- 当前发布 release 已绑定 `runtime`
|
||
- 当前发布 release 已绑定 `presentation`
|
||
- 当前发布 release 已绑定 `content bundle`
|
||
|
||
当前 `POST /events/{eventPublicID}/launch` 也已与 `canLaunch` 保持同一套前置条件。
|
||
|
||
### 3.1 开发阶段先不用 Redis
|
||
|
||
当前第一版全部依赖:
|
||
|
||
- PostgreSQL
|
||
- JWT
|
||
- refresh token 持久化
|
||
|
||
Redis 后面只在需要性能优化、限流或短期票据缓存时再接。
|
||
|
||
### 3.2 开发环境短信
|
||
|
||
当前默认可走 `console` provider。
|
||
|
||
用途:
|
||
|
||
- 本地联调无需接真实短信供应商
|
||
|
||
### 3.3 微信小程序开发态
|
||
|
||
当前支持 `dev-` 前缀 code。
|
||
|
||
适合:
|
||
|
||
- 后端联调
|
||
- workbench 快速验证
|
||
|
||
### 3.4 本地配置目录
|
||
|
||
当前支持从根目录 [event](D:/dev/cmr-mini/event) 导入本地配置文件。
|
||
|
||
相关环境变量:
|
||
|
||
- `LOCAL_EVENT_DIR`
|
||
- `ASSET_BASE_URL`
|
||
|
||
作用:
|
||
|
||
- `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
|
||
|
||
当前 migration 文件在 [migrations](D:/dev/cmr-mini/backend/migrations)。
|
||
|
||
执行原则:
|
||
|
||
1. 按编号顺序执行
|
||
2. schema 变更只通过新增 migration 完成
|
||
3. 不直接改线上已执行 migration
|
||
|
||
## 5. 开发工作台
|
||
|
||
### `POST /dev/bootstrap-demo`
|
||
|
||
它会保证 demo 数据存在:
|
||
|
||
- `tenant_demo`
|
||
- `mini-demo`
|
||
- `evt_demo_001`
|
||
- `rel_demo_001`
|
||
- `card_demo_001`
|
||
|
||
### `GET /dev/workbench`
|
||
|
||
这是当前最重要的联调工具。
|
||
|
||
可以直接测试:
|
||
|
||
- 登录
|
||
- 入口解析
|
||
- 首页聚合
|
||
- event play
|
||
- 第一阶段生产骨架对象
|
||
- 配置导入、preview build、publish build
|
||
- launch
|
||
- session start / finish
|
||
- result
|
||
- profile
|
||
|
||
补充说明:
|
||
|
||
- `publish build` 现在会真实上传 `manifest.json` 和 `asset-index.json` 到 OSS
|
||
- 如果上传失败,接口会直接报错,不再出现“数据库里已有 release,但 OSS 上没有对象”的假成功
|
||
- `Save Event Defaults` 会把当前 event 的默认 active 绑定写入:
|
||
- `currentPresentationId`
|
||
- `currentContentBundleId`
|
||
- `currentRuntimeBindingId`
|
||
- 之后 `Publish Build` 如果不显式填写这三项,会优先继承 event 默认 active 绑定
|
||
|
||
并且支持:
|
||
|
||
- quick flow
|
||
- scenario 保存/导入/导出
|
||
- curl 导出
|
||
- request history
|
||
|
||
当前第一阶段生产骨架联调台只做:
|
||
|
||
- `list`
|
||
- `create`
|
||
- `detail`
|
||
- `binding`
|
||
|
||
明确不做:
|
||
|
||
- 正式后台 UI
|
||
- `edit`
|
||
- `delete`
|
||
- `batch`
|
||
- 审核流
|
||
|
||
活动运营域第二阶段当前也只做最小动作:
|
||
|
||
- `list`
|
||
- `create`
|
||
- `detail`
|
||
- `publish 绑定`
|
||
- `import`
|
||
|
||
## 6. 当前推荐联调顺序
|
||
|
||
### 场景一:小程序快速进入
|
||
|
||
1. `bootstrap-demo`
|
||
2. `login/wechat-mini`
|
||
3. `me/entry-home`
|
||
4. `events/{id}/play`
|
||
5. `events/{id}/launch`
|
||
6. `sessions/{id}/start`
|
||
7. `sessions/{id}/finish`
|
||
8. `sessions/{id}/result`
|
||
|
||
### 场景二:APP 主身份
|
||
|
||
1. `auth/sms/send`
|
||
2. `auth/login/sms`
|
||
3. `me/entry-home`
|
||
4. `launch`
|
||
5. `session`
|
||
6. `result`
|
||
|
||
### 场景三:微信轻账号绑定手机号
|
||
|
||
1. `login/wechat-mini`
|
||
2. `auth/sms/send` with `scene=bind_mobile`
|
||
3. `auth/bind/mobile`
|
||
4. `me/profile`
|
||
|
||
### 场景四:配置发布到可启动 release
|
||
|
||
1. `bootstrap-demo`
|
||
2. `dev/events/{eventPublicID}/config-sources/import-local`
|
||
3. `dev/config-builds/preview`
|
||
4. `dev/config-builds/publish`
|
||
5. `events/{id}`
|
||
6. `events/{id}/launch`
|
||
|
||
### 场景五:第一阶段生产骨架最小闭环
|
||
|
||
在 `/dev/workbench` 的 `后台运营` 模式中,按下面顺序操作:
|
||
|
||
1. `List Places` 或 `Create Place`
|
||
2. 在该 `Place` 下 `Create Map Asset`
|
||
3. 在该 `MapAsset` 下 `Create Tile Release`
|
||
4. `Create Course Source`
|
||
5. 在该 `MapAsset` 下 `Create Course Set`
|
||
6. 在该 `CourseSet` 下 `Create Variant`
|
||
7. `Create Runtime Binding`
|
||
|
||
成功后应能拿到这些 ID:
|
||
|
||
- `placeId`
|
||
- `mapAssetId`
|
||
- `tileReleaseId`
|
||
- `courseSourceId`
|
||
- `courseSetId`
|
||
- `courseVariantId`
|
||
- `runtimeBindingId`
|
||
|
||
建议第一次联调时用这组最小规则:
|
||
|
||
- `Place` 先建 1 个
|
||
- 每个 `Place` 先只建 1 个 `MapAsset`
|
||
- 每个 `MapAsset` 先只建 1 个 `TileRelease`
|
||
- 每个 `CourseSet` 先只建 1 个默认 `CourseVariant`
|
||
- `RuntimeBinding` 先只绑定当前正在验证的 `Event`
|
||
|
||
这条链当前只验证对象关系闭环,不验证:
|
||
|
||
- 发布链切换
|
||
- `launch` 返回运行对象字段
|
||
- `EventPresentation`
|
||
- `ContentBundle`
|
||
|
||
### 场景六:第三刀最小接线验证
|
||
|
||
在 `/dev/workbench` 的 `后台运营` 模式中,先完成“场景五”,再按下面顺序操作:
|
||
|
||
1. `Get Pipeline`
|
||
2. 确认当前 `Release ID`
|
||
3. 填或复用 `Runtime Binding ID`
|
||
4. `Bind Runtime`
|
||
5. `Get Release`
|
||
6. 切回 `前台联调`
|
||
7. 对同一个 `event` 执行 `Launch`
|
||
|
||
### 场景七:活动运营域第二阶段最小闭环
|
||
|
||
在 `/dev/workbench` 的 `后台运营` 模式中,按下面顺序操作:
|
||
|
||
1. `Get Event`
|
||
2. `Create Presentation`
|
||
3. `Create Bundle`
|
||
4. `Assemble Source`
|
||
5. `Build Source`
|
||
6. 在发布区填:
|
||
- `Runtime Binding ID`
|
||
- `Presentation ID`
|
||
- `Content Bundle ID`
|
||
7. `Publish Build`
|
||
8. `Get Release`
|
||
|
||
成功后应能在 release 返回中看到:
|
||
|
||
- `runtime`
|
||
- `presentation`
|
||
- `contentBundle`
|
||
|
||
并且这 3 类绑定当前都已固化到 `event_release`。
|
||
|
||
成功后应能看到:
|
||
|
||
- `GET /admin/releases/{releasePublicID}` 返回 `runtime`
|
||
- `POST /events/{eventPublicID}/launch` 返回 `launch.runtime`
|
||
|
||
当前阶段的约束是:
|
||
|
||
- 只新增 `runtime` 字段块
|
||
- 不改旧的:
|
||
- `resolvedRelease`
|
||
- `business`
|
||
- `variant`
|
||
- release 如果没挂 `runtimeBindingId`,则 `launch.runtime` 为空
|
||
|
||
### 场景八:活动运营域第二阶段第三刀验证
|
||
|
||
在 `/dev/workbench` 的 `后台运营` 模式中,先完成“场景七”,再按下面顺序操作:
|
||
|
||
1. `Create Presentation` 或直接复用现有 `Presentation ID`
|
||
2. `Import Bundle`
|
||
3. `Get Bundle`
|
||
4. `Get Pipeline`
|
||
5. `Publish Build`
|
||
6. `Get Release`
|
||
7. 切回 `前台联调`
|
||
8. `Event Detail`
|
||
9. `Event Play`
|
||
10. `Launch`
|
||
|
||
成功后应能同时看到这三组摘要:
|
||
|
||
- `release.presentation.templateKey / version`
|
||
- `release.contentBundle.bundleType / version`
|
||
- `release.runtime.placeId / mapId / tileReleaseId / courseVariantId`
|
||
|
||
同时客户端消费侧应保持一致:
|
||
|
||
- `GET /events/{eventPublicID}`
|
||
- `GET /events/{eventPublicID}/play`
|
||
- `POST /events/{eventPublicID}/launch`
|
||
|
||
当前 Content Bundle Import 只做统一导入入口,不做复杂资源平台:
|
||
|
||
- 输入:
|
||
- `title`
|
||
- `bundleType`
|
||
- `sourceType`
|
||
- `manifestUrl`
|
||
- `version`
|
||
- `assetManifest`
|
||
- 输出:
|
||
- `bundleId`
|
||
- `bundleType`
|
||
- `version`
|
||
- `assetManifest`
|
||
- `status`
|
||
|
||
### 场景七:第四刀发布闭环验证
|
||
|
||
在 `/dev/workbench` 的 `后台运营` 模式中,先完成“场景五”,再按下面顺序操作:
|
||
|
||
1. `Create Runtime Binding`
|
||
2. `Get Pipeline`
|
||
3. 确认 `Build ID`
|
||
4. 在发布区填 `Runtime Binding ID`
|
||
5. `Publish Build`
|
||
6. `Get Release`
|
||
7. 切回 `前台联调`
|
||
8. 对同一个 `event` 执行 `Launch`
|
||
|
||
成功后应能看到:
|
||
|
||
- `POST /admin/builds/{buildID}/publish` 返回带 `runtime`
|
||
- `GET /admin/releases/{releasePublicID}` 返回同一条 `runtime`
|
||
- `POST /events/{eventPublicID}/launch` 返回同一条 `launch.runtime`
|
||
|
||
当前第四刀的兼容要求是:
|
||
|
||
- 旧的“先 `publish`,再 `bind runtime`”路径继续可用
|
||
- 新的“`publish` 时直接传 `runtimeBindingId`”优先推荐
|
||
- 不修改旧的:
|
||
- `resolvedRelease`
|
||
- `business`
|
||
- `variant`
|
||
|
||
## 6.1 地图列表与默认活动
|
||
|
||
当前 backend 已补最小地图体验入口:
|
||
|
||
- `GET /experience-maps`
|
||
- `GET /experience-maps/{mapAssetPublicID}`
|
||
|
||
语义约定:
|
||
|
||
- 地图列表按 `Place / MapAsset` 聚合
|
||
- 默认活动关系来自:
|
||
- `events.is_default_experience`
|
||
- `events.show_in_event_list`
|
||
- 当前已发布 `release` 绑定到的 `runtime.mapAsset`
|
||
- `Bootstrap Demo` 后:
|
||
- `evt_demo_001` 为默认体验活动
|
||
- `evt_demo_score_o_001`
|
||
- `evt_demo_variant_manual_001`
|
||
为普通活动,但仍会出现在地图关联活动里
|
||
|
||
当前前端可直接消费的字段:
|
||
|
||
- 地图列表:
|
||
- `placeId`
|
||
- `placeName`
|
||
- `mapId`
|
||
- `mapName`
|
||
- `coverUrl`
|
||
- `summary`
|
||
- `defaultExperienceCount`
|
||
- `defaultExperienceEventIds`
|
||
- 地图详情:
|
||
- `placeId`
|
||
- `placeName`
|
||
- `mapId`
|
||
- `mapName`
|
||
- `coverUrl`
|
||
- `summary`
|
||
- `tileBaseUrl`
|
||
- `tileMetaUrl`
|
||
- `defaultExperiences[]`
|
||
|
||
## 7. 当前后续开发建议
|
||
|
||
文档整理完之后,后面建议按这个顺序继续:
|
||
|
||
1. 抽出更通用的 `play context -> launch` 模型
|
||
2. 补赛事与报名层
|
||
3. 补页面配置和白标首页
|
||
4. 再考虑实时网关票据
|
||
|
||
不要跳回去把玩法规则塞进 backend。
|
||
|
||
|