# 开发规范 ## Git 工作流 ### 分支策略 | 分支 | 说明 | |------|------| | `main` / `master` | 生产分支,保护分支 | | `dev` | 开发集成分支 | | `feature/*` | 功能分支 | | `fix/*` | 修复分支 | | `hotfix/*` | 紧急修复 | ### 提交规范 ``` : - 变更点 1 - 变更点 2 ``` Type 列表: - `feat`: 新功能 - `fix`: Bug 修复 - `refactor`: 重构 - `docs`: 文档 - `style`: 样式 - `test`: 测试 - `chore`: 构建/工具 示例: ``` feat: 添加服务器批量导入功能 - 支持 Excel 导入 - 支持云平台同步 ``` ## 后端规范(Go) ### 目录职责 | 目录 | 职责 | |------|------| | `main.go` / `embed.go` | 应用入口 + 前端嵌入 | | `controller/` | HTTP 请求处理(参数校验、响应) | | `model/` | 数据模型定义 | | `config/` | 配置管理 (Viper) | | `middleware/` | JWT / 日志 / CORS 中间件 | | `router/` | 路由注册 | | `service/` / `repository/` | 业务逻辑 / 数据访问 | | `pkg/database/` | 数据库连接 + 显式基线建表能力 | | `pkg/agentcli/` | Agent CLI 引擎(ReAct + Evolver) | | `pkg/remoteexec/` | Go-native SSH 远程执行 | | `static/` | 前端 embed 静态资源 | ### 命名规范 - 文件名:`snake_case.go` - 类型/方法:`PascalCase` - 变量:`camelCase` - 常量:`PascalCase` 或 `ALL_CAPS` ### 统一响应格式 ```go // 成功响应 c.JSON(http.StatusOK, models.Response{ Code: 200, Message: "success", Data: result, }) // 分页响应 c.JSON(http.StatusOK, models.Response{ Code: 200, Message: "success", Data: models.ListResponse{ List: items, Total: total, }, }) // 错误响应 c.JSON(http.StatusBadRequest, models.Response{ Code: 400, Message: "参数错误: " + err.Error(), }) ``` ### Handler 模板 ```go func (h *ServerHandler) CreateServer(c *gin.Context) { // 1. 参数绑定 var req models.ServerRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: err.Error()}) return } // 2. 业务逻辑 server := models.Server{ Name: req.Name, IP: req.IP, } if err := h.db.Create(&server).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "创建失败"}) return } // 3. 返回结果 c.JSON(http.StatusOK, models.Response{Code: 200, Message: "创建成功", Data: server}) } ``` ### 注意事项 - GORM `First()` 连续查询会带上次 ID,用 `Take()` 代替 - Go 编译前设置 `GOPROXY=https://goproxy.cn,direct` - SQLite 需要 `CGO_ENABLED=1` - JWT 使用 `golang-jwt/jwt/v5`,`jwt.TimeFunc()` 已移除,用 `time.Now()` - 新增或修改代码注释末尾署名 `// Logan.Li` ## 前端规范(React + TypeScript) ### 目录职责 | 目录 | 职责 | |------|------| | `src/api/` | API 封装(按菜单域分子目录,`http.ts` 自动解包 `.data`) | | `src/pages/` | 复杂域级页面(多 Tab / 多子面板) | | `src/components/*/` | 可复用业务组件 | | `src/components/layout/` | PageShell / Sidebar / Header / ThemePicker | | `src/components/ui/` | shadcn/ui 基础组件 | | `src/locales/` | i18n 翻译文件(zh-CN.json / en-US.json) | | `src/i18n/` | i18next 初始化 | | `src/hooks/` | 自定义 Hooks | | `src/store/` | Zustand 状态管理 | | `src/types/` | TypeScript 类型(按域拆分) | | `src/utils/` | 主题 / 权限 / 导出等工具 | ### 命名规范 - 组件文件:`PascalCase.tsx`(如 `ServerManager.tsx`) - 工具文件:`camelCase.ts`(如 `formatDate.ts`) - 组件名:`PascalCase` ### PageShell 页面骨架 新页面优先使用 `PageShell` 统一布局: ```tsx import { PageShell } from '@/components/layout/PageShell'; import { useTranslation } from 'react-i18next'; export function MyPage() { const { t } = useTranslation(); return ( } actions={} toolbar={} tabs={[{ id: 'list', label: t('myModule.tabList') }]} activeTab="list" onTabChange={() => {}} variant="list" > {/* 页面内容 */} ); } ``` `variant` 取值:`default` | `list` | `config` | `workspace`。 ### 国际化 (i18n) - 框架:i18next + react-i18next - 语言:`zh-CN`(默认)/ `en-US` - 翻译文件:`src/locales/zh-CN.json` / `en-US.json` - 命名空间按模块划分:`common`、`menu`、`dashboard`、`server`、`alert`、`approval`、`audit`、`deploy`、`k8s` 等 新增文案规范: ```tsx // ✅ 使用翻译键 const { t } = useTranslation(); {t('server.batchImport')} // ❌ 禁止硬编码中文(已迁移模块) 批量导入 ``` 双语同步:修改 `zh-CN.json` 时必须同步更新 `en-US.json`。 ### UI 设计原则 - 能去掉的装饰都去掉(无边框、无多余分隔线) - 选中态用 `bg-surface-active`,不用彩色高亮 - 页面打开即用,不需要额外的"新建"按钮跳转 - 主题感知 — 使用 CSS 变量 `var(--dg-xxx)`,不硬编码颜色 - 按钮文案 2–4 字 - 禁止 `window.confirm()` / `alert()`,使用 `useConfirm()` + `toast` - Radix Dialog 必须包含 `` ### API 调用 前端通过 Vite 代理访问后端 API: ```typescript // 开发环境请求会被代理到 http://localhost:8080 // http.ts 已自动提取 Response.Data,列表返回 { list, total } import { getServers } from '@/api/server'; const { list, total } = await getServers({ page: 1 }); ``` ## 测试 ### 后端测试 ```bash cd backend go vet ./... go build -o aiops . ``` ### 前端构建测试 ```bash cd frontend npm run build npx tsc --noEmit # 类型检查(提交前零错误) npm run lint # ESLint(提交前零错误) ``` ### 独立二进制构建 ```bash ./run.sh build tag v1.5.0 ./aiops version ``` ### 集成测试 ```bash # 测试账号必须显式传入,避免对生产或共享环境误用默认凭证 AIOPS_TEST_USERNAME=admin AIOPS_TEST_PASSWORD='测试密码' \ python3 tests/integration_test.py --host localhost --port 8080 ``` ### GitHub Actions CI `.github/workflows/ci.yml` 在 `master` / `dev` 的推送与 Pull Request 上并行执行后端、Agent、前端和 SQLite + redka API 集成测试。前端 ESLint 采用阻断模式;仓库已有的 lint 错误会使 CI 失败,必须修复后才会恢复通过,不能以忽略错误的方式放行。 ## 日志 | 级别 | 使用场景 | |------|---------| | Info | 服务启动、正常操作 | | Warn | 配置缺失、降级处理 | | Error | 操作失败、异常 | | Fatal | 启动失败、不可恢复 | ```go log.Info("server started", zap.String("port", cfg.Port)) log.Error("database error", zap.Error(err)) ```