Files
aiops/CLAUDE.md
T
attacker 77c33a6fee feat: 服务器批量导入全栈实现 + SQL审计模型修复 + 审批流程增强
服务器批量导入:
- 后端 BatchCreateServers handler: 逐条校验/查重/GB→MB转换/错误明细
- 前端 CSV 解析器 + IP校验 + 模板下载 + 真实API导入
- 删除孤立占位组件 BatchImport.tsx

SQL审计:
- 修复 TableName 字段与 GORM 接口冲突 → TargetTable
- 补全路由注册 + AutoMigrate + 种子数据

审批流程增强 + 告警/菜单微调

// Logan.Li
2026-06-15 02:12:05 +08:00

314 lines
12 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.
# CLAUDE.md — EZOps AIOps
本文档为 Claude Code / Hermes 等 AI 编程助手提供在代码库中工作的指导说明。
> 作者:Logan.Li
> 语言:中文(代码注释和文档主要使用中文,注释署名 `// Logan.Li`)
## 项目概述
**EZOps AIOps** 是一个企业级智能运维平台,聚焦三大核心能力:
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 (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 分钟无数据上报即告警,不需配置规则)
- **端口告警** — 监控端口消失
## 开发规范
### ⛔ 文件大小红线
| 类型 | 上限 | 超出处理 |
|------|------|----------|
| Go handler | **400 行** | 按 sub-domain 拆分到独立文件(同一 package) |
| Go model | **300 行** | 按模块拆分 |
| React 组件 (.tsx) | **700 行** | 提取子组件到同目录 |
| 任何文件 | **700 行(硬上限)** | 必须拆分 |
```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. **编译命令**(每次必须):
```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/
```
3. **新增 handler 不绑 model** — 用独立 request struct 接收 `ShouldBindJSON`,再映射到 GORM model
4. **GORM 指针字段必须解引用** — model 中 `*int`/`*string` 字段传给 `fmt.Sprintf` 时先 `*field`
5. **SQLite 必须 CGO_ENABLED=1**(macOS 默认开)
### ⛔ React 前端规范
1. **API 列表响应解包** — 后端返回 `{code, data: {list: T[], total: N}}`,http.ts 提取 `.data` 后仍是 `{list, total}` 对象,组件中必须 `.list` 提取数组
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` 加菜单)
### ⛔ UI 设计原则
- **能去掉的都去掉** — 不要多余边框、高亮框、装饰性分隔线
- **按钮文案 2-4 字** — "批量导入" 而非 "批量导入用户"
- **不留占位按钮** — 功能没做好就不放按钮,不要 `toast.info('开发中')`
- **页面打开即用** — 不需要额外"新建"按钮跳转
- **主题感知** — 用 CSS 变量 `bg-[var(--dg-bg-secondary)]`,不用硬编码颜色
- **表单操作按钮在字段下方** — 用 `mt-4 pt-4 border-t` 分隔,不放 Card 标题右侧
- **主动排查同类问题** — 用户报一个 UI 问题,全局搜索同类一次性修复
### ⛔ 通用开发流程
```
分析需求 → 写代码 → go build + tsc --noEmit → ./run.sh restart → 浏览器验证 → git commit + push
```
- **修改前端后必须在浏览器实际测试**,不能只说"刷新试试"
- **提交前编译验证**:后端 `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 用户 |
⚠️ **生产环境请修改默认密码**
## 主题系统
5 套预设主题(CSS 变量驱动):
| Key | 名称 | 场景 |
|-----|------|------|
| `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`
## 常见陷阱速查
| # | 陷阱 | 解决 |
|---|------|------|
| Go1 | go build 超时 | `unset proxy + GOPROXY=goproxy.cn + GOTOOLCHAIN=local` |
| Go2 | handler 不包裹 Response | 必须 `models.Response{Code:200, Data:...}` |
| Go3 | GORM 指针字段 | `*field` 解引用后再用 |
| 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` 类型问题 |
## 注释规范
新增或修改代码必须写中文注释,注释结尾署名 `// Logan.Li`。
```go
// ListServers 获取服务器列表 // Logan.Li
func (h *ServerHandler) ListServers(c *gin.Context) {
// 业务逻辑
}
```
## 远程仓库
```
https://gitee.com/attacker/aiops.git
Git 用户: attacker / attacker@gitee.com
```