@kood/claude-code 0.3.6 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/index.js +1 -1
  2. package/package.json +1 -1
  3. package/templates/nextjs/CLAUDE.md +228 -0
  4. package/templates/nextjs/docs/design.md +558 -0
  5. package/templates/nextjs/docs/guides/conventions.md +343 -0
  6. package/templates/nextjs/docs/guides/getting-started.md +367 -0
  7. package/templates/nextjs/docs/guides/routes.md +342 -0
  8. package/templates/nextjs/docs/library/better-auth/index.md +541 -0
  9. package/templates/nextjs/docs/library/nextjs/app-router.md +269 -0
  10. package/templates/nextjs/docs/library/nextjs/caching.md +351 -0
  11. package/templates/nextjs/docs/library/nextjs/index.md +291 -0
  12. package/templates/nextjs/docs/library/nextjs/middleware.md +391 -0
  13. package/templates/nextjs/docs/library/nextjs/route-handlers.md +382 -0
  14. package/templates/nextjs/docs/library/nextjs/server-actions.md +366 -0
  15. package/templates/nextjs/docs/library/prisma/cloudflare-d1.md +76 -0
  16. package/templates/nextjs/docs/library/prisma/config.md +77 -0
  17. package/templates/nextjs/docs/library/prisma/crud.md +90 -0
  18. package/templates/nextjs/docs/library/prisma/index.md +73 -0
  19. package/templates/nextjs/docs/library/prisma/relations.md +69 -0
  20. package/templates/nextjs/docs/library/prisma/schema.md +98 -0
  21. package/templates/nextjs/docs/library/prisma/setup.md +49 -0
  22. package/templates/nextjs/docs/library/prisma/transactions.md +50 -0
  23. package/templates/nextjs/docs/library/tanstack-query/index.md +66 -0
  24. package/templates/nextjs/docs/library/tanstack-query/invalidation.md +54 -0
  25. package/templates/nextjs/docs/library/tanstack-query/optimistic-updates.md +77 -0
  26. package/templates/nextjs/docs/library/tanstack-query/use-mutation.md +63 -0
  27. package/templates/nextjs/docs/library/tanstack-query/use-query.md +70 -0
  28. package/templates/nextjs/docs/library/zod/complex-types.md +61 -0
  29. package/templates/nextjs/docs/library/zod/index.md +56 -0
  30. package/templates/nextjs/docs/library/zod/transforms.md +51 -0
  31. package/templates/nextjs/docs/library/zod/validation.md +70 -0
  32. package/templates/tanstack-start/CLAUDE.md +7 -3
  33. package/templates/tanstack-start/docs/guides/hooks.md +28 -0
  34. package/templates/tanstack-start/docs/guides/routes.md +29 -10
@@ -0,0 +1,56 @@
1
+ # Zod
2
+
3
+ > v4 | TypeScript Schema Validation
4
+
5
+ @complex-types.md
6
+ @transforms.md
7
+ @validation.md
8
+
9
+ ---
10
+
11
+ <quick_reference>
12
+
13
+ ```typescript
14
+ // 기본
15
+ const schema = z.object({
16
+ email: z.email(), // v4!
17
+ name: z.string().min(1).trim(),
18
+ website: z.url().optional(), // v4!
19
+ age: z.number().int().positive(),
20
+ })
21
+ type Input = z.infer<typeof schema>
22
+
23
+ schema.parse(data) // 실패 시 throw
24
+ schema.safeParse(data) // { success, data/error }
25
+
26
+ // TanStack Start
27
+ export const createUser = createServerFn({ method: 'POST' })
28
+ .inputValidator(schema)
29
+ .handler(async ({ data }) => prisma.user.create({ data }))
30
+ ```
31
+
32
+ </quick_reference>
33
+
34
+ <v4_changes>
35
+
36
+ ```typescript
37
+ // ✅ v4 새 API
38
+ z.email() z.url() z.uuid()
39
+ z.iso.date() z.iso.datetime() z.iso.duration()
40
+ z.stringbool() // "true"/"yes"/"1" → true
41
+
42
+ // ❌ v3 deprecated
43
+ z.string().email() z.string().url()
44
+
45
+ // 변경사항
46
+ z.string().min(5, { error: "Too short." }) // message → error
47
+ z.strictObject({ name: z.string() }) // 추가 키 에러
48
+ z.looseObject({ name: z.string() }) // 추가 키 통과
49
+ z.string().refine(val => val.includes("@")).min(5) // refinement 체이닝
50
+
51
+ // 템플릿 리터럴
52
+ const css = z.templateLiteral([z.number(), z.enum(["px", "em", "rem"])])
53
+ // `${number}px` | `${number}em` | `${number}rem`
54
+ ```
55
+
56
+ </v4_changes>
@@ -0,0 +1,51 @@
1
+ # Zod - 변환
2
+
3
+ <patterns>
4
+
5
+ ```typescript
6
+ // Transform
7
+ const stringToLength = z.string().transform((val) => val.length)
8
+ stringToLength.parse('hello') // => 5
9
+
10
+ type In = z.input<typeof stringToLength> // string
11
+ type Out = z.output<typeof stringToLength> // number
12
+
13
+ // Pipe (검증 후 변환)
14
+ const stringToNumber = z.string()
15
+ .transform((val) => parseInt(val, 10))
16
+ .pipe(z.number().min(0).max(100))
17
+
18
+ stringToNumber.parse('50') // => 50
19
+ stringToNumber.parse('150') // throws
20
+
21
+ // Coerce (강제 변환)
22
+ z.coerce.string() // 모든 값 → 문자열
23
+ z.coerce.number() // 모든 값 → 숫자
24
+ z.coerce.boolean() // 모든 값 → 불리언
25
+ z.coerce.date() // 모든 값 → 날짜
26
+ z.coerce.bigint() // 모든 값 → BigInt
27
+
28
+ z.coerce.number().parse("42") // => 42
29
+ z.coerce.date().parse("2021-01-01") // => Date
30
+
31
+ // v4: 입력 타입이 unknown으로 변경
32
+ type In = z.input<typeof z.coerce.string()> // unknown
33
+
34
+ // v4 환경변수 불리언
35
+ z.stringbool() // "true"/"yes"/"1" → true, "false"/"no"/"0" → false
36
+
37
+ // Preprocess
38
+ const trimmed = z.preprocess(
39
+ (val) => typeof val === 'string' ? val.trim() : val,
40
+ z.string()
41
+ )
42
+
43
+ // 입력/출력 타입 분리
44
+ const Schema = z.object({
45
+ createdAt: z.string().transform((str) => new Date(str)),
46
+ })
47
+ type SchemaInput = z.input<typeof Schema> // { createdAt: string }
48
+ type SchemaOutput = z.output<typeof Schema> // { createdAt: Date }
49
+ ```
50
+
51
+ </patterns>
@@ -0,0 +1,70 @@
1
+ # Zod - 검증
2
+
3
+ <patterns>
4
+
5
+ ```typescript
6
+ // Refinement (v4: message → error)
7
+ const PasswordSchema = z.string()
8
+ .min(8)
9
+ .refine((val) => /[A-Z]/.test(val), { error: '대문자 필수' })
10
+ .refine((val) => /[0-9]/.test(val), { error: '숫자 필수' })
11
+
12
+ z.string().refine(val => val.includes("@")).min(5) // v4: refinement 후 체이닝
13
+
14
+ // Async
15
+ const schema = z.string().refine(async (val) => val.length <= 8)
16
+ await schema.parseAsync('hello')
17
+
18
+ // Superrefine
19
+ z.object({
20
+ password: z.string(),
21
+ confirmPassword: z.string(),
22
+ }).superRefine((data, ctx) => {
23
+ if (data.password !== data.confirmPassword) {
24
+ ctx.addIssue({
25
+ code: z.ZodIssueCode.custom,
26
+ message: '비밀번호 불일치',
27
+ path: ['confirmPassword'],
28
+ })
29
+ }
30
+ }) // v4: ctx.path 사용 불가
31
+
32
+ // 커스텀
33
+ const px = z.custom<`${number}px`>((val) =>
34
+ typeof val === 'string' && /^\d+px$/.test(val)
35
+ )
36
+ px.parse('42px') // ✅
37
+ px.parse('42vw') // throws
38
+
39
+ // 에러 처리
40
+ const result = schema.safeParse(data)
41
+ if (!result.success) {
42
+ result.error.errors.forEach((err) => {
43
+ console.log(err.path, err.message, err.code)
44
+ })
45
+ const flat = result.error.flatten() // { fieldErrors: { email: ['Invalid email'] } }
46
+ }
47
+
48
+ // TanStack Start
49
+ export const createUser = createServerFn({ method: 'POST' })
50
+ .inputValidator(zodValidator(createUserSchema))
51
+ .handler(async ({ data }) => prisma.user.create({ data }))
52
+
53
+ // 환경 변수
54
+ const env = z.object({
55
+ NODE_ENV: z.enum(['development', 'production', 'test']),
56
+ DATABASE_URL: z.string().url(),
57
+ API_SECRET: z.string().min(32),
58
+ }).parse(process.env)
59
+
60
+ // Middleware
61
+ const workspaceMiddleware = createMiddleware({ type: 'function' })
62
+ .inputValidator(zodValidator(z.object({ workspaceId: z.string() })))
63
+ .server(({ next, data }) => next())
64
+
65
+ // Zod Mini (v4)
66
+ import * as z from "zod/mini"
67
+ z.string().check(z.minLength(5), z.maxLength(10), z.trim())
68
+ ```
69
+
70
+ </patterns>
@@ -88,8 +88,9 @@
88
88
  src/
89
89
  ├── routes/ # __root.tsx, index.tsx, $slug.tsx
90
90
  │ └── [path]/
91
- │ ├── -components/ # 페이지 전용
92
- └── -functions/ # 페이지 전용 Server Functions
91
+ │ ├── -components/ # 페이지 전용 (필수)
92
+ ├── -hooks/ # 페이지 전용 Custom Hooks (필수)
93
+ │ └── -functions/ # 페이지 전용 Server Functions (필수)
93
94
  ├── functions/ # 공통 Server Functions
94
95
  ├── components/ui/
95
96
  ├── middleware/
@@ -97,7 +98,10 @@ src/
97
98
  └── lib/
98
99
  ```
99
100
 
100
- 공통 → `@/functions/`, 라우트 전용 → `routes/[경로]/-functions/`
101
+ **필수 규칙:**
102
+ - 페이지당 `-components/`, `-hooks/`, `-functions/` 폴더 필수 (줄 수 무관)
103
+ - Custom Hook은 페이지 크기와 무관하게 **반드시** `-hooks/` 폴더에 분리
104
+ - 공통 함수 → `@/functions/`, 라우트 전용 → `routes/[경로]/-functions/`
101
105
  </structure>
102
106
 
103
107
  ---
@@ -10,6 +10,34 @@
10
10
 
11
11
  ---
12
12
 
13
+ <mandatory_separation>
14
+
15
+ ## ⚠️ 필수 규칙: Custom Hook 분리
16
+
17
+ **모든 페이지는 Custom Hook을 `-hooks/` 폴더에 분리해야 합니다.**
18
+
19
+ - 페이지 크기(줄 수)와 **무관**하게 반드시 분리
20
+ - 10줄짜리 간단한 페이지도 Hook 분리 필수
21
+ - 페이지 컴포넌트는 오직 UI 렌더링만 담당
22
+
23
+ ```typescript
24
+ // ✅ 올바른 구조
25
+ routes/users/
26
+ ├── index.tsx // UI만
27
+ ├── -hooks/
28
+ │ └── use-users.ts // 모든 로직
29
+ ├── -components/
30
+ └── -functions/
31
+
32
+ // ❌ 잘못된 구조
33
+ routes/users/
34
+ └── index.tsx // UI + 로직 혼재
35
+ ```
36
+
37
+ </mandatory_separation>
38
+
39
+ ---
40
+
13
41
  <hook_order>
14
42
 
15
43
  ## Hook 내부 순서 (필수)
@@ -19,12 +19,16 @@ routes/
19
19
  ├── users/
20
20
  │ ├── index.tsx # /users (List)
21
21
  │ ├── $id.tsx # /users/:id (Detail)
22
- │ ├── -components/ # 페이지 전용 컴포넌트
23
- │ ├── -sections/ # 섹션 분리 (복잡한 경우)
24
- └── -hooks/ # 페이지 전용 Hook
22
+ │ ├── -components/ # 페이지 전용 컴포넌트 (필수)
23
+ │ ├── -hooks/ # 페이지 전용 Hook (필수)
24
+ ├── -functions/ # 페이지 전용 Server Functions (필수)
25
+ │ └── -sections/ # 섹션 분리 (선택, 복잡한 경우만)
25
26
  └── posts/
26
27
  ├── index.tsx
27
- └── $slug.tsx
28
+ ├── $slug.tsx
29
+ ├── -components/ # 필수
30
+ ├── -hooks/ # 필수
31
+ └── -functions/ # 필수
28
32
  ```
29
33
 
30
34
  | 접두사 | 용도 | 라우트 생성 |
@@ -33,6 +37,11 @@ routes/
33
37
  | `$` | 동적 파라미터 | ✅ 생성 |
34
38
  | `_` | Pathless Layout | ✅ 생성 (경로 없음) |
35
39
 
40
+ **⚠️ 필수 규칙:**
41
+ - 모든 페이지에 `-components/`, `-hooks/`, `-functions/` 폴더 **필수**
42
+ - 페이지 크기(줄 수)와 **무관**하게 Custom Hook은 반드시 `-hooks/` 폴더에 분리
43
+ - `-sections/`는 200줄 이상 복잡한 페이지에서만 선택적 사용
44
+
36
45
  </route_structure>
37
46
 
38
47
  ---
@@ -257,15 +266,25 @@ export const UserCard = ({
257
266
 
258
267
  ---
259
268
 
260
- <page_size_rules>
269
+ <folder_structure_rules>
270
+
271
+ ## 폴더 구조 규칙
272
+
273
+ **⚠️ 모든 페이지에 필수:**
274
+ - `-components/`: 페이지 전용 컴포넌트
275
+ - `-hooks/`: 페이지 전용 Custom Hook (줄 수 무관)
276
+ - `-functions/`: 페이지 전용 Server Functions
277
+
278
+ **선택적 사용:**
279
+ - `-sections/`: 200줄+ 복잡한 페이지에서만 사용
261
280
 
262
- | 페이지 크기 | 구조 | 예시 |
281
+ | 페이지 크기 | 필수 | 선택 |
263
282
  |------------|------|------|
264
- | ~100줄 | 단일 파일 | 간단한 페이지, 폼 |
265
- | 100-200줄 | `-components/` 분리 | 목록 + 필터 |
266
- | 200줄+ | `-sections/` + `-components/` | 대시보드, 복잡한 UI |
283
+ | ~100줄 | `-components/`, `-hooks/`, `-functions/` | - |
284
+ | 100-200줄 | `-components/`, `-hooks/`, `-functions/` | - |
285
+ | 200줄+ | `-components/`, `-hooks/`, `-functions/` | `-sections/` |
267
286
 
268
- </page_size_rules>
287
+ </folder_structure_rules>
269
288
 
270
289
  ---
271
290