2
0
Просмотр исходного кода

📦 build(project): 添加项目开发规范文档和MCP配置

- 新增MCP配置文件用于OpenAPI文档探索
- 新增11个开发规范文档覆盖所有开发场景
- 建立通用CRUD开发标准和最佳实践
- 统一前后端开发流程和技术规范
yourname 7 месяцев назад
Родитель
Сommit
41fb1d4230

+ 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>;
+    ```

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

@@ -0,0 +1,77 @@
+# 日志规范
+
+## 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
+// 在需要使用日志的文件中直接引入debug
+import debug from 'debug';
+
+// 按需定义命名空间
+const errorLogger = debug('frontend:error');
+const apiLogger = debug('frontend:api');
+const authLogger = debug('frontend:auth');
+const uiLogger = debug('frontend:ui');
+
+// 使用示例
+errorLogger('用户登录失败: %s', error.message);
+apiLogger('API请求: %s', url);
+```
+
+### 后端示例
+```typescript
+// 在需要使用日志的文件中直接引入debug
+import debug from 'debug';
+
+// 按需定义命名空间
+const errorLogger = debug('backend:error');
+const apiLogger = debug('backend:api');
+const dbLogger = debug('backend:db');
+const middlewareLogger = debug('backend:middleware');
+
+// 使用示例
+errorLogger('数据库连接失败: %s', error.message);
+dbLogger('查询执行: %s', sql);
+```
+
+## 5. 最佳实践
+1. 错误日志必须包含错误堆栈和上下文
+2. 禁止记录密码、token等敏感信息
+3. 生产环境避免使用trace级别
+4. 复杂对象使用JSON.stringify()
+
+## 6. 环境配置
+```bash
+# 开发环境
+DEBUG=*
+
+# 生产环境
+DEBUG=*:error,*:warn
+
+# 特定模块调试
+DEBUG=backend:api,backend:db

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

@@ -0,0 +1,277 @@
+# 数据库实体规范
+
+## 常见不规范问题
+  1. nullable 字段用了? 而不是!, 类型没加 null
+    错误示例:
+      ```ts
+      @Column({
+        name: 'description',
+        type: 'text',
+        nullable: true,
+        comment: '容器配置描述'
+      })
+      description?: string;
+      ```
+    正确示例:
+      ```ts
+      @Column({
+        name: 'description',
+        type: 'text',
+        nullable: true,
+        comment: '容器配置描述'
+      })
+      description!: string | null;
+      ```
+
+
+## 1. 实体基础结构
+
+```typescript
+import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
+import { z } from '@hono/zod-openapi';
+
+@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 规范
+
+### 7.1 基础类型规范
+
+```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({...})
+});
+```
+
+### 7.2 数据类型转换规范
+
+#### 7.2.1 数字类型转换
+
+对于URL参数或表单数据中的数字类型,必须使用`z.coerce.number()`进行类型转换,以确保字符串到数字的正确转换:
+
+```typescript
+// 整数类型
+z.coerce.number().int().positive().openapi({
+  description: '正整数ID',
+  example: 1
+});
+
+// 小数类型
+z.coerce.number().multipleOf(0.01).openapi({
+  description: '金额,保留两位小数',
+  example: 19.99
+});
+
+// 状态类型(0/1)
+z.coerce.number().int().min(0).max(1).openapi({
+  description: '状态(0-禁用,1-启用)',
+  example: 1
+});
+```
+
+#### 7.2.2 日期类型转换
+
+对于日期时间类型,必须使用`z.coerce.date()`进行类型转换:
+
+```typescript
+// 日期时间类型
+z.coerce.date().openapi({
+  description: '创建时间',
+  example: '2023-10-01T12:00:00Z'
+});
+
+// 日期范围查询
+const DateRangeSchema = z.object({
+  startDate: z.coerce.date().openapi({
+    description: '开始日期',
+    example: '2023-10-01T00:00:00Z'
+  }),
+  endDate: z.coerce.date().openapi({
+    description: '结束日期',
+    example: '2023-10-31T23:59:59Z'
+  })
+});
+```
+
+#### 7.2.3 布尔类型转换
+
+对于布尔类型参数,必须使用`z.coerce.boolean()`进行类型转换:
+
+```typescript
+// 布尔类型
+z.coerce.boolean().openapi({
+  description: '是否启用',
+  example: true
+});
+```
+
+### 7.3 创建/更新Schema特殊规范
+
+创建(Create)和更新(Update)Schema必须遵循以下额外规范:
+
+1. **创建Schema**:
+   - 不包含`id`字段(由数据库自动生成)
+   - 所有必填字段必须显式定义,不得为`optional()`
+   - 如字段为选填项(包括数据库允许为null的字段),必须显式添加`optional()`
+   - 必须使用适当的coerce方法处理非字符串类型
+
+```typescript
+export const CreateEntityDto = z.object({
+  name: z.string().max(255).openapi({
+    description: '名称',
+    example: '示例名称'
+  }),
+  quantity: z.coerce.number().int().min(1).openapi({
+    description: '数量',
+    example: 10
+  }),
+  price: z.coerce.number().multipleOf(0.01).openapi({
+    description: '价格',
+    example: 99.99
+  }),
+  isActive: z.coerce.boolean().default(true).openapi({
+    description: '是否激活',
+    example: true
+  }),
+  expireDate: z.coerce.date().openapi({
+    description: '过期日期',
+    example: '2024-12-31T23:59:59Z'
+  }),
+  // 选填字段示例
+  // nullable字段必须显式添加optional()
+  description: z.string().max(500).nullable().optional().openapi({
+    description: '商品描述(选填)',
+    example: '这是一个可选的商品描述信息'
+  })
+});
+```
+
+2. **更新Schema**:
+   - 不包含`id`字段(通过URL参数传递)
+   - 所有字段必须为`optional()`
+   - 必须使用适当的coerce方法处理非字符串类型
+
+```typescript
+export const UpdateEntityDto = z.object({
+  name: z.string().max(255).optional().openapi({
+    description: '名称',
+    example: '更新后的名称'
+  }),
+  quantity: z.coerce.number().int().min(1).optional().openapi({
+    description: '数量',
+    example: 20
+  }),
+  price: z.coerce.number().multipleOf(0.01).optional().openapi({
+    description: '价格',
+    example: 89.99
+  }),
+  isActive: z.coerce.boolean().optional().openapi({
+    description: '是否激活',
+    example: false
+  }),
+  expireDate: z.coerce.date().optional().openapi({
+    description: '过期日期',
+    example: '2025-12-31T23:59:59Z'
+  })
+});
+```
+```
+
+## 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)

+ 18 - 0
.roo/rules/11-admin-frontend.md

@@ -0,0 +1,18 @@
+# 管理后台前端页面开发流程规范
+
+## 适用场景
+
+管理后台页面开发,包括列表页、详情页、表单页等后台功能页面的实现流程。
+
+## 开发流程
+
+### 1. **创建页面组件**
+   - 位置: `src/client/admin/pages/[EntityName].tsx`
+
+### 2. **注册路由配置**
+   - 位置: `src/client/admin/routes.tsx`
+     ```
+
+### 3. **添加菜单配置**
+   - 位置: `src/client/admin/menu.tsx`
+

+ 375 - 0
.roo/rules/11-custom-crud.md

@@ -0,0 +1,375 @@
+# 自定义复杂CRUD开发流程规范
+
+## 适用场景
+
+适用于包含复杂业务逻辑的实体,需要手动实现服务方法和路由处理的场景,如:
+- 复杂业务规则
+- 多表关联操作
+- 特殊权限控制
+- 非标准数据处理
+
+## 开发流程
+
+### 1. **创建实体**
+   - 位置: `src/server/modules/[模块名]/[实体名].entity.ts`
+   - 定义实体类和Zod Schema
+   - 示例:
+     ```typescript
+     import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
+     import { z } from '@hono/zod-openapi';
+     
+     @Entity('your_entity')
+     export class YourEntity {
+       @PrimaryGeneratedColumn({ unsigned: true })
+       id!: number;
+       
+       @Column({ name: 'name', type: 'varchar', length: 255 })
+       name!: string;
+       
+       // 其他业务字段...
+     }
+     
+     // Zod Schema定义
+     export const YourEntitySchema = z.object({
+       id: z.number().int().positive().openapi({ description: '实体ID' }),
+       name: z.string().max(255).openapi({ description: '名称', example: '示例名称' })
+       // 其他字段Schema...
+     });
+     
+     export const CreateYourEntityDto = z.object({
+       name: z.string().max(255).openapi({ description: '名称', example: '示例名称' })
+       // 其他创建字段...
+     });
+     
+     export const UpdateYourEntityDto = z.object({
+       name: z.string().max(255).optional().openapi({ description: '名称', example: '示例名称' })
+       // 其他更新字段...
+     });
+     ```
+
+### 2. **注册实体到数据源**
+   - 在`src/server/data-source.ts`中添加实体导入和注册:
+     ```typescript
+     // 实体类导入
+     import { YourEntity } from "./modules/[模块名]/[实体名].entity"
+     
+     export const AppDataSource = new DataSource({
+       // ...其他配置
+       entities: [
+         User, Role, YourEntity // 添加新实体到数组
+       ],
+       // ...其他配置
+     });
+     ```
+
+### 3. **创建自定义Service**
+   - 位置: `src/server/modules/[模块名]/[实体名].service.ts`
+   - 实现自定义业务逻辑和数据访问
+   - 示例:
+     ```typescript
+     import { DataSource, Repository } from 'typeorm';
+     import { YourEntity } from './your-entity.entity';
+     import { CreateYourEntityDto, UpdateYourEntityDto } from './your-entity.entity';
+     import { AppError } from '@/server/utils/errorHandler';
+     
+     export class YourEntityService {
+       private repository: Repository<YourEntity>;
+       
+       constructor(dataSource: DataSource) {
+         this.repository = dataSource.getRepository(YourEntity);
+       }
+       
+       /**
+        * 获取实体列表(带复杂过滤条件)
+        */
+       async findAll(filters: any): Promise<[YourEntity[], number]> {
+         const query = this.repository.createQueryBuilder('entity');
+         
+         // 添加复杂业务过滤逻辑
+         if (filters.status) {
+           query.andWhere('entity.status = :status', { status: filters.status });
+         }
+         
+         // 多表关联查询示例
+         if (filters.includeRelated) {
+           query.leftJoinAndSelect('entity.relatedEntity', 'related');
+         }
+         
+         const [items, total] = await query.getManyAndCount();
+         return [items, total];
+       }
+       
+       /**
+        * 根据ID获取单个实体
+        */
+       async findById(id: number): Promise<YourEntity> {
+         const entity = await this.repository.findOneBy({ id });
+         if (!entity) {
+           throw new AppError('实体不存在', 404);
+         }
+         return entity;
+       }
+       
+       /**
+        * 创建实体(带业务规则验证)
+        */
+       async create(data: CreateYourEntityDto): Promise<YourEntity> {
+         // 业务规则验证示例
+         const existing = await this.repository.findOneBy({ name: data.name });
+         if (existing) {
+           throw new AppError('名称已存在', 400);
+         }
+         
+         const entity = this.repository.create(data);
+         return this.repository.save(entity);
+       }
+       
+       /**
+        * 更新实体(带业务逻辑处理)
+        */
+       async update(id: number, data: UpdateYourEntityDto): Promise<YourEntity> {
+         const entity = await this.findById(id);
+         
+         // 业务逻辑处理示例
+         if (data.name && data.name !== entity.name) {
+           // 记录名称变更日志等业务操作
+         }
+         
+         Object.assign(entity, data);
+         return this.repository.save(entity);
+       }
+       
+       /**
+        * 删除实体(带权限检查)
+        */
+       async delete(id: number, userId: number): Promise<boolean> {
+         const entity = await this.findById(id);
+         
+         // 权限检查示例
+         if (entity.createdBy !== userId) {
+           throw new AppError('没有删除权限', 403);
+         }
+         
+         await this.repository.remove(entity);
+         return true;
+       }
+       
+       /**
+        * 自定义业务方法示例
+        */
+       async customBusinessOperation(params: any): Promise<any> {
+         // 实现复杂业务逻辑
+         // 可能包含事务、多表操作等
+       }
+     }
+     ```
+
+### 4. **创建自定义API路由**
+   - 目录结构:
+     ```
+     src/server/api/[实体名]/
+     ├── get.ts       # 列表查询
+     ├── post.ts      # 创建实体
+     ├── [id]/
+     │   ├── get.ts   # 获取单个实体
+     │   ├── put.ts   # 更新实体
+     │   └── delete.ts # 删除实体
+     └── index.ts     # 路由聚合
+     ```
+   
+   - **列表查询路由示例** (get.ts):
+     ```typescript
+     import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+     import { z } from 'zod';
+     import { YourEntitySchema } from '@/server/modules/your-module/your-entity.entity';
+     import { ErrorSchema } from '@/server/utils/errorHandler';
+     import { AppDataSource } from '@/server/data-source';
+     import { YourEntityService } from '@/server/modules/your-module/your-entity.service';
+     import { AuthContext } from '@/server/types/context';
+     import { authMiddleware } from '@/server/middleware/auth.middleware';
+     
+     // 查询参数Schema
+     const ListQuery = z.object({
+       page: z.coerce.number().int().positive().default(1).openapi({
+         description: '页码',
+         example: 1
+       }),
+       pageSize: z.coerce.number().int().positive().default(10).openapi({
+         description: '每页条数',
+         example: 10
+       }),
+       status: z.coerce.number().optional().openapi({
+         description: '状态过滤',
+         example: 1
+       })
+     });
+     
+     // 响应Schema
+     const ListResponse = z.object({
+       data: z.array(YourEntitySchema),
+       pagination: z.object({
+         total: z.number().openapi({ example: 100, description: '总记录数' }),
+         current: z.number().openapi({ example: 1, description: '当前页码' }),
+         pageSize: z.number().openapi({ example: 10, description: '每页数量' })
+       })
+     });
+     
+     // 路由定义
+     const routeDef = createRoute({
+       method: 'get',
+       path: '/',
+       middleware: [authMiddleware],
+       request: {
+         query: ListQuery
+       },
+       responses: {
+         200: {
+           description: '成功获取实体列表',
+           content: { 'application/json': { schema: ListResponse } }
+         },
+         400: {
+           description: '请求参数错误',
+           content: { 'application/json': { schema: ErrorSchema } }
+         },
+         500: {
+           description: '服务器错误',
+           content: { 'application/json': { schema: ErrorSchema } }
+         }
+       }
+     });
+     
+     // 路由实现
+     const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+       try {
+         const query = c.req.valid('query');
+         const service = new YourEntityService(AppDataSource);
+         
+         const [data, total] = await service.findAll({
+           status: query.status,
+           // 其他过滤条件
+         });
+         
+         return c.json({
+           data,
+           pagination: {
+             total,
+             current: query.page,
+             pageSize: query.pageSize
+           }
+         }, 200);
+       } catch (error) {
+         const { code = 500, message = '获取列表失败' } = error as Error & { code?: number };
+         return c.json({ code, message }, code);
+       }
+     });
+     
+     export default app;
+     ```
+     
+   - **创建实体路由示例** (post.ts):
+     ```typescript
+     import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+     import { CreateYourEntityDto, YourEntitySchema } from '@/server/modules/your-module/your-entity.entity';
+     import { ErrorSchema } from '@/server/utils/errorHandler';
+     import { AppDataSource } from '@/server/data-source';
+     import { YourEntityService } from '@/server/modules/your-module/your-entity.service';
+     import { AuthContext } from '@/server/types/context';
+     import { authMiddleware } from '@/server/middleware/auth.middleware';
+     
+     // 路由定义
+     const routeDef = createRoute({
+       method: 'post',
+       path: '/',
+       middleware: [authMiddleware],
+       request: {
+         body: {
+           content: {
+             'application/json': { schema: CreateYourEntityDto }
+           }
+         }
+       },
+       responses: {
+         200: {
+           description: '成功创建实体',
+           content: { 'application/json': { schema: YourEntitySchema } }
+         },
+         400: {
+           description: '请求参数错误',
+           content: { 'application/json': { schema: ErrorSchema } }
+         },
+         500: {
+           description: '服务器错误',
+           content: { 'application/json': { schema: ErrorSchema } }
+         }
+       }
+     });
+     
+     // 路由实现
+     const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
+       try {
+         const data = await c.req.json();
+         const service = new YourEntityService(AppDataSource);
+         const result = await service.create(data);
+         return c.json(result, 200);
+       } catch (error) {
+         const { code = 500, message = '创建实体失败' } = error as Error & { code?: number };
+         return c.json({ code, message }, code);
+       }
+     });
+     
+     export default app;
+     ```
+     
+   - **路由聚合示例** (index.ts):
+     ```typescript
+     import { OpenAPIHono } from '@hono/zod-openapi';
+     import listRoute from './get';
+     import createRoute from './post';
+     import getByIdRoute from './[id]/get';
+     import updateRoute from './[id]/put';
+     import deleteRoute from './[id]/delete';
+     
+     const app = new OpenAPIHono()
+       .route('/', listRoute)
+       .route('/', createRoute)
+       .route('/', getByIdRoute)
+       .route('/', updateRoute)
+       .route('/', deleteRoute);
+     
+     export default app;
+     ```
+
+### 5. **注册路由**
+   - 在`src/server/api.ts`中添加路由注册:
+     ```typescript
+     import yourEntityRoutes from '@/server/api/your-entity/index';
+     
+     // 注册路由
+     api.route('/api/v1/your-entities', yourEntityRoutes);
+     ```
+
+### 6. **创建客户端API**
+   - 在`src/client/api.ts`中添加客户端定义:
+     ```typescript
+     import { hc } from 'hono/client';
+     import { YourEntityRoutes } from '@/server/api';
+     
+     export const yourEntityClient = hc<YourEntityRoutes>('/api/v1', {
+       fetch: axiosFetch,
+     }).api.v1['your-entities'];
+     ```
+
+### 7. **前端调用**
+    - 在页面组件(如`Users.tsx`)中:
+      - 使用`InferResponseType`提取响应类型
+      - 使用`InferRequestType`提取请求类型
+      - 示例:
+        ```typescript
+        type EntityResponse = InferResponseType<typeof entityClient.$get, 200>;
+        type CreateRequest = InferRequestType<typeof entityClient.$post>['json'];
+        ```
+
+### 8. **注册管理后台路由和菜单**
+    - **注册路由**:在`src/client/admin/routes.tsx`中添加路由配置
+      
+    - **注册菜单**:在`src/client/admin/menu.tsx`中添加菜单配置

+ 58 - 0
.roo/rules/11-entity-creation.md

@@ -0,0 +1,58 @@
+# 新实体创建流程规范
+
+## 流程概述
+
+实体创建流程分为两种模式,根据业务复杂度选择合适的实现方式:
+
+- **标准通用CRUD**:适用于简单数据模型,使用`GenericCrudService`和`createCrudRoutes`快速生成基础CRUD接口
+- **自定义复杂CRUD**:适用于包含复杂业务逻辑的实体,需要手动实现服务方法和路由处理
+
+## 适用场景选择
+
+| 类型 | 适用场景 | 技术选型 |
+|------|----------|----------|
+| 标准通用CRUD | 简单数据管理、无复杂业务逻辑、基础CRUD操作 | `GenericCrudService` + `createCrudRoutes` |
+| 自定义复杂CRUD | 复杂业务规则、多表关联操作、特殊权限控制、非标准数据处理 | 自定义Service + 手动路由实现 |
+
+## 标准通用CRUD开发流程
+
+适用于简单数据模型,无复杂业务逻辑,仅需基础CRUD操作的场景。采用`GenericCrudService`和`createCrudRoutes`快速生成接口。
+
+### 开发步骤概要
+
+1. **创建实体**:在`src/server/modules/[模块名]/[实体名].entity.ts`定义实体类和Zod Schema
+2. **注册实体**:在`src/server/data-source.ts`中注册新实体
+3. **创建Service**:继承`GenericCrudService`实现基础CRUD操作
+4. **创建API路由**:使用`createCrudRoutes`快速生成CRUD路由
+5. **注册路由**:在`src/server/api.ts`中注册路由
+6. **创建客户端API**:在`src/client/api.ts`中定义客户端调用方法
+7. **前端调用**:在页面组件中使用类型化API调用
+8. **注册路由和菜单**:
+   - 管理后台:在`src/client/admin/routes.tsx`中添加路由配置,在`src/client/admin/menu.tsx`中添加菜单配置
+   - 前台:在`src/client/home/routes.tsx`中添加路由配置
+
+详细流程请参见[标准通用CRUD开发流程规范](./11-standard-crud.md)
+## 自定义复杂CRUD开发流程
+
+适用于包含复杂业务逻辑的实体,需要手动实现服务方法和路由处理的场景,如复杂业务规则、多表关联操作、特殊权限控制等。
+
+### 开发步骤概要
+
+1. **创建实体**:在`src/server/modules/[模块名]/[实体名].entity.ts`定义实体类和Zod Schema
+2. **注册实体**:在`src/server/data-source.ts`中注册新实体
+3. **创建自定义Service**:实现包含复杂业务逻辑的数据访问方法
+4. **创建自定义API路由**:手动实现CRUD路由及处理逻辑
+5. **注册路由**:在`src/server/api.ts`中注册路由
+6. **创建客户端API**:在`src/client/api.ts`中定义客户端调用方法
+7. **前端调用**:在页面组件中使用类型化API调用
+8. **注册路由和菜单**:
+   - 管理后台:在`src/client/admin/routes.tsx`中添加路由配置,在`src/client/admin/menu.tsx`中添加菜单配置
+   - 前台:在`src/client/home/routes.tsx`中添加路由配置
+
+详细流程请参见[自定义复杂CRUD开发流程规范](./11-custom-crud.md)
+## 注意事项
+
+1. 实体Schema必须在实体文件中定义,路由中直接引用,不要重复定义
+2. 前端表格/表单字段必须与实体定义保持一致
+3. 确保所有API调用都有正确的类型推断
+4. 参考现有模块实现保持风格一致

+ 33 - 0
.roo/rules/11-home-frontend.md

@@ -0,0 +1,33 @@
+# 前台Home页面开发流程规范 (Tailwind CSS版)
+
+## 适用场景
+
+前台用户界面开发,包括首页、登录页、注册页、会员中心等面向普通用户的页面实现流程。采用原生Tailwind CSS进行样式开发。不使用antd
+
+## 目录结构
+
+```
+src/client/home/
+├── index.tsx           # 入口文件
+├── routes.tsx          # 路由配置
+├── components/         # 共享组件
+│   ├── ErrorPage.tsx   # 错误页面
+│   ├── NotFoundPage.tsx # 404页面
+│   └── ProtectedRoute.tsx # 路由保护组件
+├── hooks/              # 自定义hooks
+│   └── AuthProvider.tsx # 认证上下文
+├── layouts/            # 布局组件
+│   └── MainLayout.tsx  # 主布局
+└── pages/              # 页面组件
+    ├── HomePage.tsx    # 首页
+    ├── LoginPage.tsx   # 登录页
+    ├── RegisterPage.tsx # 注册页
+    └── MemberPage.tsx  # 会员中心
+```
+
+### 1. **创建页面组件**
+   - 位置: `src/client/home/pages/[PageName].tsx`
+
+### 2. **注册路由配置**
+   - 位置: `src/client/home/routes.tsx`
+     ```

+ 100 - 0
.roo/rules/11-standard-crud.md

@@ -0,0 +1,100 @@
+# 标准通用CRUD开发流程规范
+
+## 适用场景
+
+适用于简单数据模型,无复杂业务逻辑,仅需基础CRUD操作的场景。采用`GenericCrudService`和`createCrudRoutes`快速生成接口。
+
+## 开发流程
+
+### 1. **创建实体**
+   - 位置: `src/server/modules/[模块名]/[实体名].entity.ts`
+   - 参考已有实体文件如`user.entity.ts`
+   - 注意: 必须包含Zod Schema定义
+
+### 2. **注册实体到数据源**
+   - 在`src/server/data-source.ts`中添加实体导入和注册:
+     ```typescript
+     // 实体类导入
+     import { YourEntity } from "./modules/[模块名]/[实体名].entity"
+     
+     export const AppDataSource = new DataSource({
+       // ...其他配置
+       entities: [
+         User, Role, YourEntity // 添加新实体到数组
+       ],
+       // ...其他配置
+     });
+     ```
+
+### 3. **创建Service**
+   - 位置: `src/server/modules/[模块名]/[实体名].service.ts`
+   - 继承`GenericCrudService`
+   - 通过构造函数注入DataSource
+   ```typescript
+   import { GenericCrudService } from '@/server/utils/generic-crud.service';
+   import { DataSource } from 'typeorm';
+   import { YourEntity } from './your-entity.entity';
+   
+   export class YourEntityService extends GenericCrudService<YourEntity> {
+     constructor(dataSource: DataSource) {
+       super(dataSource, YourEntity);
+     }
+   }
+   ```
+
+### 4. **创建API路由**
+   - 使用`createCrudRoutes`快速生成CRUD路由:
+     ```typescript
+     import { createCrudRoutes } from '@/server/utils/generic-crud.routes';
+     import { YourEntity } from '@/server/modules/your-module/your-entity.entity';
+     import { YourEntitySchema, CreateYourEntityDto, UpdateYourEntityDto } from '@/server/modules/your-module/your-entity.entity';
+     import { authMiddleware } from '@/server/middleware/auth.middleware';
+     
+     const yourEntityRoutes = createCrudRoutes({
+       entity: YourEntity,
+       createSchema: CreateYourEntityDto,
+       updateSchema: UpdateYourEntityDto,
+       getSchema: YourEntitySchema,
+       listSchema: YourEntitySchema,
+       searchFields: ['name', 'description'], // 可选,指定搜索字段
+       middleware: [authMiddleware] // 可选,添加中间件
+     });
+     
+     export default yourEntityRoutes;
+     ```
+
+### 5. **注册路由**
+   - 在`src/server/api.ts`中添加路由注册:
+     ```typescript
+     import yourEntityRoutes from '@/server/api/your-entity/index';
+     
+     // 注册路由
+     api.route('/api/v1/your-entities', yourEntityRoutes);
+     ```
+
+### 6. **创建客户端API**
+   - 在`src/client/api.ts`中添加客户端定义:
+     ```typescript
+     import { hc } from 'hono/client';
+     import { YourEntityRoutes } from '@/server/api';
+     
+     export const yourEntityClient = hc<YourEntityRoutes>('/api/v1', {
+       fetch: axiosFetch,
+     }).api.v1['your-entities'];
+     ```
+
+### 7. **前端调用**
+   - 在页面组件(如`Users.tsx`)中:
+     - 使用`InferResponseType`提取响应类型
+     - 使用`InferRequestType`提取请求类型
+     - 示例:
+       ```typescript
+       type EntityResponse = InferResponseType<typeof entityClient.$get, 200>;
+       type CreateRequest = InferRequestType<typeof entityClient.$post>['json'];
+       ```
+
+### 8. **注册管理后台路由和菜单**
+    - **注册路由**:在`src/client/admin/routes.tsx`中添加路由配置
+      
+    - **注册菜单**:在`src/client/admin/menu.tsx`中添加菜单配置
+

+ 262 - 0
.roo/rules/12-generic-crud.md

@@ -0,0 +1,262 @@
+# 通用CRUD实现规范
+
+## 概述
+
+通用CRUD模块提供标准化的增删改查功能实现,通过泛型机制支持快速创建实体的RESTful API接口。本规范定义了使用通用CRUD服务和路由的标准流程和最佳实践。
+
+## 1. 通用CRUD服务 (GenericCrudService)
+
+### 1.1 基础用法
+
+通用CRUD服务提供基础的数据操作方法,所有实体服务类应继承此类:
+
+```typescript
+import { GenericCrudService } from '@/server/utils/generic-crud.service';
+import { DataSource } from 'typeorm';
+import { YourEntity } from '@/server/modules/your-module/your-entity.entity';
+
+export class YourEntityService extends GenericCrudService<YourEntity> {
+  constructor(dataSource: DataSource) {
+    super(dataSource, YourEntity);
+  }
+  
+  // 可以重写或扩展基础方法
+  async customMethod() {
+    // 自定义业务逻辑
+  }
+}
+```
+
+### 1.2 核心方法
+
+| 方法 | 描述 | 参数 | 返回值 |
+|------|------|------|--------|
+| `getList` | 获取分页列表 | `page`, `pageSize`, `keyword`, `searchFields`, `where`, `relations`, `order` | `[T[], number]` |
+| `getById` | 根据ID获取单个实体 | `id: number`, `relations?: string[]` | `T \| null` |
+| `create` | 创建实体 | `data: DeepPartial<T>` | `T` |
+| `update` | 更新实体 | `id: number`, `data: Partial<T>` | `T \| null` |
+| `delete` | 删除实体 | `id: number` | `boolean` |
+| `createQueryBuilder` | 创建查询构建器 | `alias?: string` | `QueryBuilder<T>` |
+
+### 1.3 构造函数注入
+
+必须通过构造函数注入`DataSource`,禁止直接使用全局实例:
+
+```typescript
+// 正确示例
+constructor(private dataSource: DataSource) {
+  super(dataSource, YourEntity);
+}
+
+// 错误示例
+constructor() {
+  super(AppDataSource, YourEntity); // 禁止使用全局AppDataSource
+}
+```
+
+## 2. 通用CRUD路由 (createCrudRoutes)
+
+### 2.1 基础用法
+
+通过`createCrudRoutes`函数快速创建标准CRUD路由:
+
+```typescript
+import { createCrudRoutes } from '@/server/utils/generic-crud.routes';
+import { YourEntity } from '@/server/modules/your-module/your-entity.entity';
+import { YourEntitySchema, CreateYourEntityDto, UpdateYourEntityDto } from '@/server/modules/your-module/your-entity.entity';
+import { authMiddleware } from '@/server/middleware/auth.middleware';
+
+const yourEntityRoutes = createCrudRoutes({
+  entity: YourEntity,
+  createSchema: CreateYourEntityDto,
+  updateSchema: UpdateYourEntityDto,
+  getSchema: YourEntitySchema,
+  listSchema: YourEntitySchema,
+  searchFields: ['name', 'description'], // 可选,指定搜索字段
+  relations: ['relatedEntity'], // 可选,指定关联查询关系(支持嵌套关联,如 ['relatedEntity.client'])
+  middleware: [authMiddleware] // 可选,添加中间件
+});
+
+export default yourEntityRoutes;
+```
+
+### 2.2 配置选项 (CrudOptions)
+
+| 参数 | 类型 | 描述 | 是否必需 |
+|------|------|------|----------|
+| `entity` | `new () => T` | 实体类构造函数 | 是 |
+| `createSchema` | `z.ZodSchema` | 创建实体的Zod验证 schema | 是 |
+| `updateSchema` | `z.ZodSchema` | 更新实体的Zod验证 schema | 是 |
+| `getSchema` | `z.ZodSchema` | 获取单个实体的响应 schema | 是 |
+| `listSchema` | `z.ZodSchema` | 获取列表的响应 schema | 是 |
+| `searchFields` | `string[]` | 搜索字段数组,用于关键词搜索 | 否 |
+| `relations` | `string[]` | 关联查询配置,指定需要关联查询的关系 | 否 |
+| `middleware` | `any[]` | 应用于所有CRUD路由的中间件数组 | 否 |
+
+### 2.3 生成的路由
+
+调用`createCrudRoutes`会自动生成以下标准RESTful路由:
+
+| 方法 | 路径 | 描述 |
+|------|------|------|
+| GET | `/` | 获取实体列表(支持分页、搜索、排序、关联查询) |
+| POST | `/` | 创建新实体 |
+| GET | `/{id}` | 获取单个实体详情(支持关联查询) |
+| PUT | `/{id}` | 更新实体 |
+| DELETE | `/{id}` | 删除实体 |
+
+### 2.4 路由注册
+
+生成的路由需要在API入口文件中注册:
+
+```typescript
+// src/server/api.ts
+import yourEntityRoutes from '@/server/api/your-entity/index';
+
+// 注册路由
+api.route('/api/v1/your-entities', yourEntityRoutes);
+```
+
+## 3. 实体类要求
+
+使用通用CRUD模块的实体类必须满足以下要求:
+
+1. 必须包含主键`id`字段,类型为数字
+2. 必须定义配套的Zod schema:
+   - 实体完整schema(用于响应)
+   - 创建DTO schema(用于创建请求验证)
+   - 更新DTO schema(用于更新请求验证)
+
+示例:
+
+```typescript
+// your-entity.entity.ts
+import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, OneToMany } from 'typeorm';
+import { z } from '@hono/zod-openapi';
+import { RelatedEntity } from './related-entity.entity';
+
+@Entity('your_entity')
+export class YourEntity {
+  @PrimaryGeneratedColumn({ unsigned: true })
+  id!: number;
+
+  @Column({ name: 'name', type: 'varchar', length: 255 })
+  name!: string;
+  
+  @ManyToOne(() => RelatedEntity, related => related.yourEntities)
+  relatedEntity!: RelatedEntity;
+  
+  // 其他字段...
+}
+
+// Zod schemas
+export const YourEntitySchema = z.object({
+  id: z.number().int().positive().openapi({ description: '实体ID' }),
+  name: z.string().max(255).openapi({ description: '名称', example: '示例名称' }),
+  relatedEntity: RelatedEntitySchema, // 关联实体schema
+  // 其他字段schema...
+});
+
+export const CreateYourEntityDto = z.object({
+  name: z.string().max(255).openapi({ description: '名称', example: '示例名称' }),
+  relatedEntityId: z.number().int().positive().openapi({ description: '关联实体ID', example: 1 }),
+  // 其他创建字段schema...
+});
+
+export const UpdateYourEntityDto = z.object({
+  name: z.string().max(255).optional().openapi({ description: '名称', example: '示例名称' }),
+  relatedEntityId: z.number().int().positive().optional().openapi({ description: '关联实体ID', example: 1 }),
+  // 其他更新字段schema...
+});
+```
+
+## 4. 高级用法
+
+### 4.1 自定义中间件
+
+可以为CRUD路由添加自定义中间件,如认证和权限控制:
+
+```typescript
+import { authMiddleware } from '@/server/middleware/auth.middleware';
+import { permissionMiddleware } from '@/server/middleware/permission.middleware';
+
+const yourEntityRoutes = createCrudRoutes({
+  // ...其他配置
+  middleware: [
+    authMiddleware, 
+    permissionMiddleware(['your_entity:read', 'your_entity:write'])
+  ]
+});
+```
+
+### 4.2 扩展路由
+
+生成基础CRUD路由后,可以添加自定义路由:
+
+```typescript
+import { OpenAPIHono } from '@hono/zod-openapi';
+
+const app = new OpenAPIHono()
+  .route('/', yourEntityRoutes)
+  .get('/custom-action', (c) => {
+    // 自定义路由处理逻辑
+    return c.json({ message: '自定义操作' });
+  });
+
+export default app;
+```
+
+### 4.3 重写服务方法
+
+当通用CRUD服务的默认实现不满足需求时,可以重写相应方法:
+
+```typescript
+export class YourEntityService extends GenericCrudService<YourEntity> {
+  // ...构造函数
+  
+  async getList(
+    page: number = 1,
+    pageSize: number = 10,
+    keyword?: string,
+    searchFields?: string[],
+    where: Partial<YourEntity> = {},
+    relations: string[] = [],
+    order: { [P in keyof YourEntity]?: 'ASC' | 'DESC' } = {}
+  ): Promise<[YourEntity[], number]> {
+    // 添加自定义过滤条件
+    where.isDeleted = 0; // 例如:默认过滤已删除数据
+    
+    return super.getList(page, pageSize, keyword, searchFields, where, relations, order);
+  }
+}
+```
+
+## 5. 错误处理
+
+通用CRUD模块已内置标准错误处理机制:
+
+1. 参数验证错误:返回400状态码和验证错误详情
+2. 资源不存在:返回404状态码
+3. 服务器错误:返回500状态码和错误消息
+
+所有错误响应格式统一为:
+```json
+{
+  "code": 错误代码,
+  "message": "错误描述",
+  "errors": 可选的详细错误信息
+}
+```
+
+## 6. 最佳实践
+
+1. **单一职责**:通用CRUD仅处理标准数据操作,复杂业务逻辑应在具体服务类中实现
+2. **命名规范**:
+   - 服务类:`[EntityName]Service`
+   - 路由文件:遵循RESTful资源命名规范,使用复数形式
+3. **权限控制**:始终为CRUD路由添加适当的认证和授权中间件
+4. **数据验证**:确保Zod schema包含完整的验证规则和OpenAPI元数据
+5. **搜索优化**:合理设置`searchFields`,避免在大表的文本字段上进行模糊搜索
+6. **分页处理**:所有列表接口必须支持分页,避免返回大量数据
+7. **关联查询**:使用`relations`配置时,避免过度关联导致性能问题
+8. **事务管理**:复杂操作应使用事务确保数据一致性

+ 169 - 0
.roo/rules/13-ui-style.md

@@ -0,0 +1,169 @@
+# 管理后台界面开发规范
+
+## 1. 布局规范
+
+### 1.1 整体布局结构
+- 采用三栏布局:侧边导航栏 + 顶部操作栏 + 主内容区
+- 侧边栏固定宽度240px,支持折叠功能
+- 顶部导航栏高度固定为64px
+- 主内容区边距统一为24px
+
+### 1.2 响应式设计
+- 桌面端:完整三栏布局
+- 平板端:可折叠侧边栏
+- 移动端:侧边栏转为抽屉式导航
+
+### 1.3 容器样式
+- 卡片容器使用白色背景(#ffffff)
+- 卡片阴影使用 `shadow-sm transition-all duration-300 hover:shadow-md`
+- 卡片边框使用 `border: none`
+- 卡片圆角统一为 `border-radius: 6px`
+
+## 2. 色彩规范
+
+### 2.1 主色调
+- 主色:蓝色(#1890ff),用于主要按钮、选中状态和关键交互元素
+- 辅助色:绿色(#52c41a)用于成功状态,红色(#ff4d4f)用于错误状态,黄色(#faad14)用于警告状态
+
+### 2.2 中性色
+- 背景色:浅灰(#f5f5f5)用于页面背景,白色(#ffffff)用于卡片背景
+- 文本色:深灰(#1f2937)用于主要文本,中灰(#6b7280)用于次要文本,浅灰(#9ca3af)用于提示文本
+
+## 3. 组件样式规范
+
+### 3.1 按钮样式
+- 主要按钮:使用主色调背景,白色文字
+- 按钮高度统一为40px,大型按钮使用48px
+- 按钮圆角统一为4px
+- 按钮文本使用14px字体
+- 按钮添加悬停效果:`hover:shadow-lg transition-all duration-200`
+
+### 3.2 表单元素
+- 输入框高度统一为40px
+- 输入框前缀图标颜色使用主色调
+- 表单标签宽度统一为80px
+- 表单布局使用垂直布局,标签在上,输入框在下
+- 输入框聚焦状态:`focus:border-primary focus:ring-1 focus:ring-primary`
+
+### 3.5 日期表单组件
+- 日期选择器使用 `DatePicker` 组件,时间选择使用 `TimePicker` 组件
+- 日期选择器大小与输入框保持一致:`size="middle"`
+- 日期格式统一为 `YYYY-MM-DD`,时间格式为 `HH:mm:ss`
+- 日期范围选择使用 `RangePicker` 组件,格式为 `[YYYY-MM-DD, YYYY-MM-DD]`
+- 日期选择器添加清除按钮:`allowClear`
+- 日期选择器添加占位提示:`placeholder="请选择日期"`
+- 日期选择器禁用未来日期:`disabledDate={(current) => current && current > dayjs().endOf('day')}`(根据业务需求调整)
+- 日期对象规范:始终使用dayjs对象而非原生Date对象,避免出现"isValid is not a function"错误
+  ```typescript
+  // 错误示例 - 使用原生Date对象
+  form.setFieldsValue({
+    noteDate: new Date(record.noteDate) // 导致验证失败
+  });
+  
+  // 正确示例 - 使用dayjs对象
+  form.setFieldsValue({
+    noteDate: dayjs(record.noteDate) // 正常支持验证方法
+  });
+  ```
+- 日期时间转换规范:
+  ```typescript
+  // 日期对象转字符串(提交给后端)
+  const formatDate = (date: Dayjs | null) => {
+    return date ? date.format('YYYY-MM-DD') : '';
+  };
+  
+  // 字符串转日期对象(从后端接收)
+  const parseDate = (str: string) => {
+    return str ? dayjs(str) : null;
+  };
+  
+  // 日期时间对象转字符串
+  const formatDateTime = (date: Dayjs | null) => {
+    return date ? date.format('YYYY-MM-DD HH:mm:ss') : '';
+  };
+  
+  // 日期范围转换
+  const formatDateRange = (range: [Dayjs | null, Dayjs | null]) => {
+    return range && range[0] && range[1]
+      ? [range[0].format('YYYY-MM-DD'), range[1].format('YYYY-MM-DD')]
+      : [];
+  };
+  ```
+
+### 3.3 表格样式
+- 表格添加边框:`bordered`
+- 表头背景色使用浅灰(#f9fafb)
+- 表格行添加交替背景色:`rowClassName={(record, index) => index % 2 === 0 ? 'bg-white' : 'bg-gray-50'}`
+- 支持横向滚动:`scroll={{ x: 'max-content' }}`
+
+### 3.4 卡片组件
+- 卡片标题区使用 `flex items-center justify-between` 布局
+- 统计数字使用28px字体大小
+- 添加卡片图标时使用24px大小,颜色与统计项主题匹配
+- 卡片底部添加辅助信息,使用12px浅灰色字体
+
+## 4. 页面规范
+
+### 4.1 页面标题
+- 页面标题使用 `Title level={2}` 组件
+- 标题区添加 `mb-6 flex justify-between items-center` 样式
+- 标题右侧可放置操作按钮组
+
+### 4.2 登录页面
+- 使用渐变背景:`bg-gradient-to-br from-blue-50 to-indigo-100`
+- 登录卡片居中显示,添加阴影效果:`shadow-lg`
+- 登录表单添加图标前缀增强可读性
+- 底部添加版权信息和测试账号提示
+
+### 4.3 数据展示页面
+- 数据卡片使用响应式布局,在不同屏幕尺寸下自动调整列数
+- 关键数据使用 `Statistic` 组件展示
+- 添加数据趋势指示和环比增长信息
+- 数据加载状态使用 `loading` 属性
+
+## 5. 交互规范
+
+### 5.1 悬停效果
+- 可交互元素添加悬停效果
+- 卡片悬停效果:`hover:shadow-md transition-all duration-300`
+- 按钮悬停效果:`hover:shadow-lg transition-all duration-200`
+
+### 5.2 模态框
+- 模态框使用 `destroyOnClose` 属性确保每次打开都是新实例
+- 模态框居中显示:`centered`
+- 禁止点击遮罩关闭:`maskClosable={false}`
+- 表单模态框使用垂直布局
+
+### 5.3 反馈机制
+- 操作成功/失败使用 `message` 组件提供反馈
+- 加载状态使用 `loading` 属性显示加载指示器
+- 删除等危险操作使用 `Popconfirm` 组件二次确认
+
+## 5.4 消息提示规范
+- 统一使用App.useApp()获取message实例
+  ```typescript
+  import { App } from 'antd';
+  const { message } = App.useApp();
+  ```
+- 消息提示使用明确的类型区分:
+  ```typescript
+  message.success('操作成功');
+  message.error('操作失败');
+  message.warning('警告信息');
+  message.info('提示信息');
+  ```
+- 消息显示时长统一使用默认值,重要操作可适当延长:`message.success('操作成功', 3);`
+
+## 6. 图标规范
+
+### 6.1 图标选择
+- 用户相关:UserOutlined
+- 密码相关:LockOutlined
+- 搜索相关:SearchOutlined
+- 消息相关:BellOutlined
+- 眼睛相关:EyeOutlined/EyeInvisibleOutlined
+
+### 6.2 图标样式
+- 功能图标大小统一为24px
+- 前缀图标颜色与主题匹配
+- 操作图标使用 `Button type="link"` 样式

+ 207 - 0
.roo/rules/14-crud-filtering.md

@@ -0,0 +1,207 @@
+# 通用CRUD筛选规范
+
+## 概述
+
+本规范定义了通用CRUD模块的增强筛选功能,支持多种查询模式和灵活的筛选条件。
+
+## 新增功能
+
+### 1. 筛选参数支持
+- **参数名**: `filters`
+- **类型**: JSON字符串
+- **位置**: 查询参数
+- **可选**: 是
+
+### 2. 支持的筛选操作
+
+| 操作类型 | 语法格式 | 示例 | 说明 |
+|----------|----------|------|------|
+| 精确匹配 | `"字段名": 值` | `{"status": 1}` | 等于指定值 |
+| 模糊匹配 | `"字段名": "%值%"` | `{"name": "%张%"}` | LIKE查询,包含指定值 |
+| 大于 | `"字段名": {"gt": 值}` | `{"age": {"gt": 18}}` | 大于指定值 |
+| 大于等于 | `"字段名": {"gte": 值}` | `{"age": {"gte": 18}}` | 大于等于指定值 |
+| 小于 | `"字段名": {"lt": 值}` | `{"score": {"lt": 60}}` | 小于指定值 |
+| 小于等于 | `"字段名": {"lte": 值}` | `{"score": {"lte": 60}}` | 小于等于指定值 |
+| 范围查询 | `"字段名": {"between": [最小值, 最大值]}` | `{"createdAt": {"between": ["2024-01-01", "2024-12-31"]}}` | 在指定范围内 |
+| IN查询 | `"字段名": [值1, 值2, ...]` | `{"status": [1, 2, 3]}` | 值在指定数组中 |
+| NULL匹配 | `"字段名": null` | `{"deletedAt": null}` | 字段为NULL |
+
+### 3. 组合查询
+支持多个条件同时筛选,所有条件为AND关系:
+
+```json
+{
+  "status": 1,
+  "name": "%张%",
+  "createdAt": {"gte": "2024-01-01"}
+}
+```
+
+## API使用规范
+
+### 请求格式
+```http
+GET /api/v1/entities?filters={"status":1,"name":"%张%","createdAt":{"gte":"2024-01-01"}}
+```
+
+### 响应格式
+```json
+{
+  "data": [...],
+  "pagination": {
+    "total": 100,
+    "current": 1,
+    "pageSize": 10
+  }
+}
+```
+
+### 错误处理
+- 格式错误:返回400状态码,message为"筛选条件格式错误"
+- 字段不存在:安全忽略,不影响查询
+- 类型不匹配:安全处理,返回空结果
+
+## 前端集成规范
+
+### React Hook示例
+```typescript
+const useEntityList = () => {
+  const [data, setData] = useState([]);
+  
+  const fetchData = async (filters = {}) => {
+    const response = await client.$get({
+      query: {
+        page: 1,
+        pageSize: 10,
+        filters: JSON.stringify(filters)
+      }
+    });
+    // 处理响应...
+  };
+  
+  return { data, fetchData };
+};
+```
+
+### ProTable集成
+```typescript
+const columns = [
+  {
+    title: '状态',
+    dataIndex: 'status',
+    valueType: 'select',
+    valueEnum: { 0: '禁用', 1: '启用' },
+  },
+  {
+    title: '创建时间',
+    dataIndex: 'createdAt',
+    valueType: 'dateRange',
+  },
+];
+
+const handleRequest = async (params) => {
+  const filters = {};
+  
+  if (params.status !== undefined) filters.status = params.status;
+  if (params.createdAt?.length === 2) {
+    filters.createdAt = { between: params.createdAt };
+  }
+  
+  return client.$get({
+    query: {
+      page: params.current,
+      pageSize: params.pageSize,
+      keyword: params.keyword,
+      filters: JSON.stringify(filters)
+    }
+  });
+};
+```
+
+## 后端实现规范
+
+### GenericCrudService使用
+```typescript
+// 直接使用(无需修改)
+const service = new GenericCrudService(dataSource, UserEntity);
+const [data, total] = await service.getList(
+  page, pageSize, keyword, searchFields, where, relations, order, filters
+);
+
+// 自定义实现
+export class UserService extends GenericCrudService<User> {
+  async getList(
+    page: number = 1,
+    pageSize: number = 10,
+    keyword?: string,
+    searchFields?: string[],
+    where?: Partial<User>,
+    relations: string[] = [],
+    order: any = {},
+    filters?: any
+  ) {
+    // 添加业务特定的筛选
+    const customFilters = {
+      ...filters,
+      isDeleted: 0
+    };
+    
+    return super.getList(page, pageSize, keyword, searchFields, where, relations, order, customFilters);
+  }
+}
+```
+
+## 最佳实践
+
+### 1. 性能优化
+- 为常用筛选字段添加数据库索引
+- 避免对大字段进行模糊查询
+- 合理使用分页参数
+
+### 2. 安全考虑
+- 避免传递敏感字段到filters
+- 验证用户权限相关的筛选条件
+- 限制查询结果集大小
+
+### 3. 类型安全
+```typescript
+// 推荐:定义筛选类型
+interface UserFilters {
+  status?: number;
+  name?: string;
+  age?: { gte?: number; lte?: number };
+  createdAt?: { between?: [string, string] };
+}
+
+// 使用时
+const filters: UserFilters = { status: 1 };
+```
+
+### 4. 错误处理
+```typescript
+try {
+  const filters = JSON.parse(query.filters);
+  // 验证filters结构...
+} catch (error) {
+  return { code: 400, message: '筛选条件格式错误' };
+}
+```
+
+## 常见问题
+
+### Q: 如何忽略大小写的模糊匹配?
+A: 使用标准SQL LIKE语法,数据库层面处理大小写
+
+### Q: 是否支持OR条件?
+A: 当前版本仅支持AND关系,OR条件需要自定义实现
+
+### Q: 如何处理空字符串?
+A: 空字符串会被自动忽略,不会加入筛选条件
+
+### Q: 是否支持嵌套对象筛选?
+A: 支持,使用点表示法:`{"related.field": "value"}`
+
+## 版本兼容
+- 完全向后兼容,不影响现有API调用
+- 新增参数为可选,不传递时保持原有行为
+- 错误时返回标准化错误响应

+ 185 - 0
.roo/rules/15-user-tracking.md

@@ -0,0 +1,185 @@
+# 通用CRUD操作人ID字段配置规范
+
+## 概述
+
+本规范定义了如何在通用CRUD模块中自动处理操作人ID字段,确保创建和更新操作时自动记录操作用户信息。
+
+## 新增功能
+
+通用CRUD模块已支持自动注入操作人ID字段,包含以下功能:
+
+1. **创建时自动记录创建人ID**
+2. **更新时自动记录更新人ID**
+3. **灵活配置字段名称**
+4. **向后兼容现有实现**
+
+## 配置方式
+
+### 1. 在CrudOptions中配置用户跟踪
+
+```typescript
+import { createCrudRoutes } from '@/server/utils/generic-crud.routes';
+import { YourEntity } from '@/server/modules/your-module/your-entity.entity';
+import { YourEntitySchema, CreateYourEntityDto, UpdateYourEntityDto } from '@/server/modules/your-module/your-entity.entity';
+import { authMiddleware } from '@/server/middleware/auth.middleware';
+
+const yourEntityRoutes = createCrudRoutes({
+  entity: YourEntity,
+  createSchema: CreateYourEntityDto,
+  updateSchema: UpdateYourEntityDto,
+  getSchema: YourEntitySchema,
+  listSchema: YourEntitySchema,
+  middleware: [authMiddleware],
+  // 用户跟踪配置
+  userTracking: {
+    createdByField: 'createdBy',    // 创建人ID字段名,默认 'createdBy'
+    updatedByField: 'updatedBy'     // 更新人ID字段名,默认 'updatedBy'
+  }
+});
+```
+
+### 2. 实体类定义要求
+
+实体必须包含与配置对应的字段:
+
+```typescript
+@Entity('your_entities')
+export class YourEntity {
+  @PrimaryGeneratedColumn({ unsigned: true })
+  id!: number;
+
+  // 业务字段...
+  
+  @Column({ name: 'created_by', type: 'int', nullable: true, comment: '创建用户ID' })
+  createdBy?: number;
+  
+  @Column({ name: 'updated_by', type: 'int', nullable: true, comment: '更新用户ID' })
+  updatedBy?: number;
+  
+  @CreateDateColumn({ name: 'created_at' })
+  createdAt!: Date;
+  
+  @UpdateDateColumn({ name: 'updated_at' })
+  updatedAt!: Date;
+}
+```
+
+### 3. 字段命名约定
+
+| 配置字段名 | 推荐数据库字段名 | 类型 | 说明 |
+|------------|------------------|------|------|
+| createdByField | created_by | int/string | 创建人用户ID |
+| updatedByField | updated_by | int/string | 更新人用户ID |
+
+## 配置示例
+
+### 示例1:使用默认字段名
+
+```typescript
+const routes = createCrudRoutes({
+  entity: MyEntity,
+  createSchema: CreateMyEntityDto,
+  updateSchema: UpdateMyEntityDto,
+  getSchema: MyEntitySchema,
+  listSchema: MyEntitySchema,
+  userTracking: {} // 使用默认字段名 createdBy 和 updatedBy
+});
+```
+
+### 示例2:自定义字段名
+
+```typescript
+const routes = createCrudRoutes({
+  entity: MyEntity,
+  createSchema: CreateMyEntityDto,
+  updateSchema: UpdateMyEntityDto,
+  getSchema: MyEntitySchema,
+  listSchema: MyEntitySchema,
+  userTracking: {
+    createdByField: 'created_user_id',
+    updatedByField: 'modified_user_id'
+  }
+});
+```
+
+### 示例3:只记录创建人
+
+```typescript
+const routes = createCrudRoutes({
+  entity: MyEntity,
+  createSchema: CreateMyEntityDto,
+  updateSchema: UpdateMyEntityDto,
+  getSchema: MyEntitySchema,
+  listSchema: MyEntitySchema,
+  userTracking: {
+    createdByField: 'created_by',
+    updatedByField: undefined // 不记录更新人
+  }
+});
+```
+
+### 示例4:兼容现有字段名
+
+```typescript
+const routes = createCrudRoutes({
+  entity: Linkman,
+  createSchema: CreateLinkmanDto,
+  updateSchema: UpdateLinkmanDto,
+  getSchema: LinkmanSchema,
+  listSchema: LinkmanSchema,
+  userTracking: {
+    createdByField: 'createdUserId', // 匹配现有字段
+    updatedByField: 'updatedUserId'  // 匹配现有字段
+  }
+});
+```
+
+## 工作原理
+
+1. **创建操作**:
+   - 当用户创建新记录时,系统自动从认证上下文中提取用户ID
+   - 将用户ID注入到配置的创建人字段中
+   - 如果未配置createdByField,则跳过此步骤
+
+2. **更新操作**:
+   - 当用户更新记录时,系统自动从认证上下文中提取用户ID
+   - 将用户ID注入到配置的更新人字段中
+   - 如果未配置updatedByField,则跳过此步骤
+
+3. **向后兼容**:
+   - 未配置userTracking时,保持原有行为不变
+   - 所有现有代码无需修改即可继续运行
+
+## 注意事项
+
+1. **认证要求**:必须在路由中添加`authMiddleware`才能获取用户信息
+2. **字段类型**:用户ID字段应支持存储用户ID的数据类型(通常为int或varchar)
+3. **数据库字段**:确保实体类中定义的数据库字段名与配置一致
+4. **空值处理**:如果用户未登录,相关字段将保持为null
+
+## 最佳实践
+
+1. **统一命名**:在项目中统一使用相同的字段命名约定
+2. **索引优化**:为操作人ID字段添加数据库索引以提高查询性能
+3. **关联查询**:可以通过relations配置加载操作人详情
+4. **审计功能**:结合时间戳字段实现完整的操作审计
+
+## 常见问题
+
+### Q: 如何支持字符串类型的用户ID?
+A: 实体类字段类型设置为varchar即可,系统会自动处理字符串类型
+
+### Q: 可以配置不同的用户ID字段吗?
+A: 可以,通过createdByField和updatedByField分别配置
+
+### Q: 会影响现有实体吗?
+A: 不会,只有配置了userTracking的实体才会启用此功能
+
+### Q: 如何获取操作人详情?
+A: 在relations中配置用户关联关系即可:
+```typescript
+const routes = createCrudRoutes({
+  entity: YourEntity,
+  relations: ['createdByUser', 'updatedByUser'],
+  // ...其他配置
+});

+ 1 - 0
.rooignore

@@ -0,0 +1 @@
+d8d-vite-starter