# 前端 14 页 API 契约审计(含凭据轮询) **日期**: 2026-06-06 **基线**: [audit-frontend-14p-2026-06-04-closure.md](audit-frontend-14p-2026-06-04-closure.md)(43 H,0 P0/P1) **增量范围**: 凭据轮询 `add-by-ip` / `pending_servers`;预设 `username` 字段 **方法**: 静态对照 `frontend/src/pages/*` + composables ↔ `server/api/*.py` 路由与响应形 ## 结论 | 维度 | 结果 | |------|------| | 14 页 API 路径 | **PASS** — 全部端点在后端存在且 HTTP 方法一致 | | 新增契约(Servers / Credentials) | **PASS** — 请求/响应字段前后端对齐 | | 类型集中化 | **PASS** — `PendingServerItem` / `AddByIpResponse` / `PollErrorItem` 已入 `types/api.ts` | | 单元测试 | **PASS** — `tests/test_credential_poller.py` 7 passed | | 本地门控 | **WARN** — `local_verify.sh` 因本地 MySQL 断连未跑通(环境问题,非契约缺口) | | 生产 SPA 部署 | **PASS** — `ServersPage`/`CredentialsPage` 分块已含新契约;见 [production-verification](2026-06-06-credential-polling-production-verification.md) | **新 FINDING**: 0 × P0/P1,0 × P2(契约层) --- ## 1. 凭据轮询契约(增量) ### 1.1 后端 | 方法 | 路径 | 实现 | |------|------|------| | POST | `/api/servers/add-by-ip` | `servers.py` → `poll_credentials` → 成功 `create_server` / 失败 `pending_servers` | | GET | `/api/servers/pending` | `PendingServerRepositoryImpl.list_all` | | POST | `/api/servers/pending/{id}/retry` | 再轮询;域名已存在 → 409 | | DELETE | `/api/servers/pending/{id}` | 204 | 预设 `username`: `settings.py` `GET/POST/PUT` `/presets/`、`/ssh-key-presets/`。 ### 1.2 前端 | 组件 | 调用 | |------|------| | `ServersPage.vue` | 上述四端点;`onMounted` 加载 pending | | `CredentialsPage.vue` | 预设 CRUD 含 `username`(默认 `root`) | ### 1.3 响应形对照 | 字段 | 后端 | 前端消费 | |------|------|----------| | `success` | ✓ | 分支成功/失败 | | `server` | `Server` 序列化 | 刷新列表 | | `matched_preset` / `matched_username` | ✓ | 成功 toast | | `pending_id` | ✓ | 失败后可查列表 | | `errors[]` | `PollError` 列表 | 失败对话框表格 | | `message` | 聚合摘要 | 对话框标题区 | --- ## 2. 十四页 API 矩阵 前缀均为 `/api`;`http` 客户端已含前缀,下表写相对路径。 ### 2.1 DashboardPage `/` | 端点 | 方法 | 后端 | 状态 | |------|------|------|------| | `/servers/stats` | GET | `servers.py` | OK | | `/alert-history/` | GET | `alert_history.py` | OK | | `/audit/` | GET | `audit.py` | OK | | `/servers/` | GET | `servers.py` | OK | | `/settings/bing-wallpapers/sync` | POST | `settings.py` | OK | ### 2.2 ServersPage `/servers` | 端点 | 方法 | 状态 | |------|------|------| | `/servers/` | GET/POST/PUT/DELETE | OK | | `/servers/stats` | GET | OK | | `/servers/check` | POST | OK | | `/servers/batch/install-agent` 等 | POST | OK | | `/servers/{id}/logs` | GET | OK | | `/servers/add-by-ip` | POST | **新增 OK** | | `/servers/pending` | GET | **新增 OK** | | `/servers/pending/{id}/retry` | POST | **新增 OK** | | `/servers/pending/{id}` | DELETE | **新增 OK** | | `/presets/`、`/ssh-key-presets/`、`/assets/nodes` | GET | OK(表单 composable) | ### 2.3 TerminalPage `/terminal` | 端点 | 方法 | 位置 | 状态 | |------|------|------|------| | `/auth/webssh-token` | POST | `useTerminalSessions` | OK | | `/servers/` | GET | `useTerminalSessions` | OK | | `/terminal/quick-commands` | GET/POST/PUT/DELETE | `useTerminalQuickCommands` | OK | | `/terminal/quick-commands/reorder` | PUT | `useTerminalQuickCommands` | OK | | WebSocket `/ws/terminal` | WS | 页内 | OK(RISK 已接受) | ### 2.4 FilesPage `/files` | 端点 | 方法 | Composable | 状态 | |------|------|------------|------| | `/files/browse` | GET | `useFilesBrowse`(首选) | OK | | `/sync/browse` | POST | `useFilesBrowse` 回退 | OK | | `/servers/{id}/files-capability` | GET | `useFilesPermissions` | OK | | `/servers/{id}/setup-files-sudo` | POST | `useFilesPermissions` | OK | | `/sync/read-file`、`write-file`、`file-ops`、`chmod`、`compress`、`decompress`、`file-clipboard`、`upload` | POST | `useFilesActions` 等 | OK | ### 2.5 PushPage `/push` | 端点 | 方法 | Composable | 状态 | |------|------|------------|------| | `/servers/` | GET | `usePushServers` | OK | | `/sync/preview` | POST | `usePushPreview` | OK | | `/sync/files` | POST | `usePushProgress` | OK | | `/sync/cancel` | POST | `usePushProgress` | OK | | `/servers/logs` | GET | `usePushLogs` | OK | | `/sync/reconcile-stale-logs` | POST | `usePushLogs` | OK | | `/sync/diagnose` | POST | `usePushLogs` | OK | | WebSocket `/ws/sync` | WS | `usePushProgress` | OK(RISK 已接受) | ### 2.6 ScriptsPage `/scripts` | 端点 | 方法 | 状态 | |------|------|------| | `/scripts/` | GET/POST/PUT/DELETE | OK | | `/scripts/exec` | POST | OK | | `/scripts/executions` | GET | OK | | `/scripts/executions/{id}` | GET | OK | | `/scripts/executions/{id}/stop` | POST | OK | ### 2.7 CredentialsPage `/credentials` | 端点 | 方法 | 状态 | |------|------|------| | `/presets/` | GET/POST/PUT/DELETE | OK;**username 新增** | | `/ssh-key-presets/` | GET/POST/PUT/DELETE | OK;**username 新增** | | `/scripts/credentials` | GET/POST/PUT/DELETE | OK | ### 2.8 SchedulesPage `/schedules` | 端点 | 方法 | 状态 | |------|------|------| | `/schedules/` | GET/POST/PUT/DELETE | OK | | `/sync/files` | POST(runNow) | OK | ### 2.9 RetriesPage `/retries` | 端点 | 方法 | 状态 | |------|------|------| | `/retries/` | GET | OK | | `/retries/{id}/retry` | POST | OK | | `/retries/{id}` | DELETE | OK | ### 2.10 CommandsPage `/commands` | 端点 | 方法 | 状态 | |------|------|------| | `/assets/command-logs` | GET | OK | | `/assets/ssh-sessions` | GET | OK | ### 2.11 AlertsPage `/alerts` | 端点 | 方法 | 状态 | |------|------|------| | `/alert-history/stats` | GET | OK | | `/alert-history/` | GET | OK | ### 2.12 AuditPage `/audit` | 端点 | 方法 | 状态 | |------|------|------| | `/audit/` | GET | OK | ### 2.13 SettingsPage `/settings` | 端点 | 方法 | 状态 | |------|------|------| | `/settings/` | GET | OK | | `/settings/{key}` | PUT | OK | | `/settings/telegram/test` | POST | OK | | `/settings/telegram/reveal-token` | POST | OK | | `/settings/api-key/reveal` | POST | OK | | `/settings/ip-allowlist` | GET/POST | OK | | `/settings/ip-allowlist/toggle` | POST | OK | | `/auth/password` | PUT | OK | | `/auth/totp/setup` | POST | OK | | `/auth/totp/enable` | POST | OK | | `/auth/totp/disable` | POST | OK | ### 2.14 LoginPage `/login` | 端点 | 方法 | 状态 | |------|------|------| | `/settings/bing-wallpapers` | GET | OK(公开只读) | | `/auth/login` | POST | `stores/auth`(非页内直接调) | OK | ### 2.15 全局(App / auth store) | 端点 | 方法 | 状态 | |------|------|------| | `/search/` | GET | `App.vue` | OK | | `/auth/me` | GET | `stores/auth` | OK | | `/auth/logout` | POST | `stores/auth` | OK | --- ## 3. 与 2026-06-04 closure 的差异 | 变更 | 说明 | |------|------| | ServersPage +4 端点 | 凭据轮询快速添加与失败队列 | | CredentialsPage 预设 | `username` 字段贯通 DB / API / UI | | `types/api.ts` | 新增 pending 相关类型 | | 功能指南 §12.2、§12.7 | 已更新 | | 附录 J | 新增凭据轮询专章 | 跨页 RISK(WS JWT、危险命令、bing 公开 GET)**无变化**,仍见 `risk-acceptance-single-operator.md`。 --- ## 4. 验证记录 ```bash .venv/bin/pytest tests/test_credential_poller.py -q # 7 passed cd frontend && npx vite build # OK ``` ```bash # 待环境恢复后 bash scripts/local_verify.sh cd frontend && NEXUS_E2E_BASE=http://127.0.0.1:8600 npm run test:e2e ``` --- ## 5. 后续建议 1. 生产部署前端构建物(`ServersPage` / `CredentialsPage` 新 UI)。 2. 可选 E2E:快速添加 IP → 失败列表 → 重试/删除。 3. `acceptance_catalog.py` 可增加 `add-by-ip` 条目(若纳入 L4 回归)。 **维护**: 改 API 时同步更新本报告对应行、附录 J、功能指南 §12。