first commit

This commit is contained in:
baozaotumao2025
2026-07-18 21:10:39 +08:00
commit 1b90e552a5
91 changed files with 9056 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
# API 映射
所有路径相对 `VITE_API_BASE_URL`,默认为 `/api/v1` 服务。除登录外,请求都携带 Bearer token。
| 领域 | 前端操作 | 后端端点 |
| --- | --- | --- |
| 认证 | 登录、续约、当前用户、修改密码、退出 | `POST /auth/login`, `POST /auth/refresh`, `GET /auth/me`, `PATCH /auth/password`, `POST /auth/logout` |
| 用户 | 列表、创建、启停、重置密码、删除 | `GET/POST /auth/users`, `PATCH/DELETE /auth/users/{id}`, `PATCH /auth/users/{id}/password` |
| 提供商 | 列表、详情、创建、修改、删除 | `GET/POST /providers`, `GET/PATCH/DELETE /providers/{id}` |
| 提供商 | 连通检查、模型发现 | `POST /providers/{id}/check`, `GET /providers/{id}/models` |
| 运行 | 列表、创建、详情、取消、删除 | `GET/POST /runs`, `GET/PATCH/DELETE /runs/{id}` |
| 运行 | 恢复、重试错误、单条重试、逐条结果 | `POST /runs/{id}/resume`, `POST /runs/{id}/retry-errors`, `POST /runs/{id}/results/{execution_id}/retry`, `GET /runs/{id}/results` |
| 报告 | 列表、详情 | `GET /reports`, `GET /reports/{run_id}` |
| 系统 | 健康状态 | `GET /health` |
## 数据规则
- API 响应必须通过 Zod 校验,否则转为 `INVALID_RESPONSE`,不把不可信数据交给 UI。
- 运行详情必须满足 `processed_count = completed_count + error_count``error_count` 仅统计执行异常,不包含 `verdict = fail`;终态必须有 `poll_after_seconds = 0`
- 逐条结果使用 `execution_status``completed | error`)表示调用是否完成,使用可空 `verdict``pass | fail | needs_human_review | judge_format_error | null`)表示仲裁结论;前端不读取旧 `status`
- 逐条结果的执行 ID 搜索直接使用 `GET /runs/{id}/results` 已返回的 `execution_id` 在 UI 过滤,不新增请求参数或后端端点。
- 报告的 `summary.execution_statuses``summary.verdicts` 分开统计;`by_mode` 下也分别包含 `execution_statuses``verdicts`
- `POST /runs/{id}/retry-errors` 只重试 `execution_status = error`,不重试任何仲裁结论。
- `POST /runs/{id}/results/{execution_id}/retry` 无请求体,沿用原 Run 的测试范围和自动仲裁配置,并以相同 `execution_id` 替换旧结果;仅 `completed / completed_with_errors` 状态允许提交。
- `POST /runs/{id}/resume` 无请求体,返回 `skipped_count``POST /runs/{id}/retry-errors` 无请求体,返回 `retry_count`。两者返回 202 后必须重新获取运行详情,不能将 POST 响应视为执行完成;409 时也重新获取详情。
- 单条重试返回 202 后按运行详情的 `poll_after_seconds`(缺省 2 秒)轮询,终态后重新获取结果。重跑期间旧结果可能暂时不存在,UI 保留“重新执行中”状态;404 刷新结果,409 刷新 Run,网络错误或 5xx 先刷新 Run,避免不确定是否受理时重复提交。
- `POST /runs` 总是携带新的 UUID `Idempotency-Key`
- 登录和续约都会原子替换 access/refresh token 及两个过期时间。
- access token 剩余不超过 30 分钟且用户最近 30 分钟有真实操作时,`POST /auth/refresh` 携带 UUID `Idempotency-Key`
- 网络错误和 5xx 最多尝试 3 次,且一直复用原 refresh token 和原 key409 保留凭据并等待 `refresh_after`
- 普通业务请求首次 401 共享 single-flight 续约,成功后仅重放一次;只有 refresh 本身返回 401 才清除会话。
- HTTP 204 按无响应体处理;403/404/409/422/502 映射为可操作的用户消息。
+28
View File
@@ -0,0 +1,28 @@
# 架构与主题
## 数据流
UI 页面只调用 `services/`service 先用 `schemas/` 中的 Zod schema 校验请求,再由 `api/client.ts` 发起请求并用 Zod 校验响应。跨字段业务不变量也在 schema 层完成。错误统一进入 `errors/`,日志进入 `logging/` 并在输出前递归脱敏。
```text
pages/components → services → schemas + api client → FastAPI
errors + logging
```
## Spark Design
组件仅从官方 `@agentscope-ai/design` 引入。`src/design/theme.ts` 是主题注册表,它将 Spark/Ant Design token 与业务页分开;`ThemeProvider.tsx` 只负责注入主题和切换状态;`styles.css` 使用语义 CSS 变量,不在页面内写主题颜色。
当前主题:
- `blue`:默认的深蓝安全控制台。
- `light`:以 Spark 官方 `#615CED` 为主色、`#FAFAFA` 为布局底色的浅色方案。
新增主题时,扩展 `ThemeName``themes` 注册表和对应 `[data-theme]` CSS 变量,再把两态切换控件改为选择器即可,不需要修改业务页。
## 认证与路由
access token、refresh token 和两个过期时间作为一个 JSON 对象原子保存在 `localStorage`,使多标签页共享同一会话。启动时通过 `/auth/me` 恢复身份。`AuthGuard` 保护业务路由,`AdminGuard` 保护用户管理。
`auth/activity.ts` 只记录点击、键盘、触摸和导航,30 秒内最多写入一次;轮询和页面可见本身不算活动。`auth/refresh.ts` 在用户活跃且 access token 进入最后 30 分钟时静默续约。标签页内用共享 Promise,标签页间用 Web Locks 保证只有一个 refresh;待刷新的业务请求用新 access token 重放一次。refresh 401 才清理会话,续约成功不刷新路由、当前用户查询或业务状态。
+28
View File
@@ -0,0 +1,28 @@
# 交互设计
## 主流程
1. 用户登录,系统用 `/auth/me` 确认身份和权限。
活跃用户在 access token 剩余不超过 30 分钟时静默续约;续约不跳转、不刷新页面,不清空当前任务。
2. 概览页确认后端健康、模型配置和近期运行。
3. 管理员在模型配置页建立 target/judge 配置,可查询模型并执行最小连通性检查。
4. 用户选择 smoke/all 与是否自动裁判,确认后创建运行。客户端自动携带 UUID 幂等键,避免重复提交。
5. 详情页展示探测、执行、裁判和完成阶段,按后端 `poll_after_seconds` 轮询。
6. 运行中可取消;中断后可恢复;局部错误可只重试错误样例;终态后可查看逐条结果、汇总报告或确认删除。
`cancelled / failed / pending / probing / running` 可确认后“恢复运行”;`completed_with_errors``error_count > 0` 可确认后“重试错误(N)”。提交期间按钮禁用,成功提示跳过或重试数量;409 会刷新详情以校正操作状态。
7. 逐条结果可按执行状态、仲裁结论筛选,并可按执行 ID 搜索;三项条件组合生效,执行 ID 支持忽略大小写的片段匹配。
8. `completed / completed_with_errors` 的每条结果可确认后单独“重新执行”。提交中仅该按钮显示“提交中…”,受理后该 Run 的全部单条重试按钮锁定并显示目标执行 ID“重新执行中…”,直到 Run 再次进入终态。目标结果会进入跟踪状态并置顶,暂时绕过执行状态、仲裁结论和执行 ID 筛选,用户可手动停止跟踪;原筛选值始终保留。
## 模型等待交互
- 创建成功后立即进入运行详情,不用一个无信息的全屏 loading 阻塞。
- Steps 显示当前阶段,环形进度和成功/错误/总数提供可量化反馈,当前样例 ID 说明系统仍在前进。
- 文案明确告知“可安全离开”;顶栏在全站显示活跃运行数,返回后会恢复轮询。
- 运行期间每 3 秒同步已落库的逐条结果。运行进入终态时会立即执行最后一次结果同步,再停止轮询,避免错过最后落库的样例。
- 终态是停止常规轮询的唯一条件。网络错误显示可重试状态,不把未知状态误报为失败。
- 恢复或重试成功只表示任务已重新排队;详情立即刷新,并继续严格使用最新 `poll_after_seconds` 轮询,直到 `terminal = true`
- 单条重跑会短暂删除旧结果;结果列表找不到目标执行 ID 时继续显示“正在等待跟踪结果…”,终态后用相同执行 ID 置顶展示新结果,即使新状态不符合原筛选也不消失。网络错误或 5xx 先刷新 Run 状态,发现已进入执行态时不重复提交。
## 闭环与破坏性操作
创建、修改、检查、重试等操作都有进行中状态和成功/失败反馈。取消、删除、禁用用户、重置密码等高风险操作要求确认。修改本人密码后所有旧 token 立即失效,前端清理会话并要求使用新密码登录。
+33
View File
@@ -0,0 +1,33 @@
# 测试、安全与运维
## 测试
`tests/unit` 覆盖脱敏、错误归一化、主题持久化、API 响应校验、认证原子存储、single-flight 续约、幂等重试、401 单次重放、运行数据不变量、结果语义标识和运行进入终态时的最终结果同步。`tests/integration` 验证主题切换、逐条结果筛选与搜索、单条重试结果跨筛选置顶跟踪等页面交互,以及所有 service 到后端路由的映射。
```bash
pnpm test
pnpm lint
pnpm build
```
## 安全
- 前端不包含 `TARGET_API_KEY``JUDGE_API_KEY`,也不应在 Vite 变量中暴露它们。
- 完整认证对象保存在 `localStorage` 以支持多标签页原子轮换,不分开写入 access/refresh token;生产环境必须使用 HTTPS 并保持严格 CSP,降低 XSS 窃取风险。
- 续约的待处理 refresh token 和 `Idempotency-Key` 作为一组保存;网络/5xx 失败后不换 key,refresh 401 或用户主动退出才清理凭据。
- logger 对 password、token、API key、Authorization 等键及嵌套数据递归脱敏。
- UI 权限控制只用于交互,真实授权必须由后端执行。
- 生产环境应使用 HTTPS,并将后端 CORS 限制为实际前端域名。
## 日志与错误
`VITE_LOG_LEVEL` 可为 `debug` / `info` / `warn` / `error`。生产环境推荐 `warn`。日志是结构化对象,但不发送到外部系统;如果日后引入观测平台,只需替换 `logging/logger.ts` 的输出端。React Error Boundary 处理未捕获的渲染错误,请求错误由页面提供重试入口。
## 部署
Docker 采用 Node 构建 + Nginx 静态服务两阶段镜像。Nginx 配置了 SPA history fallback、静态资源缓存和 `/healthz`。API 地址在构建时写入:
```bash
docker build --build-arg VITE_API_BASE_URL=https://api.example.com/api/v1 -t ai-safety-console-web .
docker run --rm -p 8080:80 ai-safety-console-web
```
+63
View File
@@ -0,0 +1,63 @@
# UI 设计方案
## 设计目标
界面服务于高风险模型测试操作:优先显示系统状态、当前进度、错误原因和下一步操作,同时保留类 Apple 产品的克制、层次和留白。不用装饰性动画掩盖真实等待,不将密钥或敏感请求数据作为视觉素材。
## 组件基础
按钮、表单、卡片、表格、标签、弹窗、步骤、进度和空状态统一使用项目现有的 `antd`。禁止页面自行引入第二套组件库或局部重写组件形状。两套主题只能替换颜色,不得改变组件尺寸、圆角和信息层级。
## 强制设计令牌
以下令牌定义在 `src/styles.css`,所有页面必须复用:
| 令牌 | 值 | 用途 |
| --- | --- | --- |
| `--radius-control` | `8px` | Button、Input、Select、Tag 等控件 |
| `--radius-surface` | `16px` | Card、Modal、Alert、Table 等容器 |
| `--space-card` | `24px` | 卡片和内容面板内边距 |
| `--space-section` | `24px` | 同层内容区块之间的间距 |
禁止在页面样式中新增一次性胶囊圆角(例如 `999px`)或为相同层级使用不同圆角。Switch、圆形进度和头像等由功能决定形状的组件除外。需要新尺寸时,先扩展全局令牌并补充一致性测试,再在页面使用。
颜色必须来自 `src/styles.css` 的主题变量或 `src/design/theme.ts` 的 Ant Design token。普通文字与背景对比度至少为 WCAG AA `4.5:1`;大号文字至少 `3:1`。状态不得只靠颜色表达,必须同时保留文字或图标。
## 页面布局规则
- Card 内容默认使用 `--space-card`,同级 Card 或内容区块使用 `--space-section`
- 页面不得通过负 margin 或相邻零间距制造视觉粘连。
- 同一组标签尺寸、圆角和内边距必须一致;结论只通过语义色、字重和状态点强化。
- 多列内容在 960px 以下收为单列;700px 以下保证导航、表单和统计区可重排。
- 新页面优先复用现有 PageHeader、AsyncState、ReportSummary 和 Ant Design 组件。
## 两套可切换方案
| 方案 | 用途 | 视觉特征 |
| --- | --- | --- |
| `blue` | 默认安全控制台 | 使用 Ant Design 深色算法,深蓝布局、高对比信息、冷色状态强调,适合长时间监控 |
| `light` | 浅色专业工作台 | 浅灰布局、白色表面、Spark 紫色主操作,适合报告审阅 |
登录页和应用顶栏均提供“切换前端 UI 方案”按钮。选择保存在 `localStorage`,刷新和重新登录后仍保留。
## 页面层级
- 登录:品牌与价值主张在左,唯一主任务登录在右;窄屏只保留登录任务。
- 应用框架:侧边栏承载主导航与身份,顶栏显示活跃任务和主题切换,内容区只保留当前业务。
- 数据概览:先显示可行动指标,再显示最近运行,不使用无决策价值的装饰图表。
- 表单:按完成任务的顺序分组,就地校验,主提交操作保持唯一。
- 运行详情:阶段、进度、计数和当前样例位于首屏,结果和报告位于下方标签页。
- 结果卡片:顶部使用统一 Tag 明确标识“类型 / 模式 / 执行状态 / 仲裁结论”,将后端原始值转为中文语义。执行状态和仲裁结论使用两个独立筛选器,不混合 `completed/error``pass/fail`;执行 ID 搜索与两个筛选器组合生效,并支持忽略大小写的片段匹配。所有标签使用相同的 `8px` 圆角;结论只增加字重和状态点。通过为绿色、未通过或错误为红色、待复核为橙色,文字始终保留。
- 结果卡片在 Run 完成或部分错误时提供“重新执行”;使用 Ant Design 确认框说明结果将被替换。提交、运行中状态以按钮文字和信息提示表达,不只依赖颜色;Run 非终态时同 Run 的全部单条重试按钮禁用。重试目标使用信息提示说明跟踪状态并置顶显示,不修改用户已有筛选;提示提供“停止跟踪”按钮。
## 响应式与可访问性
960px 以下将多列卡片收为单列,700px 以下将侧边栏改为页首导航。主题切换和状态不仅依赖颜色,破坏性操作使用文字和确认弹窗。系统尊重 `prefers-reduced-motion`,所有主要交互均使用语义按钮、表单标签和可见错误文案。
## 提交门禁
所有 UI 修改提交前必须运行 `pnpm check`。其中:
- `tests/unit/design/consistency.test.ts` 防止圆角、间距和规范文档漂移。
- `tests/unit/design/contrast.test.ts` 校验双主题标签与主按钮对比度。
- `tests/integration/pages.test.tsx` 验证全部页面可挂载及关键路由行为。