Merge branch 'master' of http://82.157.175.59:3000/GenarrativeAI/Genarrative
Some checks failed
CI / verify (push) Has been cancelled
Some checks failed
CI / verify (push) Has been cancelled
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
2. 管理数据、业务规则、权限校验和写操作继续统一走 `server-rs/crates/api-server`。
|
||||
3. v1 只接管已有管理能力:管理员登录、当前管理员信息、服务/数据库概览、受控 API 调试、兑换码管理、注册邀请码管理。
|
||||
4. 保持管理端清爽、可扫读、移动端可用,不在界面堆大段规则说明。
|
||||
5. 发布包内由 Web 网关把独立后台前端挂到同域 `/admin/`;Rust `api-server` 自身仍不恢复旧的 `GET /admin` 内嵌页面。
|
||||
|
||||
## 2. 用户与使用场景
|
||||
|
||||
@@ -66,7 +67,7 @@
|
||||
3. 不新增 SpacetimeDB 表结构。
|
||||
4. 不实现完整用户管理、作品审核、资产审核、充值订单后台。
|
||||
5. 不实现多角色权限体系、管理员 refresh session、多端会话管理。
|
||||
6. 不保留 `GET /admin` 同源内嵌页面作为正式后台入口。
|
||||
6. 不保留 Rust `api-server` 的 `GET /admin` 同源内嵌页面作为正式后台入口;部署态 `/admin/` 只允许由独立后台前端静态产物承接。
|
||||
|
||||
## 4. 页面与交互要求
|
||||
|
||||
@@ -144,7 +145,7 @@ API 调试页是受控接口调试台,不是通用代理工具:
|
||||
5. API 调试页可通过后端调试接口访问 `/healthz`。
|
||||
6. 兑换码管理页可创建/更新、停用兑换码,并展示返回记录。
|
||||
7. 邀请码管理页可创建/更新注册邀请码,并展示返回记录。
|
||||
8. `GET /admin` 保持 404,不恢复旧内嵌页面。
|
||||
8. 直连 Rust `api-server` 时 `GET /admin` 保持 404,不恢复旧内嵌页面;通过发布包 Web 网关访问 `/admin/` 时返回独立后台前端。
|
||||
9. `npm run check:encoding` 通过。
|
||||
|
||||
## 7. 首版任务拆解
|
||||
|
||||
@@ -154,47 +154,11 @@ claims 设计:
|
||||
2. 当前 `SpacetimeDB server/database` 配置。
|
||||
3. `SpacetimeDB` 数据库基础信息。
|
||||
4. 当前 schema 表清单。
|
||||
5. 首批关键表的行数统计。
|
||||
5. schema 表清单对应的逐表行数统计。
|
||||
|
||||
首批关键表固定覆盖:
|
||||
表统计必须以 SpacetimeDB schema 返回的表名为唯一来源,`schemaTableNames` 的数量必须与 `tableStats` 的行数一致。后台服务只对 schema 中符合安全 SQL 标识符格式的表名发起 `SELECT COUNT(*)`,不提供任意 SQL 输入能力。
|
||||
|
||||
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`
|
||||
|
||||
返回中的计数失败项必须带错误信息,不能静默吞掉。
|
||||
返回中的计数失败项必须带错误信息,不能静默吞掉。SpacetimeDB private 表或当前身份不可见的表可能在 `/sql` 下返回 `no such table` / `marked private`,这类项统一展示为“不可统计(private 或当前身份不可见)”,不作为整页读取失败处理。
|
||||
|
||||
## 8. API 调试设计
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
|
||||
对应 PRD:[后台管理独立前端工程 PRD](../prd/ADMIN_WEB_CONSOLE_PRD_2026-04-30.md)
|
||||
|
||||
落地状态:`2026-04-30` 已创建 `apps/admin-web` 独立前端工程,包含登录、总览、API 调试、兑换码管理和注册邀请码管理首版页面;根工程已补 `admin-web:*` 转发脚本。
|
||||
落地状态:`2026-04-30` 已创建 `apps/admin-web` 独立前端工程,包含登录、总览、API 调试、兑换码管理和注册邀请码管理首版页面;根工程已补 `admin-web:*` 转发脚本。`2026-05-01` 起,根构建与 Ubuntu 发布包会同步构建后台前端,并在发布包 Web 网关中以同域 `/admin/` 暴露。
|
||||
|
||||
## 1. 结论
|
||||
|
||||
后台管理端采用独立前端工程,路径固定为 `apps/admin-web`。它只负责 UI 表现、输入采集、请求发起和结果渲染;所有鉴权、聚合、写操作、SpacetimeDB 访问和业务校验继续收口在 `server-rs/crates/api-server`。
|
||||
|
||||
本方案接管旧 `api-server` 内嵌 HTML/CSS/JS 页面,旧 `GET /admin` 不再挂载。后续后台入口由独立前端工程部署产物承接。
|
||||
本方案接管旧 `api-server` 内嵌 HTML/CSS/JS 页面,Rust `api-server` 直连时旧 `GET /admin` 不再挂载。部署态后台入口由发布包内 `web-server.mjs` 承接:`/admin/` 返回独立前端静态产物,`/admin/api/*` 继续反代到 `api-server`。
|
||||
|
||||
## 2. 工程结构
|
||||
|
||||
@@ -253,9 +253,13 @@ export interface ProfileInviteCodeAdminResponse {
|
||||
|
||||
后端读取 SpacetimeDB schema 时必须请求 `/v1/database/{database}/schema?version=9`。SpacetimeDB 2.x schema HTTP API 缺少 `version` query 会返回 `400 missing field version`,后台页面只能展示读取异常,不能拿到真实表名。
|
||||
|
||||
`schemaTableNames` 与 `tableStats` 必须采用同一份 schema 表清单生成,不能再用硬编码关键表白名单补齐统计项。后台右上角显示的表数量必须等于统计表格实际行数;schema 读取失败时两者均为空,并通过 `fetchErrors` 暴露读取失败原因。
|
||||
|
||||
后端读取表行数时必须按 SpacetimeDB 2.x `/sql` 响应解析:接口返回 statement result 数组,单条结果内的 `schema.elements` 描述列名,`rows` 是按列顺序排列的数组行,例如 `rows: [[0]]`。后台服务不能再假设响应是 `{ rows: [{ row_count: 0 }] }` 的对象行形状;为了兼容小版本差异,可保留对象行兜底解析。
|
||||
|
||||
`tableStats` 中单表失败必须展示 `errorMessage`,不能让整页变成空白。
|
||||
`tableStats` 中单表失败必须展示 `errorMessage`,不能让整页变成空白。SpacetimeDB private 表或当前身份不可见的表在 `/sql` 下可能返回 `no such table` / `marked private`,后台服务必须将这类错误归一为“不可统计(private 或当前身份不可见)”,避免把预期的访问边界展示成原始 HTTP 400 故障。
|
||||
|
||||
线上如果大量表都显示“不可统计(private 或当前身份不可见)”,优先检查 `api-server` 启动环境中的 `GENARRATIVE_SPACETIME_TOKEN` / `GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN` 是否存在且属于目标库 owner。Jenkins 覆盖发布包时必须保留部署目录已有运行 token;只带迁移 token 不能让后台概览读取 private 表。
|
||||
|
||||
### 4.6 API 调试 contract
|
||||
|
||||
@@ -384,12 +388,14 @@ export interface ProfileInviteCodeAdminResponse {
|
||||
|
||||
### 7.2 构建部署
|
||||
|
||||
首版构建产物由独立后台工程输出到 `apps/admin-web/dist`。部署可以选择:
|
||||
当前发布形态固定为同域 `/admin/`:
|
||||
|
||||
1. 独立静态站点域名,例如 `https://admin.example.com`。
|
||||
2. 与主站同域不同路径,由网关把后台静态资源和 `/admin/api/*` 分别路由到正确目标。
|
||||
1. 本地单独执行 `npm run admin-web:build` 时,后台构建产物默认输出到 `apps/admin-web/dist`。
|
||||
2. 根工程执行 `npm run build` 时,会先构建主前端,再构建后台前端;任一构建失败或输出 warning 都会让构建门禁失败。
|
||||
3. Ubuntu 发布包执行 `npm run deploy:rust:remote` 时,后台前端以 Vite `--base /admin/` 构建到发布包 `web/admin/`。
|
||||
4. 发布包 `web-server.mjs` 对 `/admin` 返回 301 到 `/admin/`,对 `/admin/` 与 `/admin/*` 提供后台 SPA fallback,对 `/admin/api/*` 优先反代到 `api-server`。
|
||||
|
||||
无论哪种方式,`server-rs` 仍然是唯一管理 API 后端。
|
||||
该形态不新增后台静态端口和后台专用后端。`server-rs` 仍然是唯一管理 API 后端,后台前端不直连 SpacetimeDB。
|
||||
|
||||
### 7.3 后台工程脚本
|
||||
|
||||
@@ -399,8 +405,8 @@ export interface ProfileInviteCodeAdminResponse {
|
||||
{
|
||||
"scripts": {
|
||||
"dev": "vite --host 127.0.0.1",
|
||||
"build": "tsc --noEmit && vite build",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"build": "node ../../scripts/admin-web-build.mjs build",
|
||||
"typecheck": "node ../../scripts/admin-web-build.mjs typecheck",
|
||||
"preview": "vite preview --host 127.0.0.1"
|
||||
}
|
||||
}
|
||||
@@ -408,6 +414,8 @@ export interface ProfileInviteCodeAdminResponse {
|
||||
|
||||
如果后续接入根 npm workspace,再在根 `package.json` 增加转发脚本;本轮不要为了后台工程强行重排现有前端脚本。
|
||||
|
||||
当前工程没有启用 npm workspace,因此后台构建脚本必须从仓库根目录调用 root toolchain。`scripts/admin-web-build.mjs` 统一执行 `tsc --noEmit -p apps/admin-web/tsconfig.json` 与 Vite 构建,避免 `npm --prefix apps/admin-web` 在子目录找不到 `tsc`。
|
||||
|
||||
当前根工程同步提供以下转发脚本:
|
||||
|
||||
1. `npm run admin-web:dev`
|
||||
|
||||
@@ -138,11 +138,11 @@ npm run deploy:rust:remote
|
||||
|
||||
1. 在仓库根目录创建 `build/`。
|
||||
2. 在 `build/` 下创建当前时间命名的目标目录,例如 `build/20260422-153000/`。
|
||||
3. 使用 Vite 构建前端 release 到目标目录的 `web/`。
|
||||
3. 使用 Vite 构建主前端 release 到目标目录的 `web/`,并构建后台管理前端 release 到 `web/admin/`;后台构建固定使用 `/admin/` 作为 Vite base。
|
||||
4. 执行 `cargo build -p api-server --release --target x86_64-unknown-linux-gnu --manifest-path server-rs/Cargo.toml`,并把 `api-server` 复制到目标目录。
|
||||
5. 执行 `cargo build -p spacetime-module --release --target wasm32-unknown-unknown --manifest-path server-rs/Cargo.toml`,并把 `spacetime_module.wasm` 复制到目标目录。
|
||||
6. 把仓库根目录的 `.env` 与 `.env.local` 分别复制到目标目录根部和目标目录的 `web/` 下;复制后统一移除 UTF-8 BOM 与 CRLF,并把 `GENARRATIVE_SPACETIME_DATABASE` 覆盖为本次 `--database` 参数,避免 Jenkins 工作区里残留的旧 `.env.local` 覆盖发布包目标库。
|
||||
7. 在目标目录写入 `web-server.mjs`,用于托管 `web/` 并把 `/api/*`、`/generated-*`、`/healthz` 反代到本包内的 `api-server`。
|
||||
7. 在目标目录写入 `web-server.mjs`,用于托管 `web/` 与 `web/admin/`;其中 `/admin` 跳转到 `/admin/`,`/admin/` 提供后台 SPA,`/admin/api/*`、`/api/*`、`/generated-*`、`/healthz` 反代到本包内的 `api-server`。
|
||||
8. 在目标目录写入 `start.sh` 与 `stop.sh`;`start.sh` 会先按 `KEY=value` 子集加载发布目录根部的 `.env`、`.env.local`,兼容 UTF-8 BOM 与 CRLF,再回退到构建时通过 `--database`、`--api-port`、`--web-host`、`--web-port`、`--spacetime-host`、`--spacetime-port` 写入的默认值,其中 Web 默认只监听 `127.0.0.1`;并默认导出 `NO_COLOR=1` 与 `CARGO_TERM_COLOR=never`,避免 ANSI 控制码写入日志文件;同时按 Ubuntu 发布环境使用发布目录内 `.spacetimedb/` 作为 root-dir,不再额外设置 `--data-dir`,启动前先执行 `sync_ubuntu_spacetime_install`,优先从 `/usr/.local/share/spacetime/bin/<version>/spacetimedb-cli` 或 `$HOME/.local/share/spacetime/bin/<version>/spacetimedb-cli` 同步到 `.spacetimedb/bin/current/spacetimedb-cli`,当前线上 `spacetime` 入口为 `/usr/local/bin/spacetime`;启动参数为 `spacetime --root-dir ./.spacetimedb start --edition standalone --listen-addr <host>:<port>`,探活必须确认 `server ping` 输出包含 `Server is online:`;普通启动先无清库发布,若 publish 输出可判定为 schema 冲突,则自动导出旧库、清库发布新 wasm、导入回灌;如果以 `--clear-database` 启动,则内部 `spacetime publish` 会追加 `-c=on-conflict`,代表人工确认清库,不触发自动回灌。
|
||||
9. 默认执行 `scp -r -i ~\.ssh\dsk.pem build/<timestamp> ubuntu@82.157.175.59:/home/ubuntu/genarrative/` 上传发布包。
|
||||
|
||||
@@ -158,7 +158,9 @@ build/<timestamp>/
|
||||
├─ .env.local
|
||||
├─ web/
|
||||
│ ├─ .env
|
||||
│ └─ .env.local
|
||||
│ ├─ .env.local
|
||||
│ └─ admin/
|
||||
│ └─ index.html
|
||||
├─ api-server
|
||||
├─ spacetime_module.wasm
|
||||
├─ migration-bootstrap-secret.txt
|
||||
@@ -179,6 +181,8 @@ npm run build:rust:ubuntu -- --database genarrative-dev --web-host 127.0.0.1 --w
|
||||
npm run build:rust:ubuntu -- --skip-upload
|
||||
```
|
||||
|
||||
`--skip-web-build` 会同时跳过主前端和后台管理前端构建,仅用于调试已有发布包内容;正式发布不应使用该参数。
|
||||
|
||||
目标服务器启动:
|
||||
|
||||
```bash
|
||||
@@ -187,7 +191,7 @@ cd build/<timestamp>
|
||||
./stop.sh
|
||||
```
|
||||
|
||||
如果后续通过 Jenkins 的部署脚本把发布包覆盖到固定部署目录,部署阶段默认只替换 `web/`、`api-server`、`spacetime_module.wasm`、`migration-bootstrap-secret.txt`、`scripts/`、`.env*`、`start.sh`、`stop.sh`、`web-server.mjs`、`README.md` 等发布产物;文件产物使用普通复制,`web/`、`scripts/` 等目录产物递归复制,不会删除部署目录中的 `.spacetimedb/`、`logs/`、`run/`、`deploy-state/`、`database-migrations/` 这类运行态目录。
|
||||
如果后续通过 Jenkins 的部署脚本把发布包覆盖到固定部署目录,部署阶段默认只替换 `web/`、`api-server`、`spacetime_module.wasm`、`migration-bootstrap-secret.txt`、`scripts/`、`.env*`、`start.sh`、`stop.sh`、`web-server.mjs`、`README.md` 等发布产物;后台管理前端位于 `web/admin/`,随 `web/` 一并覆盖。文件产物使用普通复制,`web/`、`scripts/` 等目录产物递归复制,不会删除部署目录中的 `.spacetimedb/`、`logs/`、`run/`、`deploy-state/`、`database-migrations/` 这类运行态目录。Jenkins 覆盖 `.env.local` 时会保留目标部署目录已有的 `GENARRATIVE_SPACETIME_TOKEN` / `GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN`,避免后台表统计在部署后失去读取 private 表所需的 owner 身份。
|
||||
|
||||
安全边界:
|
||||
|
||||
@@ -208,7 +212,7 @@ cd build/<timestamp>
|
||||
1. Ubuntu x86_64。
|
||||
2. 已安装 `node`,用于运行发布包内的 `web-server.mjs`。
|
||||
3. 已安装 `spacetime` CLI,`start.sh` 会启动本地 SpacetimeDB 并发布 wasm。
|
||||
4. 业务密钥通过目标服务器环境变量或发布包同目录 `.env.local` 提供。
|
||||
4. 业务密钥通过目标服务器环境变量或发布包同目录 `.env.local` 提供;后台概览如果需要统计 private 表,`GENARRATIVE_SPACETIME_TOKEN` 必须是目标库 owner 或具备等效读取权限的 token。
|
||||
|
||||
## 4. 与 M7 的关系
|
||||
|
||||
|
||||
Reference in New Issue
Block a user