Merge branch 'master' of http://82.157.175.59:3000/GenarrativeAI/Genarrative
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
|
||||
日期:`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` 增加一套同源后台管理服务,满足以下首版目标:
|
||||
@@ -10,7 +14,7 @@
|
||||
2. 支持独立的管理员鉴权,不允许普通玩家 JWT 越权访问。
|
||||
3. 支持在后台查看当前服务与数据库概览信息。
|
||||
4. 支持在后台测试当前 `api-server` 已挂载接口。
|
||||
5. 保持首版工程足够轻量,不新建额外独立服务进程,不引入第二套前端工程。
|
||||
5. 保持管理能力继续收口在 `server-rs`,管理 UI 由独立后台前端工程承接。
|
||||
|
||||
## 2. 背景与约束
|
||||
|
||||
@@ -24,19 +28,20 @@
|
||||
|
||||
1. 后端统一落在 `server-rs`,不回退到 `server-node`。
|
||||
2. 不额外新起独立管理服务进程。
|
||||
3. 首版以“一个受保护管理域 + 一个同源后台页面”为落地形态。
|
||||
3. 管理 API 继续作为受保护管理域挂载在 `api-server`。
|
||||
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 的管理员鉴权中间件。
|
||||
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 不包含
|
||||
|
||||
@@ -44,7 +49,7 @@
|
||||
2. 管理员 refresh cookie / 多端会话管理。
|
||||
3. 后台直接写库、删库、执行 reducer。
|
||||
4. 任意 SQL 执行器。
|
||||
5. 新建独立 React/Vite 管理端工程。
|
||||
5. `api-server` 内嵌 HTML/CSS/JS 后台页面。
|
||||
|
||||
## 4. 总体方案
|
||||
|
||||
@@ -60,13 +65,13 @@
|
||||
|
||||
### 4.2 页面形态
|
||||
|
||||
后台管理页面采用 `api-server` 直接返回一份内嵌 HTML/CSS/JS 的管理页。
|
||||
后台管理页面不再由 `api-server` 直接返回内嵌 HTML/CSS/JS。`api-server` 仅保留管理 API,页面由独立后台前端工程调用这些接口。
|
||||
|
||||
原因:
|
||||
|
||||
1. 首版目标是“可用的后台能力”,不是新建一套复杂前端基建。
|
||||
2. 管理页面交互相对简单,直接内嵌更易随服务端一起部署。
|
||||
3. 可以避免新增构建链和静态资源发布路径。
|
||||
1. 管理 UI 需要独立演进,不应继续堆在 Rust 源码字符串中。
|
||||
2. `server-rs` 继续负责鉴权、聚合和写操作,符合前端只做表现的工程约束。
|
||||
3. 删除 `GET /admin` 后,当前服务访问该路径应返回 `404`。
|
||||
|
||||
### 4.3 数据库信息来源
|
||||
|
||||
@@ -129,7 +134,7 @@ claims 设计:
|
||||
|
||||
## 6. 后台页面设计
|
||||
|
||||
首版页面包含三个主区域:
|
||||
本节已由独立后台前端工程方案接管。历史同源页面曾包含三个主区域:
|
||||
|
||||
1. 登录卡片。
|
||||
2. 数据库概览面板。
|
||||
@@ -223,7 +228,7 @@ claims 设计:
|
||||
|
||||
默认策略:
|
||||
|
||||
1. 若未配置用户名或密码,则后台登录接口返回 `503`,后台页面显示“后台未启用”。
|
||||
1. 若未配置用户名或密码,则后台登录接口返回 `503`,独立后台前端自行展示未启用状态。
|
||||
2. 默认管理员 token TTL 为 `4` 小时。
|
||||
|
||||
## 10. 测试要求
|
||||
@@ -240,21 +245,27 @@ claims 设计:
|
||||
|
||||
## 11. 路由清单
|
||||
|
||||
首版新增路由:
|
||||
当前保留的管理 API 路由:
|
||||
|
||||
1. `GET /admin`
|
||||
2. `POST /admin/api/login`
|
||||
3. `GET /admin/api/me`
|
||||
4. `GET /admin/api/overview`
|
||||
5. `POST /admin/api/debug/http`
|
||||
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. 路由索引与技术文档已同步更新。
|
||||
6. 兑换码管理 API 可由管理员 token 调用。
|
||||
7. `GET /admin` 不再挂载,访问返回 `404`。
|
||||
8. 独立后台前端 PRD 与技术方案已补齐。
|
||||
9. 路由索引与技术文档已同步更新。
|
||||
|
||||
@@ -0,0 +1,446 @@
|
||||
# 后台管理独立前端工程技术方案
|
||||
|
||||
日期:`2026-04-30`
|
||||
|
||||
对应 PRD:[后台管理独立前端工程 PRD](../prd/ADMIN_WEB_CONSOLE_PRD_2026-04-30.md)
|
||||
|
||||
落地状态:`2026-04-30` 已创建 `apps/admin-web` 独立前端工程,包含登录、总览、API 调试、兑换码管理和注册邀请码管理首版页面;根工程已补 `admin-web:*` 转发脚本。
|
||||
|
||||
## 1. 结论
|
||||
|
||||
后台管理端采用独立前端工程,路径固定为 `apps/admin-web`。它只负责 UI 表现、输入采集、请求发起和结果渲染;所有鉴权、聚合、写操作、SpacetimeDB 访问和业务校验继续收口在 `server-rs/crates/api-server`。
|
||||
|
||||
本方案接管旧 `api-server` 内嵌 HTML/CSS/JS 页面,旧 `GET /admin` 不再挂载。后续后台入口由独立前端工程部署产物承接。
|
||||
|
||||
## 2. 工程结构
|
||||
|
||||
建议首版结构:
|
||||
|
||||
```text
|
||||
apps/
|
||||
└─ admin-web/
|
||||
├─ index.html
|
||||
├─ package.json
|
||||
├─ tsconfig.json
|
||||
├─ vite.config.ts
|
||||
└─ src/
|
||||
├─ main.tsx
|
||||
├─ app/
|
||||
│ ├─ AdminApp.tsx
|
||||
│ ├─ AdminShell.tsx
|
||||
│ └─ adminRoutes.ts
|
||||
├─ api/
|
||||
│ ├─ adminApiClient.ts
|
||||
│ └─ adminApiTypes.ts
|
||||
├─ auth/
|
||||
│ └─ adminAuthStore.ts
|
||||
├─ pages/
|
||||
│ ├─ AdminLoginPage.tsx
|
||||
│ ├─ AdminOverviewPage.tsx
|
||||
│ ├─ AdminDebugHttpPage.tsx
|
||||
│ ├─ AdminRedeemCodePage.tsx
|
||||
│ └─ AdminInviteCodePage.tsx
|
||||
└─ styles/
|
||||
└─ admin.css
|
||||
```
|
||||
|
||||
首版可使用独立 `package.json`,不要求立刻把根工程改成 npm workspace。后续如果根工程统一 workspace,再把 `apps/admin-web` 纳入统一脚本。
|
||||
|
||||
## 3. 技术栈
|
||||
|
||||
1. React + TypeScript + Vite。
|
||||
2. 图标使用 `lucide-react`。
|
||||
3. 样式首版使用普通 CSS 或 CSS Modules,不引入新的大型 UI 组件库。
|
||||
4. 请求使用浏览器 `fetch` 封装,不新增状态管理库。
|
||||
5. 不引入 SpacetimeDB TypeScript SDK;管理端不直连 SpacetimeDB。
|
||||
|
||||
## 4. API 边界
|
||||
|
||||
### 4.1 基础约定
|
||||
|
||||
所有管理端请求使用同一个 `adminApiClient`:
|
||||
|
||||
1. base URL 由 `VITE_ADMIN_API_BASE_URL` 配置。
|
||||
2. 未配置时默认同源空前缀。
|
||||
3. 有 token 时附加 `Authorization: Bearer <token>`。
|
||||
4. 后端统一响应 envelope 时,前端读取 `data`;错误优先读取 `error.details.message`,再读 `error.message`,最后回退到 HTTP 状态。
|
||||
|
||||
前端统一按以下响应形状解析,不在页面组件里重复拆 envelope:
|
||||
|
||||
```ts
|
||||
export interface ApiSuccessEnvelope<T> {
|
||||
data: T;
|
||||
meta?: unknown;
|
||||
}
|
||||
|
||||
export interface ApiErrorEnvelope {
|
||||
error?: {
|
||||
code?: string;
|
||||
message?: string;
|
||||
details?: {
|
||||
message?: string;
|
||||
[key: string]: unknown;
|
||||
} | null;
|
||||
};
|
||||
meta?: unknown;
|
||||
}
|
||||
```
|
||||
|
||||
`adminApiClient` 暴露 `request<T>()`、`get<T>()`、`post<T>()` 三层即可。页面只拿到成功数据或抛出的中文错误消息,不直接处理 `Response`。
|
||||
|
||||
### 4.2 已有管理接口
|
||||
|
||||
| 功能 | 方法与路径 | 鉴权 |
|
||||
| --- | --- | --- |
|
||||
| 管理员登录 | `POST /admin/api/login` | 无 |
|
||||
| 当前管理员 | `GET /admin/api/me` | 管理员 Bearer |
|
||||
| 服务与数据库概览 | `GET /admin/api/overview` | 管理员 Bearer |
|
||||
| 受控 HTTP 调试 | `POST /admin/api/debug/http` | 管理员 Bearer |
|
||||
| 创建/更新兑换码 | `POST /admin/api/profile/redeem-codes` | 管理员 Bearer |
|
||||
| 停用兑换码 | `POST /admin/api/profile/redeem-codes/disable` | 管理员 Bearer |
|
||||
| 创建/更新注册邀请码 | `POST /admin/api/profile/invite-codes` | 管理员 Bearer |
|
||||
|
||||
### 4.3 前端类型命名
|
||||
|
||||
后台前端首版不引入自动生成 contract。为了避免字段漂移,`apps/admin-web/src/api/adminApiTypes.ts` 必须按 `shared-contracts` 的 camelCase JSON 字段命名:
|
||||
|
||||
```ts
|
||||
export interface AdminSessionPayload {
|
||||
subject: string;
|
||||
username: string;
|
||||
displayName: string;
|
||||
roles: string[];
|
||||
issuedAt: string;
|
||||
expiresAt: string;
|
||||
}
|
||||
|
||||
export interface AdminLoginResponse {
|
||||
token: string;
|
||||
admin: AdminSessionPayload;
|
||||
}
|
||||
|
||||
export interface AdminOverviewResponse {
|
||||
service: AdminServiceOverviewPayload;
|
||||
database: AdminDatabaseOverviewPayload;
|
||||
}
|
||||
|
||||
export interface AdminServiceOverviewPayload {
|
||||
bindHost: string;
|
||||
bindPort: number;
|
||||
jwtIssuer: string;
|
||||
adminEnabled: boolean;
|
||||
spacetimeServerUrl: string;
|
||||
spacetimeDatabase: string;
|
||||
}
|
||||
|
||||
export interface AdminDatabaseOverviewPayload {
|
||||
databaseIdentity: string | null;
|
||||
ownerIdentity: string | null;
|
||||
hostType: string | null;
|
||||
schemaTableNames: string[];
|
||||
tableStats: AdminDatabaseTableStatPayload[];
|
||||
fetchErrors: string[];
|
||||
}
|
||||
|
||||
export interface AdminDatabaseTableStatPayload {
|
||||
tableName: string;
|
||||
rowCount: number | null;
|
||||
errorMessage: string | null;
|
||||
}
|
||||
|
||||
export interface AdminDebugHeaderInput {
|
||||
name: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface AdminDebugHttpRequest {
|
||||
method: string;
|
||||
path: string;
|
||||
headers?: AdminDebugHeaderInput[];
|
||||
body?: string;
|
||||
}
|
||||
|
||||
export interface AdminDebugHttpResponse {
|
||||
status: number;
|
||||
statusText: string;
|
||||
headers: AdminDebugHeaderInput[];
|
||||
bodyText: string;
|
||||
bodyJson: unknown | null;
|
||||
}
|
||||
```
|
||||
|
||||
兑换码类型同样保持 camelCase:
|
||||
|
||||
```ts
|
||||
export type ProfileRedeemCodeMode = 'public' | 'unique' | 'private';
|
||||
|
||||
export interface AdminUpsertProfileRedeemCodeRequest {
|
||||
code: string;
|
||||
mode: ProfileRedeemCodeMode;
|
||||
rewardPoints: number;
|
||||
maxUses: number;
|
||||
enabled: boolean;
|
||||
allowedUserIds: string[];
|
||||
allowedPublicUserCodes: string[];
|
||||
}
|
||||
|
||||
export interface AdminDisableProfileRedeemCodeRequest {
|
||||
code: string;
|
||||
}
|
||||
|
||||
export interface AdminUpsertProfileInviteCodeRequest {
|
||||
inviteCode: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface ProfileRedeemCodeAdminResponse {
|
||||
code: string;
|
||||
mode: ProfileRedeemCodeMode;
|
||||
rewardPoints: number;
|
||||
maxUses: number;
|
||||
globalUsedCount: number;
|
||||
enabled: boolean;
|
||||
allowedUserIds: string[];
|
||||
createdBy: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface ProfileInviteCodeAdminResponse {
|
||||
userId: string;
|
||||
inviteCode: string;
|
||||
metadata: Record<string, unknown>;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 登录 contract
|
||||
|
||||
请求:
|
||||
|
||||
```json
|
||||
{
|
||||
"username": "root",
|
||||
"password": "secret123"
|
||||
}
|
||||
```
|
||||
|
||||
成功数据:
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "<admin bearer token>",
|
||||
"admin": {
|
||||
"subject": "admin:root",
|
||||
"username": "root",
|
||||
"displayName": "root",
|
||||
"roles": ["admin"],
|
||||
"issuedAt": "2026-04-30T00:00:00Z",
|
||||
"expiresAt": "2026-04-30T04:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`503` 表示后台未启用;`401` 表示用户名或密码错误。
|
||||
|
||||
### 4.5 总览 contract
|
||||
|
||||
`GET /admin/api/overview` 返回:
|
||||
|
||||
1. `service`:`bindHost`、`bindPort`、`jwtIssuer`、`adminEnabled`、`spacetimeServerUrl`、`spacetimeDatabase`。
|
||||
2. `database`:`databaseIdentity`、`ownerIdentity`、`hostType`、`schemaTableNames`、`tableStats`、`fetchErrors`。
|
||||
|
||||
后端读取 SpacetimeDB schema 时必须请求 `/v1/database/{database}/schema?version=9`。SpacetimeDB 2.x schema HTTP API 缺少 `version` query 会返回 `400 missing field version`,后台页面只能展示读取异常,不能拿到真实表名。
|
||||
|
||||
后端读取表行数时必须按 SpacetimeDB 2.x `/sql` 响应解析:接口返回 statement result 数组,单条结果内的 `schema.elements` 描述列名,`rows` 是按列顺序排列的数组行,例如 `rows: [[0]]`。后台服务不能再假设响应是 `{ rows: [{ row_count: 0 }] }` 的对象行形状;为了兼容小版本差异,可保留对象行兜底解析。
|
||||
|
||||
`tableStats` 中单表失败必须展示 `errorMessage`,不能让整页变成空白。
|
||||
|
||||
### 4.6 API 调试 contract
|
||||
|
||||
请求:
|
||||
|
||||
```json
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/healthz",
|
||||
"headers": [],
|
||||
"body": ""
|
||||
}
|
||||
```
|
||||
|
||||
限制由后端执行:
|
||||
|
||||
1. `path` 只允许同源相对路径。
|
||||
2. 禁止绝对 URL。
|
||||
3. 禁止调试 `/admin/api/login`。
|
||||
4. 禁止覆盖危险请求头。
|
||||
5. 请求体大小和超时由后端收口。
|
||||
|
||||
### 4.7 兑换码管理 contract
|
||||
|
||||
创建/更新请求:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "WELCOME2026",
|
||||
"mode": "public",
|
||||
"rewardPoints": 100,
|
||||
"maxUses": 1,
|
||||
"enabled": true,
|
||||
"allowedUserIds": [],
|
||||
"allowedPublicUserCodes": []
|
||||
}
|
||||
```
|
||||
|
||||
停用请求:
|
||||
|
||||
兑换码管理页的最近一次接口返回记录由 `AdminApp` 维护为管理端会话态,并传入 `AdminRedeemCodePage` 渲染。页面页签通过 hash 切换时子页面会卸载,不能把最近记录只放在兑换码页面内部 `useState` 中,否则切换到其他页签再返回会展示“暂无记录”。该会话态只用于保留当前操作结果,不作为兑换码历史列表;退出登录或重新登录时清空。
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "WELCOME2026"
|
||||
}
|
||||
```
|
||||
|
||||
成功返回兑换码记录:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "WELCOME2026",
|
||||
"mode": "public",
|
||||
"rewardPoints": 100,
|
||||
"maxUses": 1,
|
||||
"globalUsedCount": 0,
|
||||
"enabled": true,
|
||||
"allowedUserIds": [],
|
||||
"createdBy": "admin:root",
|
||||
"createdAt": "2026-04-30T00:00:00Z",
|
||||
"updatedAt": "2026-04-30T00:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
前端只做基础输入约束,最终标准化、私有码用户解析、次数和奖励合法性以 `server-rs` 为准。
|
||||
|
||||
### 4.8 邀请码管理 contract
|
||||
|
||||
创建/更新请求:
|
||||
|
||||
```json
|
||||
{
|
||||
"inviteCode": "SPRING2026",
|
||||
"metadata": {
|
||||
"batch": "spring"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
成功返回邀请码记录:
|
||||
|
||||
```json
|
||||
{
|
||||
"userId": "admin",
|
||||
"inviteCode": "SPRING2026",
|
||||
"metadata": {
|
||||
"batch": "spring"
|
||||
},
|
||||
"createdAt": "2026-04-30T00:00:00Z",
|
||||
"updatedAt": "2026-04-30T00:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
邀请码页的 metadata 输入必须先在前端解析为 JSON 对象;空字符串按 `{}` 处理,数组、字符串、数字等非对象值直接提示错误。最终标准化、长度限制和邀请码合法性以 `server-rs` 为准。
|
||||
|
||||
## 5. 鉴权与会话
|
||||
|
||||
1. token key 固定为 `genarrative_admin_token`。
|
||||
2. token 首版存 localStorage。
|
||||
3. 应用启动时如果存在 token,先调用 `GET /admin/api/me`。
|
||||
4. `401` 时清空 token 并回到登录页。
|
||||
5. `403` 时展示无权限状态,不自动重试。
|
||||
6. 退出登录只清理本地 token;首版没有后台 refresh session 和服务端会话吊销。
|
||||
|
||||
## 6. 页面实现要点
|
||||
|
||||
1. `AdminShell` 承载导航、当前管理员、退出按钮和页面容器。
|
||||
2. 登录页不进入 `AdminShell`,避免未登录时展示后台导航。
|
||||
3. 总览页加载失败时展示后端错误,不吞掉 `fetchErrors`。
|
||||
4. API 调试页的 headers 使用键值行编辑,提交前转为 `[{ name, value }]`。
|
||||
5. 兑换码页的 `mode=private` 时展示允许用户输入区;其他模式提交空数组。
|
||||
6. 邀请码页只提交 `inviteCode` 与 JSON 对象 metadata,不在前端复制后端邀请码规则。
|
||||
7. 所有按钮的 loading 状态必须锁定重复提交。
|
||||
8. 移动端优先:表单单列,导航紧凑,结果面板可横向/纵向滚动。
|
||||
|
||||
## 7. 部署与联调
|
||||
|
||||
### 7.1 本地联调
|
||||
|
||||
1. 启动后端:`npm run api-server:maincloud`。
|
||||
2. 启动后台前端:在 `apps/admin-web` 执行 `npm run dev`。
|
||||
3. 后台 dev server 通过 Vite proxy 转发 `/admin/api` 到 `ADMIN_API_TARGET`;未配置时默认 `http://127.0.0.1:3100`。
|
||||
4. 若使用非 3100 端口,在仓库根目录 `.env.local` 设置 `ADMIN_API_TARGET=http://127.0.0.1:<api-server-port>`,并重启后台前端 dev server。
|
||||
5. `GENARRATIVE_API_PORT` 控制 Rust `api-server` 监听端口;`ADMIN_API_TARGET` 只控制后台前端 dev proxy 目标,二者需要指向同一个端口。
|
||||
|
||||
### 7.2 构建部署
|
||||
|
||||
首版构建产物由独立后台工程输出到 `apps/admin-web/dist`。部署可以选择:
|
||||
|
||||
1. 独立静态站点域名,例如 `https://admin.example.com`。
|
||||
2. 与主站同域不同路径,由网关把后台静态资源和 `/admin/api/*` 分别路由到正确目标。
|
||||
|
||||
无论哪种方式,`server-rs` 仍然是唯一管理 API 后端。
|
||||
|
||||
### 7.3 后台工程脚本
|
||||
|
||||
`apps/admin-web/package.json` 首版至少提供以下脚本:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"dev": "vite --host 127.0.0.1",
|
||||
"build": "tsc --noEmit && vite build",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"preview": "vite preview --host 127.0.0.1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如果后续接入根 npm workspace,再在根 `package.json` 增加转发脚本;本轮不要为了后台工程强行重排现有前端脚本。
|
||||
|
||||
当前根工程同步提供以下转发脚本:
|
||||
|
||||
1. `npm run admin-web:dev`
|
||||
2. `npm run admin-web:typecheck`
|
||||
3. `npm run admin-web:build`
|
||||
4. `npm run admin-web:preview`
|
||||
|
||||
## 8. 测试计划
|
||||
|
||||
1. `apps/admin-web`:
|
||||
- 登录成功和失败。
|
||||
- token 恢复、过期清理、退出登录。
|
||||
- 总览页正常数据、部分表统计失败、整体请求失败。
|
||||
- API 调试成功访问 `/healthz`,绝对 URL 被后端拒绝。
|
||||
- 兑换码 public/unique/private 表单提交和停用。
|
||||
- 邀请码表单提交、metadata JSON 对象校验和结果展示。
|
||||
2. 根工程:
|
||||
- `npm run check:encoding`。
|
||||
- 后续接入根 workspace 后,补充后台工程 build/typecheck 脚本。
|
||||
3. 后端:
|
||||
- 继续保留 `cargo test -p api-server --manifest-path server-rs/Cargo.toml admin`。
|
||||
- 修改后端管理 API 后必须运行 `npm run api-server:maincloud` 并手动验证 `/admin` 为 404、`/admin/api/login` 可用。
|
||||
|
||||
## 9. 后续扩展边界
|
||||
|
||||
后续新增用户管理、作品审核、资产审核、订单/充值管理时,必须先补对应 PRD 和技术方案,并在 `server-rs` 增加受保护管理 API。不要让 `apps/admin-web` 直接读取 SpacetimeDB 或复制业务规则。
|
||||
|
||||
## 10. 实施顺序
|
||||
|
||||
1. 先创建 `apps/admin-web` 工程骨架,确保空应用可 `dev/build`。
|
||||
2. 再实现 `adminApiTypes` 与 `adminApiClient`,用 `/admin/api/login` 做第一条真实链路。
|
||||
3. 接入 `adminAuthStore` 和启动恢复逻辑,确认 `401` 会清理本地 token。
|
||||
4. 完成 `AdminShell` 与四页路由,再分别接入总览、API 调试、兑换码和邀请码接口。
|
||||
5. 最后补测试、运行 `npm run check:encoding`,并确认 `GET /admin` 仍由 `api-server` 返回 `404`。
|
||||
|
||||
当前实现已完成第 1 至第 4 步。验证以实际命令输出为准。
|
||||
@@ -17,16 +17,17 @@
|
||||
1. 构建产物目录统一使用 `build/<版本号>/`。
|
||||
2. 默认使用 Jenkins `BUILD_NUMBER` 作为版本号,避免依赖时间戳;如有需要也允许显式传 `BUILD_VERSION`。
|
||||
3. `构建` 与 `构建并部署` 在 `checkout scm` 后、实际构建前必须执行 `git reset --hard HEAD` 与 `git clean -fd`,避免固定源码目录内的 Git 变更和未跟踪文件影响发布包;不使用 `-x`,避免删除 `node_modules/` 等忽略目录后与 `RUN_NPM_CI=false` 冲突。
|
||||
4. `部署` 流水线允许人工启动;没有上游触发 cause 时按人工部署处理,不再直接失败。
|
||||
5. `部署` 流水线仅在存在上游触发 cause 时校验上游作业名与传入的 `EXPECTED_UPSTREAM_JOB` 一致;如配置了环境变量 `GENARRATIVE_ALLOWED_UPSTREAM_JOB`,还必须与该值一致。
|
||||
6. `构建并部署` 在触发 `部署` 前先释放自己的构建节点,避免单执行器节点出现死锁。
|
||||
7. `部署` 不重新构建,不重新上传,不从 Jenkins 插件仓库复制产物,直接使用上游构建节点的本地 `build/<版本号>/` 目录。
|
||||
8. `部署` 流水线读取触发原因时必须使用 `currentBuild.getBuildCauses(...)` 这类白名单方法,不能直接访问 `currentBuild.rawBuild`,否则会被 Jenkins Script Security 拦截。
|
||||
9. 由于 Jenkins Pipeline 的 `build` 步骤触发下游时,原因类型通常是 `org.jenkinsci.plugins.workflow.support.steps.build.BuildUpstreamCause`,实现上需要同时兼容它和经典的 `hudson.model.Cause$UpstreamCause`,否则会把真实的上游触发误判成人工执行。
|
||||
10. 如果线上进程的启停必须经过 `sudo`,只允许 `start.sh` / `stop.sh` 这两个 hook 使用 `sudo -n` 执行,部署目录清空与文件覆盖仍保持普通权限。
|
||||
11. `WEB_PORT` 必须在 `构建并部署` 与 `部署` 两条流水线之间使用同名参数传递;部署脚本会把最终端口写入固定部署目录 `.env.local` 的 `GENARRATIVE_WEB_PORT`,避免 `sudo` 启动 hook 时环境变量被清理导致端口回退。
|
||||
12. `DATABASE` 必须匹配 SpacetimeDB CLI 数据库名规则 `^[a-z0-9]+(-[a-z0-9]+)*$`:只能使用小写字母、数字,并用单个短横线分隔;大写字母、点号、下划线、首尾短横线和连续短横线都会被拒绝,否则 `spacetime publish` 会报 `invalid characters in database name`。
|
||||
13. Jenkins 日志必须能看到构建参数中的 SpacetimeDB 发布数据库,以及 `start.sh` 最终加载环境文件后的运行时数据库、server 和 root-dir,避免 `.env.local` 覆盖默认值后无法判断实际发布目标。
|
||||
4. `构建并部署` 可选填写 `COMMIT_HASH`。留空时使用 Jenkins SCM 当前检出的提交;填写时只能是 7 到 40 位十六进制 commit hash,流水线会先按 SCM checkout 得到仓库,再尽量拉取 `origin` 全部分支引用、解析该 hash 并 detached checkout 到对应 commit 后构建。
|
||||
5. `部署` 流水线允许人工启动;没有上游触发 cause 时按人工部署处理,不再直接失败。
|
||||
6. `部署` 流水线仅在存在上游触发 cause 时校验上游作业名与传入的 `EXPECTED_UPSTREAM_JOB` 一致;如配置了环境变量 `GENARRATIVE_ALLOWED_UPSTREAM_JOB`,还必须与该值一致。
|
||||
7. `构建并部署` 在触发 `部署` 前先释放自己的构建节点,避免单执行器节点出现死锁。
|
||||
8. `部署` 不重新构建,不重新上传,不从 Jenkins 插件仓库复制产物,直接使用上游构建节点的本地 `build/<版本号>/` 目录。
|
||||
9. `部署` 流水线读取触发原因时必须使用 `currentBuild.getBuildCauses(...)` 这类白名单方法,不能直接访问 `currentBuild.rawBuild`,否则会被 Jenkins Script Security 拦截。
|
||||
10. 由于 Jenkins Pipeline 的 `build` 步骤触发下游时,原因类型通常是 `org.jenkinsci.plugins.workflow.support.steps.build.BuildUpstreamCause`,实现上需要同时兼容它和经典的 `hudson.model.Cause$UpstreamCause`,否则会把真实的上游触发误判成人工执行。
|
||||
11. 如果线上进程的启停必须经过 `sudo`,只允许 `start.sh` / `stop.sh` 这两个 hook 使用 `sudo -n` 执行,部署目录清空与文件覆盖仍保持普通权限。
|
||||
12. `WEB_PORT` 必须在 `构建并部署` 与 `部署` 两条流水线之间使用同名参数传递;部署脚本会把最终端口写入固定部署目录 `.env.local` 的 `GENARRATIVE_WEB_PORT`,避免 `sudo` 启动 hook 时环境变量被清理导致端口回退。
|
||||
13. `DATABASE` 必须匹配 SpacetimeDB CLI 数据库名规则 `^[a-z0-9]+(-[a-z0-9]+)*$`:只能使用小写字母、数字,并用单个短横线分隔;大写字母、点号、下划线、首尾短横线和连续短横线都会被拒绝,否则 `spacetime publish` 会报 `invalid characters in database name`。
|
||||
14. Jenkins 日志必须能看到构建参数中的 SpacetimeDB 发布数据库,以及 `start.sh` 最终加载环境文件后的运行时数据库、server 和 root-dir,避免 `.env.local` 覆盖默认值后无法判断实际发布目标。
|
||||
|
||||
## 3. 节点与工作区要求
|
||||
|
||||
@@ -119,13 +120,14 @@ jenkins/Jenkinsfile.build-and-deploy
|
||||
|
||||
核心流程:
|
||||
|
||||
1. `checkout scm` 后执行 `git reset --hard HEAD` 与 `git clean -fd` 清理工作区。
|
||||
2. 复用与 `构建` 相同的构建命令生成 `build/<BUILD_VERSION>/`。
|
||||
3. 归档 `build/<BUILD_VERSION>/**`。
|
||||
4. 记录当前 `NODE_NAME`、源码根目录、版本号。
|
||||
5. 构建时额外透传 `--web-port <WEB_PORT>`,默认生成监听 `25001` 的发布包。
|
||||
6. 构建日志会输出 `SpacetimeDB 发布数据库: <DATABASE>`,发布包启动日志会输出最终 `database/server/root-dir`。
|
||||
7. 触发 `部署` 流水线,并传递:
|
||||
1. `checkout scm` 后,如果 `COMMIT_HASH` 非空,则先拉取远端分支和 tag,解析该 hash 指向的 commit,并 detached checkout 到该提交。
|
||||
2. 执行 `git reset --hard HEAD` 与 `git clean -fd` 清理工作区。
|
||||
3. 复用与 `构建` 相同的构建命令生成 `build/<BUILD_VERSION>/`。
|
||||
4. 归档 `build/<BUILD_VERSION>/**`。
|
||||
5. 记录当前 `NODE_NAME`、源码根目录、版本号与实际构建 commit。
|
||||
6. 构建时额外透传 `--web-port <WEB_PORT>`,默认生成监听 `25001` 的发布包。
|
||||
7. 构建日志会输出 `SpacetimeDB 发布数据库: <DATABASE>`、`构建 commit: <COMMIT>`,发布包启动日志会输出最终 `database/server/root-dir`。
|
||||
8. 触发 `部署` 流水线,并传递:
|
||||
- `BUILD_VERSION`
|
||||
- `SOURCE_WORKSPACE_ROOT`
|
||||
- `SOURCE_NODE_NAME`
|
||||
@@ -180,6 +182,7 @@ jenkins/Jenkinsfile.build-and-deploy
|
||||
7. `MIGRATION_EXPORT_TOKEN`
|
||||
8. `MIGRATION_IMPORT_TOKEN`
|
||||
9. `DATABASE`:发布包默认数据库名,默认 `genarrative-pipeline-local-test`,必须匹配 `^[a-z0-9]+(-[a-z0-9]+)*$`。
|
||||
10. `COMMIT_HASH`:可选指定构建提交;如果目标 commit 不在 Jenkins 当前浅克隆历史中,流水线会尝试 unshallow,仍找不到时构建失败。
|
||||
|
||||
如果你选择启用 `RUN_DEPLOY_HOOKS_WITH_SUDO=true`,推荐提前在服务器上增加一份最小 sudoers 配置,例如:
|
||||
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
# 抓大鹅 Match3D B4+B5 spacetime-client 与 api-server facade 落地记录
|
||||
|
||||
日期:`2026-04-30`
|
||||
|
||||
## 1. 本阶段目标
|
||||
|
||||
本文件记录 B4+B5 的技术落地范围:把 B3 已生成的 Match3D SpacetimeDB procedure 接到 `spacetime-client`,再通过 `api-server` 暴露给前端使用的 HTTP facade。
|
||||
|
||||
本阶段不改 SpacetimeDB 表结构,不新增 migration,不接入真实题材素材生成,也不改前端即时反馈实现。
|
||||
|
||||
## 2. 已落地范围
|
||||
|
||||
### 2.1 SpacetimeDB bindings
|
||||
|
||||
使用仓库封装脚本重新生成 bindings:
|
||||
|
||||
```powershell
|
||||
npm run spacetime:generate
|
||||
```
|
||||
|
||||
Windows 下 SpacetimeDB CLI 可能在 Rust bindings 已生成后输出 `Could not format generated files: 文件名或扩展名太长。 (os error 206)`。脚本已调整为:当 CLI 退出码为 `0` 且只是格式化警告时继续同步生成文件。
|
||||
|
||||
生成文件仍视为机器产物,禁止手写修改。
|
||||
|
||||
### 2.2 spacetime-client facade
|
||||
|
||||
新增:
|
||||
|
||||
```text
|
||||
server-rs/crates/spacetime-client/src/match3d.rs
|
||||
```
|
||||
|
||||
并在 `spacetime-client/src/lib.rs` 导出 `match3d` 模块与 Match3D Record 类型。
|
||||
|
||||
已覆盖:
|
||||
|
||||
1. 创作会话:create / get / submit message / finalize / compile draft。
|
||||
2. 作品:list / get detail / update / publish / delete / public gallery list。
|
||||
3. 运行态:start / get / click / stop / restart / time-up。
|
||||
|
||||
`mapper.rs` 负责把 procedure 返回的 JSON 字符串解析为稳定 Record,不把 generated bindings 泄露到 `api-server`。
|
||||
|
||||
### 2.3 api-server HTTP facade
|
||||
|
||||
新增:
|
||||
|
||||
```text
|
||||
server-rs/crates/api-server/src/match3d.rs
|
||||
```
|
||||
|
||||
并在 `main.rs` 注册模块,在 `app.rs` 挂载路由。
|
||||
|
||||
已挂载路由:
|
||||
|
||||
```text
|
||||
POST /api/creation/match3d/sessions
|
||||
GET /api/creation/match3d/sessions/{session_id}
|
||||
POST /api/creation/match3d/sessions/{session_id}/messages
|
||||
POST /api/creation/match3d/sessions/{session_id}/messages/stream
|
||||
POST /api/creation/match3d/sessions/{session_id}/actions
|
||||
POST /api/creation/match3d/sessions/{session_id}/compile
|
||||
|
||||
GET /api/creation/match3d/works
|
||||
GET /api/creation/match3d/works/{profile_id}
|
||||
PATCH /api/creation/match3d/works/{profile_id}
|
||||
PUT /api/creation/match3d/works/{profile_id}
|
||||
DELETE /api/creation/match3d/works/{profile_id}
|
||||
POST /api/creation/match3d/works/{profile_id}/publish
|
||||
|
||||
GET /api/runtime/match3d/gallery
|
||||
POST /api/runtime/match3d/works/{profile_id}/runs
|
||||
GET /api/runtime/match3d/runs/{run_id}
|
||||
POST /api/runtime/match3d/runs/{run_id}/click
|
||||
POST /api/runtime/match3d/runs/{run_id}/stop
|
||||
POST /api/runtime/match3d/runs/{run_id}/restart
|
||||
POST /api/runtime/match3d/runs/{run_id}/time-up
|
||||
```
|
||||
|
||||
`api-server` 返回 `shared-contracts` 中的 Match3D DTO,前端不需要感知 SpacetimeDB 内部 JSON 快照结构。
|
||||
|
||||
## 3. 创作 Agent 当前口径
|
||||
|
||||
B5 首版先采用确定性配置抽取,不在本阶段新增真实 LLM prompt:
|
||||
|
||||
1. 创建会话时可从 `themeText / seedText / clearCount / difficulty / referenceImageSrc` 形成配置。
|
||||
2. 发送消息时根据用户文本或 `quickFillRequested` 更新题材、需要消除次数和难度。
|
||||
3. `match3d_compile_draft` 动作调用 SpacetimeDB `compile_match3d_draft`,生成 draft work profile。
|
||||
|
||||
后续若要接真实 LLM turn,应复用现有创作 Agent 公共编排,并保持 submit/finalize 两阶段职责不变。
|
||||
|
||||
## 4. 运行态确认协议
|
||||
|
||||
B5 保持 PRD 调整后的边界:
|
||||
|
||||
1. 前端负责点击、飞入、入槽、三消、腾格、胜负等即时表现。
|
||||
2. 后端通过 `click_match3d_item`、`finish_match3d_time_up` 等 procedure 做权威确认。
|
||||
3. HTTP response 会把 SpacetimeDB `Accepted / VersionConflict / RunFinished` 等状态归一到前端 shared contract 可消费的 `accepted / rejectReason / run` 结构。
|
||||
4. `snapshotVersion` 继续作为前端即时反馈和后端确认之间的版本校验字段。
|
||||
|
||||
## 5. shared contract 对齐
|
||||
|
||||
本阶段补齐 Rust shared contract 与 TypeScript contract 的已知差异:
|
||||
|
||||
1. `Match3DAgentSessionSnapshotResponse` 增加 `anchorPack`。
|
||||
2. `Match3DResultDraftResponse` 增加 `profileId / summaryText / totalItemCount`,同时保留 `summary` 兼容结果页读取。
|
||||
3. `PutMatch3DWorkRequest` 增加可选 `themeText`,结果页可编辑题材;旧请求缺省时 API 会沿用已有作品题材。
|
||||
|
||||
## 6. 验收命令
|
||||
|
||||
本阶段至少执行:
|
||||
|
||||
```powershell
|
||||
cargo check -p spacetime-client --manifest-path server-rs\Cargo.toml
|
||||
cargo check -p api-server --manifest-path server-rs\Cargo.toml
|
||||
cargo test -p shared-contracts match3d --manifest-path server-rs\Cargo.toml
|
||||
npm run check:encoding
|
||||
npm run api-server:maincloud
|
||||
```
|
||||
|
||||
`api-server:maincloud` 是修改后端后的必跑项;如果本地缺少 Maincloud 环境或 SpacetimeDB 发布态不一致,需要在最终结果里明确说明。
|
||||
|
||||
## 7. 后续接入点
|
||||
|
||||
1. F1/F2/F3 可把 mock client 替换到上述 HTTP facade。
|
||||
2. F4 平台分发可先读取 `/api/runtime/match3d/gallery` 的已发布作品列表。
|
||||
3. 若后续要记录排行榜或作品播放统计,需要补 Match3D 成绩表或 play record procedure,并同步更新 migration。
|
||||
@@ -0,0 +1,55 @@
|
||||
# 注册环节邀请码与管理员邀请码方案
|
||||
|
||||
更新时间:`2026-04-30`
|
||||
|
||||
## 背景
|
||||
|
||||
旧版“我的 Tab 填邀请码”设计把邀请码绑定放在登录后的个人面板中,容易让老账号重复发现入口,也不利于承接带邀请码的分享链接。本方案将邀请码填写收口到注册链路:未登录用户打开带 `inviteCode` 或 `invite_code` 查询参数的链接时,前端自动打开注册弹窗并预填邀请码。
|
||||
|
||||
## 落地边界
|
||||
|
||||
1. 注册入口复用当前手机号验证码登录自动建号能力,不新增独立注册系统。
|
||||
2. 已登录用户不自动弹注册弹窗;登录后的“我的 Tab”只保留“邀请好友”,不再提供“填邀请码”入口。
|
||||
3. 邀请码只在本次手机号验证码登录创建新账号时尝试绑定。老账号登录时即使请求体带邀请码,也不会绑定。
|
||||
4. 链接邀请码无效或不可用时不阻断注册,登录响应返回短错误提示,由前端展示;不写邀请关系、不发邀请奖励。
|
||||
5. 普通登录态下的 `/api/profile/referrals/redeem-code` 不再允许手动填码,统一返回“邀请码仅注册时填写”。
|
||||
|
||||
## 数据与接口
|
||||
|
||||
`profile_invite_code` 增加 `metadata_json` 字段,默认 `{}`,用于保存渠道、活动、批次等元数据。旧迁移导入数据缺失该字段时由 `migration.rs` 补 `{}`。
|
||||
|
||||
新增管理员接口:
|
||||
|
||||
- `POST /admin/api/profile/invite-codes`
|
||||
|
||||
请求:
|
||||
|
||||
```json
|
||||
{
|
||||
"inviteCode": "SPRING2026",
|
||||
"metadata": {
|
||||
"campaign": "spring"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
管理员邀请码写入 SpacetimeDB 时使用虚拟主体:
|
||||
|
||||
```text
|
||||
admin:{管理员用户名}:{邀请码}
|
||||
```
|
||||
|
||||
管理员码只做归因和被邀请人奖励,不给虚拟主体写邀请人钱包流水。
|
||||
|
||||
手机号登录响应新增:
|
||||
|
||||
- `created`:本次登录是否创建新账号。
|
||||
- `referral`:注册邀请码绑定结果;仅当本次提交了邀请码时返回。
|
||||
|
||||
## 验收标准
|
||||
|
||||
1. 未登录用户访问 `/?inviteCode=ABC123` 自动打开注册弹窗并预填 `ABC123`。
|
||||
2. 有效邀请码注册成功后,被邀请人获得陶泥币奖励,邀请关系落库。
|
||||
3. 无效邀请码注册成功但不绑定,并返回短提示。
|
||||
4. 管理员可添加邀请码并写入 metadata,重复提交同管理员同码更新 metadata。
|
||||
5. 管理员邀请码被使用时不产生 `admin:*` 虚拟主体的钱包流水。
|
||||
@@ -7,13 +7,16 @@
|
||||
- [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md):冻结 SpacetimeDB 表结构变更约束、自动迁移可接受范围、冲突后的系统行为,以及保留旧数据的增量迁移流程;凡涉及 `spacetime publish`、表字段调整或 `migration.rs` 对齐时优先参考。
|
||||
- [SPACETIMEDB_LOCAL_REPLICA_IDENTITY_MISMATCH_FIX_2026-04-30.md](./SPACETIMEDB_LOCAL_REPLICA_IDENTITY_MISMATCH_FIX_2026-04-30.md):记录本地 standalone 启动时报 `mismatched database identity` 的 root-dir/replica 数据残留根因、备份重建步骤和脚本诊断口径。
|
||||
- [LLM_MODEL_ROUTING_RPG_AND_CREATION_2026-04-30.md](./LLM_MODEL_ROUTING_RPG_AND_CREATION_2026-04-30.md):冻结 RPG 运行时剧情推理使用 `doubao-seed-character-251128` 的 `/chat/completions`,以及所有模板创作大模型推理使用 `deepseek-v3-2-251201` 的 `/responses`。
|
||||
- [PROFILE_INVITE_CODE_REGISTRATION_AND_ADMIN_2026-04-30.md](./PROFILE_INVITE_CODE_REGISTRATION_AND_ADMIN_2026-04-30.md):冻结邀请码从“我的 Tab 填写”迁到注册环节的前后端边界、`profile_invite_code.metadata_json` 表结构扩展、管理员邀请码虚拟主体和奖励规则。
|
||||
- [MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md](./MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md):冻结抓大鹅 Match3D 首版 demo 的独立玩法域、表与 procedure、HTTP facade、前端即时反馈/后端权威确认协议,以及可并行开发包。
|
||||
- [MATCH3D_DOMAIN_AND_CONTRACTS_STAGE1_2026-04-30.md](./MATCH3D_DOMAIN_AND_CONTRACTS_STAGE1_2026-04-30.md):冻结抓大鹅 Match3D B1+B2 的纯领域规则 crate、Rust/TypeScript shared contracts,以及 Stage1 不触碰 SpacetimeDB 表和 api-server 的边界。
|
||||
- [MATCH3D_F1_CREATION_ENTRY_AND_AGENT_UI_2026-04-30.md](./MATCH3D_F1_CREATION_ENTRY_AND_AGENT_UI_2026-04-30.md):记录抓大鹅 F1 创作入口、Agent 工作区、参考图入口、本地 mock client 与后续 B5 HTTP facade 替换点。
|
||||
- [MATCH3D_F2_RESULT_AND_PUBLISH_2026-04-30.md](./MATCH3D_F2_RESULT_AND_PUBLISH_2026-04-30.md):冻结抓大鹅 F2 结果页、基础信息编辑、发布前试玩入口、发布门槛、自动保存和已发布作品二次编辑恢复口径。
|
||||
- [MATCH3D_SPACETIME_CLIENT_AND_API_FACADE_2026-04-30.md](./MATCH3D_SPACETIME_CLIENT_AND_API_FACADE_2026-04-30.md):记录抓大鹅 B4+B5 已落地的 SpacetimeDB bindings、`spacetime-client` facade、`api-server` HTTP 路由、shared contract 对齐和验收命令。
|
||||
- [PLATFORM_MOBILE_BOTTOM_DOCK_VIEWPORT_FIX_2026-04-30.md](./PLATFORM_MOBILE_BOTTOM_DOCK_VIEWPORT_FIX_2026-04-30.md):记录平台首页底部 dock 在手机浏览器地址栏展开时脱离可见区域的根因,以及 `100dvh`、固定底部锚点和安全区占位的修复口径。
|
||||
- [SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md](./SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md):记录 SpacetimeDB private 表迁移 JSON 导出/导入 procedure、迁移操作员授权、HTTP 413 分片导入、Jenkins 自动迁移回灌和导入脚本参数。
|
||||
- [JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md](./JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md):记录 `Genarrative-Database-Export` / `Genarrative-Database-Import` 两条 SCM-backed 数据库迁移流水线参数、默认 dry-run、token 边界和 `CHUNK_SIZE` 413 规避参数。
|
||||
- [ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md](./ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md):冻结后台管理独立前端工程 `apps/admin-web` 的技术方案,明确管理端只做表现、全部数据和写操作走 `server-rs` 的 `/admin/api/*`,并接管旧 `GET /admin` 内嵌页面的 UI 职责。
|
||||
- [RPG_PROMPT_FRONTEND_REMOVAL_AND_SERVER_RS_MIGRATION_2026-04-28.md](./RPG_PROMPT_FRONTEND_REMOVAL_AND_SERVER_RS_MIGRATION_2026-04-28.md):冻结 RPG 提示词禁止存在前端的边界,明确前端只保留 API client,角色私聊/NPC 对话/剧情续写等 prompt 统一收口到 `server-rs`。
|
||||
- [RPG_CREATION_RESULT_VIEW_BACKEND_TRUTH_MIGRATION_2026-04-28.md](./RPG_CREATION_RESULT_VIEW_BACKEND_TRUTH_MIGRATION_2026-04-28.md):冻结 RPG 创作结果页保存、Agent session/result preview 真相优先级和结果页入口裁决迁移到后端 result-view 的落地边界。
|
||||
- [RPG_CREATION_PROFILE_GENERATION_BACKEND_MIGRATION_2026-04-28.md](./RPG_CREATION_PROFILE_GENERATION_BACKEND_MIGRATION_2026-04-28.md):记录 RPG 创作 profile 生成移除非浏览器 legacy AI 回退,统一通过 `server-rs` 的 `/api/runtime/custom-world/profile` 生成世界底稿。
|
||||
@@ -61,7 +64,7 @@
|
||||
- [CREATION_AGENT_PUBLISH_GATE_NORMALIZE_WRITEBACK_FIX_2026-04-24.md](./CREATION_AGENT_PUBLISH_GATE_NORMALIZE_WRITEBACK_FIX_2026-04-24.md):记录结果页 profile 归一化回写丢失顶层 `worldHook / playerPremise` 导致 publish gate 继续误报结构 blocker 的根因,并冻结前端归一化保留发布字段的修复口径。
|
||||
|
||||
- [CUSTOM_WORLD_RESULT_ENTITY_GENERATION_FIX_2026-04-24.md](./CUSTOM_WORLD_RESULT_ENTITY_GENERATION_FIX_2026-04-24.md):记录世界结果页在 Agent 草稿模式下新增场景、新增 NPC 生成成功但结果页字段不可用的根因,并冻结 `api-server` 生成归一化层补齐 profile 字段的修复口径。
|
||||
- [ADMIN_CONSOLE_SERVICE_DESIGN_2026-04-23.md](./ADMIN_CONSOLE_SERVICE_DESIGN_2026-04-23.md):冻结 Rust `api-server` 内后台管理服务首版方案,明确管理员用户名密码登录、管理员 JWT 鉴权、数据库概览、受控 API 调试台与同源管理页面的落地边界。
|
||||
- [ADMIN_CONSOLE_SERVICE_DESIGN_2026-04-23.md](./ADMIN_CONSOLE_SERVICE_DESIGN_2026-04-23.md):冻结 Rust `api-server` 内后台管理 API 首版方案;同源内嵌页面已取消,管理员登录、管理员 JWT 鉴权、数据库概览、受控 API 调试台和兑换码管理 API 保留给独立后台前端工程复用。
|
||||
- [SPACETIME_MODULE_LIB_RS_SPLIT_EXECUTION_2026-04-23.md](./SPACETIME_MODULE_LIB_RS_SPLIT_EXECUTION_2026-04-23.md):冻结 `server-rs/crates/spacetime-module/src/lib.rs` 的模块地图、二级落位点与迁移顺序,要求后续 SpacetimeDB 主工程改动按对应模块落位,不再继续堆回单大文件。
|
||||
- [CUSTOM_WORLD_DRAFT_FOUNDATION_API_SERVER_LLM_MIGRATION_2026-04-23.md](./CUSTOM_WORLD_DRAFT_FOUNDATION_API_SERVER_LLM_MIGRATION_2026-04-23.md):冻结 `draft_foundation` 从 SpacetimeDB 内部规则编译迁到 `api-server + platform-llm` 的边界,明确草稿必须由 `api-server` 真实调 LLM 生成,SpacetimeDB 只负责落库。
|
||||
- [CUSTOM_WORLD_AGENT_LLM_REPLY_RESTORE_2026-04-22.md](./CUSTOM_WORLD_AGENT_LLM_REPLY_RESTORE_2026-04-22.md):恢复 Custom World Agent 聊天必须走大模型推理的 Rust 落地方案,冻结 submit/finalize 两阶段职责、旧 Node 提示词原样搬运、SSE 流式回复与 session 回写边界。
|
||||
@@ -78,7 +81,7 @@
|
||||
- [JENKINS_RUST_BUILD_DEPLOY_PIPELINES_2026-04-23.md](./JENKINS_RUST_BUILD_DEPLOY_PIPELINES_2026-04-23.md):冻结 Jenkins `构建 / 部署 / 构建并部署` 三条流水线的职责、版本号传递、上游触发门禁、本地目录部署脚本、发布包覆盖策略,以及部署阶段 SpacetimeDB schema 冲突自动导出、清库发布、导入回灌能力。
|
||||
- [JENKINS_DEPLOY_ENV_BOM_FIX_2026-04-25.md](./JENKINS_DEPLOY_ENV_BOM_FIX_2026-04-25.md):记录 Jenkins 部署时 `.env.local` 首行 UTF-8 BOM 导致 `start.sh` 加载失败的根因,并冻结发布包构建、部署脚本和启动脚本的环境文件净化规则。
|
||||
- [RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md](./RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md):冻结 Rust 本地一键联调脚本与 Ubuntu 发布包构建脚本的执行口径,覆盖 `npm run dev:rust`、`npm run build:rust:ubuntu`、Vite release、Linux `api-server`、SpacetimeDB wasm、启动停止脚本、默认 scp 上传、安全清库开关,以及发布包内 schema 冲突自动迁移脚本。
|
||||
- [RUST_API_SERVER_ROUTE_INDEX_2026-04-22.md](./RUST_API_SERVER_ROUTE_INDEX_2026-04-22.md):记录当前 Rust `api-server` 已挂载的 101 条 Axum 路由,并补充管理后台入口与管理接口索引,按 auth、assets、runtime、custom world、story、generated path 等挂载面归类,用于对照 Node 能力基线与切流 smoke 清单。
|
||||
- [RUST_API_SERVER_ROUTE_INDEX_2026-04-22.md](./RUST_API_SERVER_ROUTE_INDEX_2026-04-22.md):记录当前 Rust `api-server` 已挂载的 Axum 路由,并补充管理 API 索引,按 auth、assets、runtime、custom world、story、generated path 等挂载面归类,用于对照 Node 能力基线与切流 smoke 清单。
|
||||
- [BACKEND_REWRITE_CROSS_CUTTING_GOVERNANCE_2026-04-22.md](./BACKEND_REWRITE_CROSS_CUTTING_GOVERNANCE_2026-04-22.md):冻结后端重写收口阶段的横向治理规则,覆盖 TypeScript contract 到 Rust DTO 映射、SpacetimeDB schema 演进、大对象 / workflow cache 存储边界和文档维护门禁。
|
||||
- [PLATFORM_LLM_TEXT_GATEWAY_DESIGN_2026-04-21.md](./PLATFORM_LLM_TEXT_GATEWAY_DESIGN_2026-04-21.md):`platform-llm` 文本模型网关首版设计,冻结 OpenAI 兼容 `/chat/completions`、SSE 增量解析、错误模型与重试边界。
|
||||
- [API_SERVER_PLATFORM_LLM_PROXY_DESIGN_2026-04-21.md](./API_SERVER_PLATFORM_LLM_PROXY_DESIGN_2026-04-21.md):`api-server` 接入 `platform-llm` 的最小代理设计,冻结 `/api/llm/chat/completions` 的配置、状态注入与首版非流式兼容边界。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Rust API Server 路由索引(2026-04-23)
|
||||
|
||||
更新时间:`2026-04-23`
|
||||
更新时间:`2026-04-30`
|
||||
|
||||
## 1. 文档目标
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
|
||||
## 2. 当前统计
|
||||
|
||||
当前 Rust `api-server` 从 `app.rs` 可抽取到 `101` 条路由:
|
||||
当前 Rust `api-server` 从 `app.rs` 可抽取到 `102` 条路由:
|
||||
|
||||
1. 管理后台接口:`5` 条。
|
||||
1. 管理后台 API:`6` 条。
|
||||
2. 内部鉴权调试接口:`2` 条。
|
||||
3. AI task 接口:`9` 条。
|
||||
4. assets / OSS 接口:`15` 条。
|
||||
@@ -26,13 +26,16 @@
|
||||
|
||||
## 3. 路由清单
|
||||
|
||||
### 3.1 管理后台
|
||||
### 3.1 管理后台 API
|
||||
|
||||
1. `GET /admin`
|
||||
2. `POST /admin/api/login`
|
||||
3. `GET /admin/api/me`
|
||||
4. `GET /admin/api/overview`
|
||||
5. `POST /admin/api/debug/http`
|
||||
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` 同源内嵌页面入口已取消挂载,后台 UI 后续由独立前端工程承接。
|
||||
|
||||
### 3.2 内部鉴权调试
|
||||
|
||||
|
||||
Reference in New Issue
Block a user