release: nexus btpanel session fix and app-v2

This commit is contained in:
Codex Release Bot
2026-07-08 22:31:31 +08:00
commit 1933f0af6e
2457 changed files with 350105 additions and 0 deletions
@@ -0,0 +1,912 @@
# Nexus 6.0 — 功能开发指南(SSOT
> **版本**: 2026-06-04
> **读者**: 接续开发工程师、AI Agent
> **定位**: 后续功能开发的**主参考文档**(比 handoff 更细、比 changelog 更稳)
> **关联**: [linux-dev-paths.md](linux-dev-paths.md) · [local-integration-test.md](local-integration-test.md) · [risk-acceptance-single-operator.md](risk-acceptance-single-operator.md)
---
## 目录
1. [项目概述](#1-项目概述)
2. [技术栈与仓库结构](#2-技术栈与仓库结构)
3. [启动模式与配置](#3-启动模式与配置)
4. [架构分层与请求生命周期](#4-架构分层与请求生命周期)
5. [认证、会话与安全](#5-认证会话与安全)
6. [数据模型(19 表)](#6-数据模型19-表)
7. [Redis 与实时数据流](#7-redis-与实时数据流)
8. [后台任务(Primary Worker](#8-后台任务primary-worker)
9. [后端 API 全览](#9-后端-api-全览)
10. [核心业务模块详解](#10-核心业务模块详解)
11. [前端 SPA 架构](#11-前端-spa-架构)
12. [15 个业务页面功能说明](#12-15-个业务页面功能说明)
13. [Composables 与状态管理](#13-composables-与状态管理)
14. [WebSocket 与 WebSSH](#14-websocket-与-webssh)
15. [Agent 与子机协议](#15-agent-与子机协议)
16. [安装向导](#16-安装向导)
17. [本地开发、测试与门控](#17-本地开发测试与门控)
18. [部署与运维](#18-部署与运维)
19. [扩展开发指南](#19-扩展开发指南)
20. [不可改项与已接受风险](#20-不可改项与已接受风险)
21. [文档索引](#21-文档索引)
---
## 1. 项目概述
Nexus 是面向 **2000+ 子服务器** 的运维管理平台(中心机 + Agent 架构),核心能力:
| 能力域 | 说明 |
|--------|------|
| **服务器资产** | CRUD、分类、Platform/Node、心跳监控、健康检查 |
| **文件管理** | SSH 远程浏览/编辑/chmod/压缩,sudo 提权 |
| **批量推送** | Nexus 主机 rsync → 子机,4 种 sync 模式,ZIP 上传,调度与重试 |
| **脚本执行** | 脚本库 + 临时命令,SSH 并行或 Agent 长任务 |
| **WebSSH** | 浏览器终端,多 Tab,命令日志 |
| **告警** | CPU/内存/磁盘阈值,WebSocket + Telegram,恢复通知 |
| **审计** | 全 CUD + 登录/WebSSH/推送 审计 |
| **安全** | JWT + TOTP + IP 白名单 + Fernet 凭据加密 |
**生产域名**: `https://api.synaglobal.vip`
**后端端口**: `8600`
**前端入口**: `/app/`Vue 3 SPAVite 构建到 `web/app/`
---
## 2. 技术栈与仓库结构
### 2.1 技术栈
| 层 | 技术 |
|----|------|
| 后端 | Python 3.11+ · FastAPI · Async SQLAlchemy · Pydantic v2 |
| 数据库 | MySQL 8.x |
| 缓存/实时 | Redis 7(心跳、告警、WS 跨 worker、脚本执行状态) |
| SSH | asyncssh 连接池 |
| 前端 | Vue 3 · TypeScript · Vuetify 4 · Pinia · Vite |
| 编辑器/终端 | Monaco Editor · xterm.js |
| 进程守护 | Supervisor + Python self_monitor + Shell health_monitor |
### 2.2 目录结构
```
Nexus/
├── server/ # FastAPI 后端(Clean Architecture
│ ├── main.py # 入口、lifespan、中间件、路由挂载
│ ├── config.py # Pydantic Settings + DB 覆盖
│ ├── api/ # 路由层(JWT、校验、审计)
│ ├── application/services/ # 业务编排
│ ├── domain/models/ # SQLAlchemy ORM19 表)
│ ├── infrastructure/ # DB/Redis/SSH/Telegram 实现
│ └── background/ # 后台循环任务
├── frontend/ # Vue 3 SPA 源码
│ └── src/
│ ├── pages/ # 14 个页面
│ ├── components/ # 按模块分子目录
│ ├── composables/ # 业务逻辑(files/push/terminal…)
│ ├── stores/ # Piniaauth、files
│ ├── api/index.ts # HTTP 客户端
│ └── router/index.ts # Hash 路由
├── web/app/ # 静态挂载点(index.html + assets/
│ └── install.html # 安装向导(独立静态页,非 Vue)
├── deploy/ # Supervisor、nginx、门控、部署脚本
├── docker/ # compose 环境生成
├── scripts/ # 本地 dev、验收、MCP
├── tests/ # pytest API 测试
└── docs/ # 设计、审计、changelog
```
### 2.3 架构分层(禁止跨层直连)
```
frontend/pages → api/index.ts → server/api/*.py
→ application/services/*.py
→ infrastructure/*
→ domain/models
```
- **API 层**: 路由 + Pydantic + `Depends(get_current_admin)`,不写裸 SQL
- **Service 层**: 业务编排,经 Repository 访问 DB
- **Infrastructure**: SSH 池、Redis、Telegram、Fernet
- **Domain**: ORM 模型,无 FastAPI 依赖
---
## 3. 启动模式与配置
### 3.1 两种启动模式
| 模式 | 条件 | 可用能力 |
|------|------|----------|
| **安装模式** | 仓库根无 `.env` | `/api/install/*``/app/install.html`、静态文件;其他 API **503** |
| **正常模式** | 存在 `.env``SECRET_KEY` / `API_KEY` / `ENCRYPTION_KEY` / `DATABASE_URL` 齐全 | 全功能 + 后台任务 |
`is_install_mode()`**运行时** 检测 `.env`,安装向导写入后可立即切换(需重启 worker 加载完整 lifespan)。
### 3.2 配置三写(安装向导 Step 3)
安装成功时**同时写入**
| 目标 | 内容 |
|------|------|
| `web/data/config.json` | 共享配置(API_BASE_URL、DB、API_KEY |
| `.env` | `NEXUS_*` 前缀,Python 启动必需 |
| MySQL `settings` 表 | 可热覆盖的动态项(阈值、Telegram、pool 等) |
**不可从 DB 覆盖**(仅 `.env`):`SECRET_KEY``API_KEY``ENCRYPTION_KEY``DATABASE_URL`
### 3.3 重要环境变量(`NEXUS_` 前缀)
| 变量 | 说明 | 可 DB 覆盖 |
|------|------|------------|
| `NEXUS_DATABASE_URL` | `mysql+aiomysql://...` | ❌ |
| `NEXUS_SECRET_KEY` | JWT HS256 | ❌ |
| `NEXUS_API_KEY` | Agent 全局密钥 | ❌ |
| `NEXUS_ENCRYPTION_KEY` | Fernet 凭据加密 | ❌ |
| `NEXUS_REDIS_URL` | 默认 `redis://127.0.0.1:6379/0` | ✅ |
| `NEXUS_API_BASE_URL` | 公网 URLAgent curl 安装) | ✅ |
| `NEXUS_CORS_ORIGINS` | 逗号分隔 | ✅ |
| `NEXUS_DEPLOY_PATH` | 部署根路径 | ✅ |
| `NEXUS_DB_POOL_SIZE` / `MAX_OVERFLOW` | 连接池 | ✅ |
| `NEXUS_CPU/MEM/DISK_ALERT_THRESHOLD` | 告警阈值 % | ✅ |
| `NEXUS_TELEGRAM_BOT_TOKEN` / `CHAT_ID` | 告警推送 | ✅ |
| `NEXUS_LOGIN_ALLOWLIST_*` | 登录 IP 白名单 | ✅ |
| `NEXUS_JWT_ACCESS_TOKEN_EXPIRE_MINUTES` | 默认 60 | ✅ |
| `NEXUS_TEST_ADMIN_PASSWORD` | 本地测试登录(不入 git) | — |
完整映射见 `server/config.py``DB_OVERRIDE_MAP`
---
## 4. 架构分层与请求生命周期
### 4.1 HTTP 请求(普通 API
```
Client → CORS → JwtAuthMiddleware → DbSessionMiddleware → Router
→ request.state.db
→ Service → Repo → MySQL
```
- **DbSessionMiddleware**: 每请求一个 `AsyncSession`,请求结束 close
- **例外**: WebSocket、`/api/install/` 自建 session
### 4.2 Primary Worker 锁
多 worker uvicorn 时,**仅一个** worker 运行后台任务:
1. Redis `SETNX nexus:primary_worker`TTL 30s,续期)
2. Redis 不可用时 fallback`flock /tmp/nexus-primary.lock`
后台任务列表见 [§8](#8-后台任务primary-worker)。
### 4.3 静态文件与 SPA
- FastAPI 挂载 `web/app/``/app/`
- Vue 使用 **Hash 路由** `#/servers`,刷新不依赖 nginx try_files
- 构建: `cd frontend && npx vite build` → 输出 `web/app/index.html` + `assets/`
---
## 5. 认证、会话与安全
### 5.1 管理端 JWT
| 项目 | 说明 |
|------|------|
| 登录 | `POST /api/auth/login`username + password + 可选 TOTP |
| Access Token | 响应 body**仅存内存**Pinia `auth.ts` |
| Refresh Token | HttpOnly Cookie `nexus_refresh``POST /api/auth/refresh` |
| 过期 | Access 默认 60min;前端过期前 5min 主动 refresh |
| 失效 | 改密/TOTP 变更 → `token_version` 递增,旧 JWT 失效 |
| 防暴破 | 5 次失败 / 15min → HTTP 429 |
| 会话空闲 | 8 小时(refresh 重用检测) |
**JWT 中间件公开前缀**(无需 Bearer:
`/api/auth/login` · `/api/auth/refresh` · `/api/auth/logout` · `/api/agent/` · `/api/install/` · `/api/settings/bing-wallpapers` · `/health` · `/ws/` · OpenAPI
### 5.2 TOTP
| API | 说明 |
|-----|------|
| `POST /api/auth/totp/setup` | 返回 QR + secret |
| `POST /api/auth/totp/enable` | 验证码确认 |
| `POST /api/auth/totp/disable` | 需当前密码 + TOTP |
### 5.3 敏感操作二次验证(Re-auth
| 场景 | API | 需当前密码 |
|------|-----|------------|
| 查看 API Key | `POST /api/settings/api-key/reveal` | ✅ |
| 查看 Telegram Token | `POST /api/settings/telegram/reveal-token` | ✅ |
| 查看 Agent Key | `POST /api/servers/{id}/agent-key` | ✅ |
| 生成安装命令 | `POST /api/servers/{id}/agent-install-cmd` | ✅ |
| 改密 | `PUT /api/auth/password` | ✅ |
### 5.4 Agent API Key
| 层级 | 行为 |
|------|------|
| Per-server | `servers.agent_api_key``nxs-*`),优先 |
| 全局回退 | `NEXUS_API_KEY`legacy,单人运维已接受) |
| 未知 server_id | **拒绝**batch 安装仍可能用 global key |
Header: `X-API-Key` 或 queryAgent 脚本约定)。
### 5.5 凭据存储
- `Server.password` / `ssh_key_private` → Fernet`ENCRYPTION_KEY`
- API 响应: `password_set: true`**不返明文**
- 密码预设: `encrypted_pw` 字段,前端 POST 后不入 localStorage
### 5.6 登录 IP 白名单
- `settings` + `.env`: `LOGIN_ALLOWLIST_ENABLED`
- 手动 IP + 订阅 URL 解析(`ip_allowlist_refresh` 每 2h
- 登录 API 在 JWT 之前校验客户端 IP
---
## 6. 数据模型(19 表)
定义文件: `server/domain/models/__init__.py`
| ORM | 表名 | 用途 | 关键字段 |
|-----|------|------|----------|
| `Platform` | `platforms` | 资产模板 | `name`, `category`, `default_protocols` |
| `Node` | `nodes` | 资产树节点 | `parent_id`, `sort_order` |
| `Server` | `servers` | 子服务器 | `domain`, `port`, SSH 凭据, `target_path`, `agent_api_key`, `is_online`, `system_info`, `files_elevation` |
| `SyncLog` | `sync_logs` | 推送历史 | `status`, `sync_mode`, 字节/文件统计, `operator` |
| `Admin` | `admins` | 管理员 | `password_hash`, `totp_*`, `token_version` |
| `LoginAttempt` | `login_attempts` | 登录尝试 | 防暴破 |
| `Setting` | `settings` | KV 配置 | `key` PK, `value` |
| `PasswordPreset` | `password_presets` | SSH 密码模板 | `encrypted_pw` |
| `SshKeyPreset` | `ssh_key_presets` | SSH 密钥模板 | `encrypted_private_key` |
| `PushSchedule` | `push_schedules` | 定时任务 | `cron_expr`, `server_ids`, `schedule_type` push/script |
| `PushRetryJob` | `push_retry_jobs` | 失败重试 | 指数退避, `max_retries=3` |
| `AuditLog` | `audit_logs` | 审计(**7 天**自动清理) | `action`, `target_*`, `ip_address` |
| `Script` | `scripts` | 脚本库 | `content`, `category` |
| `ScriptExecution` | `script_executions` | 执行记录 | `results` JSON, `status` |
| `DbCredential` | `db_credentials` | DB 凭据 | 脚本内 `$DB_*` 替换 |
| `AlertLog` | `alert_logs` | 告警历史(**7 天**自动清理) | `is_recovery` |
| `SshSession` | `ssh_sessions` | WebSSH 会话 | UUID `id` |
| `CommandLog` | `command_logs` | 终端命令 | `command` ≤2000 字符 |
| `QuickCommand` | `quick_commands` | 终端快捷命令 | `sort_order` |
---
## 7. Redis 与实时数据流
### 7.1 Key 约定
| Key 模式 | TTL | 内容 |
|----------|-----|------|
| `heartbeat:{server_id}` | 600s | 最新心跳字段(HSET |
| `alerts:{server_id}` | 3600s | 活跃告警集合 |
| `sync:cancel:{batch_id}` | — | 推送取消标记 |
| `nexus:alerts` | Pub/Sub | 跨 worker WS 广播 |
| `script:exec:{id}` | — | 脚本执行实时状态 |
| `nexus:primary_worker` | 30s | Primary 锁 |
### 7.2 心跳数据流
```
Agent(60s) → POST /api/agent/heartbeat
→ Redis 实时写入
→ 前端 Dashboard 读 APIoverlay Redis
→ 每 600s heartbeat_flush → MySQL servers 历史字段
→ 超阈值 → WebSocket alert + Telegram5min 防抖)
→ 恢复 → recovery 通知
```
---
## 8. 后台任务(Primary Worker
| 模块 | 间隔 | 文件 | 职责 |
|------|------|------|------|
| `heartbeat_flush` | 600s | `background/heartbeat_flush.py` | Redis → MySQL 心跳持久化 |
| `script_execution_flush` | 60s | `background/script_execution_flush.py` | 脚本状态 Redis → MySQLstuck 检测 |
| `self_monitor` | 30s | `background/self_monitor.py` | Redis/MySQL/WS 自检;Telegram |
| `schedule_runner` | 60s | `background/schedule_runner.py` | Cron/once 调度 → 推送或脚本 |
| `retry_runner` | 300s | `background/retry_runner.py` | `push_retry_jobs` SKIP LOCKED 重试 |
| `ip_allowlist_refresh` | 7200s | `background/ip_allowlist_refresh.py` | 订阅 URL 更新白名单 |
| `upload_staging_cleanup` | 3600s | `background/upload_staging_cleanup.py` | 清理 `/tmp/nexus_upload_*` >24h |
| `alert_log_purge` | 24h | `background/alert_log_purge.py` | 清理 `alert_logs` >7d |
| `audit_log_purge` | 24h | `background/audit_log_purge.py` | 清理 `audit_logs` >7d |
---
## 9. 后端 API 全览
### 9.1 认证 `/api/auth`
| 方法 | 路径 | 鉴权 |
|------|------|------|
| POST | `/login` | 公开 |
| POST | `/refresh` | Cookie |
| POST | `/logout` | 公开 |
| POST | `/totp/setup|enable|disable` | JWT |
| PUT | `/password` | JWT + re-auth |
| POST | `/webssh-token` | JWT |
| GET | `/me` | JWT |
### 9.2 Agent `/api/agent`
| 方法 | 路径 | 鉴权 |
|------|------|------|
| POST | `/heartbeat` | X-API-Key |
| POST | `/script-callback` | X-API-Key + job token |
### 9.3 服务器 `/api/servers`
CRUD、stats、categories、logs、CSV import/export、batch agent install/upgrade/uninstall、**batch detect-path**SSH 在 `/www/wwwroot` 下搜索 `crmeb` 目录写入 `target_path`)、health check、files-capability、setup-files-sudo、单台 agent 操作。
### 9.4 同步 `/api/sync``sync_v2.py`,核心)
| 分类 | 端点示例 |
|------|----------|
| 推送 | `POST /files`, `/preview`, `/cancel` |
| 远程文件 | `/browse`, `/file-ops`, `/read-file`, `/write-file`, `/chmod`, `/compress`… |
| 本机文件 | `/browse-local`, `/local-file-ops`, `/upload`, `/upload-zip` |
| 工具 | `/validate-source-path`, `/diagnose`, `/reconcile-stale-logs` |
### 9.5 文件浏览 `/api/files`
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/browse?server_id=&path=` | JWT + ETag 缓存 |
### 9.6 脚本 `/api/scripts`
脚本 CRUD、`POST /exec`、executions 停止/重试/stuck、DB 凭据 CRUD。
### 9.7 设置族 `/api/settings` + 子路由
| 路由器 | 前缀 | 内容 |
|--------|------|------|
| settings | `/api/settings` | 系统 KV、Telegram、IP 白名单、bing 壁纸 |
| schedule | `/api/schedules` | 调度 CRUD |
| preset | `/api/presets` | 密码预设 |
| ssh_key_preset | `/api/ssh-key-presets` | SSH 密钥预设 |
| alert_history | `/api/alert-history` | 告警列表/统计 |
| audit | `/api/audit` | 审计分页 |
| retry | `/api/retries` | 重试队列 |
### 9.8 其他
| 模块 | 前缀 | 说明 |
|------|------|------|
| assets | `/api/assets` | Platform/Node/ssh-sessions/command-logs |
| terminal | `/api/terminal` | 快捷命令 CRUD |
| search | `/api/search` | 全局搜索 |
| install | `/api/install` | 安装向导 |
| health | `/health`, `/health/detail` | 探活 |
### 9.9 WebSocket
| 路径 | Token | 用途 |
|------|-------|------|
| `/ws/alerts` | Access JWT | 告警/恢复/系统 |
| `/ws/sync` | Access JWT | 推送进度 |
| `/ws/terminal/{id}` | WebSSH JWT | 终端 Koko 协议 |
---
## 10. 核心业务模块详解
### 10.1 推送引擎 SyncEngineV2
文件: `server/application/services/sync_engine_v2.py`
| 概念 | 说明 |
|------|------|
| 执行位置 | **Nexus 中心机** 上执行 `rsync`SSH 到子机 |
| 并发 | `asyncio.Semaphore`,默认 max 10 |
| 超时 | rsync 300s + 30s grace |
| 认证 | sshpass -e(密码)或临时 key 文件 0600 |
| 失败 | 写 `sync_logs` + 可选 `push_retry_jobs` |
| 取消 | Redis `sync:cancel:{batch_id}` |
| 预览 | `rsync --dry-run --stats` |
**Sync 模式**`sync_mode`:
| 模式 | rsync 参数 | 行为 |
|------|------------|------|
| `incremental` | `-az` | 默认增量 |
| `full` | `-az --delete` | 删除目标多余文件 |
| `checksum` | `-az --checksum` | 校验和 |
| `overwrite` | `-az --inplace` | 原地覆盖 |
**源路径安全**: `resolve_nexus_push_source_path()` 禁止 `/etc` 等系统路径;ZIP 解压至 `UPLOAD_STAGING_PREFIX` 下暂存目录。
### 10.2 远程文件浏览
- `GET /api/files/browse``files_browse_service.list_remote_directory`
- 远程命令: `ls -la` + `shlex.quote(path)`
- ETag: 目录 mtime + 条目数,支持 `If-None-Match` → 304
- 前端: `useFilesStore` 内存缓存 + TTL
**Files elevation**`files_elevation` 字段):
| 值 | 行为 |
|----|------|
| `off` | 不 sudo |
| `auto` | 写失败时尝试 sudo |
| `always_sudo` | 始终 sudo |
`POST /api/servers/{id}/setup-files-sudo` 远程配置 sudoers(密码走 stdin)。
### 10.3 脚本执行
文件: `server/application/services/script_service.py`
| 模式 | 条件 | 路径 |
|------|------|------|
| SSH 短命令 | 超时内完成 | asyncssh 并行,Semaphore |
| Agent 长任务 | 超时 > 阈值 | nohup + callback URL + Redis 状态 |
- DB 凭据: 脚本内 `$DB_HOST` 等占位符替换
- 危险命令: `check_dangerous_command()` WARN 日志(不阻断)
- 停止: `POST /scripts/executions/{id}/stop`
### 10.4 服务器 Agent
| 操作 | API | 方式 |
|------|-----|------|
| 安装 | batch/single install | SSH curl agent 脚本 |
| 升级 | upgrade-agent | SSH 拉取 agent.py |
| 卸载 | uninstall-agent | SSH systemctl stop |
| 安装命令 | agent-install-cmd | 返回 curl**禁止**暴露 global API_KEY |
Agent 心跳 JSON 含 CPU/内存/磁盘/负载;变化 >10% 或超阈值时主动告警。
### 10.5 告警与 Telegram
- 阈值: `CPU/MEM/DISK_ALERT_THRESHOLD`(默认 80%
- 防抖: WebSocket 5minTelegram 同类型去重
- 恢复: 指标回落 → recovery 事件
- 推送完成: `send_telegram_sync_complete`
---
## 11. 前端 SPA 架构
### 11.1 构建与开发
| 项 | 值 |
|----|-----|
| 开发 | `cd frontend && npm run dev``http://localhost:3000/app/` |
| API 代理 | Vite proxy `/api``/ws``127.0.0.1:8600` |
| 构建输出 | `web/app/``base: '/app/'` |
| 路由 | Hash `#/path` |
### 11.2 入口链路
```
main.ts → App.vue(侧栏/搜索)→ router-view
→ pages/*.vue
→ composables → api/index.ts → /api/*
```
### 11.3 HTTP 客户端(`src/api/index.ts`
| 能力 | 实现 |
|------|------|
| Token | 内存 access JWT |
| 401 | 自动 refresh 一次 |
| 202 | `TotpRequiredError` |
| 429 | 锁定文案 |
| 304 | 文件 browse ETag |
| Upload | FormData 不设 JSON Content-Type |
### 11.4 Pinia Stores
| Store | 职责 |
|-------|------|
| `auth` | token、admin、login/logout/refresh |
| `files` | selectedServer、currentPath、browse 缓存 |
其余状态在 composable 或页面 `ref` 中。
---
## 12. 15 个业务页面功能说明
> 路由均位于 `#/` 下;除 Login 外需 JWT。
### 12.1 DashboardPage `/`
| 功能 | API/机制 |
|------|----------|
| 统计卡片 | `GET /servers/stats` |
| 服务器分页表 | `useServerPagination` |
| 告警摘要 | `GET /alert-history/?limit=5` |
| 资源概览 | 拉 200 台算 CPU/内存均值 |
| 分类分布 | stats.categories |
| 最近审计 | `GET /audit/?limit=10` |
| 实时刷新 | `useWebSocket` → 告警时 reload stats |
| 快捷跳转 | 终端/文件 `?server_id=` |
### 12.2 ServersPage `/servers`
| 功能 | API |
|------|-----|
| CRUD | `/servers/` |
| **快速添加(仅 IP** | `POST /servers/add-by-ip` — 轮询全部密码/SSH 预设;成功返回 `matched_preset` / `matched_username` |
| **连接失败列表** | `GET /servers/pending` |
| **失败重试 / 删除** | `POST /servers/pending/{id}/retry``DELETE /servers/pending/{id}` |
| 批量选择 | 安装/升级/卸载 Agent、**检测目标路径**、健康检查、删除 |
| **检测目标路径** | `POST /servers/batch/detect-path` — Body: `{ server_ids }`SSH 在 `/www/wwwroot` 下搜索 `crmeb` 目录写入 `target_path`;结果弹窗逐台展示 |
| **列表快捷编辑** | 目标路径列 ✏️ → `PUT /servers/{id}` `{ target_path }` |
| CSV 导出 | 客户端生成(无密码列) |
| CSV 导入 | `POST /servers/import` FormData |
| 详情面板 | 系统信息 + `GET /servers/{id}/logs` |
| 表单 | `ServerFormDialog` + `useServerFormDialog` |
详见附录 J(凭据轮询契约)。
### 12.3 TerminalPage `/terminal`
| 功能 | 说明 |
|------|------|
| 多 Tab | `useTerminalSessions` |
| WebSSH | `POST /auth/webssh-token``WS /ws/terminal/{id}?token=` |
| xterm | FitAddon、256 色 |
| 命令栏 | shell 高亮、`sendCmd`/`sendCtrl` |
| 快捷命令 | `GET /terminal/quick-commands` |
| 路由入参 | `#/terminal?server_id=123` 自动开 Tab |
| 清理 | `onBeforeUnmount``disposeAllSessions` |
### 12.4 FilesPage `/files`
薄编排页,逻辑在 composables
| 子模块 | 能力 |
|--------|------|
| Toolbar | 上传、刷新、上级目录 |
| List | 排序、多选、双击进目录 |
| Editor | Monaco`POST /sync/read-file|write-file` |
| 权限 | files-capability 检测、sudo 提示 |
| 热键 | 复制/粘贴/删除(`useFilesHotkeys` |
| 跨机传输 | 工具栏/右键跳转 `#/server-transfer`(见 §12.4.1 |
### 12.4.1 ServerTransferPage `/server-transfer`
| 能力 | 说明 |
|------|------|
| 源机浏览 | `POST /sync/browse`,多选 + 手动绝对路径 |
| 直传 | `POST /sync/server-transfer`(单文件 ≤500MB |
| 打包投递 | `POST /sync/server-transfer/deliver` + 可选解压 |
| 深链 | `?source=&path=&paths=` 自文件页预填 |
### 12.5 PushPage `/push`
| 功能 | API/WS |
|------|--------|
| 源/目标路径 | 表单校验 |
| ZIP 上传 | `POST /sync/upload-zip` |
| 服务器网格 | 分类全选 |
| 预览 | `POST /sync/preview` 并发 |
| 推送 | `POST /sync/files` + `/ws/sync` 进度 |
| 取消 | `POST /sync/cancel` |
| 历史 | sync_logs 分页、诊断、对账 |
### 12.6 ScriptsPage `/scripts`
| 功能 | API |
|------|-----|
| 脚本 CRUD | `GET/POST/PUT/DELETE /scripts/`(分类 ops/deploy/check/cleanup |
| Monaco 编辑 | `ScriptContentEditor` · `content` 字段 |
| 库内执行 | `POST /scripts/exec``script_id``command` 二选一) |
| 临时命令 | 页内 quick exec 面板 |
| 长任务 / DB 凭据 | `long_task``credential_id``GET /scripts/exec-config` |
| 提交执行 | `POST /scripts/exec` **立即返回** `running`(后台批次) |
| 全局进度 | `App.vue` + `useScriptExecutionQueue`WS `script_progress` / `script_complete` |
| 历史 | `GET /scripts/executions?script_id=` |
| 停止 / 重试 / 卡住 | `POST .../stop``.../retry``.../mark-stuck` |
### 12.7 ScriptRunsPage `/script-runs` · `/script-runs/:id`
| 功能 | API |
|------|-----|
| 执行看板列表 | `GET /scripts/executions`(状态筛选 running/completed/partial/failed |
| 单次明细 | `GET /scripts/executions/{id}` · 失败分组 · 复制清单 · 跳转终端 |
| 重试 / 停止 | 同 ScriptsPage |
| 入口 | 侧栏「脚本看板」;Telegram 深链 `#/script-runs/{id}` |
### 12.8 CredentialsPage `/credentials`
三 Tab:密码预设、SSH 密钥、DB 凭据;编辑时空密码表示不修改。
| Tab | API | 契约要点 |
|-----|-----|----------|
| 密码预设 | `GET/POST /presets/``PUT/DELETE /presets/{id}` | 字段 `name``username`(默认 `root`)、`encrypted_pw`;列表返回 `username` |
| SSH 密钥 | `GET/POST /ssh-key-presets/``PUT/DELETE /ssh-key-presets/{id}` | 同上 `username`;私钥 `private_key` 仅创建/更新时传 |
| DB 凭据 | `GET/POST /scripts/credentials``PUT/DELETE /scripts/credentials/{id}` | 脚本执行用 DB 连接,与 SSH 轮询无关 |
`username``credential_poller``add-by-ip` / retry 时与预设密码或私钥组合尝试 SSH。
### 12.9 SchedulesPage `/schedules`
| 功能 | API / 行为 |
|------|------------|
| 类型 | `schedule_type`: `push`rsync)或 `script`ScriptService |
| 运行模式 | `run_mode`: `cron`5 字段 cron_expr)或 `once`fire_at |
| 推送字段 | `source_path`(必填)、`target_path`(可选,留空走各机配置)、`sync_mode` |
| 脚本字段 | `script_id``script_content``exec_timeout``long_task` |
| 列表 | `next_run` API 计算;`GET /schedules/` |
| 立即执行 | push → `POST /sync/files`script → `POST /scripts/exec` |
| 后台 | `schedule_runner` 60s 扫描到期项 |
### 12.10 RetriesPage `/retries`
失败推送重试队列;`POST /retries/{id}/retry`
### 12.11 CommandsPage `/commands`
| 视图 | API | 筛选 |
|------|-----|------|
| 命令视图 | `GET /assets/command-logs` | server_id |
| 会话视图 | `GET /assets/ssh-sessions` | server_id |
| 推送日志 | `GET /servers/logs` | server_id、status、sync_mode、trigger_type |
### 12.12 AlertsPage `/alerts`
告警统计 + 分页;按 type/status 过滤。
### 12.13 AuditPage `/audit`
操作审计;action/user/date 过滤;`normalizeAuditList`
### 12.14 SettingsPage `/settings`
系统名/阈值/连接池、Telegram、改密、TOTP、API Key reveal、IP 白名单、终端快捷命令设置。
### 12.15 LoginPage `/login`
JWT 登录、TOTP、429 锁定、开放重定向防护(`//` 拒绝)、bing 壁纸背景。
---
## 13. Composables 与状态管理
### 13.1 模块索引
| 目录 | 入口 | 用途 |
|------|------|------|
| `composables/files/` | `useFilesPage` | 文件页总编排 |
| `composables/push/` | `usePushPage` | 推送页总编排 |
| `composables/terminal/` | `useTerminalSessions` | WebSSH 会话 |
| `composables/servers/` | `useServerFormDialog` | 服务器表单 |
| `composables/useWebSocket.ts` | — | 告警 WS |
| `composables/useServerPagination.ts` | — | 分页表 |
### 13.2 新增页面 Checklist
1. `frontend/src/pages/XxxPage.vue`
2. `router/index.ts` 注册路由
3. `App.vue` 侧栏 nav 项
4. `types/api.ts` 补充类型
5. 后端 API + 审计日志
6. E2E: `frontend/e2e/full-acceptance.spec.mjs`
---
## 14. WebSocket 与 WebSSH
### 14.1 告警 WS `/ws/alerts`
- 连接: `buildWebSocketUrl('/ws/alerts', { token: accessToken })`
- 消息类型: alert / recovery / system / **script_progress** / **script_complete**
- App.vue`useWebSocket` + `useScriptExecutionQueue`(全局进度条与完成 Alert
- WS 断线时队列 3s 轮询直至终态
### 14.2 推送 WS `/ws/sync`
- batch_id 维度进度
- `usePushProgress` 维护 per-server 状态
### 14.3 WebSSH
- 独立 JWT: `purpose=webssh`, `server_id`, 15min
- 绑定路径 server_id,防 IDOR
- Koko 消息: `TERMINAL_INIT`, `DATA`, `RESIZE`, `CLOSE`
- 命令日志: Enter 时写 `command_logs`
**已接受风险**: JWT 走 query stringADR-011),见 risk-acceptance 文档。
---
## 15. Agent 与子机协议
### 15.1 网络模型
| 方向 | 端口 | 用途 |
|------|------|------|
| 子机 → 中心 | 443 出站 | 心跳、script callback |
| 中心 → 子机 | 22 | 推送、文件、脚本、Agent 安装 |
| 子机本机 | 127.0.0.1:8601 | Agent HTTP(可选) |
### 15.2 心跳 Payload(摘要)
`server_id`, `cpu`, `memory`, `disk`, `load`, `uptime`, `agent_version`, `system_info`, ...
### 15.3 脚本回调
长任务完成后 Agent `POST /api/agent/script-callback`,携带 job id 与 per-server 结果。
---
## 16. 安装向导
| 步骤 | UI | API |
|------|-----|-----|
| 1 | 环境检查 | `GET /install/env-check` |
| 2 | MySQL/Redis 配置 | `POST /install/init-db` |
| 3 | 三写配置 | 同上(写 .env + config.json + settings |
| 4 | 创建管理员 | `POST /install/create-admin`install_token |
| 5 | 锁定 | `POST /install/lock` |
静态页: `web/app/install.html`Tailwind,非 Vue SPA)。
锁定后 `/install/status` → 404,防止信息泄露。
---
## 17. 本地开发、测试与门控
### 17.1 快速启动
```bash
# Docker MySQL + Redis
docker compose up -d mysql redis
# 生成 .env(若无)
python3 docker/generate_env.py && python3 docker/sync_root_env.py
# 启动 API
bash scripts/start-dev.sh # → http://127.0.0.1:8600
# 前端
cd frontend && npm run dev # → http://localhost:3000/app/
```
### 17.2 验证命令
| 级别 | 命令 |
|------|------|
| L2b | `bash scripts/local_verify.sh` |
| L2c | `.venv/bin/pytest tests/ -q` |
| L3 | `bash deploy/pre_deploy_check.sh` |
| L4 | `python3 scripts/run_nexus_acceptance.py --base http://127.0.0.1:8600 --with-ui` |
| E2E | `cd frontend && NEXUS_E2E_BASE=http://127.0.0.1:8600 npm run test:e2e` |
### 17.3 七道门控
`deploy/pre_deploy_check.sh`Changelog、Audit、Test、Ruff、Import、Bandit、Review。
---
## 18. 部署与运维
### 18.1 生产部署
```bash
git push origin main
bash deploy/pre_deploy_check.sh
bash deploy/deploy-production.sh
# 或手动: ssh nexus "cd $DEPLOY && git reset --hard origin/main && supervisorctl restart nexus"
# 前端: bash deploy/deploy-frontend.sh
```
### 18.2 三层守护
| 层 | 机制 |
|----|------|
| 1 | Supervisor 进程重启 |
| 2 | `self_monitor` 30s |
| 3 | `health_monitor.sh` cron 1min → 连续失败 restart + Telegram |
### 18.3 健康检查
- `GET /health` → 纯文本 `ok`
- `GET /health/detail` → JSON(需 JWT
---
## 19. 扩展开发指南
### 19.1 新增 REST API
1. 设计文档 `docs/design/specs/YYYY-MM-DD-*.md`
2. Service + Repository(若需)
3. `server/api/xxx.py` + `Depends(get_current_admin)`
4. `main.py` include_router
5. 审计: `AuditLog` 写入
6. `tests/test_api.py` 或专项测试
7. Changelog + 审计 8 步
### 19.2 新增前端功能
1. 明确页面 vs 对话框 vs composable 边界
2. 类型先进 `types/api.ts`
3. 错误用 `formatApiError` + snackbar**禁止静默吞错**
4. 敏感数据不进 localStorage
5. Playwright 抽测关键路径
### 19.3 新增后台任务
1. 仅 primary worker 注册(`main.py` lifespan
2. 循环内 try/except + logger,不可空 pass
3. 需可关闭(CancelledError
4. 文档 + changelog
### 19.4 数据库变更
1. 修改 `domain/models`
2. 启动时 `init_db` 或手写迁移 SQL(生产谨慎)
3. 不可破坏 `ENCRYPTION_KEY` 下已有密文
---
## 20. 不可改项与已接受风险
### 20.1 不可改(架构/安全一致性)
| 项 | 原因 |
|----|------|
| `API_KEY` | Agent 与加密回退一致 |
| `SECRET_KEY` | JWT 与已有 token |
| `ENCRYPTION_KEY` | 已加密凭据 |
| `DATABASE_URL` | 启动绑定 |
### 20.2 已接受风险(单人运维)
`docs/project/risk-acceptance-single-operator.md`
- WebSocket / WebSSH JWT 在 query
- Agent global API_KEY 回退
- 危险命令仅 WARN 不阻断
- dev docker-compose 默认密码
---
## 21. 文档索引
| 文档 | 用途 |
|------|------|
| **本文** | 功能开发 SSOT(架构 + 模块概览) |
| **[附录](nexus-functional-development-guide-appendix.md)** | API 字段表、Files/Push/Terminal 调用链、E2E/L4 对照、组件映射 |
| [AI-HANDOFF-2026-06-03.md](AI-HANDOFF-2026-06-03.md) | 会话接续 |
| [linux-dev-paths.md](linux-dev-paths.md) | Linux 路径 |
| [local-integration-test.md](local-integration-test.md) | 本地验收 |
| [script-execution.md](script-execution.md) | 脚本执行细节 |
| [alert-push-policy.md](alert-push-policy.md) | 告警策略 |
| [deploy.md](deploy.md) | 部署补充 |
| [development-acceptance-standard.md](development-acceptance-standard.md) | L0L5 验收 |
| `docs/design/specs/` | 新功能设计 |
| `docs/changelog/` | 每次变更记录 |
---
## 22. 详细参考(附录摘要)
完整查表见 **[nexus-functional-development-guide-appendix.md](nexus-functional-development-guide-appendix.md)**。
| 附录 | 内容 |
|------|------|
| **A** | `/api/sync` 全 21 端点 + Pydantic 字段 + WS 推送时序 |
| **B** | Files 页组件树、composable 依赖图、操作→API 映射 |
| **C** | Push 页 composable 与推送时序 |
| **D** | Terminal / WebSSH 调用链 |
| **E** | schedules/retries/audit/scripts/agent/search API 明细 |
| **F** | 15 页 ↔ composable ↔ 组件对照表 |
| **G** | L4 验收 + Playwright 15 用例对照 |
| **H** | HTTP 错误码与前端处理 |
| **I** | 扩展开发检查清单 |
---
**维护约定**: 新增模块或变更 API/页面时,**同步更新本文 + 附录对应章节** + changelog(≥10 行)。