yourname 5 月之前
父节点
当前提交
78b601f7a1

+ 75 - 0
.gitea/workflows/release.yaml

@@ -0,0 +1,75 @@
+name: Docker Build and Push
+on:
+  push:
+    tags:
+      - 'release/*'  # 匹配所有release开头的标签,如release/v0.1.6
+
+jobs:
+  build-and-push:
+    runs-on: ubuntu-latest
+    steps:
+      - run: echo "🎉 该作业由 ${{ gitea.event_name }} 事件自动触发。"
+      - run: echo "🐧 此作业当前在 Gitea 托管的 ${{ runner.os }} 服务器上运行!"
+      - run: echo "🔎 您的标签名称是 ${{ gitea.ref_name }},仓库是 ${{ gitea.repository }}。"
+      - name: 检出仓库代码
+        uses: actions/checkout@v4
+      - run: echo "💡 ${{ gitea.repository }} 仓库已克隆到运行器。"
+      - run: echo "🖥️ 工作流现在已准备好在运行器上测试您的代码。"
+      - name: 列出仓库中的文件
+        run: |
+          ls ${{ gitea.workspace }}
+      - run: echo "🍏 此作业的状态是 ${{ job.status }}。"
+
+      - name: 设置 Docker Buildx
+        uses: docker/setup-buildx-action@v3
+      
+      - name: 从标签名中提取版本号
+        id: extract_version
+        run: |
+          # 从标签名中提取版本号,例如从 release/v0.1.6 中提取 v0.1.6
+          VERSION=$(echo "${{ gitea.ref_name }}" | sed 's|release/||')
+          echo "VERSION=$VERSION" >> $GITHUB_ENV
+          echo "提取的版本号:$VERSION"
+      
+      - name: 登录 Docker 注册表
+        uses: docker/login-action@v3
+        with:
+          registry: registry.cn-beijing.aliyuncs.com
+          username: ${{ secrets.ALI_DOCKER_REGISTRY_USERNAME }}
+          password: ${{ secrets.ALI_DOCKER_REGISTRY_PASSWORD }}
+
+      - name: 构建并推送
+        uses: docker/build-push-action@v5
+        with:
+          context: .
+          file: ./Dockerfile
+          push: true
+          tags: |
+            registry.cn-beijing.aliyuncs.com/d8dcloud/d8d-ai-design-prd:release-${{ env.VERSION }}
+      - name: 更新服务器上的 Docker 容器 
+        uses: appleboy/ssh-action@v1.2.2
+        with:
+          host: ${{ secrets.SERVER_HOST }}
+          port: ${{ secrets.SERVER_PORT }}
+          username: ${{ secrets.SERVER_USER }}
+          key: ${{ secrets.SERVER_SSH_KEY }}
+          script: |
+            # 进入项目目录
+            cd /mnt/k8s_home/app/d8d-fun-vite
+
+            
+            # 备份当前的 deployment.yaml 文件
+            cp deployment.yaml deployment.yaml.bak
+            
+            # 更新 deployment.yaml 中的镜像版本
+            sed -i "s|registry.cn-beijing.aliyuncs.com/d8dcloud/d8d-ai-design-prd:.*|registry.cn-beijing.aliyuncs.com/d8dcloud/d8d-ai-design-prd:release-${{ env.VERSION }}|g" deployment.yaml
+            
+            # 检查文件是否成功更新
+            echo "更新后的 deployment.yaml 内容:"
+            cat deployment.yaml
+            
+            # 更新
+            kubectl apply -f deployment.yaml
+            
+            # 显示d8d-fun-vite pod状态
+            kubectl get pods -n default -l app=d8d-fun-vite

+ 41 - 0
.gitignore

@@ -0,0 +1,41 @@
+# prod
+dist/
+dist-server/
+
+bun.lock
+package-lock.json
+
+# dev
+.yarn/
+!.yarn/releases
+.vscode/*
+!.vscode/launch.json
+!.vscode/*.code-snippets
+.idea/workspace.xml
+.idea/usage.statistics.xml
+.idea/shelf
+
+# deps
+node_modules/
+.wrangler
+
+# env
+.env
+.env.production
+.env.development
+.dev.vars
+
+# logs
+logs/
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+# misc
+.DS_Store
+
+.pnpm-store
+old

+ 15 - 0
.roo/mcp.json

@@ -0,0 +1,15 @@
+{
+  "mcpServers": {
+    "openapi": {
+      "command": "npx",
+      "args": [
+        "-y",
+        "mcp-openapi-schema-explorer@latest",
+        "https://pre-136-107-template-6.r.d8d.fun/doc",
+        "--output-format",
+        "json"
+      ],
+      "env": {}
+    }
+  }
+}

+ 25 - 0
.roo/rules/01-general.md

@@ -0,0 +1,25 @@
+# 基础规范
+
+## 项目结构
+
+```
+src/
+├── client/       # 前端代码 (React + Vite)
+├── server/       # 后端代码 (Hono + TypeORM)
+│   ├── api/      # API路由
+│   ├── migrations/ # 数据库迁移脚本
+│   ├── modules/  # 业务模块
+│   └── middleware/ # 中间件
+```
+
+## 技术栈
+
+### 前端
+- React 18
+- TypeScript (严格模式)
+- Vite 构建工具
+
+### 后端
+- Hono 框架
+- TypeORM (mysql)
+- Redis (缓存/会话管理)

+ 5 - 0
.roo/rules/02-typescript.md

@@ -0,0 +1,5 @@
+# TypeScript规范
+
+1. **严格模式**
+   - 启用所有严格类型检查选项
+   - 避免使用`any`类型

+ 8 - 0
.roo/rules/03-modules.md

@@ -0,0 +1,8 @@
+# 模块化规范
+
+1. **模块组织**
+   - 按功能划分模块
+   - 每个模块包含:
+     - 实体定义
+     - 服务层
+     - 路由控制器

+ 22 - 0
.roo/rules/04-api.md

@@ -0,0 +1,22 @@
+# 接口定义规范
+
+1. **DTO定义**
+   - 必须包含`description`字段说明用途
+   - 必须包含`example`字段提供示例值
+   - 示例:
+     ```typescript
+     export const CreateUserDto = z.object({
+       username: z.string().min(3).max(20).openapi({
+          example: 'john_doe',
+          description: '用户名, 3-20个字符'
+        }),
+       password: z.string().min(6).openapi({
+          example: 'password123',
+          description: '密码, 最少6位'
+       })
+     })
+     ```
+
+2. **API响应**
+   - 统一的API响应格式
+   - 完善的Swagger文档

+ 5 - 0
.roo/rules/05-database.md

@@ -0,0 +1,5 @@
+# 数据库规范
+
+1. **迁移管理**
+   - 使用迁移脚本管理表结构变更
+   - 实体类与数据库表严格映射

+ 19 - 0
.roo/rules/06-service-di.md

@@ -0,0 +1,19 @@
+# 依赖注入规范
+
+1. **依赖注入原则**
+   - 服务类必须通过构造函数注入依赖
+   - 禁止直接实例化全局对象(AppDataSource等)
+   - 不需要import { Injectable } from '@nestjs/common';, 本项目没用@nestjs
+   - 示例:
+     ```typescript
+     // Good - 通过构造函数注入
+     export class UserService {
+       constructor(private dataSource: DataSource) {}
+     }
+
+     // Bad - 使用全局实例
+     export class UserService {
+       constructor() {
+         this.repository = AppDataSource.getRepository(User);
+       }
+     }

+ 272 - 0
.roo/rules/07-openapi.md

@@ -0,0 +1,272 @@
+# Hono OpenAPI规范
+
+## 常见不规范问题
+1. **路径参数问题**:
+   - ❌ 使用冒号定义路径参数: `/:id`
+   - ✅ 必须使用花括号: `/{id}`
+     
+2. **参数Schema缺失**:
+   - ❌ 未定义params Schema
+   - ✅ 必须定义并添加OpenAPI元数据
+
+3. **参数获取方式**:
+   - ❌ 使用`c.req.param()`
+   - ✅ 必须使用`c.req.valid('param')`
+
+4. **URL参数类型转换**:
+   - ❌ 直接使用z.number()验证URL查询参数
+   - ✅ 必须使用z.coerce.number()自动转换字符串参数
+
+5. **OpenAPI元数据**:
+   - ❌ 路径参数缺少OpenAPI描述
+   - ✅ 必须包含example和description
+
+6. **api响应**:
+   - ❌ 200响应码缺少
+   - ✅ 200也必须写,c.json(result, 200)
+
+7. **认证中间件**:
+   - ❌ security: [{ Bearer: [] }],
+   - ✅ middleware: [authMiddleware],
+
+8. **子路由路径**:
+   - ❌ path: '/users',
+   - ✅ path: '/',
+   - ❌ path: '/users/{id}',
+   - ✅ path: '/{id}',
+
+## 核心规范
+### 1. 路由定义
+
+### 2. 查询参数处理
+- **URL参数类型**:
+  - URL查询参数总是以字符串形式传递
+  - 必须正确处理字符串到其他类型的转换
+- **数字参数处理**:
+  ```typescript
+  // 错误方式 - 直接使用z.number()
+  z.number().int().positive() // 无法处理字符串参数
+
+  // 正确方式 - 使用z.coerce.number()
+  z.coerce.number().int().positive() // 自动转换字符串参数
+  ```
+- **布尔参数处理**:
+  ```typescript
+  // 错误方式 - 直接使用z.boolean()
+  z.boolean() // 无法处理字符串参数
+
+  // 正确方式 - 使用z.coerce.boolean()
+  z.coerce.boolean() // 自动转换字符串参数
+  ```
+- **路径参数**:
+  - 必须使用花括号 `{}` 定义 (例: `/{id}`)
+  - 必须定义 params Schema 并添加 OpenAPI 元数据:
+    ```typescript
+    const GetParams = z.object({
+      id: z.string().openapi({
+        param: { name: 'id', in: 'path' },
+        example: '1',
+        description: '资源ID'
+      })
+    });
+    ```
+  - 路由定义中必须包含 params 定义:
+    ```typescript
+    request: { params: GetParams }
+    ```
+  - 必须使用 `c.req.valid('param')` 获取路径参数
+
+- **请求定义**:
+  ```typescript
+  request: {
+    body: {
+      content: {
+        'application/json': { schema: YourZodSchema }
+      }
+    }
+  }
+  ```
+
+- **响应定义**:
+  ```typescript
+  responses: {
+    200: {
+      description: '成功响应描述',
+      content: { 'application/json': { schema: SuccessSchema } }
+    },
+    400: {
+      description: '客户端错误',
+      content: { 'application/json': { schema: ErrorSchema } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: ErrorSchema } }
+    }
+  }
+  ```
+  列表响应定义示例
+  ```typescript
+  // 列表响应Schema, 响应时,data应统一用实体中定义的schema
+  import { RackInfoSchema } from '@/server/modules/racks/rack-info.entity';
+  const RackListResponse = z.object({
+    data: z.array(RackInfoSchema),
+    pagination: z.object({
+      total: z.number().openapi({
+        example: 100,
+        description: '总记录数'
+      }),
+      current: z.number().openapi({
+        example: 1,
+        description: '当前页码'
+      }),
+      pageSize: z.number().openapi({
+        example: 10,
+        description: '每页数量'
+      })
+    })
+  });
+  ```
+
+- **路由示例**:
+  ```typescript
+  const routeDef = createRoute({
+    method: 'post',
+    path: '/',
+    middleware: [authMiddleware],
+    request: {
+      body: {
+        content: { 'application/json': { schema: CreateSchema } }
+      }
+    },
+    responses: {
+      200: { ... },
+      400: { ... },
+      500: { ... }
+    }
+  });
+  ```
+
+### 2. 错误处理
+- 错误响应必须使用统一格式: `{ code: number, message: string }`
+- 必须与OpenAPI定义完全一致
+- 处理示例:
+  ```typescript
+  try {
+    // 业务逻辑
+  } catch (error) {
+    return c.json({ code: 500, message: '操作失败' }, 500);
+  }
+  ```
+
+### 3. dataSource引入
+- 示例:
+  ```typescript
+  import { AppDataSource } from '@/server/data-source';
+  ```
+
+### 4. service初始化
+- 示例:
+  ```typescript
+  import { WorkspaceService } from '@/server/modules/workspaces/workspace.service';
+  const workspaceService = new WorkspaceService(AppDataSource);
+
+### 5. 用户context获取
+- 示例:
+  ```typescript
+  const user = c.get('user');
+  ```
+  - 注意: 确保 `c.get('user')` 已经在 `authMiddleware` 中设置
+
+### 6. AuthContext引用
+- 示例:
+  ```typescript
+  import { AuthContext } from '@/server/types/context';
+  ```
+
+### 7. createRoute, OpenAPIHono 引入
+- 示例:
+  ```typescript
+  import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+  ```
+
+### 8. ErrorSchema 引入
+- 示例:
+  ```typescript
+  import { ErrorSchema } from '@/server/utils/errorHandler';
+  ```
+
+## 进阶规范
+### 1. 路由聚合
+当多个相关路由需要组合时:
+1. **文件结构**:
+   - 拆分为独立文件 (`create.ts`, `list.ts` 等)
+   - 创建 `index.ts` 聚合所有子路由
+
+  ```
+  src/server/api/
+  ├── [resource]/          # 资源路由目录
+  │   ├── [id]/           # 带ID的子路由
+  │   │   ├── get.ts      # 获取单条
+  │   │   ├── put.ts      # 更新单条  
+  │   │   └── delete.ts   # 删除单条
+  │   ├── get.ts          # 列表查询
+  │   ├── post.ts         # 创建资源
+  │   └── index.ts        # 聚合导出
+  ```
+
+2. **实现**:
+   ```typescript   
+    import listRoute from './get';
+    import createRackRoute from './post';
+    import getByIdRoute from './[id]/get';
+    import updateRoute from './[id]/put';
+    import deleteRoute from './[id]/delete';
+    import { OpenAPIHono } from '@hono/zod-openapi';
+
+    const app = new OpenAPIHono()
+      .route('/', listRoute)
+      .route('/', createRackRoute)
+      .route('/', getByIdRoute)
+      .route('/', updateRoute)
+      .route('/', deleteRoute)
+
+    export default app;
+   ```
+
+3. **优势**:
+   - 保持模块化
+   - 简化维护
+   - 统一API入口
+
+## 路由文件代码结构规范
+  +imports: 依赖导入
+  +serviceInit: 服务初始化
+  +paramsSchema: 路径参数定义
+  +responseSchema: 响应定义
+  +errorSchema: 错误定义
+  +routeDef: 路由定义
+  +app: 路由实例
+
+## src/server/api.ts 统一引入
+```ts
+import authRoute from '@/server/api/auth/index'
+const routes = api.route('/api/v1/auth', authRoute)
+```
+
+## 完整示例
+```typescript
+// 路由实例
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+  try {
+    // 业务逻辑
+    return c.json(result, 200);
+  } catch (error) {
+    return c.json({ 
+      code: 500, 
+      message: error instanceOf Error ? error.message : '操作失败' 
+    }, 500);
+  }
+});
+
+export default app;
+```

+ 82 - 0
.roo/rules/08-rpc.md

@@ -0,0 +1,82 @@
+# RPC 调用规范
+
+## 常见不规范问题
+1. **InferResponseType有[':id']时问题**:
+   - ❌ InferResponseType<typeof zichanClient[':id'].$get, 200>
+   - ✅ $get要加中括号 InferResponseType<typeof zichanClient[':id']['$get'], 200>
+
+## 核心原则
+1. **类型安全**:
+   - 所有RPC调用必须基于OpenAPI定义的类型
+   - 客户端和服务端类型必须严格匹配
+
+2. **一致性**:
+   - RPC调用路径必须与OpenAPI路由定义一致
+   - 错误处理格式必须统一
+
+3. **api版本**:
+   - 所有RPC调用必须基于OpenAPI定义的版本
+   - 版本号必须与OpenAPI版本号一致
+   目前仅支持v1版本
+   示例:
+   ```typescript
+   import { authClient } from '@/client/api';
+   ```
+
+## 客户端规范
+### 1. 客户端初始化
+```typescript
+import { hc } from 'hono/client'
+import { AuthRoutes } from '@/server/api';
+
+export const authClient = hc<AuthRoutes>('/', {
+  fetch: axiosFetch,
+}).api.v1.auth;
+```
+
+### 2. 方法调用
+- 必须使用解构方式组织RPC方法
+- 方法命名必须与OpenAPI路由定义一致
+- 示例:
+```typescript
+const res = await authClient.templates.blank[':templateType'].$get({
+  param: {
+    templateType
+  }
+});
+if (res.status !== 200) {
+  throw new Error(res.message);
+}
+const templateInfo = await res.json();
+```
+
+### 3. 类型提取规范
+- **响应类型提取**:
+  - 使用 `InferResponseType` 从客户端方法提取响应类型
+  - 必须指定正确的响应状态码(通常为200)
+  - 示例:
+    ```typescript
+    type ResponseType = InferResponseType<typeof client.method.$get, 200>['data'];
+    ```
+
+- **请求类型提取**:
+  - 使用 `InferRequestType` 从客户端方法提取请求类型
+  - 必须指定正确的请求参数类型('json'|'form'|'param')
+  - 示例:
+    ```typescript
+    type RequestType = InferRequestType<typeof client.method.$post>['json'];
+    ```
+
+- **类型命名规范**:
+  - 响应类型: `[ResourceName]`
+  - 请求类型: `[ResourceName]Post` 或 `[ResourceName]Put`
+  - 示例:
+    ```typescript
+    import type { InferRequestType, InferResponseType } from 'hono/client'
+    type ZichanInfo = InferResponseType<typeof zichanClient.$get, 200>['data'][0];
+    type ZichanListResponse = InferResponseType<typeof zichanClient.$get, 200>;
+    type ZichanDetailResponse = InferResponseType<typeof zichanClient[':id']['$get'], 200>;
+    type CreateZichanRequest = InferRequestType<typeof zichanClient.$post>['json'];
+    type UpdateZichanRequest = InferRequestType<typeof zichanClient[':id']['$put']>['json'];
+    type DeleteZichanResponse = InferResponseType<typeof zichanClient[':id']['$delete'], 200>;
+    ```

+ 71 - 0
.roo/rules/09-logging.md

@@ -0,0 +1,71 @@
+# 日志规范
+
+## 1. 基础配置
+- 前后端统一使用debug库
+- 开发环境:启用所有日志级别
+- 生产环境:通过环境变量`DEBUG`控制日志级别
+- 安装依赖:已安装`debug@4.4.1`和`@types/debug`
+
+## 2. 命名空间规范
+格式:`<应用>:<模块>:<功能>`  
+示例:
+```
+frontend:auth:login    # 前端-认证-登录
+backend:api:middleware # 后端-API-中间件
+backend:db:query       # 后端-数据库-查询
+k8s:deployment:create  # K8S-部署-创建
+```
+
+## 3. 日志级别
+| 级别   | 使用场景                     |
+|--------|----------------------------|
+| error  | 系统错误、异常情况            |
+| warn   | 警告性事件                   |
+| info   | 重要业务流程信息              |
+| debug  | 调试信息                     |
+| trace  | 详细跟踪信息(慎用)            |
+
+## 4. 实现示例
+
+### 前端示例
+```typescript
+// src/client/utils/logger.ts
+import debug from 'debug';
+
+export const logger = {
+  error: debug('frontend:error'),
+  api: debug('frontend:api'),
+  auth: debug('frontend:auth'),
+  ui: debug('frontend:ui')
+};
+```
+
+### 后端示例
+```typescript
+// src/server/utils/logger.ts
+import debug from 'debug';
+
+export const logger = {
+  error: debug('backend:error'),
+  api: debug('backend:api'),
+  db: debug('backend:db'),
+  middleware: debug('backend:middleware')
+};
+```
+
+## 5. 最佳实践
+1. 错误日志必须包含错误堆栈和上下文
+2. 禁止记录密码、token等敏感信息
+3. 生产环境避免使用trace级别
+4. 复杂对象使用JSON.stringify()
+
+## 6. 环境配置
+```bash
+# 开发环境
+DEBUG=*
+
+# 生产环境
+DEBUG=*:error,*:warn
+
+# 特定模块调试
+DEBUG=backend:api,backend:db

+ 117 - 0
.roo/rules/10-entity.md

@@ -0,0 +1,117 @@
+# 数据库实体规范
+
+## 1. 实体基础结构
+
+```typescript
+import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
+import { z } from 'zod';
+
+@Entity('table_name') // 使用小写下划线命名表名
+export class EntityName {
+  // 字段定义...
+}
+```
+
+## 2. 主键定义规范
+
+```typescript
+@PrimaryGeneratedColumn({ unsigned: true }) // 必须使用无符号整数
+id!: number; // 使用非空断言(!)和明确类型
+```
+
+## 3. 列定义规范
+
+```typescript
+@Column({ 
+  name: '字段名称',       // 必须添加并与数据表字段名称一致
+  type: 'varchar',       // 明确指定数据库类型
+  length: 255,           // 字符串必须指定长度
+  nullable: true,        // 明确是否可为空
+  default: undefined,    // 默认值(可选)
+  comment: '字段说明'     // 必须添加中文注释
+})
+fieldName!: FieldType;   // 类型必须明确
+```
+
+## 4. 数据类型规范
+
+| 业务类型       | 数据库类型               | TypeScript 类型       |
+|----------------|-------------------------|-----------------------|
+| 主键ID         | int unsigned            | number                |
+| 短文本         | varchar(length)         | string                |
+| 长文本         | text                    | string                |
+| 整数           | int                     | number                |
+| 小数           | decimal(precision,scale)| number                |
+| 布尔状态       | tinyint                 | number (0/1)          |
+| 日期时间       | timestamp               | Date                  |
+
+## 5. 状态字段规范
+
+```typescript
+// 禁用状态 (0启用 1禁用)
+@Column({ name: 'is_disabled', type: 'tinyint', default: 1 })
+isDisabled!: number;
+
+// 删除状态 (0未删除 1已删除) 
+@Column({ name: 'is_deleted',type: 'tinyint', default: 0 })
+isDeleted!: number;
+```
+
+## 6. 时间字段规范
+
+```typescript
+// 创建时间 (自动设置)
+@Column({ 
+  name: 'created_at',
+  type: 'timestamp', 
+  default: () => 'CURRENT_TIMESTAMP'
+})
+createdAt!: Date;
+
+// 更新时间 (自动更新)
+@Column({
+  name: 'updated_at',
+  type: 'timestamp',
+  default: () => 'CURRENT_TIMESTAMP',
+  onUpdate: 'CURRENT_TIMESTAMP' 
+})
+updatedAt!: Date;
+```
+
+## 7. Zod Schema 规范
+
+```typescript
+export const EntitySchema = z.object({
+  id: z.number().int().positive().openapi({ description: 'ID说明' }),
+  // 字符串字段
+  fieldName: z.string()
+    .max(255)
+    .nullable()
+    .openapi({ 
+      description: '字段说明',
+      example: '示例值'
+    }),
+  // 数字字段  
+  numberField: z.number()
+    .default(默认值)
+    .openapi({...}),
+  // 日期字段
+  dateField: z.date().openapi({...})
+});
+```
+
+## 8. 命名规范
+
+- 实体类名:PascalCase (如 RackInfo)
+- 表名:snake_case (如 rack_info)
+- 字段名:camelCase (如 rackName)
+- 数据库列名:snake_case (如 rack_name)
+
+## 9. 最佳实践
+
+1. 所有字段必须添加字段名称(name)及注释(comment)
+2. 必须明确指定 nullable 属性
+3. 状态字段使用 tinyint 并注明取值含义
+4. 必须包含 createdAt/updatedAt 时间字段
+5. 每个实体必须配套 Zod Schema 定义
+6. Schema 必须包含 OpenAPI 元数据(description/example)