MineDock MVP 控制台
- -{{ output }}
- diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 67bd750..499292e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,9 +29,12 @@ jobs: - name: Install frontend dependencies run: task frontend:install - - name: Check Go fmt + - name: Run formatting checks run: task fmt + - name: Run lint checks + run: task lint + - name: Run Go tests run: task test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b9a6a83..0bbee86 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,6 +33,12 @@ jobs: - name: Install frontend dependencies run: task frontend:install + - name: Run frontend format checks + run: task frontend:fmt + + - name: Run frontend lint checks + run: task frontend:lint + - name: Build frontend once run: task frontend:build diff --git a/.gitignore b/.gitignore index 2b3ce74..991a266 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ .github/agents/ +.github/prompts/ +.agent/ \ No newline at end of file diff --git a/Taskfile.yml b/Taskfile.yml index 0137858..fdc0a24 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -58,6 +58,18 @@ tasks: cmds: - npm run build + frontend:lint: + desc: Run frontend ESLint checks + dir: frontend + cmds: + - npm run lint + + frontend:fmt: + desc: Run frontend Prettier format checks + dir: frontend + cmds: + - npm run format:check + dev: desc: Run backend and frontend dev servers in parallel deps: @@ -79,6 +91,12 @@ tasks: desc: Run global formatting checks deps: - backend:fmt + - frontend:fmt + + lint: + desc: Run global lint checks + deps: + - frontend:lint vet: desc: Run global vet checks diff --git a/docs/00_Root_Context.md b/docs/00_Root_Context.md index 10744fd..8f98311 100644 --- a/docs/00_Root_Context.md +++ b/docs/00_Root_Context.md @@ -1,45 +1,67 @@ # MineDock Root Context -## 1. 项目核心定义与最终目标 -MineDock 是一个用于管理本地 Docker 容器实例的最小可行系统。 -当前阶段目标是:跑通一个测试容器的“创建”与“销毁”完整流程,并提供最基本的列表查询能力。 +## 1. 说明 +MineDock 是一个用于管理 Docker 容器实例的系统 -## 2. 全局系统边界 -- 后端仅实现对本地 Docker 引擎的调用。 -- 当前阶段使用 SQLite 持久化实例基础状态(container_id、name、status)。 -- 前端提供实例生命周期四段交互动作: - - 获取列表 - - 创建(仅创建容器,不自动启动) - - 开启(启动已创建容器) - - 关闭(停止运行中容器) - - 删除(彻底删除已停止容器) -- 暂不处理 Cgroups 内存限制与跨环境一致性问题。 -- 直接使用现成公开镜像进行流程验证。 +## 2. 目标 +实现一个支持易配置,功能强的游戏服务器容器化管理平台 -## 3. 全局命名与契约约定 -- HTTP 接口统一挂载在 `/api` 前缀下。 -- 资源命名采用复数形式:`/api/instances`。 -- JSON 字段命名采用 snake_case(如 `container_id`)。 -- 实例状态字段 `status` 的业务值遵循: - - `Running` - - `Stopped` +## 3. 当前系统边界 +### 所有权边界 +#### 边界内 +- 本系统创建的容器 +- 本系统的数据库及其数据 +- 本系统的工作目录及容器挂载配置的数据卷目录 +#### 边界外 +- 非本系统创建的容器 +- 宿主机的其他进程 +- 除上述工作与挂载目录外的其他宿主机文件系统 +### 功能边界 +#### 边界内 +- 容器的生命周期管理与资源配额调度 +- 容器内游戏服务器的快速安装与运行 +- 在线终端交互与控制指令下发 +- 游戏数据的持久化与灾灾备 (快照、备份与回档) +#### 边界外 +- 游戏服务端程序本身的更新与热修复 +### 数据边界 +#### 边界内 +- Docker SDK返回的运行时信息 +- 容器的标准输出日志流 +- 容器的端口暴露配置 +#### 边界外 +- Docker Daemon的集群状态 +- 主机底层的网络状态(如防火墙配置) +### 用户边界 +#### 边界内 +- 单管理员环境结构下的全局容器管控 +#### 边界外 +- 复杂的多租户资源隔离与细粒度角色控制 (RBAC) -## 4. 顶层目录架构规范 +## 4. 目录规范 +```text MineDock/ -├── docs/ # 架构与文档 -├── backend/ # Go 后端代码 -│ ├── main.go # 程序入口 -│ └── internal/ # 内部包 -│ ├── api/ # 路由 -│ ├── model/ # 数据结构定义 -│ ├── service/ # 业务逻辑 -│ ├── store/ # 内存状态管理 -│ └── utils/ # 工具函数 -└── frontend/ # 前端代码 - └── src/ - ├── api/ # HTTP 请求封装 - ├── components/ # UI 组件 - ├── composables/ # 组合式函数 - ├── stores/ # 状态管理 - ├── locales/ # i18n 语言文件 - └── assets/ # 静态资源 +├── backend/ # 后端 Go 服务 +│ ├── data/ # 数据存储目录(如 SQLite 数据库文件) +│ ├── internal/ # 内部私有代码 +│ │ ├── api/ # 路由与 HTTP 处理层 (Handlers, Routers) +│ │ ├── model/ # 领域数据模型定义实体 (如 Instance) +│ │ ├── service/ # 核心业务逻辑服务 (如调用 Docker CLI/SDK) +│ │ └── store/ # 数据持久化/存储交互层 +│ ├── main.go # 后端程序入口 +│ └── go.mod # Go 依赖配置 +├── frontend/ # 前端 Vue 项目 +│ ├── src/ +│ │ ├── api/ # 统一管理后端接口定义与请求封装 +│ │ ├── components/ # 全局复用组件(非全局使用的应当就近存放业务内) +│ │ ├── composables/ # 复用的组合式 API (如 useInstances) +│ │ ├── locales/ # 多语言 i18n 配置文件 +│ │ ├── router/ # 路由配置与全局路由守卫 +│ │ ├── stores/ # 全局跨组件状态管理 (Pinia) +│ │ └── views/ # 路由级别的业务页面组件 +│ ├── package.json # Npm 依赖配置 +│ └── vite.config.js # Vite 构建配置 +├── docs/ # 相关架构规范与领域文档 +├── Taskfile.yml # 自动化任务构建配置 +└── Readme.md # 项目文档与入口 +``` diff --git a/docs/01_Backend_Standards.md b/docs/01_Backend_Standards.md new file mode 100644 index 0000000..fca6c3a --- /dev/null +++ b/docs/01_Backend_Standards.md @@ -0,0 +1,21 @@ +# 后端规范 + +后端基于以下核心选型构建: +- **开发语言**:Go +- **持久化存储**:SQLite +- **核心依赖**:Docker SDK + +## 架构依赖规则 +为保证代码的可测试性与可维护性,`internal` 目录下的四层架构必须遵循单向依赖规则,严禁循环引用: +- **`api` 层**:作为程序的入口与防腐层,负责依赖注入 `service`,并处理 HTTP 相关的解析与返回。 +- **`service` 层**:作为纯粹的业务中枢,内部调用 `store` 进行持久化获取或通过外部组件交互。 +- **`store` 层**:负责底层数据落地设计(如 SQLite 语句),对外暴露 Interface 或直接的数据操作方法。 +- **`model` 层**:最为底层,被上述三层共同引用,不应依赖 `api`/`service`/`store` 的任何代码。 + +## 编码质量与规范 +- **代码格式化与校验**:`go fmt` 与 `go vet` +- **错误处理**: + - 核心逻辑层要求显式返回 `error`,并在合适的网络层封装为统一规范的 JSON HTTP 响应体(如 `{"status": "error", "message": "..."}`)。 + - 透传错误时,应使用 `%w` (如 `fmt.Errorf("操作容器失败: %w", err)`)保留错误堆栈及上下文。 +- **Panic 处理**:业务处理流程中严禁主动触发 `panic`。仅系统引导阶段(如 SQLite 数据源加载失败、配置文件解析失败等无法提供服务的场景)被允许 `panic` +- **无状态设计**:作为管理平台,除了 `store` 与外部环境,`api` 层与 `service` 层应保持无状态,以防发生状态数据不一致的异常 diff --git a/docs/01_Frontend_Standards.md b/docs/01_Frontend_Standards.md new file mode 100644 index 0000000..d963cbc --- /dev/null +++ b/docs/01_Frontend_Standards.md @@ -0,0 +1,25 @@ +# 前端规范 + +前端基于以下核心选型构建: +- **构建工具**:Vite +- **核心框架**:Vue 3 (Composition API) +- **开发语言**: TypeScript +- **状态管理**:Pinia +- **路由控制**:Vue Router + +## 代码质量 +- **代码格式化与校验**: 使用 ESLint + Prettier + +## 模块化与主题化 +前端 UI 必须具备高度的模块化,以支持动态主题(如浅色/暗色模式切换)和未来可能的皮肤更换 +- **禁止硬编码样式**:所有颜色、间距、字体大小必须使用 CSS 变量引入 +- **变量分层**: + - 基础变量:如 `--blue-500`, `--gray-900` + - 语义变量:如 `--bg-primary`, `--text-danger`, `--border-color` +- **主题切换实现**:通过动态修改 `` 或 `
` 的 `data-theme` 属性(如 `data-theme="dark"`),结合 CSS 变量覆盖实现低成本主题切换 + +## 国际化规范 +提供多语言支持 +- **文案分离**:所有的界面静态文本禁止在 `.vue` 或 `.js` 文件中硬编码,必须通过 Vue I18n 等插件引入 +- **文件组织**:语言包统一存放于 `src/locales/`,按语言划分(如 `zh-CN.json`, `en-US.json`) +- **动态变量插值**:涉及动态数据的文案使用插值符,例如:"成功启动容器 {containerName}" diff --git a/docs/02_API_Contracts.md b/docs/02_API_Contracts.md new file mode 100644 index 0000000..e9c73e9 --- /dev/null +++ b/docs/02_API_Contracts.md @@ -0,0 +1,13 @@ +# MineDock API Contracts + +前后端接口定义,后端与Docker Daemon的交互流等 + +## 1. 容器实例生命周期接口 (Instance Lifecycle) + +| 方法 | 路径 | 说明 | 请求参数 | 返回结果 | +| --- | --- | --- | --- | --- | +| GET | `/api/instances` | 获取当前所有容器的列表 | 无 | `[{"container_id":"xxx", "name":"xxx", "status":"xxx"}]` | +| POST | `/api/instances` | 创建一个新容器(初始为 Stopped) | `{"name": "测试服1号"}` | `{"status": "success", "container_id": "xxx"}` | +| POST | `/api/instances/:id/start` | 启动指定容器实例 | 无(ID 在路径中) | `{"status": "success"}` | +| POST | `/api/instances/:id/stop` | 停止指定容器实例 | 无(ID 在路径中) | `{"status": "success"}` | +| DELETE | `/api/instances/:id` | 彻底删除指定容器实例 | 无(ID 在路径中) | `{"status": "success"}` | diff --git a/docs/domain_instance_lifecycle.md b/docs/domain_instance_lifecycle.md index 74dcc04..e8de601 100644 --- a/docs/domain_instance_lifecycle.md +++ b/docs/domain_instance_lifecycle.md @@ -1,6 +1,6 @@ -# 领域切片:容器实例生命周期(Instance Lifecycle) +# 容器实例生命周期 -## 1. 领域说明 +## 1. 说明 该领域负责容器实例的完整生命周期管理: - 查询当前实例列表 - 创建新实例(不自动启动) @@ -10,44 +10,26 @@ 该领域是当前系统的核心业务能力。 -## 2. 领域数据结构 +## 2. 数据结构 -### 2.1 Instance(后端) +### Instance(后端) ```go -// 容器相关 -// Instances 表 type Instance struct { - ContainerID string `json:"container_id"` // 映射的 Docker 容器唯一标识 - Name string `json:"name"` // 服务端名称 (比如 "测试服1号") - Status string `json:"status"` // 当前运行态 (Running, Stopped) + // 映射的 Docker 容器唯一标识 + ContainerID string `json:"container_id"` + // 服务端名称 (比如 "测试服1号") + Name string `json:"name"` + // 当前运行态 (Running, Stopped) + Status string `json:"status"` } ``` -### 2.2 字段语义与约束 -- `container_id`:Docker 容器唯一标识。 -- `name`:实例名称(例如“测试服1号”)。 -- `status`:实例运行状态,当前约定值为 `Running` 或 `Stopped`。 +## 3. HTTP 接口 +具体的接口定义请参考 [02_API_Contracts.md](02_API_Contracts.md#1-容器实例生命周期接口-instance-lifecycle)。 -## 3. 领域 HTTP 接口契约 - -| 方法 | 路径 | 说明 | 请求参数 | 返回结果 | -| --- | --- | --- | --- | --- | -| GET | `/api/instances` | 获取当前所有容器的列表 | 无 | `[{"container_id":"xxx", "name":"xxx", "status":"xxx"}]` | -| POST | `/api/instances` | 创建一个新容器(初始为 Stopped) | `{"name": "测试服1号"}` | `{"status": "success", "container_id": "xxx"}` | -| POST | `/api/instances/:id/start` | 启动指定容器实例 | 无(ID 在路径中) | `{"status": "success"}` | -| POST | `/api/instances/:id/stop` | 停止指定容器实例 | 无(ID 在路径中) | `{"status": "success"}` | -| DELETE | `/api/instances/:id` | 彻底删除指定容器实例 | 无(ID 在路径中) | `{"status": "success"}` | - -## 4. 领域状态流转(当前实现语义) +## 4. 状态流转(当前实现语义) - 创建成功后:实例进入 `Stopped`,并写入 SQLite 持久化存储。 - 启动成功后:实例状态更新为 `Running`。 - 停止成功后:实例状态更新为 `Stopped`。 - 删除成功后:销毁 Docker 容器,同时从 SQLite 中删除该实例记录;若实例仍为 `Running`,删除请求会被拒绝(需先停止)。 - 列表查询:以后端从 Docker 引擎读取的受管容器为准,并同步更新 SQLite 中的实例状态信息。 - -## 5. 领域内外依赖关系 -- 领域内部依赖后端模块: - - API 路由层 - - 业务服务层 - - SQLite 持久化存储层 -- 领域对外通过 HTTP 提供统一契约,前端仅调用该契约,不直接触达 Docker 引擎或数据库。 diff --git a/docs/ops_devops.md b/docs/ops_engineering_standards.md similarity index 85% rename from docs/ops_devops.md rename to docs/ops_engineering_standards.md index 78adcef..e513a30 100644 --- a/docs/ops_devops.md +++ b/docs/ops_engineering_standards.md @@ -1,11 +1,8 @@ # Ops & Infrastructure -本文档定义了 MineDock 项目的本地开发工作流、自动化构建与 CI/CD 规范。 - -## 1. 核心构建工具 -项目根目录维护一个统一的 `Taskfile.yml`,屏蔽底层各语言组件的启动差异。 -**当前支持的指令:** +本文档定义了项目的本地开发工作流、自动化构建与 CI/CD 规范 +## 1. 构建命令 | 指令 | 作用 | 说明 | | --- | --- | --- | | `task --list-all` | 查看可用任务 | 输出当前支持的任务列表 | @@ -20,10 +17,7 @@ | `task vet` | 执行全局静态检查 | 当前依赖 `backend:vet` | | `task test` | 执行全局测试 | 当前依赖 `backend:test` | -## 2. 环境依赖约束 - -本地开发与构建至少需要以下工具: - +## 2. 环境依赖 | 组件 | 用途 | | --- | --- | | Go | 后端编译与运行 | @@ -32,8 +26,7 @@ | task | 统一任务入口 | ## 3. CI/CD 对接规范 - -项目已在仓库内新增 GitHub Actions 工作流: +GitHub Actions 工作流: - `.github/workflows/ci.yml` - `.github/workflows/release.yml` diff --git a/frontend/.prettierignore b/frontend/.prettierignore new file mode 100644 index 0000000..b81cfda --- /dev/null +++ b/frontend/.prettierignore @@ -0,0 +1,4 @@ +dist +node_modules +coverage +*.log diff --git a/frontend/.prettierrc.json b/frontend/.prettierrc.json new file mode 100644 index 0000000..0854841 --- /dev/null +++ b/frontend/.prettierrc.json @@ -0,0 +1,9 @@ +{ + "printWidth": 100, + "semi": true, + "singleQuote": false, + "trailingComma": "all", + "tabWidth": 2, + "useTabs": false, + "vueIndentScriptAndStyle": false +} diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js new file mode 100644 index 0000000..5706cb7 --- /dev/null +++ b/frontend/eslint.config.js @@ -0,0 +1,60 @@ +import js from "@eslint/js"; +import tsPlugin from "@typescript-eslint/eslint-plugin"; +import tsParser from "@typescript-eslint/parser"; +import eslintConfigPrettier from "eslint-config-prettier"; +import vuePlugin from "eslint-plugin-vue"; +import globals from "globals"; +import vueParser from "vue-eslint-parser"; + +export default [ + { + ignores: ["dist/**", "node_modules/**"], + }, + js.configs.recommended, + ...vuePlugin.configs["flat/recommended"], + { + files: ["**/*.{ts,vue}"], + languageOptions: { + parser: vueParser, + parserOptions: { + parser: tsParser, + project: "./tsconfig.json", + tsconfigRootDir: import.meta.dirname, + sourceType: "module", + ecmaVersion: "latest", + extraFileExtensions: [".vue"], + }, + globals: { + ...globals.browser, + }, + }, + plugins: { + "@typescript-eslint": tsPlugin, + }, + rules: { + "@typescript-eslint/consistent-type-imports": [ + "error", + { + prefer: "type-imports", + }, + ], + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-floating-promises": "error", + "@typescript-eslint/no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + }, + ], + "vue/multi-word-component-names": "off", + }, + }, + { + files: ["**/*.d.ts"], + rules: { + "@typescript-eslint/no-explicit-any": "off", + }, + }, + eslintConfigPrettier, +]; diff --git a/frontend/index.html b/frontend/index.html index 3171d39..2a5df57 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -3,10 +3,11 @@ -{{ output }}
-