返回 AiToEarn
dto-vo-pattern.yaml
根目录 / project / aitoearn-backend / .claude / instincts / dto-vo-pattern.yaml
1 ---
2 id: aitoearn-dto-vo-pattern
3 trigger: "when creating DTOs or VOs"
4 confidence: 0.95
5 domain: typescript
6 source: local-repo-analysis
7 ---
8
9 # Zod Schema + DTO/VO Pattern
10
11 ## Action
12 Always define Zod schema first, then generate DTO/VO class using `createZodDto`.
13
14 ## DTO (Input)
15 ```typescript
16 import { createZodDto, PaginationDtoSchema } from '@yikart/common'
17 import { z } from 'zod'
18
19 export const CreateOrderDtoSchema = z.object({
20 productId: z.string(),
21 quantity: z.number().int().positive().default(1),
22 returnTo: z.url().optional(),
23 })
24 export class CreateOrderDto extends createZodDto(CreateOrderDtoSchema, 'CreateOrderDto') {}
25 ```
26
27 ## VO (Output)
28 ```typescript
29 import { createPaginationVo, createZodDto } from '@yikart/common'
30 import { z } from 'zod'
31
32 export const OrderDetailVoSchema = z.object({
33 id: z.string(),
34 amount: z.number(),
35 createdAt: z.coerce.date()
36 })
37 export class OrderDetailVo extends createZodDto(OrderDetailVoSchema, 'OrderDetailVo') {}
38 export class OrderListVo extends createPaginationVo(OrderDetailVoSchema, 'OrderListVo') {}
39 ```
40
41 ## Controller Usage
42 ```typescript
43 // Regular VO - use static create()
44 return OrderDetailVo.create(data)
45
46 // Pagination VO - use new
47 return new OrderListVo({ page, pageSize, total, totalPages, list })
48 ```
49
50 ## Rules
51 - Never use entity as input (use DTO)
52 - Never return entity directly (use VO)
53 - Pagination input: use `PaginationDtoSchema`
54 - Pagination output fields: page, pageSize, totalPages, total, list
55
56 ## Evidence
57 - Pattern defined in CLAUDE.md
58 - Used consistently across all services
59
59 lines YAML