## 🛠️ 專業技能與方法論

### Zod 核心能力
| 領域 | 精通內容 |
|------|----------|
| 基礎型別 | `string`/`number`/`boolean`/`bigint`/`date`/`undefined`/`null`/`void`/`never`/`unknown`/`any` |
| 複合結構 | `object`、`array`、`tuple`、`record`、`map`、`set` |
| 組合 | `union`、`discriminatedUnion`、`intersection`、`lazy` |
| 轉換 | `transform`、`preprocess`、`pipe`、`coerce` |
| 精煉 | `refine`、`superRefine`、`.min`/`.max`/`.email`/`.url`/`.uuid`/`.regex` |
| 型別推導 | `z.infer`、`z.input`、`z.output`、`z.ZodTypeAny` 泛型約束 |

### 實戰模式庫

#### 1. Boundary Schema Pattern
```typescript
import { z } from "zod";

export const UserIdSchema = z.string().uuid();
export const PaginationSchema = z.object({
  page: z.coerce.number().int().min(1).default(1),
  pageSize: z.coerce.number().int().min(1).max(100).default(20),
});
```

#### 2. Discriminated Union（API 回應）
```typescript
const SuccessSchema = z.object({ status: z.literal("ok"), data: z.unknown() });
const ErrorSchema = z.object({ status: z.literal("error"), code: z.string(), message: z.string() });
export const ApiResponseSchema = z.discriminatedUnion("status", [SuccessSchema, ErrorSchema]);
```

#### 3. 可重用欄位與 DRY
```typescript
const TimestampFields = {
  createdAt: z.coerce.date(),
  updatedAt: z.coerce.date(),
};
export const BaseEntitySchema = z.object({ id: z.string().uuid(), ...TimestampFields });
```

#### 4. 環境變數（啟動驗證）
```typescript
const EnvSchema = z.object({
  NODE_ENV: z.enum(["development", "test", "production"]),
  DATABASE_URL: z.string().url(),
  PORT: z.coerce.number().default(3000),
});
export const env = EnvSchema.parse(process.env);
```

#### 5. 表單與 API 雙向 schema
- `CreateSchema`：無 `id`、無唯讀欄位
- `UpdateSchema`：`CreateSchema.partial()` 或 `pick` 必要欄位
- 回應 schema：含 server 生成欄位

### 框架整合
- **tRPC**：`input` validator 與 router-level middleware
- **Next.js**：Server Actions 輸入驗證、Route Handler `req.json()` 驗證
- **React Hook Form**：`zodResolver`、defaultValues 與 schema 對齊
- **OpenAPI**：`zod-to-openapi` / `zod-openapi` 產生 contract
- **AI/LLM**：結構化輸出 schema、`safeParse` 失敗時 retry 策略

### 錯誤處理工具箱
```typescript
function formatZodError(error: z.ZodError) {
  return error.flatten(); // 或 error.format() 依前端需求
}
```
- 生產環境：log `error.issues` 結構，不 log 原始 PII payload
- 國際化：將 `message` 對應 i18n key，而非硬編碼多語字串在 schema 深處

### 測試策略
- 為每個 schema 準備：**合法最小案例**、**邊界值**、**典型非法案例**
- 使用 `expect(() => Schema.parse(x)).toThrow()` 或 snapshot `safeParse` 結果
- 對 `transform` 鏈測試 `z.input` vs `z.output` 差異

### 效能與維護
- 避免過深巢狀 `refine`；優先 `superRefine` 一次收集多錯誤
- 大型 union 考慮 `discriminatedUnion` 提升推斷與效能
- Schema 檔案模組化：`schemas/user.ts`、`schemas/common.ts`

### 升級與遷移
- 辨識 breaking changes（必填欄位新增、enum 刪除、transform 行為變更）
- 提供雙寫/雙讀過渡期 schema（`z.union([LegacySchema, NewSchema])`）