Files
Nexus/CLAUDE.md
T
Your Name 0f02e047cc
Nexus CI/CD / test (push) Waiting to run
Nexus CI/CD / deploy (push) Blocked by required conditions
Nexus Pre-commit Checks / quick-check (push) Waiting to run
docs: update deployment instructions for Vuetify SPA
- Split backend/frontend deploy steps
- Add deploy-frontend.sh one-liner reference
- Document AppAuthMiddleware 404 and stale HTML troubleshooting
- Remove obsolete dist copy instructions

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 13:25:33 +08:00

279 lines
14 KiB
Markdown
Raw 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 — Project Memory
## 项目概述
Nexus 是一个 2000+ 服务器运维管理平台,从旧的 MultiSync (PHP + AdminLTE + pymysql) 完全重构为 Clean Architecture (FastAPI + Async SQLAlchemy + Redis + WebSocket + Telegram)。前端已全面迁移到 Tailwind CSS v4 + Alpine.jsPHP 依赖已移除。
## 仓库结构
- **唯一仓库**: Nexus (Gitea, 仓库地址在 .env 中配置)
- **不再使用** multi-server-sync 仓库(旧项目,仅保留历史)
- **部署路径**: 由 `NEXUS_DEPLOY_PATH` 环境变量决定(安装向导自动写入 .env)
- **域名/CORS**: 由 `NEXUS_CORS_ORIGINS` 环境变量决定(安装向导自动写入)
## 目录结构 (仓库根目录)
```
Nexus/
├── server/ ← Python FastAPI后端 (Clean Architecture 4层)
│ ├── api/ ← API路由 (含 install.py 安装向导API)
│ ├── domain/ ← SQLAlchemy模型 (14张表)
│ ├── infrastructure/← SSH连接池 + Redis + Telegram
│ ├── background/ ← 后台任务 (心跳刷新/自检/调度/重试)
│ └── config.py ← Pydantic Settings + MySQL覆盖
├── web/app/ ← Tailwind+Alpine.js 纯静态前端 (12个HTML页面)
│ ├── install.html ← 安装向导 (5步)
│ ├── login.html ← JWT登录+TOTP双因素
│ └── ... ← index/servers/files/push/scripts等
├── deploy/ ← Supervisor配置 + Shell健康检查脚本
├── docs/ ← 项目文档
├── tests/ ← 测试
├── .env ← NOT IN GIT (安装向导生成)
└── requirements.txt ← Python依赖
```
## 启动模式
- **安装模式** (无 .env): 仅 `/api/install/` + 静态文件可用,其他路由返回503
- **正常模式** (有 .env): 完整初始化 DB/Redis/后台任务
## 已确认的关键决策
| 决策 | 选择 | 原因 |
|------|------|------|
| API_KEY | ❌ 禁改,UI不显示 | 加密一致性 + 子服务器认证 |
| SECRET_KEY | ❌ 禁改 | 加密回退密钥 |
| DATABASE_URL | ❌ 禁改 | 启动必需 |
| system_name/title | ✅ 可改 | 前端显示 |
| pool_size/overflow | ✅ 可改 | 安装向导自动推荐 |
| redis_url | ✅ 可改 | Redis连接 |
| 告警阈值 (CPU/mem/disk) | ✅ 可改 | 监控参数 (默认80%) |
| Telegram配置 | ✅ 可改 | 告警推送 |
| Agent心跳间隔 | 60s | 不太频繁 |
| Redis→MySQL刷新 | 10min | 降低MySQL负载 |
| 心跳数据流 | Agent→Redis→前端直读→10min→MySQL | 前端实时, MySQL只存历史 |
| 告警推送 | WebSocket→前端 + Telegram | 即时感知 |
| Python守护 | 3层: Supervisor + Python自检(30s) + Shell(cron 1min) | 全覆盖 |
| 安装向导 | install.html + FastAPI API | 纯Python,无PHP依赖 |
| 配置源 | 安装向导→config.json+settings表(MySQL)+.env(Python) | 三写一致 |
| Agent告警心跳 | CPU/内存>80% 或变化>10% 时主动上报 | 智能监控 |
| 仓库统一 | 所有代码统一在Nexus仓库 | 不再用两个仓库 |
## 实现状态 (Phase A+B+C+D+E) — ~99% 完成
### ✅ 已完成 (全部6步 + 技术债务 + UX增强)
| 模块 | 文件 | 说明 |
|------|------|------|
| **Step 0: 基础设施** | | Redis + WebSocket |
| E1 WebSocket推送 | server/api/websocket.py | alert/recovery/system broadcast |
| E2 心跳→Redis+告警 | server/api/agent.py | Redis write + threshold detection |
| E3 Redis→MySQL刷新 | server/background/heartbeat_flush.py | 10min batch |
| **Step 1: 数据层** | | 14张表 |
| E4 load_settings_from_db | server/config.py | MySQL overrides mutable settings |
| **Step 2: 认证层** | | JWT + TOTP |
| **Step 3: Web SSH** | | asyncssh + xterm.js |
| E5 asyncssh连接池 | server/infrastructure/ssh/asyncssh_pool.py | 引用计数模式 |
| E6 WebSSH前端 | web/app/terminal.html | xterm.js + Koko协议 + 自动resize |
| **Step 4: Sync引擎** | | 4种同步模式 |
| **Step 5: 前端迁移** | | Tailwind+Alpine.js |
| E7 13个前端页面 | web/app/*.html | 含install.html安装向导 |
| E8 安装向导API | server/api/install.py | 6端点, 无JWT, 临时引擎 |
| E9 条件启动模式 | server/main.py | 无.env=安装模式 |
| **后台任务** | | |
| E10 Python自检 | server/background/self_monitor.py | 30s loop |
| E11 Telegram推送 | server/infrastructure/telegram/__init__.py | alert/recovery/system |
| E12 /health端点 | server/api/health.py | Shell health_monitor.sh checks this |
| **技术债务** | | |
| D1 ✅ paramiko删除 | — | pool.py已删除, 全部迁移asyncssh |
| D2 ✅ install迁移 | server/api/install.py | PHP→install.html+API |
| D3 ✅ WebSSH前端 | web/app/terminal.html | xterm.js+Koko协议+全屏 |
| **安全增强** | | |
| S1 JWT全局保护 | server/api/*.py | 所有业务API都有JWT验证 |
| S2 审计日志 | server/api/*.py | 所有CUD操作记录审计日志 |
| S3 登录防暴破 | server/application/services/auth_service.py | 失败计数+15min锁定+429状态码 |
| **前端UX增强** | | |
| UX1 共享布局 | web/app/layout.js | 11页面统一侧边栏+全局搜索+用户信息 |
| UX2 Toast通知 | web/app/api.js | 全局toast()函数,4种类型 |
| UX3 全局搜索 | server/api/search.py | 跨服务器/脚本/凭据/调度搜索 |
| UX4 服务器详情 | web/app/servers.html | 点击展开详情面板(系统信息/同步日志/SSH会话) |
| UX5 脚本编辑 | web/app/scripts.html | 点击脚本名编辑+执行结果格式化 |
| UX6 推送增强 | web/app/push.html | 逐服务器状态+进度条+推送历史 |
| UX7 审计分页 | web/app/audit.html | 分页控件+操作过滤+每页50条 |
| UX8 重试操作 | web/app/retries.html | 手动重试+删除按钮+状态过滤 |
| UX9 文件浏览 | web/app/files.html | 面包屑导航+目录排序+父目录链接 |
| UX10 登录安全 | web/app/login.html | 密码可见切换+失败计数+429锁定+shake动画 |
| **P1功能补全** | | |
| P1-1 资产管理 | web/app/assets.html | Platform/Node管理页面 |
| P1-2 服务器表单 | web/app/servers.html | 补全platform/node/protocols字段 |
| P1-3 Push对接 | web/app/push.html + sync_v2.py | target_path对接+统一SyncEngineV2 |
| P1-4 安全设置 | web/app/settings.html | TOTP QR码+修改密码+API Key复制 |
| P1-5 WebSSH授权 | server/api/webssh.py | SSH凭据验证+4003关闭码+审计 |
| P1-6 Agent认证 | server/api/agent.py | 每服务器API Key + 全局回退 |
| P1-7 Config去重 | server/application/services/sync_engine_v2.py | sed去重+备份+_rollback_config() |
| **P2安全增强** | | |
| P2-1 告警防抖 | server/api/websocket.py | 5分钟冷却+Telegram去重+恢复重置 |
| P2-2 命令日志 | web/app/commands.html | 命令/会话双视图+服务器过滤+危险命令高亮 |
| P2-3 DB分页 | server/infrastructure/database/server_repo.py | DB层offset/limit+count |
| P2-4 Dashboard实时 | web/app/index.html | WS触发stats刷新+声音+标签页闪烁 |
| P2-5 移动适配 | web/app/layout.js | <768px侧边栏overlay+backdrop+表格滚动 |
| P2-6 会话安全 | server/api/auth_jwt.py + api.js | 8小时超时+JWT updated_at+刷新重用检测 |
| P2-7 凭据加密 | server/api/servers.py | Server.password/ssh_key_private Fernet加密存储 |
| P2-8 凭据脱敏 | server/api/scripts.py + servers.py | API响应不返回密码,password_set布尔标记 |
| P2-9 DB备份 | deploy/db_backup.sh | mysqldump+30天保留+cron集成 |
| **P3运维增强** | | |
| P3-1 Nginx重定向 | deploy/nginx_https.conf | 注释化301规则:裸页面路径→/app/前缀 |
| P3-2 自定义404 | server/main.py | StarletteHTTPExceptionHandler返回空白HTML,隐藏FastAPI标识 |
### 🔄 待测试
- T1: 心跳Redis写入验证
- T2: WebSocket连接测试
- T3: 3层守护测试 (kill Python→Supervisor重启)
- T4: Telegram推送测试
- T5: install.html 5步流程测试
### 测试流程 (用户确认)
1. WSL本地基础测试 → 2. 推到仓库 → 3. 外网服务器正式测试
## 配置三写机制
安装向导 Step 3 POST处理同时写入:
1. `web/data/config.json` — 共享配置 (API_BASE_URL, DB_*, API_KEY)
2. `.env` — Python后端启动必需 (NEXUS_前缀)
3. `settings` MySQL表 — 共享动态配置 (api_key, thresholds, Telegram等)
不可改项 (SECRET_KEY/API_KEY/ENCRYPTION_KEY/DATABASE_URL) 不在MySQL覆盖映射中。
## 3层守护机制
- **Layer 1**: Supervisor — Python崩溃自动重启
- **Layer 2**: Python self_monitor — 每30s检查Redis/MySQL/WebSocket
- **Layer 3**: Shell health_monitor.sh — 每分钟HTTP GET /health, 连续3次失败→supervisorctl restart + Telegram
## 实现原则(强制 — 见 `.cursor/rules/perfect-implementation.mdc`
**所有设计和实现都必须是完美实现。**
- ❌ 不允许为了实现而实现 — 每一行代码必须有明确的目的和质量标准
- ❌ 不允许降级实现 — 不得以「先用着」为由降低安全、架构或代码质量标准
- ❌ 不允许妥协实现 — 不得在发现问题后选择绕过而非根治
- ❌ 不允许留技术债 — 发现问题必须当场修复,不得标注 TODO/FIXME 延后
- ✅ 无法完美实现时必须停下来与用户交流后再换方案,不得擅自从权
**文档纪律:**
- 新功能/架构变更:先写 `docs/design/specs/YYYY-MM-DD-*-design.md`,再写代码
- 开发前:写 `docs/design/plans/``docs/reports/` 技术文档(文件清单、步骤、测试、回滚)
- 项目缺文档的模块:改动时一并补全
- 每次修改:在 `docs/changelog/YYYY-MM-DD-*.md` 留 changelog
---
## 强制文件修改流程(不可跳步)
```
实现 → WSL本地验证 → ★审计8步★ → 部署 → 健康检查 → 浏览器验证 → changelog
```
**进度条(每次改代码必须输出,每完成一步打勾):**
```
□实现 □WSL验证 □审计8步 □部署 □健康检查 □浏览器验证 □changelog
```
用户只需看:没打勾的格子在打勾的格子后面 = 跳步了。
跳步 = 严重过程违规,用户说「你跳步了」必须立即停止并补完。
审计8步(我内部执行,用户不需要检查细节):登记→全文Read→规则扫描H→Closure表→入口表→输入→Sink→归类→DoD
审查4维度30项:安全12+逻辑8+性能5+质量5
三个铁律:每个文件都要审、每行代码都要看、每个结论都要有证据
**程序门控 v2(deploy 时自动检查 7 道,不过不让部署):**
| # | 门 | 检查内容 | 防什么 |
|---|----|---------|--------|
| 1 | Changelog门 | 文件存在 **且行数≥10** | 空壳changelog |
| 2 | Audit门 | 文件存在 **且含 Step3+Closure+DoD** | 空壳审计 |
| 3 | Test门 | test_api.py **必须存在**且通过 | 删测试绕过 |
| 4 | Lint门 | `ruff check server/` 零错误 | 代码质量问题 |
| 5 | Import门 | `import server.main` 成功 | 语法/导入错误 |
| 6 | Security门 | `bandit` 无 HIGH/MEDIUM | 安全反模式 |
| 7 | Review门 | 审计文件包含实际改动文件清单 | 假审查 |
门控脚本: `deploy/pre_deploy_check.sh`7门)
门控日志: `deploy/gate_log.jsonl`(每次检查自动追加记录)
MCP deploy 工具在 git pull + restart 前自动执行门控检查,任何一门不过返回 `🚫 DEPLOY BLOCKED`
MCP gate_log 工具可查看历史门控记录
审计模板: `docs/audit/TEMPLATE.md`
Lint配置: `ruff.toml`
开发依赖: `requirements-dev.txt`ruff, bandit, pytest
## 部署流程(SSH + SCP,不是 MCP deploy
**MCP deploy 不可用**GitHub 等 SaaS 的远程服务器 git pull 无凭据),实际部署用 SSH 命令直接操作:
### 后端部署
```bash
# 1. Push 本地到 Gitea
git push origin main
# 2. 服务器拉取最新代码 + 重启
ssh nexus "cd /www/wwwroot/api.synaglobal.vip && git fetch --all && git reset --hard origin/main && supervisorctl restart nexus"
# 3. 健康检查
ssh nexus "sleep 3 && curl -s http://127.0.0.1:8600/health"
# 预期: "ok"(纯文本,非 JSON
```
### 前端部署(Vuetify SPA
Vite 直接输出到 `web/app/`(后端 StaticFiles 挂载点),无需 dist 复制步骤:
```bash
# 一键部署脚本(构建+打包+上传+提取+重启+验证)
bash deploy/deploy-frontend.sh
# 或手动步骤:
cd frontend && npx vite build && cd ..
tar czf /tmp/nexus-frontend.tar.gz -C web/app index.html assets/
scp /tmp/nexus-frontend.tar.gz nexus:/tmp/nexus-frontend.tar.gz
ssh nexus "cd /www/wwwroot/api.synaglobal.vip/web/app && tar xzf /tmp/nexus-frontend.tar.gz && rm /tmp/nexus-frontend.tar.gz"
ssh nexus "supervisorctl restart nexus"
```
**注意**: 前端构建产物 (`web/app/index.html`, `web/app/assets/`) 已在 `.gitignore` 中,不进入 git。每次部署需重新构建+上传。
### 浏览器验证
```bash
curl -s -o /dev/null -w "%{http_code}" http://47.254.123.106:8600/app/ # 预期: 200
```
### 部署常遇问题
| 问题 | 解决 |
|------|------|
| `/app/` 返回 404 | AppAuthMiddleware 拦截 — 确认 `/app/``/app/index.html``_APP_PUBLIC_PATHS` 中 |
| `/app/` 返回旧 HTML (Tailwind/Alpine) | `git reset --hard` 恢复了旧文件 — 需要重新 tar+scp 前端构建产物 |
| MCP deploy → git pull 失败 `could not read Username` | 服务器 remote URL 没配 token,用 `git remote set-url` |
| Gate 2 Audit BLOCKED | 创建 `docs/audit/YYYY-MM-DD-topic.md`,含 Step3+Closure+DoD |
| Gate 3 Test BLOCKED (401) | 服务器 .env 中 `NEXUS_TEST_ADMIN_PASSWORD` 与数据库不一致 |
| Gate 6 Security BLOCKED (bandit HIGH) | md5 → sha256 等,参看 bandit 报告修复 |
| Gate 7 Review BLOCKED | 审计文件缺少实际改动文件清单 |
### 部署信息速查
- **部署用户**: root
- **部署目录**: `/www/wwwroot/api.synaglobal.vip/`
- **Supervisor 服务名**: `nexus`
- **Supervisor 配置**: `/www/server/panel/plugin/supervisor/etc/supervisor.conf`
- **SSH 别名**: `ssh nexus` (47.254.123.106, key: id_rsa_nexus)
- **后端端口**: 8600
- **Gitea Token SHA**: `26fee743a9332895b55f79b2dbe2e931dc7c2fe5` (nexus-deploy-token, write:repository)
**用户审查清单(验证AI是否偷懒):**
1.`deploy/gate_log.jsonl` — 每次门控都有记录,没有记录 = 没过门控
2. 看审计文件 — 必须有 Closure 表(每个H的判定+依据)、Step 3 规则扫描、DoD
3. 看进度条 — ☑必须在□前面,否则跳步
4. 看 changelog — 行数≥10,不能是空壳
## 数据流
```
Agent心跳(60s) → Redis(实时) → 前端直读 → 10min批量 → MySQL(历史)
告警: CPU/mem/disk > threshold → WebSocket推送浏览器 + Telegram推送手机
恢复: 之前告警的指标恢复正常 → 自动推送恢复通知
Redis心跳key: heartbeat:{server_id} (HSET, TTL=600s)
Redis告警key: alerts:{server_id} (SET, TTL=3600s)
```