2026-06-04 23:01:03 +08:00
|
|
|
|
# Nexus 6.0 — 功能开发指南 · 附录(详细参考)
|
|
|
|
|
|
|
|
|
|
|
|
> **主文档**: [nexus-functional-development-guide.md](nexus-functional-development-guide.md)
|
2026-06-06 23:50:05 +08:00
|
|
|
|
> **版本**: 2026-06-06
|
2026-06-04 23:01:03 +08:00
|
|
|
|
> **用途**: API 请求体、前端调用链、E2E/L4 对照、组件映射 — 接续开发时查表用
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 附录 A — `/api/sync` 端点与 Pydantic 模型
|
|
|
|
|
|
|
|
|
|
|
|
定义: `server/api/schemas.py` · 路由: `server/api/sync_v2.py` · 前缀: `/api/sync`
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路径 | 请求模型 | 说明 |
|
|
|
|
|
|
|------|------|----------|------|
|
|
|
|
|
|
| POST | `/files` | `SyncFiles` | 批量 rsync 推送 |
|
|
|
|
|
|
| POST | `/preview` | `SyncPreview` | dry-run 预览(单台代表服务器) |
|
|
|
|
|
|
| POST | `/file-ops` | `FileOperation` | 远程 delete/rename/mkdir |
|
|
|
|
|
|
| POST | `/file-clipboard` | `FileClipboardApply` | 远程 copy/move 批量粘贴 |
|
|
|
|
|
|
| POST | `/browse` | `SyncBrowse` | 远程目录列表(POST 兼容路径) |
|
|
|
|
|
|
| POST | `/browse-local` | `SyncBrowseLocal` | Nexus 本机 staging 目录浏览 |
|
|
|
|
|
|
| POST | `/local-file-ops` | `LocalFileOperation` | staging 内 delete/rename |
|
|
|
|
|
|
| POST | `/local-file-preview` | `LocalFilePreview` | staging 文件预览 |
|
|
|
|
|
|
| POST | `/cancel` | `SyncCancel` | 按 batch_id 取消推送 |
|
|
|
|
|
|
| POST | `/reconcile-stale-logs` | `ReconcileStaleLogs` | 将 stuck `running` 日志标失败 |
|
|
|
|
|
|
| POST | `/validate-source-path` | `ValidateSourcePath` | 校验本机源目录 |
|
|
|
|
|
|
| POST | `/diagnose` | `SyncDiagnose` | 单台推送失败诊断 |
|
|
|
|
|
|
| POST | `/file-diff` | `FileSyncDiff` | 本地 vs 远程单文件 diff |
|
|
|
|
|
|
| POST | `/upload` | multipart | 上传到 staging |
|
|
|
|
|
|
| POST | `/upload-zip` | multipart | ZIP 解压到 staging |
|
|
|
|
|
|
| POST | `/verify` | `SyncVerify` | 推送后 md5 校验 |
|
|
|
|
|
|
| POST | `/download` | `FileDownload` | 远程文件下载流 |
|
|
|
|
|
|
| POST | `/read-file` | `FileRead` | 读远程文本(≤5MB) |
|
|
|
|
|
|
| POST | `/write-file` | `FileWrite` | 写远程文本 + 可选 etag 乐观锁 |
|
|
|
|
|
|
| POST | `/chmod` | `FileChmod` | chmod/chown |
|
|
|
|
|
|
| POST | `/compress` | `FileCompress` | tar.gz/zip 压缩 |
|
|
|
|
|
|
| POST | `/decompress` | `FileDecompress` | 解压到绝对路径 |
|
|
|
|
|
|
|
|
|
|
|
|
### A.1 核心模型字段
|
|
|
|
|
|
|
|
|
|
|
|
**SyncFiles**(推送)
|
|
|
|
|
|
|
|
|
|
|
|
| 字段 | 类型 | 默认 | 约束 |
|
|
|
|
|
|
|------|------|------|------|
|
|
|
|
|
|
| `server_ids` | `int[]` | — | min 1 |
|
|
|
|
|
|
| `source_path` | `str` | — | Nexus 本机绝对路径,禁系统敏感路径 |
|
|
|
|
|
|
| `target_path` | `str?` | null | 远程绝对路径;空则用各服务器 `target_path` |
|
|
|
|
|
|
| `sync_mode` | `str` | `incremental` | `incremental\|full\|overwrite\|checksum` |
|
|
|
|
|
|
| `batch_size` | `int` | 50 | 1–200 |
|
|
|
|
|
|
| `concurrency` | `int` | 10 | 1–50 |
|
|
|
|
|
|
| `batch_id` | `str?` | null | 12 位 hex;须先连 `/ws/sync` 再 POST |
|
|
|
|
|
|
|
|
|
|
|
|
**SyncPreview**
|
|
|
|
|
|
|
|
|
|
|
|
| 字段 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `server_id` | 代表服务器(单台 dry-run) |
|
|
|
|
|
|
| `verbose` | true 时返回文件列表(≤200 行) |
|
|
|
|
|
|
| 其余 | 同 SyncFiles 的 path/mode |
|
|
|
|
|
|
|
|
|
|
|
|
**FileOperation**
|
|
|
|
|
|
|
|
|
|
|
|
| operation | 必填 | 远程命令 |
|
|
|
|
|
|
|-----------|------|----------|
|
|
|
|
|
|
| `delete` | `path` | `rm -rf` |
|
|
|
|
|
|
| `rename` | `path`, `new_path` | `mv` |
|
|
|
|
|
|
| `mkdir` | `path` | `mkdir -p` |
|
|
|
|
|
|
|
|
|
|
|
|
**FileClipboardApply**
|
|
|
|
|
|
|
|
|
|
|
|
| 字段 | 约束 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `mode` | `copy` → `cp -r`;`move` → `mv -t` |
|
|
|
|
|
|
| `sources` | 1–50 条远程绝对路径 |
|
|
|
|
|
|
| `dest_dir` | 目标目录绝对路径 |
|
|
|
|
|
|
|
|
|
|
|
|
**FileRead / FileWrite**
|
|
|
|
|
|
|
|
|
|
|
|
| 字段 | FileRead | FileWrite |
|
|
|
|
|
|
|------|----------|-----------|
|
|
|
|
|
|
| `max_size` | 默认 1MB,max 5MB | — |
|
|
|
|
|
|
| `content` | — | max 5MB |
|
|
|
|
|
|
| `etag` | — | 乐观锁,冲突 409 |
|
|
|
|
|
|
|
|
|
|
|
|
**FileChmod**
|
|
|
|
|
|
|
|
|
|
|
|
| 字段 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `mode` | 3–4 位八进制 `^[0-7]{3,4}$` |
|
|
|
|
|
|
| `owner` / `group` | 可选;group 须同时有 owner |
|
|
|
|
|
|
| `recursive` | 目录递归 |
|
|
|
|
|
|
|
|
|
|
|
|
### A.2 推送 WS 协议(`/ws/sync`)
|
|
|
|
|
|
|
|
|
|
|
|
1. 前端生成 `batch_id`(12 hex)
|
|
|
|
|
|
2. **先** `WebSocket` 连接 `/ws/sync?token=&batch_id=`
|
|
|
|
|
|
3. **再** `POST /api/sync/files` 带相同 `batch_id`
|
|
|
|
|
|
4. 消息: per-server 状态(pending/running/success/failed/cancelled)、进度百分比、错误摘要
|
|
|
|
|
|
5. 取消: `POST /api/sync/cancel` `{ batch_id }`
|
|
|
|
|
|
|
|
|
|
|
|
### A.3 文件浏览双通道
|
|
|
|
|
|
|
|
|
|
|
|
| 通道 | 方法 | 优势 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| REST | `GET /api/files/browse?server_id=&path=` | ETag + 304,前端首选 |
|
|
|
|
|
|
| Sync 兼容 | `POST /api/sync/browse` | 旧网关/部署回退 |
|
|
|
|
|
|
|
|
|
|
|
|
前端 `useFilesBrowse.fetchBrowseListing` 先 GET,失败再 POST。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 附录 B — 文件页(Files)调用链
|
|
|
|
|
|
|
|
|
|
|
|
### B.1 组件树
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
FilesPage.vue
|
|
|
|
|
|
├── FilesToolbar.vue # 服务器选择、刷新、上传、新建
|
|
|
|
|
|
├── FilesPermissionAlert.vue # files-capability / sudo 提示
|
|
|
|
|
|
├── FilesStatusBar.vue # 条目统计、SSH 用户
|
|
|
|
|
|
├── FilesBreadcrumb.vue # 路径面包屑
|
|
|
|
|
|
├── FilesList.vue # v-data-table + 行操作
|
|
|
|
|
|
├── FilesDialogs.vue # 删除/重命名/chmod/压缩等对话框
|
|
|
|
|
|
└── FileEditorWorkbench.vue # Monaco 编辑 + 预览
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
`provideFilesPage(page)` → 子组件通过 `injectFilesPage()` 取上下文(`filesPageContext.ts`)。
|
|
|
|
|
|
|
|
|
|
|
|
### B.2 Composable 依赖图
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
useFilesPage
|
|
|
|
|
|
├── useFilesStore (Pinia) # selectedServer, currentPath, files, cache
|
|
|
|
|
|
├── useFilesSelection # selectedFiles 多选
|
|
|
|
|
|
├── useFilesBrowse(fileFilter) # browse(), ETag, preload Monaco
|
|
|
|
|
|
│ └── GET /api/files/browse | POST /api/sync/browse
|
|
|
|
|
|
├── useFilesPermissions # files-capability, setup-files-sudo
|
|
|
|
|
|
│ └── GET /api/servers/{id}/files-capability
|
|
|
|
|
|
│ └── POST /api/servers/{id}/setup-files-sudo
|
|
|
|
|
|
├── useFilesNavigation # 面包屑、goUp、openEntry、?server_id=
|
|
|
|
|
|
├── useFilesEditor # read/write/preview
|
|
|
|
|
|
│ └── POST /api/sync/read-file | write-file
|
|
|
|
|
|
├── useFilesActions # CRUD、clipboard、upload、compress
|
|
|
|
|
|
│ └── POST /api/sync/file-ops | file-clipboard | upload | chmod | compress…
|
|
|
|
|
|
├── useFilesClipboard # 跨目录 copy/cut/paste 状态
|
|
|
|
|
|
└── useFilesHotkeys # Ctrl+C/V、Delete、F5 刷新
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### B.3 关键 API 映射(用户操作 → 端点)
|
|
|
|
|
|
|
|
|
|
|
|
| 用户操作 | Composable | API |
|
|
|
|
|
|
|----------|------------|-----|
|
|
|
|
|
|
| 选服务器/进目录 | `useFilesBrowse.browse` | `GET /files/browse` |
|
|
|
|
|
|
| 保存编辑器 | `useFilesEditor.save` | `POST /sync/write-file` |
|
|
|
|
|
|
| 删除/重命名/新建目录 | `useFilesActions` | `POST /sync/file-ops` |
|
|
|
|
|
|
| 复制/剪切/粘贴 | `useFilesActions` + clipboard | `POST /sync/file-clipboard` |
|
|
|
|
|
|
| 上传 | `useFilesActions.doUpload` | `POST /sync/upload` |
|
|
|
|
|
|
| chmod | `useFilesActions.doChmod` | `POST /sync/chmod` |
|
|
|
|
|
|
| 压缩/解压 | `useFilesActions` | `POST /sync/compress` / `decompress` |
|
|
|
|
|
|
| 下载 | `useFilesActions.downloadFile` | `POST /sync/download` |
|
|
|
|
|
|
| 配置 sudo | `useFilesPermissions.setupFilesSudo` | `POST /servers/{id}/setup-files-sudo` |
|
|
|
|
|
|
| 打开终端 | `useFilesNavigation.openInTerminal` | 路由 `#/terminal?server_id=` |
|
|
|
|
|
|
|
|
|
|
|
|
### B.4 Store 缓存策略(`stores/files.ts`)
|
|
|
|
|
|
|
|
|
|
|
|
- Key: `{serverId}:{path}`
|
|
|
|
|
|
- 存 ETag + entries + fetchedAt
|
|
|
|
|
|
- `invalidateAfterMutation` 在写操作后清除当前目录及父目录缓存
|
|
|
|
|
|
- `pageReady`: 首次 browse 完成后为 true(避免空态闪烁)
|
|
|
|
|
|
|
|
|
|
|
|
### B.5 路由 Query 参数
|
|
|
|
|
|
|
|
|
|
|
|
| 参数 | 行为 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `?server_id=123` | `useFilesNavigation` 自动选中并 browse |
|
|
|
|
|
|
| `?path=/var/www` | 初始路径(须与 server_id 同用) |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 附录 C — 推送页(Push)调用链
|
|
|
|
|
|
|
|
|
|
|
|
### C.1 Composable 依赖图
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
usePushPage
|
|
|
|
|
|
├── usePushForm # source_path, target_path, sync_mode, batch 参数
|
|
|
|
|
|
├── usePushServers # 服务器列表、分类、全选、在线过滤
|
|
|
|
|
|
├── usePushLogs # sync_logs 历史分页
|
|
|
|
|
|
├── usePushProgress # WS + doPush + cancel
|
|
|
|
|
|
│ └── WS /ws/sync
|
|
|
|
|
|
│ └── POST /api/sync/files, /cancel
|
|
|
|
|
|
└── usePushPreview # 预览对话框、confirmAndPush
|
|
|
|
|
|
└── POST /api/sync/preview (并发代表服务器)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### C.2 推送流程(时序)
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
|
participant UI as PushPage
|
|
|
|
|
|
participant WS as /ws/sync
|
|
|
|
|
|
participant API as /api/sync/files
|
|
|
|
|
|
participant Eng as SyncEngineV2
|
|
|
|
|
|
|
|
|
|
|
|
UI->>UI: generate batch_id (12 hex)
|
|
|
|
|
|
UI->>WS: connect(token, batch_id)
|
|
|
|
|
|
UI->>API: POST /files {batch_id, server_ids, ...}
|
|
|
|
|
|
Eng->>WS: per-server progress
|
|
|
|
|
|
WS->>UI: update pushStatus
|
|
|
|
|
|
Eng->>Eng: rsync over SSH (semaphore)
|
|
|
|
|
|
UI->>API: POST /cancel (optional)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### C.3 相关端点(Push 页间接使用)
|
|
|
|
|
|
|
|
|
|
|
|
| 功能 | API |
|
|
|
|
|
|
|------|-----|
|
|
|
|
|
|
| 校验源路径 | `POST /sync/validate-source-path` |
|
|
|
|
|
|
| ZIP 源 | `POST /sync/upload-zip` |
|
|
|
|
|
|
| 失败诊断 | `POST /sync/diagnose` |
|
|
|
|
|
|
| 对账 stuck 日志 | `POST /sync/reconcile-stale-logs` |
|
|
|
|
|
|
| 推送后校验 | `POST /sync/verify` |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 附录 D — 终端页(Terminal)调用链
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
TerminalPage.vue
|
|
|
|
|
|
├── TerminalToolbar.vue
|
|
|
|
|
|
├── TerminalTabBar.vue
|
|
|
|
|
|
├── TerminalServerPicker.vue
|
|
|
|
|
|
├── TerminalArea.vue # xterm 实例
|
|
|
|
|
|
├── TerminalCmdBar.vue # 命令输入 + 高亮
|
|
|
|
|
|
└── TerminalQuickBar.vue # 快捷命令
|
|
|
|
|
|
|
|
|
|
|
|
useTerminalSessions
|
|
|
|
|
|
├── POST /api/auth/webssh-token { server_id }
|
|
|
|
|
|
├── WebSocket /ws/terminal/{session_uuid}?token=
|
|
|
|
|
|
├── Koko: TERMINAL_INIT, DATA, RESIZE, CLOSE
|
|
|
|
|
|
└── onBeforeUnmount → disposeAllSessions
|
|
|
|
|
|
|
|
|
|
|
|
useTerminalQuickCommands → GET/POST /api/terminal/quick-commands
|
|
|
|
|
|
useTerminalSettings → localStorage 主题/字体(非敏感)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**WebSSH JWT**: `purpose=webssh`, 绑定 `server_id`, 15min;路径 param `id` 须与 token 内 server_id 一致。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 附录 E — 其余 API 模块明细
|
|
|
|
|
|
|
|
|
|
|
|
### E.1 调度 `/api/schedules`(`settings.py` 内)
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路径 | 说明 |
|
|
|
|
|
|
|------|------|------|
|
2026-06-08 02:45:17 +08:00
|
|
|
|
| GET | `/` | 列表(含 `next_run`、`target_path`、`schedule_type`、`run_mode`) |
|
|
|
|
|
|
| POST | `/` | 创建 push:`source_path`、`target_path?`、`sync_mode`、`cron_expr`/`fire_at`;script:`script_id`/`script_content` |
|
|
|
|
|
|
| PUT | `/{id}` | 更新(allowlist 含 `target_path`) |
|
2026-06-04 23:01:03 +08:00
|
|
|
|
| DELETE | `/{id}` | 删除 |
|
|
|
|
|
|
|
2026-06-08 02:45:17 +08:00
|
|
|
|
`PushSchedule.target_path` 留空时 runner / `runNow` 与各机 `servers.target_path` 一致。
|
|
|
|
|
|
|
|
|
|
|
|
后台 `schedule_runner` 每分钟扫描 `enabled=1` 且到期项 → SyncEngineV2 或 ScriptService。
|
2026-06-04 23:01:03 +08:00
|
|
|
|
|
|
|
|
|
|
### E.2 重试 `/api/retries`
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路径 | 说明 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| GET | `/` | 待重试队列 |
|
|
|
|
|
|
| POST | `/{id}/retry` | 手动触发 |
|
|
|
|
|
|
| DELETE | `/{id}` | 移出队列 |
|
|
|
|
|
|
|
|
|
|
|
|
`retry_runner` 每 5min,`SELECT … FOR UPDATE SKIP LOCKED`,指数退避,max 3 次。
|
|
|
|
|
|
|
|
|
|
|
|
### E.3 审计 `/api/audit`
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路径 | Query |
|
|
|
|
|
|
|------|------|-------|
|
|
|
|
|
|
| GET | `/` | `page`, `page_size`, `action`, `username`, `date_from`, `date_to` |
|
|
|
|
|
|
|
|
|
|
|
|
### E.4 告警 `/api/alert-history`
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路径 | 说明 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| GET | `/` | 分页列表 |
|
|
|
|
|
|
| GET | `/stats` | 汇总统计 |
|
|
|
|
|
|
|
|
|
|
|
|
### E.5 预设
|
|
|
|
|
|
|
|
|
|
|
|
| 前缀 | 用途 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `/api/presets` | 密码预设 CRUD |
|
|
|
|
|
|
| `/api/ssh-key-presets` | SSH 密钥预设 CRUD |
|
|
|
|
|
|
| `/api/scripts/credentials` | DB 凭据(脚本 `$DB_*`) |
|
|
|
|
|
|
|
|
|
|
|
|
### E.6 脚本 `/api/scripts`
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路径 | 说明 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| POST | `/exec` | `{ script_id?, command?, server_ids, timeout }` |
|
|
|
|
|
|
| GET | `/executions` | 分页执行记录 |
|
|
|
|
|
|
| POST | `/executions/{id}/stop` | SIGTERM/SIGKILL |
|
|
|
|
|
|
| POST | `/executions/{id}/retry` | 重新执行 |
|
|
|
|
|
|
| GET | `/exec-config` | 超时阈值等前端展示用 |
|
|
|
|
|
|
|
|
|
|
|
|
### E.7 Agent `/api/agent`
|
|
|
|
|
|
|
|
|
|
|
|
**Heartbeat body(摘要)**
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"server_id": 1,
|
|
|
|
|
|
"cpu": 12.5,
|
|
|
|
|
|
"memory": 45.0,
|
|
|
|
|
|
"disk": 60.0,
|
|
|
|
|
|
"load": [0.1, 0.2, 0.15],
|
|
|
|
|
|
"agent_version": "6.0.x",
|
|
|
|
|
|
"system_info": { "hostname": "...", "os": "..." }
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Script callback**: Agent 长任务完成后 POST,更新 Redis + MySQL execution。
|
|
|
|
|
|
|
|
|
|
|
|
### E.8 搜索 `/api/search`
|
|
|
|
|
|
|
|
|
|
|
|
`GET /?q=` — 并行查 servers、scripts、db_credentials、schedules(limit 各 10)。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 附录 F — 前端页面 ↔ 组件 ↔ Composable 映射
|
|
|
|
|
|
|
|
|
|
|
|
| 页面 | 主要 Composable | 关键子组件 |
|
|
|
|
|
|
|------|-----------------|------------|
|
|
|
|
|
|
| DashboardPage | `useWebSocket`, `useServerPagination` | StatCardsRow |
|
|
|
|
|
|
| ServersPage | `useServerFormDialog`, `useServerPagination` | ServerFormDialog |
|
|
|
|
|
|
| TerminalPage | `useTerminalSessions`, `useTerminalCmdBar` | TerminalArea, TerminalTabBar |
|
|
|
|
|
|
| FilesPage | `useFilesPage` | FilesToolbar, FilesList, FileEditorWorkbench |
|
|
|
|
|
|
| PushPage | `usePushPage` | PushToolbar, PushServerGrid, PushProgressList |
|
|
|
|
|
|
| ScriptsPage | 页内逻辑 + Monaco | ScriptEditorDialog |
|
|
|
|
|
|
| CredentialsPage | 三 Tab CRUD | — |
|
|
|
|
|
|
| SchedulesPage | cron 表单 | ScheduleFormDialog |
|
|
|
|
|
|
| RetriesPage | 列表 + retry | — |
|
|
|
|
|
|
| CommandsPage | 双视图切换 | — |
|
|
|
|
|
|
| AlertsPage | 过滤 + 分页 | — |
|
|
|
|
|
|
| AuditPage | `normalizeAuditList` | — |
|
|
|
|
|
|
| SettingsPage | TOTP/API Key/IP 白名单 | TerminalQuickCommandsSettings |
|
|
|
|
|
|
| LoginPage | `useAuthStore.login` | — |
|
|
|
|
|
|
|
|
|
|
|
|
### F.1 全局布局(`App.vue`)
|
|
|
|
|
|
|
|
|
|
|
|
- 侧栏 14 项导航(v-list)
|
|
|
|
|
|
- 顶栏:全局搜索 → `GET /api/search`
|
|
|
|
|
|
- 用户菜单:主题切换、退出
|
|
|
|
|
|
- `useWebSocket` 告警 toast + Dashboard 刷新触发
|
|
|
|
|
|
|
|
|
|
|
|
### F.2 类型定义
|
|
|
|
|
|
|
|
|
|
|
|
所有 API 响应类型优先维护在 `frontend/src/types/api.ts`;新增字段先改类型再改 composable。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 附录 G — 验收与 E2E 对照
|
|
|
|
|
|
|
|
|
|
|
|
### G.1 L4 统一入口
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python3 scripts/run_nexus_acceptance.py --base http://127.0.0.1:8600 --with-ui
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
阶段:
|
|
|
|
|
|
|
|
|
|
|
|
| Phase | 内容 |
|
|
|
|
|
|
|-------|------|
|
|
|
|
|
|
| API | `tests/test_api.py` + `tests/test_api_extended.py` |
|
|
|
|
|
|
| UI | `frontend/e2e/full-acceptance.spec.mjs`(15 用例) |
|
|
|
|
|
|
| Unit | `--with-unit` 时跑路径/权限单测 |
|
|
|
|
|
|
|
|
|
|
|
|
功能 rollup 映射: `tests/acceptance_catalog.py` → `FEATURES[]`。
|
|
|
|
|
|
|
|
|
|
|
|
### G.2 Playwright 用例 ↔ 页面
|
|
|
|
|
|
|
|
|
|
|
|
| 用例 ID | 路由 | 验证点 |
|
|
|
|
|
|
|---------|------|--------|
|
|
|
|
|
|
| 01 | `#/` | 登录 + Dashboard 卡片 |
|
|
|
|
|
|
| 02 | `#/servers` | 添加对话框、批量选择 |
|
|
|
|
|
|
| 03 | `#/` | 全局搜索输入 |
|
|
|
|
|
|
| 04 | `#/terminal` | 终端页可见 |
|
|
|
|
|
|
| 05 | `#/files` | 文件页可见 |
|
|
|
|
|
|
| 06 | `#/push` | 预览按钮(不真推送) |
|
|
|
|
|
|
| 07 | `#/scripts` | 新建脚本对话框 |
|
|
|
|
|
|
| 08 | `#/credentials` | 三 Tab 切换 |
|
|
|
|
|
|
| 09 | `#/schedules` | 新建调度对话框 |
|
|
|
|
|
|
| 10 | `#/retries` | 重试列表 |
|
|
|
|
|
|
| 11 | `#/commands` | 命令/会话视图 |
|
|
|
|
|
|
| 12 | `#/alerts` | 告警页 |
|
|
|
|
|
|
| 13 | `#/audit` | 审计页 |
|
|
|
|
|
|
| 14 | `#/settings` | 设置区块 |
|
|
|
|
|
|
| 15 | `#/` | 主题切换 + 登出 |
|
|
|
|
|
|
|
|
|
|
|
|
**环境变量**
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
NEXUS_E2E_BASE=http://127.0.0.1:8600
|
|
|
|
|
|
NEXUS_E2E_USER=admin
|
|
|
|
|
|
NEXUS_E2E_PASSWORD=*** # 必填;测试账号勿开 TOTP
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### G.3 API 测试环境
|
|
|
|
|
|
|
|
|
|
|
|
与 E2E 共用 `.env` 中 `NEXUS_TEST_ADMIN_PASSWORD`(`seed_local_admin.py` 写入)。
|
|
|
|
|
|
|
|
|
|
|
|
### G.4 本地验证脚本
|
|
|
|
|
|
|
|
|
|
|
|
`bash scripts/local_verify.sh` — ruff、import、pytest 子集、前端 typecheck(若可用)。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-06-06 23:50:05 +08:00
|
|
|
|
## 附录 J — 凭据轮询与 pending servers
|
|
|
|
|
|
|
|
|
|
|
|
定义: `server/application/services/credential_poller.py` · 路由: `server/api/servers.py` · 表: `pending_servers`
|
|
|
|
|
|
|
|
|
|
|
|
### J.1 API
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路径 | 请求体 | 成功响应 | 失败/待定 |
|
|
|
|
|
|
|------|------|--------|----------|-----------|
|
|
|
|
|
|
| POST | `/api/servers/add-by-ip` | `AddByIpRequest`: `domain`(必填), `port?`(默认 22), `name?` | `{ success: true, server, matched_preset, matched_username }` | `{ success: false, pending_id, errors[], message }` — 写入 pending |
|
|
|
|
|
|
| GET | `/api/servers/pending` | — | `{ items: PendingServer[], total }` | — |
|
|
|
|
|
|
| POST | `/api/servers/pending/{id}/retry` | `{}` | 同 add-by-ip | 同 add-by-ip;域名已存在 → **409** 并删除 pending |
|
|
|
|
|
|
| DELETE | `/api/servers/pending/{id}` | — | **204** | 404 |
|
|
|
|
|
|
|
|
|
|
|
|
**PollErrorItem**(`errors[]`): `preset_type`(`password` \| `ssh_key`)、`preset_name`、`username`、`error`。
|
|
|
|
|
|
|
|
|
|
|
|
**PendingServer**(列表项): `id`, `name`, `domain`, `port`, `attempts`, `last_error`, `last_attempt_at`, `created_at` 及可选 `agent_port`, `target_path`, `category`, `platform_id`, `node_id`。
|
|
|
|
|
|
|
|
|
|
|
|
### J.2 轮询顺序
|
|
|
|
|
|
|
|
|
|
|
|
1. 解密全部 `password_presets`(按 id 升序),再全部 `ssh_key_presets`
|
|
|
|
|
|
2. 每条使用预设 `username`(缺省 `root`)调用 `try_ssh_login`
|
|
|
|
|
|
3. 首条成功 → `create_server` + 审计 `create_server`;全部失败 → `pending_servers` upsert + 审计 `add_by_ip_failed`
|
|
|
|
|
|
|
|
|
|
|
|
### J.3 前端(ServersPage)
|
|
|
|
|
|
|
|
|
|
|
|
| 用户操作 | API |
|
|
|
|
|
|
|----------|-----|
|
|
|
|
|
|
| 打开「快速添加」对话框 | — |
|
|
|
|
|
|
| 提交 IP | `POST /servers/add-by-ip` |
|
|
|
|
|
|
| 失败弹窗展示 `errors[]` | — |
|
|
|
|
|
|
| 页面加载 / 刷新失败列表 | `GET /servers/pending` |
|
|
|
|
|
|
| 行内重试 | `POST /servers/pending/{id}/retry` |
|
|
|
|
|
|
| 行内删除 | `DELETE /servers/pending/{id}` |
|
|
|
|
|
|
|
|
|
|
|
|
类型定义: `frontend/src/types/api.ts` — `PendingServerItem`, `AddByIpResponse`, `PollErrorItem`。
|
|
|
|
|
|
|
|
|
|
|
|
### J.4 预设 username(CredentialsPage)
|
|
|
|
|
|
|
|
|
|
|
|
| 端点 | 新增字段 |
|
|
|
|
|
|
|------|----------|
|
|
|
|
|
|
| `POST/PUT /api/presets/` | `username`(默认 `root`) |
|
|
|
|
|
|
| `POST/PUT /api/ssh-key-presets/` | `username`(默认 `root`) |
|
|
|
|
|
|
| `GET` 列表 | 每项含 `username` |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-06-04 23:01:03 +08:00
|
|
|
|
## 附录 H — 错误码与前端处理约定
|
|
|
|
|
|
|
|
|
|
|
|
| HTTP | 场景 | 前端处理 |
|
|
|
|
|
|
|------|------|----------|
|
|
|
|
|
|
| 401 | JWT 过期 | `fetchAuthed` 自动 refresh 一次 |
|
|
|
|
|
|
| 202 | 需 TOTP | `TotpRequiredError` → 显示 TOTP 输入 |
|
|
|
|
|
|
| 304 | Browse ETag 命中 | 用缓存 entries |
|
|
|
|
|
|
| 409 | write-file etag 冲突 | 提示合并/覆盖 |
|
|
|
|
|
|
| 429 | 登录锁定 | Login 页显示剩余时间 |
|
|
|
|
|
|
| 503 | 安装模式 | 引导 `/app/install.html` |
|
|
|
|
|
|
|
|
|
|
|
|
统一错误文案: `formatApiError(err)` + `$snackbar`。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 附录 I — 新增功能检查清单(扩展)
|
|
|
|
|
|
|
|
|
|
|
|
### 新 Sync 相关端点
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] `schemas.py` Pydantic + path validator
|
|
|
|
|
|
- [ ] `sync_v2.py` 路由 + `_audit_sync`
|
|
|
|
|
|
- [ ] `tests/test_api.py` 或 `test_sync_*.py`
|
|
|
|
|
|
- [ ] 前端 `http.post('/sync/...')` + types
|
|
|
|
|
|
- [ ] 更新附录 A + 主文档 §10
|
|
|
|
|
|
- [ ] changelog ≥10 行
|
|
|
|
|
|
|
|
|
|
|
|
### 新 Files 操作
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] `useFilesActions` 方法 + `FilesDialogs` UI
|
|
|
|
|
|
- [ ] 热键(若适用)注册到 `useFilesHotkeys`
|
|
|
|
|
|
- [ ] browse 缓存 invalidate
|
|
|
|
|
|
- [ ] E2E 05 或专项用例
|
|
|
|
|
|
|
|
|
|
|
|
### 新页面(第 15 页)
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] `pages/XxxPage.vue`
|
|
|
|
|
|
- [ ] `router/index.ts` + `App.vue` nav
|
|
|
|
|
|
- [ ] `acceptance_catalog.py` + Playwright 用例
|
|
|
|
|
|
- [ ] `run_nexus_acceptance` 报告可 rollup
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
**维护**: 改 API/composable 时同步更新对应附录章节。
|