# Nexus 设计标准

> 最后更新: 2026-05-22  
> 适用范围: 所有功能迭代、代码审查、安全审计

---

## 1. 安全模型：信任管理员 + 防注入/XSS

**核心理念: 认证管理员是可信用户，但必须防御注入攻击和 XSS。**

运维管理后台的认证管理员即为可信用户，应用层不对操作内容做业务限制。
但必须防御技术层面的攻击向量（命令注入、路径注入、XSS）。

**依据**:
- 使用者均为经过认证的运维管理员
- 绕过应用层限制的门槛极低（SSH 直连即可）
- 应用层业务限制增加维护成本，假安全感大于实际安全收益
- 但技术层面注入攻击是真实风险，必须防御

**实施要求**:
- 所有 API 端点必须校验 JWT 令牌（`Depends(get_current_admin)`）
- WebSocket 连接必须通过 JWT 查询参数认证（ADR-011）
- Agent 通信使用 X-API-Key 认证
- Shell 命令参数必须 `shlex.quote()` 防注入
- 前端禁止在模板字面量中直接输出用户内容（防 XSS）
- 数据库凭据加密存储（Fernet + AES-CBC）

**不做的事**:
- ❌ 不在应用层限制上传文件类型
- ❌ 不在应用层限制文件写入目标路径
- ❌ 不在应用层限制执行命令的业务内容
- ❌ 不做 RBAC 权限体系（保持"鉴权即信任"）
- ❌ 不做会话录像（asciicast）

---

## 2. 配置存储

| 层 | 存储 | 用途 |
|----|------|------|
| 热层 | Redis | 心跳、缓存、告警去重、Pub/Sub (TTL 管理) |
| 持久层 | MySQL | 服务器、日志、设置、审计 |
| 文件 | `.env` | 启动必需: DB连接、SECRET_KEY、API_KEY |

**配置加载优先级**: `.env` (启动) → MySQL settings 表 (动态覆盖)

**原则**: 可热配项走 MySQL settings（`load_settings_from_db` 启动时加载），不可热配项走 `.env`。

**不可改配置** (`.env` only):
- SECRET_KEY, API_KEY, ENCRYPTION_KEY, DATABASE_URL

**可改配置** (MySQL settings 可覆盖):
- system_name/title, pool_size/overflow, redis_url, 告警阈值, Telegram 配置

---

## 3. 性能基线

| 指标 | 值 |
|------|-----|
| API 安全并发 | ≤50 |
| P50 延迟 | <60ms |
| P95 延迟 | <300ms |
| 最大文件上传 | 500MB |
| sync_logs 保留 | 30 天 |
| 心跳批量刷到 MySQL | 每 10min |
| SSH 连接池 | 最大 100 连接，空闲 5min 关闭 |

---

## 4. 代码规范

### Python 后端

- 所有 API 路由使用 Pydantic 模型验证请求体（`server/api/schemas.py`）
- 所有 API 路由使用 JWT 认证（`Depends(get_current_admin)`）
- Shell 命令参数必须 `shlex.quote()` 防注入
- DB session 由 DbSessionMiddleware 自动管理，通过 `request.state.db` 共享
- Service 层通过依赖注入获取 Repository 实例（`server/api/dependencies.py`）
- 加密使用 Fernet (Python) + AES-CBC (PHP 兼容)，密钥统一从 API_KEY/SECRET_KEY 派生
- Redis 操作使用 `redis.asyncio`，连接池为 `BlockingConnectionPool`

### 前端 (Tailwind + Alpine.js)

- 所有页面引入 `api.js` 共享模块（JWT 自动刷新、apiFetch 封装）
- JWT 令牌存储在 localStorage，自动刷新（2分钟内到期触发）
- 所有 API 调用使用 `apiFetch()` 自动附带 Authorization 头
- CORS 由 `NEXUS_CORS_ORIGINS` 环境变量配置
- 侧边栏和导航在所有页面保持一致

---

## 5. 测试标准

**收尾前必修**: 部署完成后必须用浏览器直接访问页面验证核心流程。curl / API 测试不能替代浏览器验收。

**检查清单**:
- [ ] 登录 → 仪表盘正常加载（含 WebSocket 实时更新）
- [ ] 核心页面可交互（点击、表单提交有响应）
- [ ] 浏览器 Console 无报错
- [ ] 浏览器 Network 面板无 404/500
- [ ] JWT 令牌自动刷新正常

---

## 6. 架构模式

### 后台任务

| 任务 | 间隔 | 文件 |
|------|------|------|
| heartbeat_flush | 10min | `server/background/heartbeat_flush.py` |
| self_monitor | 30s | `server/background/self_monitor.py` |
| schedule_runner | 60s | `server/background/schedule_runner.py` |
| retry_runner | 5min | `server/background/retry_runner.py` |
| asyncssh_cleanup | 60s | `server/infrastructure/ssh/asyncssh_pool.py` |

所有后台任务使用 `asyncio.create_task()` 在 `lifespan` 中启动，支持优雅关闭。

### SSH 连接池

引用计数模式 (ADR-004):
- `ssh_pool.acquire(server)` → 获取/创建连接，ref_count +1
- `ssh_pool.release(server_id)` → ref_count -1，空闲连接保留复用
- 清理循环每 60s 扫描，空闲 >5min 的连接自动关闭

### WebSocket 两层架构 (ADR-010)

- Layer 1: 内存 `ConnectionManager` 管理本 worker 的 WebSocket 连接
- Layer 2: Redis Pub/Sub `nexus:alerts` 频道中继跨 worker 消息
- Ping/pong 心跳 30s，僵尸连接 60s 清理

---

## 7. 不做清单（永久）

- ❌ RBAC 权限体系 (保持"鉴权即信任")
- ❌ 会话录像 asciicast (不需要)
- ❌ 移动端适配 (运维不会用手机管理服务器)
- ❌ MQTT 协议 (HTTP+Redis 足够 2000 台)
- ❌ 文件差异比较
- ❌ 图片/PDF 预览
- ❌ 推送结果邮件报告
