Files
Nexus/docs/project/nexus-functional-development-guide.md
2026-07-08 22:31:31 +08:00

913 lines
33 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 行)。