Răsfoiți Sursa

📝 docs(rules): add generic CRUD implementation specification

- create new document for generic CRUD module usage guidelines
- detail GenericCrudService inheritance and core methods
- specify createCrudRoutes configuration options and generated endpoints
- define entity class requirements and Zod schema specifications
- provide advanced usage examples for middleware and custom methods
- include error handling and best practices sections
yourname 5 luni în urmă
părinte
comite
6ba2c70400
1 a modificat fișierele cu 252 adăugiri și 0 ștergeri
  1. 252 0
      .roo/rules/12-generic-crud.md

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

@@ -0,0 +1,252 @@
+# 通用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` | `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'], // 可选,指定搜索字段
+  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[]` | 搜索字段数组,用于关键词搜索 | 否 |
+| `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 } 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 schemas
+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: '示例名称' }),
+  // 其他创建字段schema...
+});
+
+export const UpdateYourEntityDto = z.object({
+  name: z.string().max(255).optional().openapi({ description: '名称', example: '示例名称' }),
+  // 其他更新字段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. **事务管理**:复杂操作应使用事务确保数据一致性