feat: 服务器批量导入全栈实现 + SQL审计模型修复 + 审批流程增强
服务器批量导入: - 后端 BatchCreateServers handler: 逐条校验/查重/GB→MB转换/错误明细 - 前端 CSV 解析器 + IP校验 + 模板下载 + 真实API导入 - 删除孤立占位组件 BatchImport.tsx SQL审计: - 修复 TableName 字段与 GORM 接口冲突 → TargetTable - 补全路由注册 + AutoMigrate + 种子数据 审批流程增强 + 告警/菜单微调 // Logan.Li
This commit is contained in:
1 parent
6545597412
commit
77c33a6fee
16 files changed
+863
-573
No files matched your search
@@ -1,28 +1,194 @@
|
||||
# EZOps AIOps — AI 开发全局规范
|
||||
# CLAUDE.md — EZOps AIOps
|
||||
|
||||
> 本文件供 AI 编程助手(Claude/Cursor/Copilot/Hermes)自动读取并遵循。
|
||||
> 定义项目架构约束、代码规范、拆分策略和开发流程。
|
||||
> 作者: Logan.Li · 语言: 中文(代码注释中文 + 署名 `// Logan.Li`)
|
||||
本文档为 Claude Code / Hermes 等 AI 编程助手提供在代码库中工作的指导说明。
|
||||
|
||||
> 作者:Logan.Li
|
||||
> 语言:中文(代码注释和文档主要使用中文,注释署名 `// Logan.Li`)
|
||||
|
||||
## 项目概述
|
||||
|
||||
**EZOps AIOps** — AI 智能运维平台,涵盖 13 大模块:
|
||||
服务器管理 · 云资源(账号/域名/账单) · K8s 集群 · 监控告警(Agent) · CI/CD 流水线 ·
|
||||
自动化运维(CronJob/Script/Ansible) · 审批流程 · AI 智能运维(告警分析/故障诊断/预测/脚本生成) ·
|
||||
导航收藏 · 审计日志 · 系统管理(用户/LDAP) · 监控 Agent(双通道: 指标采集+远程命令)
|
||||
**EZOps AIOps** 是一个企业级智能运维平台,聚焦三大核心能力:
|
||||
|
||||
- **远程仓库**: https://gitee.com/attacker/aiops.git
|
||||
- **Git 用户**: attacker / attacker@gitee.com
|
||||
1. **资产管理** — 服务器管理、云资源(云账号/域名/账单)、K8s 集群
|
||||
2. **监控告警** — Agent 采集指标、告警引擎(资源阈值/离线检测)、告警中心、日志能力、链路追踪、监控大屏
|
||||
3. **自动化运维 / AIOps** — CronJob/Script/Ansible 自动化、资源申请审批、AI 智能运维(告警分析/故障诊断/脚本生成)
|
||||
|
||||
### 核心特性
|
||||
|
||||
- **Agent 双通道** — 指标采集通道(10s 上报 `/proc`)+ 远程任务通道(5s 轮询执行命令)
|
||||
- **LDAP 集成** — 配置管理、用户导入、OU 管理、LDAP 用户 CRUD
|
||||
- **资源申请审批** — 云服务器申请、应用部署申请(Git 地址/端口/Nacos 等配置),动态表单
|
||||
- **5 套主题** — CSS 变量驱动,暗色/亮色/紫色/绿色/玫红一键切换
|
||||
- **WebShell** — WebSocket 终端,在线 SSH 操作服务器
|
||||
|
||||
## 技术栈
|
||||
|
||||
| 层 | 技术 | 端口 |
|
||||
|---|---|---|
|
||||
| 后端 | Go 1.21 + Gin + GORM + SQLite (+ MySQL/PG 可选) + JWT + Zap | 8080 |
|
||||
| 后端 | Go 1.21 + Gin + GORM + SQLite (CGO) + JWT + Zap | 8080 |
|
||||
| 前端 | React 19 + TypeScript + Vite + Tailwind + shadcn/ui + Zustand + TanStack Query | 5173 |
|
||||
| Agent | Go 1.24 (CGO_ENABLED=0 静态二进制, amd64+arm64) | — |
|
||||
|
||||
## 核心规则
|
||||
## 常用命令
|
||||
|
||||
### 快速启动
|
||||
|
||||
```bash
|
||||
./run.sh start # 启动前后端
|
||||
./run.sh stop # 停止服务
|
||||
./run.sh restart # 重启服务
|
||||
./run.sh status # 查看服务状态
|
||||
./run.sh logs # 查看实时日志
|
||||
```
|
||||
|
||||
### 后端 (backend/)
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
|
||||
# 编译(每次修改后端必须执行)
|
||||
unset http_proxy https_proxy && export GOPROXY=https://goproxy.cn,direct && GOTOOLCHAIN=local CGO_ENABLED=1 go build -o aiops-server ./cmd/
|
||||
|
||||
# 直接运行
|
||||
go run ./cmd/
|
||||
|
||||
# 代码检查
|
||||
go vet ./...
|
||||
```
|
||||
|
||||
### 前端 (frontend/)
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm run dev # 开发服务器 (端口 5173)
|
||||
npm run build # 生产构建
|
||||
npx tsc --noEmit # 类型检查(提交前必须零错误)
|
||||
```
|
||||
|
||||
### Agent (agent/)
|
||||
|
||||
```bash
|
||||
cd agent
|
||||
|
||||
# 本地构建(macOS 测试用)
|
||||
CGO_ENABLED=0 go build -o aiops-agent .
|
||||
|
||||
# 交叉编译
|
||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o aiops-agent-linux-amd64 .
|
||||
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o aiops-agent-linux-arm64 .
|
||||
|
||||
# 运行 Agent
|
||||
./aiops-agent --server http://localhost:8080 --token <JWT_TOKEN>
|
||||
```
|
||||
|
||||
## 架构说明
|
||||
|
||||
### 项目结构
|
||||
|
||||
```
|
||||
aiops/
|
||||
├── backend/
|
||||
│ ├── cmd/
|
||||
│ │ ├── main.go # 应用入口
|
||||
│ │ └── seed.go # 种子数据(用户/角色/审批模板/LDAP配置)
|
||||
│ ├── internal/
|
||||
│ │ ├── config/config.go # Viper 配置
|
||||
│ │ ├── models/ # GORM 模型(每模块独立文件)
|
||||
│ │ └── api/
|
||||
│ │ ├── handlers/ # HTTP handler(按模块拆分,每文件 <400 行)
|
||||
│ │ ├── middleware/auth.go # JWT + Admin 中间件
|
||||
│ │ └── routes/routes.go # 路由注册
|
||||
│ ├── pkg/database/database.go # DB 连接 + AutoMigrate
|
||||
│ └── scripts/mock.go # Mock 种子(已废弃)
|
||||
│
|
||||
├── frontend/
|
||||
│ ├── src/
|
||||
│ │ ├── components/
|
||||
│ │ │ ├── dashboard/ # 仪表盘(统计/图表/最近活动)
|
||||
│ │ │ ├── server/ # 服务器管理
|
||||
│ │ │ ├── cloud/ # 云资源管理
|
||||
│ │ │ ├── k8s/ # K8s 集群管理
|
||||
│ │ │ ├── deploy/ # 应用发布(CI/CD 流水线)
|
||||
│ │ │ ├── monitor/ # 监控告警(指标/告警中心/日志/大屏/Agent告警)
|
||||
│ │ │ ├── automation/ # 自动化运维(CronJob/Script/Ansible)
|
||||
│ │ │ ├── approval/ # 资源申请审批
|
||||
│ │ │ ├── aiops/ # AI 智能运维
|
||||
│ │ │ ├── system/ # 系统管理(用户/LDAP/审计)
|
||||
│ │ │ ├── navigation/ # 站内导航
|
||||
│ │ │ └── layout/ # 布局(Sidebar/Header)
|
||||
│ │ ├── services/
|
||||
│ │ │ ├── api.ts # API 定义(按模块分组)
|
||||
│ │ │ └── http.ts # Axios 封装(拦截器自动注入 Token)
|
||||
│ │ ├── store/ # Zustand 状态管理
|
||||
│ │ ├── hooks/ # React hooks(useConfirm 等)
|
||||
│ │ └── types/index.ts # 全局类型
|
||||
│ └── App.tsx # 路由 + 顶层 Provider
|
||||
│
|
||||
├── agent/ # 监控 Agent(独立 Go module)
|
||||
│ ├── main.go # CLI 入口
|
||||
│ ├── collector/ # /proc 采集器(CPU/内存/磁盘/端口)
|
||||
│ ├── task/ # 远程任务执行器(command/script)
|
||||
│ ├── reporter/http.go # HTTP 上报
|
||||
│ └── model/model.go # 数据结构
|
||||
│
|
||||
└── run.sh # 一键启动脚本
|
||||
```
|
||||
|
||||
### 后端分层
|
||||
|
||||
```
|
||||
handlers/ (HTTP 处理) → models/ (GORM 数据操作)
|
||||
↓
|
||||
middleware/auth.go (JWT 验证)
|
||||
```
|
||||
|
||||
**新增模块 4 步**:
|
||||
1. `models/xxx.go` — 定义 GORM 模型
|
||||
2. `handlers/xxx.go` — 实现 handler(所有返回必须用 `models.Response{Code:200}` 包裹)
|
||||
3. `routes/routes.go` — 注册路由
|
||||
4. `pkg/database/database.go` — 添加 AutoMigrate
|
||||
|
||||
### API 响应格式
|
||||
|
||||
```go
|
||||
// 统一响应(所有 handler 必须遵循)
|
||||
type Response struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
// 列表响应(Data 内层)
|
||||
type ListResponse struct {
|
||||
List interface{} `json:"list"`
|
||||
Total int64 `json:"total"`
|
||||
}
|
||||
```
|
||||
|
||||
**前端 http.ts 已自动提取 `.data`**,所以组件中拿到的是 `Response.Data`。列表 API 返回 `{list, total}`,组件中需 `.list` 提取数组。
|
||||
|
||||
### 认证流程
|
||||
|
||||
```
|
||||
Login(本地/LDAP fallback) → JWT Token → 前端 Zustand persist 存储
|
||||
→ http.ts 自动注入 Bearer → JWTAuth 中间件验证 → AdminAuth 中间件(管理类路由)
|
||||
```
|
||||
|
||||
### Agent 双通道架构
|
||||
|
||||
```
|
||||
指标通道: ticker(10s) → collect(/proc) → POST /agent/report
|
||||
任务通道: ticker(5s) → GET /agent/tasks/poll → execute → POST /agent/tasks/:id/result
|
||||
```
|
||||
|
||||
### 告警引擎
|
||||
|
||||
- 内嵌后端 cron 定时器,每分钟扫描 AgentReport
|
||||
- **资源阈值告警** — CPU/内存/磁盘超阈值(需配置规则)
|
||||
- **主机离线告警** — 内置检测(3 分钟无数据上报即告警,不需配置规则)
|
||||
- **端口告警** — 监控端口消失
|
||||
|
||||
## 开发规范
|
||||
|
||||
### ⛔ 文件大小红线
|
||||
|
||||
@@ -30,31 +196,30 @@
|
||||
|------|------|----------|
|
||||
| Go handler | **400 行** | 按 sub-domain 拆分到独立文件(同一 package) |
|
||||
| Go model | **300 行** | 按模块拆分 |
|
||||
| React 组件 (.tsx) | **700 行** | 提取子组件到同目录,主组件负责编排 |
|
||||
| TypeScript 工具/服务 | **500 行** | 按功能域拆分 |
|
||||
| 任何文件 | **700 行(硬上限)** | 必须拆分,无例外 |
|
||||
| React 组件 (.tsx) | **700 行** | 提取子组件到同目录 |
|
||||
| 任何文件 | **700 行(硬上限)** | 必须拆分 |
|
||||
|
||||
**拆分策略**:
|
||||
- **Go**: 同 package 下按职责拆文件(如 `automation.go` → `automation_cron.go` + `automation_script.go` + `automation_playbook.go`),共享 struct 放原文件或新建 `automation_types.go`
|
||||
- **React**: 子组件提取到同目录独立 `.tsx` 文件(如 `SystemManager.tsx` → `SystemManager.tsx` + `SystemUserTab.tsx` + `SystemLdapTab.tsx`),通过 props 传递数据和回调
|
||||
- **Mock 数据**: 按模块拆分(如 `data.ts` → `data/servers.ts` + `data/cloud.ts` + `data/k8s.ts` + `index.ts` 汇总导出)
|
||||
```bash
|
||||
# 检查超限文件
|
||||
find backend -name "*.go" -not -path "*/vendor/*" | xargs wc -l | awk '$1 > 400 && $2 != "total"'
|
||||
find frontend/src -name "*.tsx" -o -name "*.ts" | xargs wc -l | awk '$1 > 700 && $2 != "total"'
|
||||
```
|
||||
|
||||
### ⛔ Go 代码规范
|
||||
|
||||
1. **所有 handler 返回必须用 `models.Response{Code:200, Data:...}` 包裹** — 前端 `http.ts` 从 `json.data` 取值,裸 `gin.H{}` 会导致前端拿到 undefined 静默失败
|
||||
2. **Go 编译命令**(每次必须):
|
||||
2. **编译命令**(每次必须):
|
||||
```bash
|
||||
cd ~/devops/aiops/backend && unset http_proxy https_proxy && export GOPROXY=https://goproxy.cn,direct && GOTOOLCHAIN=local CGO_ENABLED=1 go build -o aiops-server ./cmd/
|
||||
cd backend && unset http_proxy https_proxy && export GOPROXY=https://goproxy.cn,direct && GOTOOLCHAIN=local CGO_ENABLED=1 go build -o aiops-server ./cmd/
|
||||
```
|
||||
3. **新增 handler 不绑 model** — 用独立 request struct 接收 `ShouldBindJSON`,再映射到 GORM model
|
||||
4. **GORM 指针字段必须解引用** — model 中 `*int`/`*string` 字段传给 `fmt.Sprintf` 时先 `*field`
|
||||
5. **SQLite 必须 CGO_ENABLED=1**(macOS 默认开)
|
||||
6. **新模块 4 步**: Model → Handler → Routes(routes.go 注册) → AutoMigrate(database.go 添加)
|
||||
|
||||
### ⛔ React 前端规范
|
||||
|
||||
1. **API 列表响应解包** — 后端返回 `{code, data: {list: T[], total: N}}`,http.ts 提取 `.data` 后仍是 `{list, total}` 对象,组件中必须 `.list` 提取数组
|
||||
2. **禁止 `window.confirm()`/`alert()`** — 用 `ConfirmProvider`(`useConfirm()` hook)替代 confirm,用 `toast.error()`/`toast.success()` 替代 alert
|
||||
2. **禁止 `window.confirm()`/`alert()`** — 用 `ConfirmProvider`(`useConfirm()` hook)替代,用 `toast.error()`/`toast.success()` 替代 alert
|
||||
3. **Radix Dialog 必须有 `<DialogDescription>`** — 至少加 `<DialogDescription className="sr-only">`
|
||||
4. **Token 不在 localStorage** — 用 `useUserStore.getState().token`(Zustand persist)
|
||||
5. **新增组件 2 步**: API 层(`services/api.ts` 添加) → 组件+路由(`App.tsx` 加 Route,`Sidebar.tsx` 加菜单)
|
||||
@@ -78,77 +243,41 @@
|
||||
- **修改前端后必须在浏览器实际测试**,不能只说"刷新试试"
|
||||
- **提交前编译验证**:后端 `go build ./...`,前端 `npx tsc --noEmit && npm run build`
|
||||
- **Git 提交**: `git add -A && git commit -m "feat: 描述" && git push origin master`
|
||||
- **大变更前先 git commit** — 方便回滚
|
||||
- **开发日志**: 每次开发后更新 `docs/dev-log.md`
|
||||
|
||||
## 架构约束
|
||||
## 默认账号
|
||||
|
||||
### 目录结构(核心部分)
|
||||
| 用户名 | 密码 | 角色 |
|
||||
|--------|------|------|
|
||||
| admin | 123456 | 超级管理员 |
|
||||
| ops01 | 123456 | 运维 |
|
||||
| dev01 | 123456 | 开发 |
|
||||
| logan | zxc987 | LDAP 用户 |
|
||||
|
||||
```
|
||||
backend/
|
||||
├── cmd/main.go + seed.go # 入口 + 种子数据
|
||||
├── internal/
|
||||
│ ├── config/config.go # Viper 配置
|
||||
│ ├── models/ # GORM 模型(每模块独立文件)
|
||||
│ └── api/
|
||||
│ ├── handlers/ # HTTP handler(按模块拆分,每文件 <400 行)
|
||||
│ ├── middleware/auth.go # JWT + Admin 中间件
|
||||
│ └── routes/routes.go # 路由注册
|
||||
├── pkg/database/database.go # DB 连接 + AutoMigrate
|
||||
└── scripts/mock.go # Mock 种子
|
||||
⚠️ **生产环境请修改默认密码**
|
||||
|
||||
frontend/
|
||||
├── src/
|
||||
│ ├── components/{模块}/ # 页面组件(每文件 <700 行,超出拆子组件)
|
||||
│ ├── services/{api.ts, http.ts} # API 服务层
|
||||
│ ├── store/ # Zustand 状态管理
|
||||
│ ├── hooks/ # React hooks
|
||||
│ └── types/index.ts # 全局类型定义
|
||||
├── App.tsx # 路由 + 顶层 Provider
|
||||
## 主题系统
|
||||
|
||||
agent/ # 监控 Agent(独立 Go module)
|
||||
├── main.go # CLI 入口
|
||||
├── collector/ # /proc 采集器
|
||||
├── task/ # 远程任务执行器
|
||||
└── reporter/http.go # HTTP 上报
|
||||
```
|
||||
5 套预设主题(CSS 变量驱动):
|
||||
|
||||
### API 响应格式
|
||||
| Key | 名称 | 场景 |
|
||||
|-----|------|------|
|
||||
| `ocean-deep` | 深海蓝(默认) | 暗色主界面 |
|
||||
| `light-professional` | 专业亮色 | 亮色模式 |
|
||||
| `midnight-purple` | 午夜紫 | 个性化 |
|
||||
| `forest-green` | 森林绿 | 个性化 |
|
||||
| `dark-rose` | 暗夜玫红 | 个性化 |
|
||||
|
||||
```go
|
||||
// 统一响应(所有 handler 必须遵循)
|
||||
type Response struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
// 列表响应(Data 内层)
|
||||
type ListResponse struct {
|
||||
List interface{} `json:"list"`
|
||||
Total int64 `json:"total"`
|
||||
}
|
||||
```
|
||||
|
||||
### 认证流程
|
||||
|
||||
```
|
||||
Login(本地/LDAP fallback) → JWT Token → 前端 Zustand persist 存储 → http.ts 自动注入 Bearer
|
||||
→ JWTAuth 中间件验证 → 需 admin 权限的路由额外 AdminAuth 中间件
|
||||
```
|
||||
|
||||
### Agent 双通道架构
|
||||
|
||||
```
|
||||
指标通道: ticker(10s) → collect(/proc) → POST /agent/report
|
||||
任务通道: ticker(5s) → GET /agent/tasks/poll → execute → POST /agent/tasks/:id/result
|
||||
```
|
||||
|
||||
### 主题系统
|
||||
|
||||
5 套主题(CSS 变量驱动): `ocean-deep`(默认暗色) · `light-professional`(亮色) · `midnight-purple` · `forest-green` · `dark-rose`
|
||||
所有组件必须用 `var(--dg-xxx)` 变量,禁止硬编码颜色值。
|
||||
|
||||
## 访问地址
|
||||
|
||||
- 前端:`http://localhost:5173`
|
||||
- 后端:`http://localhost:8080`
|
||||
- 健康检查:`http://localhost:8080/health`
|
||||
- Agent 下载:`http://localhost:8080/agent/arch`
|
||||
|
||||
## 常见陷阱速查
|
||||
|
||||
| # | 陷阱 | 解决 |
|
||||
@@ -156,17 +285,29 @@ Login(本地/LDAP fallback) → JWT Token → 前端 Zustand persist 存储 →
|
||||
| Go1 | go build 超时 | `unset proxy + GOPROXY=goproxy.cn + GOTOOLCHAIN=local` |
|
||||
| Go2 | handler 不包裹 Response | 必须 `models.Response{Code:200, Data:...}` |
|
||||
| Go3 | GORM 指针字段 | `*field` 解引用后再用 |
|
||||
| Go4 | mock.go 重运行 | UNIQUE constraint → 用 API 注入新数据 |
|
||||
| Go4 | GORM First() 连续查带上次 ID | 用 `Take()` |
|
||||
| Go5 | go map literal 不能有 duplicate key | 检查重复键 |
|
||||
| FE1 | 白屏无堆栈 | 90% 是列表 `{list,total}` 未解包 |
|
||||
| FE2 | confirm() 冻结自动化 | 用 `useConfirm()` |
|
||||
| FE3 | Token 获取 | `useUserStore.getState().token`,不是 localStorage |
|
||||
| FE4 | Radix Dialog 警告 | 必须有 `<DialogDescription>` |
|
||||
| FE5 | browser_click 不触发 toggle | 改用 `browser_console` 注入 `.click()` |
|
||||
| FE6 | API 字段名不匹配 | 前端 `base_dn` vs 后端 `ou_dn` 类型问题 |
|
||||
|
||||
## 文件大小监控
|
||||
## 注释规范
|
||||
|
||||
```bash
|
||||
# 检查超限文件(CI 检查脚本)
|
||||
find backend -name "*.go" -not -path "*/vendor/*" | xargs wc -l | awk '$1 > 400 && $2 != "total"'
|
||||
find frontend/src -name "*.tsx" -o -name "*.ts" | xargs wc -l | awk '$1 > 700 && $2 != "total"'
|
||||
新增或修改代码必须写中文注释,注释结尾署名 `// Logan.Li`。
|
||||
|
||||
```go
|
||||
// ListServers 获取服务器列表 // Logan.Li
|
||||
func (h *ServerHandler) ListServers(c *gin.Context) {
|
||||
// 业务逻辑
|
||||
}
|
||||
```
|
||||
|
||||
## 远程仓库
|
||||
|
||||
```
|
||||
https://gitee.com/attacker/aiops.git
|
||||
Git 用户: attacker / attacker@gitee.com
|
||||
```
|
||||
Reference in new issue
Block a user