Files
Genarrative/docs/technical/ADMIN_CONSOLE_SERVICE_DESIGN_2026-04-23.md
kdletters cbc27bad4a
Some checks failed
CI / verify (push) Has been cancelled
init with react+axum+spacetimedb
2026-04-26 18:06:23 +08:00

261 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 后台管理服务设计
日期:`2026-04-23`
## 1. 目标
为当前 Rust `api-server` 增加一套同源后台管理服务,满足以下首版目标:
1. 支持管理员用户名密码登录。
2. 支持独立的管理员鉴权,不允许普通玩家 JWT 越权访问。
3. 支持在后台查看当前服务与数据库概览信息。
4. 支持在后台测试当前 `api-server` 已挂载接口。
5. 保持首版工程足够轻量,不新建额外独立服务进程,不引入第二套前端工程。
## 2. 背景与约束
当前仓库已具备:
1. Rust `api-server` 主链。
2. 基于 JWT + refresh session 的普通用户登录体系。
3. `SpacetimeDB + spacetime-client` 的主数据面。
本次后台管理服务必须继续遵守:
1. 后端统一落在 `server-rs`,不回退到 `server-node`
2. 不额外新起独立管理服务进程。
3. 首版以“一个受保护管理域 + 一个同源后台页面”为落地形态。
4. 数据库信息必须尽量读取真实数据库侧信息,不能只展示硬编码假数据。
## 3. 首版范围
### 3.1 包含
1. `GET /admin`:后台管理页面入口。
2. `POST /admin/api/login`:管理员用户名密码登录。
3. `GET /admin/api/me`:当前管理员会话信息。
4. `GET /admin/api/overview`:服务与数据库概览。
5. `POST /admin/api/debug/http`:受控 HTTP 接口调试。
6. 基于 Bearer JWT 的管理员鉴权中间件。
### 3.2 不包含
1. 多角色管理员体系。
2. 管理员 refresh cookie / 多端会话管理。
3. 后台直接写库、删库、执行 reducer。
4. 任意 SQL 执行器。
5. 新建独立 React/Vite 管理端工程。
## 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 的管理页。
原因:
1. 首版目标是“可用的后台能力”,不是新建一套复杂前端基建。
2. 管理页面交互相对简单,直接内嵌更易随服务端一起部署。
3. 可以避免新增构建链和静态资源发布路径。
### 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. 路由清单
首版新增路由:
1. `GET /admin`
2. `POST /admin/api/login`
3. `GET /admin/api/me`
4. `GET /admin/api/overview`
5. `POST /admin/api/debug/http`
## 12. 完成定义
满足以下条件时,本任务视为完成:
1. `api-server` 内存在受保护后台管理域。
2. 管理员用户名密码可登录。
3. 普通用户 token 无法访问后台接口。
4. 后台能看到服务和数据库真实概览。
5. 后台能调试当前服务 HTTP 接口。
6. 路由索引与技术文档已同步更新。