backend-config-management-proposal.md 6.7 KB

配置驱动应用的后台管理方案建议

本文用于整理当前这类“配置驱动型地图游戏应用”的后台管理建议,面向:

  • PostgreSQL 数据库
  • Go 中间层
  • 后台管理系统
  • 客户端静态配置发布

目标是解决一个核心问题:

配置文件会越来越大,如何在后台可维护、可复用、可审核、可发布、可回滚。


1. 总体原则

最稳的方案不是“数据库直接存一大份 game.json 给客户端读”,而是:

数据库管理编辑态,发布时编译成运行态静态配置文件。

也就是两套形态:

编辑态

  • 存在 PostgreSQL
  • 适合后台表单编辑
  • 支持版本管理
  • 支持对象复用
  • 支持审核、比对、回滚

运行态

  • 由 Go 中间层装配生成
  • 输出为静态 JSON
  • 上传到 OSS/CDN
  • 客户端只读取发布后的静态配置

这条路线最适合当前项目。


2. 不建议的做法

不建议把后台做成:

  • 一张表里存一个超大的 jsonb
  • 后台直接编辑整份 game.json
  • 客户端通过 API 动态拼装所有配置

这样后面会遇到这些问题:

  • 配置复用困难
  • diff 难看
  • 回滚困难
  • 审核困难
  • 局部编辑体验差
  • 客户端运行态不稳定

3. 推荐的核心对象

建议后台和数据库先固定这 5 个核心对象:

Map

地图底座。

负责:

  • 瓦片资源
  • meta 信息
  • 磁偏角
  • 初始视角

Playfield

玩法空间对象定义。

负责:

  • KML 来源
  • 控制点覆盖信息
  • 区域对象
  • 危险区
  • 采集物
  • 起终点信息

说明:

  • Playfield 是上位概念
  • course 只是其中一种特化形式

GameMode

玩法模板。

负责:

  • 顺序赛
  • 积分赛
  • 后续幽灵赛、迷雾赛、金币赛等

也就是:

  • game.mode
  • session
  • punch
  • scoring
  • guidance
  • visibility
  • finish
  • telemetry
  • feedback

ResourcePack

资源包。

负责:

  • 音效 profile
  • 文创内容
  • 图标
  • HUD 主题
  • 动效 profile

Event

最终活动实例。

负责引用:

  • 一个 Map
  • 一个 Playfield
  • 一个 GameMode
  • 一个 ResourcePack

并允许少量活动级覆盖。

一句话:

Event = Map + Playfield + GameMode + ResourcePack + EventOverrides


4. 数据库建模建议

建议每个核心对象都分成:

  • 主表
  • version 表

4.1 主表

主表存稳定元信息:

  • id
  • slug
  • name
  • status
  • current_version_id
  • created_at
  • updated_at

4.2 version 表

version 表存每个版本的具体内容:

  • id
  • parent_id
  • version_no
  • schema_version
  • content_jsonb
  • created_by
  • created_at
  • change_note

4.3 推荐表

建议至少有:

  • maps
  • map_versions
  • playfields
  • playfield_versions
  • game_modes
  • game_mode_versions
  • resource_packs
  • resource_pack_versions
  • events
  • event_versions

5. 为什么要做版本表

版本表的价值非常大:

  • 支持草稿
  • 支持发布版
  • 支持 diff
  • 支持回滚
  • 支持审计
  • 支持多人协作

如果没有版本表,后面后台管理一定会越来越难维护。


6. JSONB 的使用建议

推荐策略是:

  • 稳定字段结构化
  • 变化快的配置内容放 jsonb

例如主表中:

  • slug
  • name
  • status

放结构化列。

而玩法具体配置、资源清单、覆盖字段,放在 content_jsonb

这样兼顾:

  • 查询效率
  • 结构灵活性
  • 配置扩展性

7. 后台编辑方式建议

后台不要直接给运营一个大 JSON 编辑框作为主要方式。

推荐做法:

  • 地图编辑页
  • Playfield 编辑页
  • 玩法规则页
  • 资源包页
  • 活动编排页

按模块表单化编辑。

最后由 Go 中间层负责装配成最终配置 JSON。

也就是:

后台是“编辑结构化对象”,不是“手工拼最终运行文件”。


8. 发布机制建议

发布时建议按下面流程:

  1. 后台选定某个 Event Version
  2. Go 中间层读取它引用的:
    • Map Version
    • Playfield Version
    • GameMode Version
    • ResourcePack Version
  3. 做装配
  4. 做校验
  5. 生成最终运行态 JSON
  6. 上传 OSS/CDN
  7. 记录一条 release

客户端只读:

  • 已发布的静态配置 URL

不要让客户端直接查数据库 API 动态拼。


9. 推荐增加 Release 层

建议增加:

  • event_releases

字段例如:

  • id
  • event_id
  • event_version_id
  • release_no
  • manifest_url
  • published_by
  • published_at
  • status

它的作用:

  • 一键回滚
  • 客户端锁定某次 release
  • 管理历史发布记录
  • 灰度验证

10. Go 中间层建议职责

Go 中间层不要只做 CRUD。

建议它至少承担这 4 类职责:

10.1 校验

  • schema 校验
  • 引用存在校验
  • 字段完整性校验
  • 规则约束校验

10.2 装配

把:

  • Map
  • Playfield
  • GameMode
  • ResourcePack
  • Event Overrides

装配成最终配置结构。

10.3 发布

  • 生成最终静态 JSON
  • 上传到 OSS/CDN
  • 记录 release

10.4 对比与预览

  • 给后台显示 diff
  • 给发布前做预览

一句话:

Go 中间层本质上是配置编译器。


11. 校验建议

建议尽量做强校验。

至少包括:

  • schemaVersion 合法
  • 引用对象存在
  • KML 路径存在
  • 地图 meta 存在
  • 玩法字段完整

以及玩法特定约束,例如:

  • 顺序赛必须有 start / finish
  • 积分赛 control set 需要 score 或可派生 score
  • punch.radiusMeters > 0
  • skip.radiusMeters > punch.radiusMeters

这样能把很多错误挡在发布前。


12. 和当前静态目录的关系

当前你已经有类似目录:

  • map/
  • kml/
  • event/

这很好,可以继续保留。

建议把它理解成:

  • 数据库 = 编辑态
  • 这些目录 = 发布产物态

也就是后台发布后,Go 中间层继续生成:

  • event/classic-sequential.json
  • event/score-o.json
  • map/...
  • kml/...

客户端保持现有读取方式不变。


13. 推荐的后续实施顺序

建议按这个顺序落地:

第一步

先建 5 个核心对象模型:

  • Map
  • Playfield
  • GameMode
  • ResourcePack
  • Event

第二步

为每个对象补版本表。

第三步

Go 中间层实现“装配成最终 JSON”。

第四步

实现“发布到 OSS/CDN”。

第五步

后台逐步从 JSON 编辑过渡到模块化表单编辑。


14. 一句话总结

这类配置驱动应用最稳的后台方案是:

PostgreSQL 管结构化、可版本化的编辑态对象;Go 中间层负责校验、装配和发布;客户端只消费发布后的静态 JSON。

这样才能做到:

  • 可复用
  • 可扩展
  • 可审核
  • 可回滚
  • 可稳定运行