272 lines
8.9 KiB
Markdown
272 lines
8.9 KiB
Markdown
# 后台管理服务设计
|
||
|
||
日期:`2026-04-23`
|
||
|
||
更新:`2026-04-30`
|
||
|
||
> 状态说明:本文件中的管理员鉴权、`/admin/api/*` 管理接口、数据库概览与受控 API 调试设计继续有效;同源内嵌 HTML/CSS/JS 后台页面已废弃。后续后台 UI 迁移到独立前端工程,当前 `api-server` 不再挂载 `GET /admin` 页面入口。独立后台前端的产品边界见 [`../prd/ADMIN_WEB_CONSOLE_PRD_2026-04-30.md`](../prd/ADMIN_WEB_CONSOLE_PRD_2026-04-30.md),技术方案见 [`ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md`](./ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md)。
|
||
|
||
## 1. 目标
|
||
|
||
为当前 Rust `api-server` 增加一套同源后台管理服务,满足以下首版目标:
|
||
|
||
1. 支持管理员用户名密码登录。
|
||
2. 支持独立的管理员鉴权,不允许普通玩家 JWT 越权访问。
|
||
3. 支持在后台查看当前服务与数据库概览信息。
|
||
4. 支持在后台测试当前 `api-server` 已挂载接口。
|
||
5. 保持管理能力继续收口在 `server-rs`,管理 UI 由独立后台前端工程承接。
|
||
|
||
## 2. 背景与约束
|
||
|
||
当前仓库已具备:
|
||
|
||
1. Rust `api-server` 主链。
|
||
2. 基于 JWT + refresh session 的普通用户登录体系。
|
||
3. `SpacetimeDB + spacetime-client` 的主数据面。
|
||
|
||
本次后台管理服务必须继续遵守:
|
||
|
||
1. 后端统一落在 `server-rs`,不回退到 `server-node`。
|
||
2. 不额外新起独立管理服务进程。
|
||
3. 管理 API 继续作为受保护管理域挂载在 `api-server`。
|
||
4. 数据库信息必须尽量读取真实数据库侧信息,不能只展示硬编码假数据。
|
||
|
||
## 3. 首版范围
|
||
|
||
### 3.1 包含
|
||
|
||
1. `POST /admin/api/login`:管理员用户名密码登录。
|
||
2. `GET /admin/api/me`:当前管理员会话信息。
|
||
3. `GET /admin/api/overview`:服务与数据库概览。
|
||
4. `POST /admin/api/debug/http`:受控 HTTP 接口调试。
|
||
5. `POST /admin/api/profile/redeem-codes`:兑换码创建/更新。
|
||
6. `POST /admin/api/profile/redeem-codes/disable`:兑换码停用。
|
||
7. 基于 Bearer JWT 的管理员鉴权中间件。
|
||
|
||
### 3.2 不包含
|
||
|
||
1. 多角色管理员体系。
|
||
2. 管理员 refresh cookie / 多端会话管理。
|
||
3. 后台直接写库、删库、执行 reducer。
|
||
4. 任意 SQL 执行器。
|
||
5. `api-server` 内嵌 HTML/CSS/JS 后台页面。
|
||
|
||
## 4. 总体方案
|
||
|
||
### 4.1 部署形态
|
||
|
||
后台管理服务直接挂载在现有 `server-rs/crates/api-server` 内,作为同一个 Axum 进程的一部分。
|
||
|
||
原因:
|
||
|
||
1. 当前 `api-server` 已具备配置、JWT、错误包裹、日志与同源路由能力。
|
||
2. 后台本质上是服务运维与调试面,不值得单独再起一个网关或 BFF。
|
||
3. 同源可以避免开发期额外 CORS 和 cookie 域问题。
|
||
|
||
### 4.2 页面形态
|
||
|
||
后台管理页面不再由 `api-server` 直接返回内嵌 HTML/CSS/JS。`api-server` 仅保留管理 API,页面由独立后台前端工程调用这些接口。
|
||
|
||
原因:
|
||
|
||
1. 管理 UI 需要独立演进,不应继续堆在 Rust 源码字符串中。
|
||
2. `server-rs` 继续负责鉴权、聚合和写操作,符合前端只做表现的工程约束。
|
||
3. 删除 `GET /admin` 后,当前服务访问该路径应返回 `404`。
|
||
|
||
### 4.3 数据库信息来源
|
||
|
||
数据库概览不走本地 CLI shell,也不依赖前端直接访问数据库。
|
||
|
||
首版采用两类信息源:
|
||
|
||
1. 服务端配置与连接信息:来自 `api-server` 当前 `AppConfig`。
|
||
2. SpacetimeDB 真正的数据库元信息与表行数:由 `api-server` 通过 SpacetimeDB 官方 HTTP API 读取。
|
||
|
||
读取口径:
|
||
|
||
1. `/v1/database/{database}`:读取数据库基础信息。
|
||
2. `/v1/database/{database}/schema`:读取 schema 信息。
|
||
3. `/v1/database/{database}/sql`:对受控表执行 `SELECT COUNT(*)` 统计。
|
||
|
||
说明:
|
||
|
||
1. 首版只做只读概览,不暴露任意 SQL 输入。
|
||
2. 表清单由后端显式维护,避免用户在后台拼接任意查询。
|
||
|
||
## 5. 管理员鉴权设计
|
||
|
||
### 5.1 管理员账号来源
|
||
|
||
首版不复用普通玩家账号仓储,不把管理员账号混进 `module-auth` 用户表。
|
||
|
||
管理员账号来自环境变量:
|
||
|
||
1. `GENARRATIVE_ADMIN_USERNAME`
|
||
2. `GENARRATIVE_ADMIN_PASSWORD`
|
||
|
||
原因:
|
||
|
||
1. 管理员是平台运维身份,不等于玩家账号。
|
||
2. 首版目标是尽快落地可靠后台,不引入额外管理员表迁移。
|
||
3. 环境变量方案最适合当前阶段的单后台入口。
|
||
|
||
### 5.2 管理员 JWT
|
||
|
||
后台登录成功后签发独立管理员 Bearer JWT。
|
||
|
||
claims 设计:
|
||
|
||
1. 继续复用 `platform-auth::AccessTokenClaims`。
|
||
2. `roles` 固定包含 `admin`。
|
||
3. `sub` 使用稳定管理员主体,例如 `admin:<username>`。
|
||
4. `sid` 使用后台会话 ID。
|
||
5. 不写 refresh cookie。
|
||
|
||
### 5.3 权限校验
|
||
|
||
新增 `require_admin_auth` 中间件,校验规则如下:
|
||
|
||
1. Bearer token 必须可被当前 JWT 配置正确验签。
|
||
2. `roles` 中必须包含 `admin`。
|
||
3. `sub` 必须匹配当前管理员配置主体。
|
||
|
||
普通用户 token 即使同样由本服务签发,只要不带 `admin` 角色,也一律拒绝访问后台接口。
|
||
|
||
## 6. 后台页面设计
|
||
|
||
本节已由独立后台前端工程方案接管。历史同源页面曾包含三个主区域:
|
||
|
||
1. 登录卡片。
|
||
2. 数据库概览面板。
|
||
3. API 调试面板。
|
||
|
||
交互原则:
|
||
|
||
1. 页面简洁,不默认塞说明性长文案。
|
||
2. 移动端优先,窄屏下卡片改纵向堆叠。
|
||
3. API 调试结果在独立结果面板展示,不在按钮下方临时插一段文本。
|
||
|
||
## 7. 数据库概览设计
|
||
|
||
`GET /admin/api/overview` 返回以下信息:
|
||
|
||
1. 当前服务监听信息。
|
||
2. 当前 `SpacetimeDB server/database` 配置。
|
||
3. `SpacetimeDB` 数据库基础信息。
|
||
4. 当前 schema 表清单。
|
||
5. 首批关键表的行数统计。
|
||
|
||
首批关键表固定覆盖:
|
||
|
||
1. `runtime_setting`
|
||
2. `runtime_snapshot`
|
||
3. `user_browse_history`
|
||
4. `profile_dashboard_state`
|
||
5. `profile_wallet_ledger`
|
||
6. `profile_played_world`
|
||
7. `profile_save_archive`
|
||
8. `story_session`
|
||
9. `story_event`
|
||
10. `battle_state`
|
||
11. `inventory_slot`
|
||
12. `quest_record`
|
||
13. `quest_log`
|
||
14. `treasure_record`
|
||
15. `npc_state`
|
||
16. `custom_world_profile`
|
||
17. `custom_world_gallery_entry`
|
||
18. `custom_world_agent_session`
|
||
19. `custom_world_agent_message`
|
||
20. `custom_world_agent_operation`
|
||
21. `custom_world_draft_card`
|
||
22. `big_fish_creation_session`
|
||
23. `big_fish_agent_message`
|
||
24. `big_fish_asset_slot`
|
||
25. `big_fish_runtime_run`
|
||
26. `puzzle_work_profile`
|
||
27. `puzzle_agent_session`
|
||
28. `puzzle_agent_message`
|
||
29. `puzzle_runtime_run`
|
||
30. `ai_task`
|
||
31. `ai_task_stage`
|
||
32. `ai_text_chunk`
|
||
33. `ai_result_reference`
|
||
34. `asset_object`
|
||
35. `asset_entity_binding`
|
||
|
||
返回中的计数失败项必须带错误信息,不能静默吞掉。
|
||
|
||
## 8. API 调试设计
|
||
|
||
`POST /admin/api/debug/http` 提供一个受控 HTTP 调试代理。
|
||
|
||
请求参数:
|
||
|
||
1. `method`
|
||
2. `path`
|
||
3. `headers`
|
||
4. `body`
|
||
|
||
限制:
|
||
|
||
1. 只允许访问当前服务同源相对路径。
|
||
2. 调试回环地址由服务端按当前 `bind_host` 解析;若服务监听在 `0.0.0.0` 或 `::`,后台自动改走 loopback,避免把通配监听地址直接当成调试目标。
|
||
2. 禁止调 `/admin/api/login` 本身,避免自套娃。
|
||
3. 禁止覆盖 `host`、`content-length` 等危险头。
|
||
4. 请求超时固定收口。
|
||
5. 返回调试结果时回显状态码、响应头、响应文本预览。
|
||
|
||
该能力用于验证当前服务端接口,不等价于通用代理工具。
|
||
|
||
## 9. 配置项
|
||
|
||
新增以下环境变量:
|
||
|
||
1. `GENARRATIVE_ADMIN_USERNAME`
|
||
2. `GENARRATIVE_ADMIN_PASSWORD`
|
||
3. `GENARRATIVE_ADMIN_TOKEN_TTL_SECONDS`
|
||
|
||
默认策略:
|
||
|
||
1. 若未配置用户名或密码,则后台登录接口返回 `503`,独立后台前端自行展示未启用状态。
|
||
2. 默认管理员 token TTL 为 `4` 小时。
|
||
|
||
## 10. 测试要求
|
||
|
||
至少覆盖:
|
||
|
||
1. 管理员登录成功。
|
||
2. 管理员密码错误返回 `401`。
|
||
3. 普通用户 token 访问后台接口返回 `403`。
|
||
4. 未登录访问后台接口返回 `401`。
|
||
5. 后台概览接口在未启用管理员配置时返回 `503`。
|
||
6. API 调试接口能成功访问 `/healthz`。
|
||
7. API 调试接口拒绝绝对 URL 和后台自身登录接口。
|
||
|
||
## 11. 路由清单
|
||
|
||
当前保留的管理 API 路由:
|
||
|
||
1. `POST /admin/api/login`
|
||
2. `GET /admin/api/me`
|
||
3. `GET /admin/api/overview`
|
||
4. `POST /admin/api/debug/http`
|
||
5. `POST /admin/api/profile/redeem-codes`
|
||
6. `POST /admin/api/profile/redeem-codes/disable`
|
||
|
||
`GET /admin` 已取消挂载,后续由独立后台前端工程承接页面入口。
|
||
|
||
## 12. 完成定义
|
||
|
||
当前管理 API 保留与内嵌页面移除满足以下条件时,本任务视为完成:
|
||
|
||
1. `api-server` 内存在受保护后台管理域。
|
||
2. 管理员用户名密码可登录。
|
||
3. 普通用户 token 无法访问后台接口。
|
||
4. 后台能看到服务和数据库真实概览。
|
||
5. 后台能调试当前服务 HTTP 接口。
|
||
6. 兑换码管理 API 可由管理员 token 调用。
|
||
7. `GET /admin` 不再挂载,访问返回 `404`。
|
||
8. 独立后台前端 PRD 与技术方案已补齐。
|
||
9. 路由索引与技术文档已同步更新。
|