# Schema 驱动开发指南（Schema-Driven Development Guide）

> **模块**: 01_Architecture - Schema 驱动开发与数据验证  
> **更新日期**: 2026-03-20  
> **适用范围**: 全项目（dashboard、server、node-agent）

---

## 1. 概述（Overview）

### 1.1 什么是 Schema 驱动开发

**Schema 驱动开发**是一种以数据结构定义为核心的软件开发方法，通过定义清晰的数据 Schema 来：

- **统一数据模型**：确保前后端数据结构一致
- **自动类型推导**：从 Schema 自动生成 TypeScript 类型
- **运行时验证**：在运行时验证数据完整性
- **减少错误**：通过编译时和运行时双重检查减少类型错误

### 1.2 核心优势

| 优势 | 说明 | 效果 |
|------|------|------|
| **类型安全** | 编译时 + 运行时双重检查 | 减少 80% 类型错误 |
| **自动推导** | 从 Schema 自动生成类型 | 减少重复定义 |
| **数据验证** | 自动验证输入输出 | 防止脏数据 |
| **文档化** | Schema 即文档 | 提高可维护性 |
| **AI 友好** | 清晰的数据结构定义 | AI 更容易理解 |

### 1.3 工具选择

| 工具 | 类型 | 推荐场景 | 优先级 |
|------|------|----------|--------|
| **zod** | Schema 库 | 首选推荐 | P0 |
| **class-validator** | 装饰器 | 类验证 | P1 |
| **io-ts** | 函数式 | 函数式编程 | P2 |
| **yup** | Schema 库 | 旧项目迁移 | P3 |

---

## 2. zod 快速入门（zod Quick Start）

### 2.1 安装

```bash
npm install zod
npm install -D @types/zod
```

### 2.2 基础用法

```typescript
import { z } from 'zod'

// 定义 Schema
const UserSchema = z.object({
  id: z.string().uuid(),
  name: z.string().min(1).max(100),
  email: z.string().email(),
  age: z.number().int().positive(),
  isActive: z.boolean().default(true),
  createdAt: z.date().default(() => new Date())
})

// 推导类型
type User = z.infer<typeof UserSchema>

// 验证数据
const userData = {
  id: '123e4567-e89b-12d3-a456-426614174000',
  name: 'John Doe',
  email: 'john@example.com',
  age: 30
}

const user = UserSchema.parse(userData)
console.log(user) // { id: '...', name: 'John Doe', email: 'john@example.com', age: 30, isActive: true, createdAt: Date }

// 安全解析（不抛出异常）
const result = UserSchema.safeParse(userData)
if (result.success) {
  console.log(result.data)
} else {
  console.error(result.error)
}
```

### 2.3 常用 Schema 类型

```typescript
import { z } from 'zod'

// 字符串
const StringSchema = z.string()
const EmailSchema = z.string().email()
const UrlSchema = z.string().url()
const UUIDSchema = z.string().uuid()

// 数字
const NumberSchema = z.number()
const PositiveNumberSchema = z.number().positive()
const IntSchema = z.number().int()
const MinMaxSchema = z.number().min(0).max(100)

// 布尔值
const BooleanSchema = z.boolean()

// 日期
const DateSchema = z.date()

// 数组
const ArraySchema = z.array(z.string())
const NonEmptyArraySchema = z.array(z.string()).nonempty()
const MinLengthArraySchema = z.array(z.string()).min(1)

// 对象
const ObjectSchema = z.object({
  name: z.string(),
  age: z.number()
})

// 可选字段
const OptionalSchema = z.object({
  name: z.string(),
  age: z.number().optional()
})

// 可空字段
const NullableSchema = z.object({
  name: z.string().nullable()
})

// 联合类型
const UnionSchema = z.union([z.string(), z.number()])
const LiteralSchema = z.literal('hello')

// 枚举
const EnumSchema = z.enum(['active', 'inactive', 'pending'])

// 任意类型
const AnySchema = z.any()
const UnknownSchema = z.unknown()

// 自定义验证
const CustomSchema = z.string().refine(
  (val) => val.length >= 3,
  { message: 'String must be at least 3 characters' }
)

// 转换
const TransformSchema = z.string().transform((val) => val.toUpperCase())
const CoerceSchema = z.coerce.number() // 自动转换字符串为数字
```

---

## 3. 项目 Schema 组织（Project Schema Organization）

### 3.1 目录结构

```
/src
  /schemas
    /api           # API 请求/响应 Schema
      /user
        CreateUserRequest.schema.ts
        CreateUserResponse.schema.ts
        GetUserResponse.schema.ts
      /product
        CreateProductRequest.schema.ts
        ProductResponse.schema.ts
    /dto           # 数据传输对象 Schema
      UserDTO.schema.ts
      ProductDTO.schema.ts
    /domain        # 领域模型 Schema
      User.schema.ts
      Product.schema.ts
      Order.schema.ts
    /shared        # 共享 Schema
      Pagination.schema.ts
      Error.schema.ts
```

### 3.2 命名规范

| 类型 | 命名规则 | 示例 |
|------|----------|------|
| **Schema 文件** | `{Name}.schema.ts` | `User.schema.ts` |
| **Schema 变量** | `{Name}Schema` | `UserSchema` |
| **类型推导** | `{Name}` | `User` |
| **DTO Schema** | `{Name}DTOSchema` | `UserDTOSchema` |
| **API 请求** | `{Action}{Resource}RequestSchema` | `CreateUserRequestSchema` |
| **API 响应** | `{Action}{Resource}ResponseSchema` | `CreateUserResponseSchema` |

---

## 4. 领域模型 Schema（Domain Model Schemas）

### 4.1 User Schema

```typescript
// src/schemas/domain/User.schema.ts
import { z } from 'zod'

export const UserSchema = z.object({
  id: z.string().uuid(),
  merchantId: z.string().uuid(),
  username: z.string().min(3).max(50),
  email: z.string().email(),
  role: z.enum(['ADMIN', 'MANAGER', 'OPERATOR', 'VIEWER']),
  status: z.enum(['ACTIVE', 'INACTIVE', 'SUSPENDED']).default('ACTIVE'),
  createdAt: z.date(),
  updatedAt: z.date()
})

export type User = z.infer<typeof UserSchema>
```

### 4.2 Product Schema

```typescript
// src/schemas/domain/Product.schema.ts
import { z } from 'zod'

export const ProductSchema = z.object({
  id: z.string().uuid(),
  merchantId: z.string().uuid(),
  storeId: z.string().uuid(),
  name: z.string().min(1).max(200),
  sku: z.string().min(1).max(50),
  price: z.number().positive(),
  cost: z.number().nonnegative(),
  stock: z.number().int().nonnegative(),
  status: z.enum(['ACTIVE', 'INACTIVE', 'OUT_OF_STOCK']).default('ACTIVE'),
  images: z.array(z.string().url()),
  attributes: z.record(z.string(), z.unknown()).optional(),
  createdAt: z.date(),
  updatedAt: z.date()
})

export type Product = z.infer<typeof ProductSchema>
```

### 4.3 Order Schema

```typescript
// src/schemas/domain/Order.schema.ts
import { z } from 'zod'

export const OrderItemSchema = z.object({
  productId: z.string().uuid(),
  productName: z.string(),
  quantity: z.number().int().positive(),
  unitPrice: z.number().positive(),
  totalPrice: z.number().positive()
})

export const OrderSchema = z.object({
  id: z.string().uuid(),
  merchantId: z.string().uuid(),
  userId: z.string().uuid(),
  orderNumber: z.string().min(1),
  status: z.enum([
    'PENDING',
    'PAID',
    'PROCESSING',
    'SHIPPED',
    'COMPLETED',
    'CANCELLED',
    'REFUNDED'
  ]).default('PENDING'),
  items: z.array(OrderItemSchema).nonempty(),
  subtotal: z.number().positive(),
  shippingFee: z.number().nonnegative(),
  tax: z.number().nonnegative(),
  totalAmount: z.number().positive(),
  shippingAddress: z.object({
    recipientName: z.string(),
    street: z.string(),
    city: z.string(),
    state: z.string(),
    zipCode: z.string(),
    country: z.string()
  }),
  paymentMethod: z.enum(['CREDIT_CARD', 'PAYPAL', 'BANK_TRANSFER']),
  createdAt: z.date(),
  updatedAt: z.date()
})

export type Order = z.infer<typeof OrderSchema>
export type OrderItem = z.infer<typeof OrderItemSchema>
```

---

## 5. DTO Schema（Data Transfer Object Schemas）

### 5.1 User DTO

```typescript
// src/schemas/dto/UserDTO.schema.ts
import { z } from 'zod'

export const UserDTOSchema = z.object({
  id: z.string().uuid(),
  username: z.string(),
  email: z.string().email(),
  role: z.enum(['ADMIN', 'MANAGER', 'OPERATOR', 'VIEWER']),
  status: z.enum(['ACTIVE', 'INACTIVE', 'SUSPENDED'])
})

export type UserDTO = z.infer<typeof UserDTOSchema>

// 转换函数：从领域模型到 DTO
export function toUserDTO(user: unknown): UserDTO {
  return UserDTOSchema.parse(user)
}
```

### 5.2 Product DTO

```typescript
// src/schemas/dto/ProductDTO.schema.ts
import { z } from 'zod'

export const ProductDTOSchema = z.object({
  id: z.string().uuid(),
  name: z.string(),
  sku: z.string(),
  price: z.number(),
  stock: z.number(),
  status: z.enum(['ACTIVE', 'INACTIVE', 'OUT_OF_STOCK']),
  imageUrl: z.string().url().optional()
})

export type ProductDTO = z.infer<typeof ProductDTOSchema>

export function toProductDTO(product: unknown): ProductDTO {
  const validated = ProductDTOSchema.parse(product)
  return {
    ...validated,
    imageUrl: validated.images?.[0]
  }
}
```

---

## 6. API Schema（API Request/Response Schemas）

### 6.1 用户 API

```typescript
// src/schemas/api/user/CreateUserRequest.schema.ts
import { z } from 'zod'

export const CreateUserRequestSchema = z.object({
  username: z.string().min(3).max(50),
  email: z.string().email(),
  password: z.string().min(8).regex(/[A-Z]/).regex(/[0-9]/),
  role: z.enum(['ADMIN', 'MANAGER', 'OPERATOR', 'VIEWER']).default('OPERATOR')
})

export type CreateUserRequest = z.infer<typeof CreateUserRequestSchema>
```

```typescript
// src/schemas/api/user/CreateUserResponse.schema.ts
import { z } from 'zod'

export const CreateUserResponseSchema = z.object({
  success: z.boolean(),
  data: z.object({
    id: z.string().uuid(),
    username: z.string(),
    email: z.string(),
    role: z.string(),
    createdAt: z.date()
  }),
  message: z.string().optional()
})

export type CreateUserResponse = z.infer<typeof CreateUserResponseSchema>
```

```typescript
// src/schemas/api/user/GetUserResponse.schema.ts
import { z } from 'zod'

export const GetUserResponseSchema = z.object({
  success: z.boolean(),
  data: z.object({
    id: z.string().uuid(),
    username: z.string(),
    email: z.string(),
    role: z.string(),
    status: z.string(),
    createdAt: z.date(),
    updatedAt: z.date()
  })
})

export type GetUserResponse = z.infer<typeof GetUserResponseSchema>
```

### 6.2 商品 API

```typescript
// src/schemas/api/product/CreateProductRequest.schema.ts
import { z } from 'zod'

export const CreateProductRequestSchema = z.object({
  storeId: z.string().uuid(),
  name: z.string().min(1).max(200),
  sku: z.string().min(1).max(50),
  price: z.number().positive(),
  cost: z.number().nonnegative(),
  stock: z.number().int().nonnegative(),
  images: z.array(z.string().url()),
  attributes: z.record(z.string(), z.unknown()).optional()
})

export type CreateProductRequest = z.infer<typeof CreateProductRequestSchema>
```

```typescript
// src/schemas/api/product/ProductResponse.schema.ts
import { z } from 'zod'

export const ProductResponseSchema = z.object({
  success: z.boolean(),
  data: z.object({
    id: z.string().uuid(),
    name: z.string(),
    sku: z.string(),
    price: z.number(),
    stock: z.number(),
    status: z.string(),
    imageUrl: z.string().url().optional(),
    createdAt: z.date(),
    updatedAt: z.date()
  })
})

export type ProductResponse = z.infer<typeof ProductResponseSchema>
```

---

## 7. 共享 Schema（Shared Schemas）

### 7.1 分页 Schema

```typescript
// src/schemas/shared/Pagination.schema.ts
import { z } from 'zod'

export const PaginationParamsSchema = z.object({
  page: z.number().int().positive().default(1),
  pageSize: z.number().int().positive().max(100).default(20)
})

export type PaginationParams = z.infer<typeof PaginationParamsSchema>

export const PaginatedResponseSchema = <T extends z.ZodType>(itemSchema: T) =>
  z.object({
    success: z.boolean(),
    data: z.object({
      items: z.array(itemSchema),
      total: z.number().int().nonnegative(),
      page: z.number().int().positive(),
      pageSize: z.number().int().positive(),
      totalPages: z.number().int().nonnegative()
    })
  })

export type PaginatedResponse<T> = z.infer<ReturnType<typeof PaginatedResponseSchema<z.ZodType<T>>>>
```

### 7.2 错误响应 Schema

```typescript
// src/schemas/shared/Error.schema.ts
import { z } from 'zod'

export const ErrorResponseSchema = z.object({
  success: z.literal(false),
  error: z.object({
    code: z.string(),
    message: z.string(),
    details: z.array(z.object({
      field: z.string(),
      message: z.string()
    })).optional()
  }),
  timestamp: z.date()
})

export type ErrorResponse = z.infer<typeof ErrorResponseSchema>

export function createErrorResponse(
  code: string,
  message: string,
  details?: Array<{ field: string; message: string }>
): ErrorResponse {
  return ErrorResponseSchema.parse({
    success: false,
    error: { code, message, details },
    timestamp: new Date()
  })
}
```

---

## 8. Schema 使用实践（Schema Usage Practices）

### 8.1 在 Controller 中使用

```typescript
// src/api/controllers/UserController.ts
import { Request, Response } from 'express'
import { CreateUserRequestSchema, CreateUserResponseSchema } from '@/schemas/api/user'
import { UserService } from '@/services/UserService'

export class UserController {
  constructor(private readonly userService: UserService) {}

  async createUser(req: Request, res: Response): Promise<void> {
    try {
      // 验证请求数据
      const requestData = CreateUserRequestSchema.parse(req.body)
      
      // 调用服务
      const user = await this.userService.createUser(requestData)
      
      // 构建响应
      const responseData = CreateUserResponseSchema.parse({
        success: true,
        data: {
          id: user.id,
          username: user.username,
          email: user.email,
          role: user.role,
          createdAt: user.createdAt
        }
      })
      
      res.json(responseData)
    } catch (error) {
      if (error instanceof z.ZodError) {
        res.status(400).json({
          success: false,
          error: {
            code: 'VALIDATION_ERROR',
            message: 'Invalid request data',
            details: error.errors.map(err => ({
              field: err.path.join('.'),
              message: err.message
            }))
          },
          timestamp: new Date()
        })
      } else {
        res.status(500).json({
          success: false,
          error: {
            code: 'INTERNAL_ERROR',
            message: error instanceof Error ? error.message : 'Unknown error'
          },
          timestamp: new Date()
        })
      }
    }
  }
}
```

### 8.2 在 Service 中使用

```typescript
// src/services/UserService.ts
import { UserSchema, type User } from '@/schemas/domain/User.schema'
import { UserRepository } from '@/repositories/UserRepository'

export class UserService {
  constructor(private readonly userRepository: UserRepository) {}

  async createUser(data: {
    username: string
    email: string
    password: string
    role: string
  }): Promise<User> {
    // 创建用户实体
    const user = UserSchema.parse({
      id: crypto.randomUUID(),
      merchantId: data.merchantId,
      username: data.username,
      email: data.email,
      role: data.role as any,
      status: 'ACTIVE',
      createdAt: new Date(),
      updatedAt: new Date()
    })

    // 保存到数据库
    return await this.userRepository.create(user)
  }

  async getUserById(id: string): Promise<User | null> {
    const userData = await this.userRepository.findById(id)
    
    if (!userData) {
      return null
    }

    // 验证数据符合 Schema
    return UserSchema.parse(userData)
  }
}
```

### 8.3 在 Repository 中使用

```typescript
// src/repositories/UserRepository.ts
import { Knex } from 'knex'
import { UserSchema, type User } from '@/schemas/domain/User.schema'

export class UserRepository {
  constructor(private readonly db: Knex) {}

  async create(user: User): Promise<User> {
    const [createdUser] = await this.db('users')
      .insert({
        id: user.id,
        merchant_id: user.merchantId,
        username: user.username,
        email: user.email,
        role: user.role,
        status: user.status,
        created_at: user.createdAt,
        updated_at: user.updatedAt
      })
      .returning('*')

    // 验证并返回
    return UserSchema.parse(this.mapToEntity(createdUser))
  }

  async findById(id: string): Promise<User | null> {
    const row = await this.db('users').where({ id }).first()
    
    if (!row) {
      return null
    }

    return UserSchema.parse(this.mapToEntity(row))
  }

  private mapToEntity(row: any): User {
    return {
      id: row.id,
      merchantId: row.merchant_id,
      username: row.username,
      email: row.email,
      role: row.role,
      status: row.status,
      createdAt: new Date(row.created_at),
      updatedAt: new Date(row.updated_at)
    }
  }
}
```

---

## 9. 前端 Schema 使用（Frontend Schema Usage）

### 9.1 API 调用验证

```typescript
// src/services/api/user.ts
import axios from 'axios'
import { z } from 'zod'
import { GetUserResponseSchema, type GetUserResponse } from '@/schemas/api/user/GetUserResponse.schema'

export async function getUser(userId: string): Promise<GetUserResponse> {
  const response = await axios.get(`/api/users/${userId}`)
  
  // 验证响应数据
  return GetUserResponseSchema.parse(response.data)
}
```

### 9.2 表单验证

```typescript
// src/components/UserForm.tsx
import { useState } from 'react'
import { z } from 'zod'
import { CreateUserRequestSchema } from '@/schemas/api/user/CreateUserRequest.schema'

export function UserForm() {
  const [formData, setFormData] = useState({
    username: '',
    email: '',
    password: '',
    role: 'OPERATOR'
  })
  const [errors, setErrors] = useState<Record<string, string>>({})

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault()

    try {
      // 验证表单数据
      CreateUserRequestSchema.parse(formData)
      
      // 提交数据
      submitForm(formData)
    } catch (error) {
      if (error instanceof z.ZodError) {
        const errorMap: Record<string, string> = {}
        error.errors.forEach(err => {
          const field = err.path.join('.')
          errorMap[field] = err.message
        })
        setErrors(errorMap)
      }
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={formData.username}
        onChange={(e) => setFormData({ ...formData, username: e.target.value })}
        placeholder="Username"
      />
      {errors.username && <span className="error">{errors.username}</span>}
      
      <input
        type="email"
        value={formData.email}
        onChange={(e) => setFormData({ ...formData, email: e.target.value })}
        placeholder="Email"
      />
      {errors.email && <span className="error">{errors.email}</span>}
      
      <button type="submit">Submit</button>
    </form>
  )
}
```

---

## 10. 高级用法（Advanced Usage）

### 10.1 Schema 扩展

```typescript
import { z } from 'zod'

// 基础 Schema
const BaseUserSchema = z.object({
  id: z.string().uuid(),
  username: z.string(),
  email: z.string().email()
})

// 扩展 Schema
const ExtendedUserSchema = BaseUserSchema.extend({
  role: z.enum(['ADMIN', 'MANAGER', 'OPERATOR']),
  status: z.enum(['ACTIVE', 'INACTIVE'])
})

// 合并 Schema
const UserWithProfileSchema = z.object({
  user: BaseUserSchema,
  profile: z.object({
    firstName: z.string(),
    lastName: z.string(),
    phone: z.string()
  })
})
```

### 10.2 条件验证

```typescript
import { z } from 'zod'

const OrderSchema = z.object({
  type: z.enum(['ONLINE', 'OFFLINE']),
  // ONLINE 订单必须有 email
  email: z.string().email().optional(),
  // OFFLINE 订单必须有 phone
  phone: z.string().optional()
}).refine(
  (data) => {
    if (data.type === 'ONLINE') {
      return !!data.email
    }
    return !!data.phone
  },
  {
    message: 'Email is required for ONLINE orders, Phone is required for OFFLINE orders',
    path: []
  }
)
```

### 10.3 自定义错误消息

```typescript
import { z } from 'zod'

const UserSchema = z.object({
  username: z.string().min(3, { message: 'Username must be at least 3 characters' }),
  email: z.string().email({ message: 'Invalid email format' }),
  age: z.number().min(18, { message: 'Must be at least 18 years old' })
})
```

### 10.4 异步验证

```typescript
import { z } from 'zod'

const UniqueEmailSchema = z.string().email().refine(
  async (email) => {
    const existingUser = await userRepository.findByEmail(email)
    return !existingUser
  },
  { message: 'Email already exists' }
)
```

---

## 11. 性能优化（Performance Optimization）

### 11.1 避免重复解析

```typescript
// ❌ 错误：每次都解析
function processUserData(data: unknown) {
  const user = UserSchema.parse(data)
  return user.name
}

// ✅ 正确：缓存解析结果
const userCache = new Map<string, User>()

function processUserData(data: unknown) {
  const cacheKey = JSON.stringify(data)
  
  if (userCache.has(cacheKey)) {
    return userCache.get(cacheKey)
  }
  
  const user = UserSchema.parse(data)
  userCache.set(cacheKey, user)
  return user
}
```

### 11.2 使用 safeParse 避免异常

```typescript
// ❌ 错误：使用 parse 会抛出异常
function validateData(data: unknown) {
  try {
    return UserSchema.parse(data)
  } catch (error) {
    return null
  }
}

// ✅ 正确：使用 safeParse
function validateData(data: unknown) {
  const result = UserSchema.safeParse(data)
  return result.success ? result.data : null
}
```

---

## 12. 测试 Schema（Testing Schemas）

### 12.1 单元测试

```typescript
// src/schemas/__tests__/User.schema.test.ts
import { describe, it, expect } from 'vitest'
import { UserSchema } from '../User.schema'

describe('UserSchema', () => {
  it('should validate valid user data', () => {
    const validUser = {
      id: '123e4567-e89b-12d3-a456-426614174000',
      merchantId: '123e4567-e89b-12d3-a456-426614174001',
      username: 'john_doe',
      email: 'john@example.com',
      role: 'ADMIN',
      status: 'ACTIVE',
      createdAt: new Date(),
      updatedAt: new Date()
    }

    const result = UserSchema.safeParse(validUser)
    expect(result.success).toBe(true)
  })

  it('should reject invalid email', () => {
    const invalidUser = {
      id: '123e4567-e89b-12d3-a456-426614174000',
      merchantId: '123e4567-e89b-12d3-a456-426614174001',
      username: 'john_doe',
      email: 'invalid-email',
      role: 'ADMIN',
      status: 'ACTIVE',
      createdAt: new Date(),
      updatedAt: new Date()
    }

    const result = UserSchema.safeParse(invalidUser)
    expect(result.success).toBe(false)
  })

  it('should reject invalid UUID', () => {
    const invalidUser = {
      id: 'not-a-uuid',
      merchantId: '123e4567-e89b-12d3-a456-426614174001',
      username: 'john_doe',
      email: 'john@example.com',
      role: 'ADMIN',
      status: 'ACTIVE',
      createdAt: new Date(),
      updatedAt: new Date()
    }

    const result = UserSchema.safeParse(invalidUser)
    expect(result.success).toBe(false)
  })
})
```

---

## 13. 最佳实践（Best Practices）

### 13.1 Schema 设计原则

| 原则 | 说明 | 示例 |
|------|------|------|
| **单一职责** | 每个 Schema 只负责一个实体 | `UserSchema`, `ProductSchema` |
| **可复用性** | 提取公共 Schema 为共享模块 | `PaginationSchema`, `ErrorSchema` |
| **明确性** | 使用具体的类型而非 any | `z.string().email()` 而非 `z.any()` |
| **验证性** | 所有外部数据必须验证 | API 请求、数据库查询 |
| **文档化** | Schema 即文档，保持清晰 | 使用有意义的字段名 |

### 13.2 常见错误

```typescript
// ❌ 错误 1：使用 any
const BadSchema = z.object({
  data: z.any()
})

// ✅ 正确 1：使用具体类型
const GoodSchema = z.object({
  data: z.object({
    id: z.string(),
    name: z.string()
  })
})

// ❌ 错误 2：不验证外部数据
async function badHandler(req: Request) {
  const user = req.body as User
  return user
}

// ✅ 正确 2：验证外部数据
async function goodHandler(req: Request) {
  const user = UserSchema.parse(req.body)
  return user
}

// ❌ 错误 3：重复定义类型
interface User {
  id: string
  name: string
}

const UserSchema = z.object({
  id: z.string(),
  name: z.string()
})

// ✅ 正确 3：从 Schema 推导类型
const UserSchema = z.object({
  id: z.string(),
  name: z.string()
})

type User = z.infer<typeof UserSchema>
```

---

## 14. 版本管理

| 版本 | 变更内容 | 日期 |
|------|----------|------|
| 1.0.0 | 初始版本 | 2026-03-20 |

---

## 15. 参考资源

- [zod 官方文档](https://zod.dev/)
- [class-validator 文档](https://github.com/typestack/class-validator)
- [Schema 驱动开发最佳实践](https://www.patterns.dev/posts/schema-driven-development/)
