# 后台管理独立前端工程 PRD 日期:`2026-04-30` ## 1. 目标 本 PRD 定义当前项目的后台管理独立前端工程 v1。目标不是重做一套后端,也不是把玩家端前端改造成后台,而是在 monorepo 内新增一个独立管理端应用,正式承接已经从 `api-server` 内嵌页面移出的后台 UI。 首版目标: 1. 后台 UI 独立落在 `apps/admin-web`,不再写入 Rust 源码字符串。 2. 管理数据、业务规则、权限校验和写操作继续统一走 `server-rs/crates/api-server`。 3. v1 只接管已有管理能力:管理员登录、当前管理员信息、服务/数据库概览、受控 API 调试、兑换码管理。 4. 保持管理端清爽、可扫读、移动端可用,不在界面堆大段规则说明。 ## 2. 用户与使用场景 ### 2.1 目标用户 1. 项目开发者:用于本地或测试环境快速查看 `api-server` 与 SpacetimeDB 连接状态。 2. 运维/运营人员:用于创建、更新、停用兑换码,以及确认后台接口是否可用。 3. 后续后台功能开发者:以本工程作为后续用户、作品、资产、审核等管理模块的承载壳。 ### 2.2 首版高频场景 1. 管理员打开后台登录页,输入环境变量配置的管理员用户名和密码。 2. 登录后进入总览页,确认当前服务监听、JWT issuer、SpacetimeDB server/database、schema 表数量和关键表统计。 3. 在 API 调试页对当前 `api-server` 的同源相对路径发起受控请求,排查接口状态。 4. 在兑换码管理页创建或更新公共码、唯一码、私有码,并在需要时停用兑换码。 ## 3. 功能范围 ### 3.1 包含 1. 独立前端工程骨架:`apps/admin-web`。 2. 登录页: - 调用 `POST /admin/api/login`。 - 登录成功后保存管理员 Bearer token。 - 登录失败直接展示后端返回的错误消息。 3. 管理端 Shell: - 顶部显示当前管理员、登录状态和退出按钮。 - 侧边或底部导航包含“总览”“API 调试”“兑换码”。 - 移动端导航改为底部或顶部紧凑标签。 4. 总览页: - 调用 `GET /admin/api/me` 恢复管理员会话。 - 调用 `GET /admin/api/overview` 展示服务和数据库概览。 - 表统计允许部分失败,并直接展示失败项。 5. API 调试页: - 调用 `POST /admin/api/debug/http`。 - 只允许填写同源相对路径,不提供绝对 URL 输入暗示。 - 调试结果在独立结果面板展示状态码、响应头、响应文本和 JSON 预览。 6. 兑换码管理页: - 调用 `POST /admin/api/profile/redeem-codes` 创建/更新兑换码。 - 调用 `POST /admin/api/profile/redeem-codes/disable` 停用兑换码。 - 支持 `public`、`unique`、`private` 三种模式。 - 私有码支持输入内部 `userId` 和公开陶泥号,提交给后端统一解析。 ### 3.2 不包含 1. 不新建后台专用后端服务、BFF、Express 服务或 PostgreSQL 数据面。 2. 不让管理端直接连接 SpacetimeDB TypeScript SDK。 3. 不新增 SpacetimeDB 表结构。 4. 不实现完整用户管理、作品审核、资产审核、充值订单后台。 5. 不实现多角色权限体系、管理员 refresh session、多端会话管理。 6. 不保留 `GET /admin` 同源内嵌页面作为正式后台入口。 ## 4. 页面与交互要求 ### 4.1 登录页 登录页只保留必要输入和状态反馈: 1. 用户名输入框。 2. 密码输入框。 3. 登录按钮。 4. 登录失败状态。 5. 后台未启用状态。 后台未启用时,前端根据 `POST /admin/api/login` 的 `503` 响应展示不可登录状态,不额外引导用户在页面配置环境变量。 ### 4.2 总览页 总览页必须能快速扫读: 1. 服务状态:监听地址、端口、JWT issuer。 2. SpacetimeDB 配置:server URL、database。 3. 数据库元信息:database identity、owner identity、host type。 4. 表清单与表统计:展示成功计数和失败原因。 总览页不展示任意 SQL 输入框。 ### 4.3 API 调试页 API 调试页是受控接口调试台,不是通用代理工具: 1. method 使用选择控件。 2. path 只接受 `/xxx` 形式。 3. headers 使用结构化键值编辑。 4. body 使用文本框。 5. 结果展示在固定结果面板,不在按钮下方临时插入内容。 ### 4.4 兑换码管理页 兑换码管理页首版采用一个创建/更新表单和一个停用表单: 1. code:提交前可在前端 trim,但最终标准化以服务端为准。 2. mode:`public`、`unique`、`private`。 3. rewardPoints:必须为正整数,最终校验以服务端为准。 4. maxUses:必须为正整数,最终校验以服务端为准。 5. enabled:创建/更新时可切换。 6. allowedUserIds:私有码允许的内部用户 ID 列表。 7. allowedPublicUserCodes:私有码允许的公开陶泥号列表。 提交成功后展示后端返回的兑换码记录;失败时展示后端错误消息。 ## 5. 数据与权限边界 1. 管理端所有请求必须经过 `/admin/api/*`。 2. 管理端持有的管理员 token 只用于后台接口,不复用玩家登录 token。 3. 普通玩家 token 访问管理接口应被后端拒绝。 4. 管理端不持久化密码。 5. token 首版可保存在 localStorage;退出登录时立即清除。 6. SpacetimeDB 表、reducer、procedure、迁移和权限判断均不由管理端直接处理。 ## 6. 验收标准 1. `apps/admin-web` 可以独立启动和构建。 2. 登录页可完成管理员登录,错误和未启用状态展示清楚。 3. 登录后刷新页面可通过 `GET /admin/api/me` 恢复会话。 4. 总览页可展示 `GET /admin/api/overview` 的服务与数据库数据。 5. API 调试页可通过后端调试接口访问 `/healthz`。 6. 兑换码管理页可创建/更新、停用兑换码,并展示返回记录。 7. `GET /admin` 保持 404,不恢复旧内嵌页面。 8. `npm run check:encoding` 通过。 ## 7. 首版任务拆解 首版编码按以下模块收口,避免独立后台工程继续扩散成未定义功能: 1. 工程骨架:创建 `apps/admin-web`,补齐 Vite、TypeScript、React 入口和独立构建脚本。 2. API client:只封装 `/admin/api/*`,统一处理 Bearer token、统一 envelope 和后端错误消息。 3. 登录与会话:实现登录、启动恢复、`401` 清理、退出登录四个状态流。 4. 页面 Shell:实现桌面侧栏/顶部栏与移动端紧凑导航,不在未登录状态渲染后台导航。 5. 总览页:展示 `service`、`database`、`tableStats`、`fetchErrors`,部分失败不阻断整页。 6. API 调试页:实现 method、path、headers、body 输入和独立结果面板。 7. 兑换码页:实现创建/更新、停用、三种 mode 切换和私有码用户列表输入。 8. 验证:完成后台工程 typecheck/build、根工程编码检查,以及 `/admin` 仍为 404 的后端验证。 ## 8. 交互修正记录 ### 8.1 兑换码记录页签保持 兑换码管理页的“记录”面板展示最近一次创建、更新或停用接口返回的兑换码记录。该记录在管理端会话内切换“总览”“API 调试”“兑换码”页签时必须保留,避免运营人员切页核对信息后丢失刚返回的结果。退出登录、登录新会话或刷新浏览器页面时可以清空该前端会话态;持久化查询能力后续由新的后端查询接口承接,不在首版用前端伪造历史列表。