diff --git a/apps/server/prisma/data/dev.db b/apps/server/prisma/data/dev.db index 2dc1782..f443b4d 100644 Binary files a/apps/server/prisma/data/dev.db and b/apps/server/prisma/data/dev.db differ diff --git a/apps/web/src/pages/login/service.ts b/apps/web/src/pages/login/service.ts index 92f2539..5b7b6f1 100644 --- a/apps/web/src/pages/login/service.ts +++ b/apps/web/src/pages/login/service.ts @@ -1,5 +1,5 @@ import { Message, Notification } from '@arco-design/web-react'; -import { net } from '@shared'; +import { net } from '../../utils'; import type { NavigateFunction } from 'react-router'; import { useGlobalStore } from '../../stores/global'; import type { AuthLoginResponse, AuthURLResponse } from './types'; diff --git a/apps/web/src/pages/login/types.ts b/apps/web/src/pages/login/types.ts index bda3385..238bb9d 100644 --- a/apps/web/src/pages/login/types.ts +++ b/apps/web/src/pages/login/types.ts @@ -1,4 +1,4 @@ -import type { APIResponse } from '@shared'; +import type { APIResponse } from '../../utils'; export interface User { id: string; diff --git a/apps/web/src/pages/project/detail/service.ts b/apps/web/src/pages/project/detail/service.ts index 15b60d0..36691eb 100644 --- a/apps/web/src/pages/project/detail/service.ts +++ b/apps/web/src/pages/project/detail/service.ts @@ -1,4 +1,4 @@ -import { type APIResponse, net } from '@shared'; +import { type APIResponse, net } from '../../../utils'; import type { Branch, Commit, diff --git a/apps/web/src/pages/project/list/service.ts b/apps/web/src/pages/project/list/service.ts index 641aec8..243d312 100644 --- a/apps/web/src/pages/project/list/service.ts +++ b/apps/web/src/pages/project/list/service.ts @@ -1,4 +1,4 @@ -import { type APIResponse, net } from '@shared'; +import { type APIResponse, net } from '../../../utils'; import type { Project } from '../types'; class ProjectService { diff --git a/apps/web/src/stores/global.tsx b/apps/web/src/stores/global.tsx index 4135d32..b629834 100644 --- a/apps/web/src/stores/global.tsx +++ b/apps/web/src/stores/global.tsx @@ -1,4 +1,4 @@ -import { type APIResponse, net } from '@shared'; +import { type APIResponse, net } from '../utils'; import { create } from 'zustand'; interface User { diff --git a/apps/web/src/shared/index.ts b/apps/web/src/utils/index.ts similarity index 100% rename from apps/web/src/shared/index.ts rename to apps/web/src/utils/index.ts diff --git a/apps/web/src/shared/request.ts b/apps/web/src/utils/request.ts similarity index 100% rename from apps/web/src/shared/request.ts rename to apps/web/src/utils/request.ts diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index a41183b..36c4a80 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -24,7 +24,7 @@ "@pages/*": ["./src/pages/*"], "@styles/*": ["./src/styles/*"], "@assets/*": ["./src/assets/*"], - "@shared": ["./src/shared"] + "@shared": ["src/utils"] } }, "include": ["src"] diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..68f0cab --- /dev/null +++ b/docs/README.md @@ -0,0 +1,22 @@ +# MiniCI 文档中心 + +欢迎查阅 MiniCI 开发者文档。本项目是一个轻量级的自研 CI 系统。 + +## 目录索引 + +- [系统架构](./architecture.md) - 核心设计与模块划分 +- [决策记录 (ADR)](./decisions/0001-tech-stack.md) - 技术选型背后的逻辑 +- [约束与禁区](./constraints.md) - 开发中不可触碰的红线 +- [编码规范](./conventions.md) - 风格与最佳实践 +- [踩坑指南](./pitfalls.md) - 已解决的问题与易错点 +- [当前进度](./status.md) - 项目现状与待办 +- [AI 助手说明](./ai.md) - 专门为 coding agent 准备的作业指南 + +## 快速上手 + +```bash +pnpm install +pnpm dev +``` + +项目访问:前端 `localhost:3000` (Rsbuild),后端 `localhost:3001` (Koa)。 diff --git a/docs/ai.md b/docs/ai.md new file mode 100644 index 0000000..a821fa7 --- /dev/null +++ b/docs/ai.md @@ -0,0 +1,22 @@ +# AI 助手作业指南 (ai.md) + +你好,Agent!在处理 MiniCI 项目时,请遵循以下原则: + +## 1. 增加新 API 的步骤 + +1. 在 `controllers/` 对应模块下创建/修改 `dto.ts` 定义输入。 +2. 在 `index.ts` 中编写类,使用 `@Controller` 和 `@Post/Get` 等装饰器。 +3. 如果涉及数据库,修改 `schema.prisma` 并运行 `npx prisma db push`。 +4. 在前端 `pages/` 对应的 `service.ts` 中添加调用方法。 + +## 2. 核心逻辑位置 + +- 如果要修改 **流水线如何运行**,请看 `apps/server/runners/pipeline-runner.ts`。 +- 如果要修改 **任务调度**,请看 `apps/server/libs/execution-queue.ts`。 +- 如果要修改 **路由扫描**,请看 `apps/server/libs/route-scanner.ts`。 + +## 3. 交互规范 + +- 前端请求请使用 `@shared` 别名导入 `net` 实例。 +- 始终保持代码简洁,优先使用现有的 `libs` 工具类。 +- 修改代码后,务必确认 `pnpm dev` 是否能正常编译通过。 diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..a34370d --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,29 @@ +# 系统架构 + +## 1. 概览 + +MiniCI 采用典型的 **Monorepo** 架构,前端 React 配合后端 Koa,数据持久化使用 SQLite。 + +## 2. 核心模块 + +### 2.1 后端 (apps/server) + +- **Route System**: 基于 TC39 装饰器的自动扫描路由。 +- **Execution Queue**: 单例模式的执行队列,控制并发并支持任务持久化恢复。 +- **Pipeline Runner**: 核心执行逻辑,利用 `zx` 在独立的工作目录下运行 Shell 脚本。 +- **Data Access**: Prisma ORM 提供类型安全的数据访问。 + +### 2.2 前端 (apps/web) + +- **Build Tool**: Rsbuild (基于 Rspack),提供极速的开发体验。 +- **UI Framework**: React 19 + Arco Design。 +- **State Management**: Zustand 实现轻量级全局状态。 + +## 3. 部署流 (Pipeline Flow) + +1. 用户触发部署 -> 创建 `Deployment` 记录 (Status: pending)。 +2. `ExecutionQueue` 捕获新任务 -> 实例化 `PipelineRunner`。 +3. `GitManager` 准备工作目录 (`git clone` 或 `git pull`)。 +4. `PipelineRunner` 逐个执行 `Step` 脚本。 +5. 执行过程中实时更新 `Deployment.buildLog`。 +6. 完成后更新状态为 `success` 或 `failed`。 diff --git a/docs/constraints.md b/docs/constraints.md new file mode 100644 index 0000000..9a81420 --- /dev/null +++ b/docs/constraints.md @@ -0,0 +1,20 @@ +# 约束与禁区 + +## 1. 路由规范 + +- **禁止** 在 `app.ts` 中手动编写 `router.get/post`。 +- **必须** 使用 `@Controller` 和 `@Get/Post` 装饰器,并放在 `controllers/` 目录下。 + +## 2. 数据库安全 + +- **禁止** 绕过 Prisma 直接操作数据库文件。 +- **禁止** 在生产环境中手动修改 `dev.db`。 + +## 3. 环境变量 + +- **禁区**: 严禁将敏感 Token 或密钥直接硬编码在代码或 `schema.prisma` 中。 +- 请使用 `.env` 文件配合 `dotenv` 加载。 + +## 4. 依赖管理 + +- **禁止** 混合使用 npm/yarn,必须统一使用 `pnpm`。 diff --git a/docs/conventions.md b/docs/conventions.md new file mode 100644 index 0000000..56d8a30 --- /dev/null +++ b/docs/conventions.md @@ -0,0 +1,49 @@ +# 编码规范 + +## 1. 命名习惯 + +- **前端组件**: PascalCase (如 `ProjectCard.tsx`)。 +- **后端文件**: kebab-case (如 `route-scanner.ts`)。 +- **DTO**: 文件名为 `dto.ts`,类名为 `XxxDTO`。 + +## 2. 代码组织 + +web 项目代码组织如下: + +```yaml +├── web/ +│ ├── pages/ +│ │ ├── components/ # 页面组件 +│ │ ├── index.tsx # 页面入口组件 +│ │ ├── service.ts # 当前页面使用到的 api 请求方法和纯函数 +│ │ ├── types.ts # 当前页面使用到的类型定义 +│ │ └── ... +│ └── hooks/ # 通用 hooks (不止一个组件引用) +│ └── stores/ # 全局状态 +│ └── utils/ # 通用工具类 +│ └── styles/ # 全局样式 +│ └── assets/ # 静态资源 +│ └── components/ # 通用组件 +│ └── types/ # 全局类型定义 +│ └── ... +``` + +## 3. 响应格式 + +- 后端统一返回 `APIResponse` 结构: + + ```json + { "code": 0, "data": {}, "message": "success", "timestamp": 12345678 } + ``` + +- 由 `RouteScanner` 中的 `wrapControllerMethod` 自动封装。 + +## 3. 异步处理 + +- 统一使用 `async/await`。 +- 后端错误通过抛出异常由 `exception.ts` 中间件统一捕获。 + +## 4. 格式化 + +- 使用 Biome 进行 Lint 和 Format。 +- 提交代码前建议运行 `pnpm --filter web format`。 diff --git a/docs/decisions/0001-tech-stack.md b/docs/decisions/0001-tech-stack.md new file mode 100644 index 0000000..b90346d --- /dev/null +++ b/docs/decisions/0001-tech-stack.md @@ -0,0 +1,14 @@ +# ADR 0001: 技术选型 + +## 背景 +需要构建一个轻量级、易扩展且易于本地部署的 CI 系统。 + +## 决策 +- **语言**: 全栈 TypeScript,确保模型定义在前后端的一致性。 +- **后端框架**: Koa。相比 Express 更加轻量,利用 async/await 处理异步中间件更优雅。 +- **数据库**: SQLite。CI 系统通常是单机或小规模使用,SQLite 无需独立服务,运维成本极低。 +- **执行工具**: `zx`。相比原生的 `child_process`,`zx` 处理 Shell 交互更加直观和安全。 + +## 后果 +- 优势:开发效率极高,部署简单。 +- 挑战:SQLite 在极高并发写入(如数百个任务同时输出日志)时可能存在性能瓶颈。 diff --git a/docs/decisions/0002-state.md b/docs/decisions/0002-state.md new file mode 100644 index 0000000..ce2a367 --- /dev/null +++ b/docs/decisions/0002-state.md @@ -0,0 +1,15 @@ +# ADR 0002: 状态管理 + +## 背景 +需要在前端管理用户信息、全局配置以及各页面的复杂 UI 状态。 + +## 决策 +- **全局状态**: 使用 Zustand。 +- **理由**: + - 相比 Redux 模板代码极少。 + - 相比 Context API 性能更好且不引起全量重绘。 + - 符合 React 19 的 Concurrent 模式。 +- **持久化**: 对关键状态(如 Token)使用 Zustand 的 persist 中间件。 + +## 后果 +状态管理逻辑高度内聚在 `apps/web/src/stores` 中。 diff --git a/docs/decisions/0003-pipeline-execution.md b/docs/decisions/0003-pipeline-execution.md new file mode 100644 index 0000000..f232b3b --- /dev/null +++ b/docs/decisions/0003-pipeline-execution.md @@ -0,0 +1,12 @@ +# ADR 0003: 流水线执行策略 + +## 背景 +如何确保流水线执行的隔离性与可靠性。 + +## 决策 +- **工作目录**: 每个项目在服务器上拥有独立的 `projectDir`。 +- **执行器**: 采用线性执行。目前不支持多步骤并行,以确保日志顺序的确定性。 +- **队列**: 使用内存队列 + 数据库扫描实现。系统重启后能通过数据库中的 `pending` 状态恢复任务。 + +## 后果 +目前的隔离级别为目录级。未来可能需要引入 Docker 容器化执行以增强安全性。 diff --git a/docs/pitfalls.md b/docs/pitfalls.md new file mode 100644 index 0000000..e156c4a --- /dev/null +++ b/docs/pitfalls.md @@ -0,0 +1,21 @@ +# 踩坑指南 (Pitfalls) + +## 1. Prisma 客户端生成 + +- **现象**: 修改 `schema.prisma` 后代码报错找不到类型。 +- **解决**: 需要在 `apps/server` 下运行 `pnpm prisma generate`。本项目将生成的代码放在了 `generated/` 目录而非 node_modules,请注意引用路径。 + +## 2. zx 环境变量继承 + +- **现象**: 在流水线脚本中找不到 `node` 或 `git` 命令。 +- **解决**: `PipelineRunner` 在调用 `zx` 时必须手动扩展 `env: { ...process.env, ...userEnv }`,否则会丢失系统 PATH。 + +## 3. Koa BodyParser 顺序 + +- **现象**: 获取不到 `ctx.request.body`。 +- **解决**: `koa-bodyparser` 中间件必须在 `router` 中间件之前注册。 + +## 4. SQLite 并发写入 + +- **现象**: 部署日志极快输出时偶发 `SQLITE_BUSY`。 +- **解决**: 适当增加 `better-sqlite3` 的 busy timeout。 diff --git a/docs/status.md b/docs/status.md new file mode 100644 index 0000000..0304f75 --- /dev/null +++ b/docs/status.md @@ -0,0 +1,19 @@ +# 当前进度 (Status) + +## 已完成 ✅ + +- 基础 Monorepo 框架搭设 +- TC39 装饰器路由系统 +- 项目管理 (CRUD) +- 基础流水线执行流程 (Git Clone -> zx Run -> Log Update) +- 前端项目列表与详情页预览 + +## 进行中 🚧 + +- 部署记录的分页查询优化 + +## 待办 📅 + +- [ ] Gitea Webhook 自动触发 +- [ ] 用户权限管理 (RBAC) +- [ ] 日志实时 Websocket 推送 diff --git a/package.json b/package.json index 7917ce0..37fde8f 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "ark-ci", + "name": "MiniCI", "version": "1.0.0", "description": "", "scripts": { diff --git a/specs/instructions.md b/specs/instructions.md new file mode 100644 index 0000000..93988d2 --- /dev/null +++ b/specs/instructions.md @@ -0,0 +1,90 @@ +# MiniCI 项目开发指南 + +MiniCI 是一个轻量级的持续集成(CI)系统,采用 Monorepo 架构。 + +## 技术栈 + +### 核心架构 + +- **Monorepo**: 使用 pnpm workspace 管理。 +- **包管理器**: pnpm。 +- **代码格式化**: Biome。 + +### 后端 (apps/server) + +- **框架**: Koa (v3)。 +- **语言**: TypeScript。 +- **路由**: 基于 TC39 装饰器的自定义路由系统。 +- **数据库**: SQLite + Prisma ORM。 +- **任务执行**: `zx` (Shell 脚本执行), 自研 `ExecutionQueue` (任务队列)。 +- **日志**: Pino。 +- **验证**: Zod。 + +### 前端 (apps/web) + +- **框架**: React 19。 +- **构建工具**: Rsbuild。 +- **样式**: Tailwind CSS + Arco Design + Less。 +- **状态管理**: Zustand。 +- **路由**: React Router 7。 +- **请求**: Axios。 + +## 项目结构 + +```text +MiniCI/ +├── apps/ +│ ├── server/ # 后端服务 +│ │ ├── controllers/ # 控制器层 (路由处理) +│ │ ├── decorators/ # TC39 路由装饰器 +│ │ ├── libs/ # 核心逻辑库 (Git, 队列, 路由扫描) +│ │ ├── runners/ # 流水线执行器 +│ │ ├── prisma/ # 数据库模型定义 +│ │ └── generated/ # Prisma 生成的代码 +│ └── web/ # 前端应用 +│ ├── src/ +│ │ ├── pages/ # 页面组件及对应的 Service/Types +│ │ ├── components/ # 通用组件 +│ │ ├── stores/ # Zustand 状态管理 +│ │ └── shared/ # 通用请求和工具类 +└── specs/ # 项目规范与文档 +``` + +## 开发规范 + +### 1. 后端路由 + +必须使用装饰器定义路由。 + +- 类必须标记 `@Controller('prefix')`。 +- 方法必须标记 `@Get('path')`, `@Post('path')` 等。 +- 路由自动扫描并在 `app.ts` 中通过 `initMiddlewares` 加载。 + +### 2. 数据库操作 + +- 使用 Prisma 客户端 (`apps/server/libs/prisma.ts`)。 +- 修改模型后运行 `pnpm --filter server prisma generate`。 + +### 3. 前端开发 + +- 优先使用 **Arco Design** 组件。 +- 样式使用 **Tailwind CSS**。 +- 每个页面或模块应包含自己的 `service.ts`(处理 API 请求)和 `types.ts`。 + +### 4. 任务执行逻辑 + +- 所有流水线执行都通过 `ExecutionQueue` 调度。 +- 具体的执行逻辑位于 `PipelineRunner`,它会处理 Git 仓库的准备和步骤脚本的执行。 + +## 常用命令 + +- **全量开发**: `pnpm dev` +- **后端单独开发**: `pnpm --filter server dev` +- **前端单独开发**: `pnpm --filter web dev` +- **数据库同步**: `npx prisma db push` (在 server 目录下) + +## 注意事项 + +- **安全性**: 执行流水线脚本时需注意命令注入风险,目前主要由 `zx` 处理。 +- **性能**: 构建日志实时写入数据库,注意大规模并发下的 IO 压力。 +- **编码**: 遵循项目中的 Biome 配置进行代码格式化。