服务器批量导入: - 后端 BatchCreateServers handler: 逐条校验/查重/GB→MB转换/错误明细 - 前端 CSV 解析器 + IP校验 + 模板下载 + 真实API导入 - 删除孤立占位组件 BatchImport.tsx SQL审计: - 修复 TableName 字段与 GORM 接口冲突 → TargetTable - 补全路由注册 + AutoMigrate + 种子数据 审批流程增强 + 告警/菜单微调 // Logan.Li
12 KiB
12 KiB
CLAUDE.md — EZOps AIOps
本文档为 Claude Code / Hermes 等 AI 编程助手提供在代码库中工作的指导说明。
作者:Logan.Li 语言:中文(代码注释和文档主要使用中文,注释署名
// Logan.Li)
项目概述
EZOps AIOps 是一个企业级智能运维平台,聚焦三大核心能力:
- 资产管理 — 服务器管理、云资源(云账号/域名/账单)、K8s 集群
- 监控告警 — Agent 采集指标、告警引擎(资源阈值/离线检测)、告警中心、日志能力、链路追踪、监控大屏
- 自动化运维 / 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) | — |
常用命令
快速启动
./run.sh start # 启动前后端
./run.sh stop # 停止服务
./run.sh restart # 重启服务
./run.sh status # 查看服务状态
./run.sh logs # 查看实时日志
后端 (backend/)
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/)
cd frontend
npm run dev # 开发服务器 (端口 5173)
npm run build # 生产构建
npx tsc --noEmit # 类型检查(提交前必须零错误)
Agent (agent/)
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 步:
models/xxx.go— 定义 GORM 模型handlers/xxx.go— 实现 handler(所有返回必须用models.Response{Code:200}包裹)routes/routes.go— 注册路由pkg/database/database.go— 添加 AutoMigrate
API 响应格式
// 统一响应(所有 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 行(硬上限) | 必须拆分 |
# 检查超限文件
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 代码规范
- 所有 handler 返回必须用
models.Response{Code:200, Data:...}包裹 — 前端http.ts从json.data取值,裸gin.H{}会导致前端拿到 undefined 静默失败 - 编译命令(每次必须):
cd backend && unset http_proxy https_proxy && export GOPROXY=https://goproxy.cn,direct && GOTOOLCHAIN=local CGO_ENABLED=1 go build -o aiops-server ./cmd/ - 新增 handler 不绑 model — 用独立 request struct 接收
ShouldBindJSON,再映射到 GORM model - GORM 指针字段必须解引用 — model 中
*int/*string字段传给fmt.Sprintf时先*field - SQLite 必须 CGO_ENABLED=1(macOS 默认开)
⛔ React 前端规范
- API 列表响应解包 — 后端返回
{code, data: {list: T[], total: N}},http.ts 提取.data后仍是{list, total}对象,组件中必须.list提取数组 - 禁止
window.confirm()/alert()— 用ConfirmProvider(useConfirm()hook)替代,用toast.error()/toast.success()替代 alert - Radix Dialog 必须有
<DialogDescription>— 至少加<DialogDescription className="sr-only"> - Token 不在 localStorage — 用
useUserStore.getState().token(Zustand persist) - 新增组件 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。
// ListServers 获取服务器列表 // Logan.Li
func (h *ServerHandler) ListServers(c *gin.Context) {
// 业务逻辑
}
远程仓库
https://gitee.com/attacker/aiops.git
Git 用户: attacker / attacker@gitee.com