@kood/claude-code 0.1.5 → 0.1.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.
- package/dist/index.js +21 -243
- package/package.json +1 -1
- package/templates/hono/CLAUDE.md +10 -6
- package/templates/hono/docs/deployment/index.md +5 -0
- package/templates/hono/docs/library/hono/index.md +6 -0
- package/templates/hono/docs/library/prisma/index.md +3 -0
- package/templates/npx/CLAUDE.md +8 -2
- package/templates/tanstack-start/CLAUDE.md +105 -259
- package/templates/tanstack-start/docs/deployment/cloudflare.md +37 -424
- package/templates/tanstack-start/docs/deployment/index.md +57 -286
- package/templates/tanstack-start/docs/deployment/nitro.md +36 -318
- package/templates/tanstack-start/docs/deployment/railway.md +40 -409
- package/templates/tanstack-start/docs/deployment/vercel.md +43 -465
- package/templates/tanstack-start/docs/design/accessibility.md +56 -326
- package/templates/tanstack-start/docs/design/color.md +37 -179
- package/templates/tanstack-start/docs/design/components.md +77 -311
- package/templates/tanstack-start/docs/design/index.md +24 -87
- package/templates/tanstack-start/docs/design/safe-area.md +51 -250
- package/templates/tanstack-start/docs/design/spacing.md +57 -276
- package/templates/tanstack-start/docs/design/tailwind-setup.md +45 -359
- package/templates/tanstack-start/docs/design/typography.md +40 -284
- package/templates/tanstack-start/docs/guides/best-practices.md +3 -8
- package/templates/tanstack-start/docs/guides/env-setup.md +3 -3
- package/templates/tanstack-start/docs/library/better-auth/2fa.md +27 -115
- package/templates/tanstack-start/docs/library/better-auth/advanced.md +22 -105
- package/templates/tanstack-start/docs/library/better-auth/index.md +17 -66
- package/templates/tanstack-start/docs/library/better-auth/plugins.md +11 -88
- package/templates/tanstack-start/docs/library/better-auth/session.md +12 -92
- package/templates/tanstack-start/docs/library/better-auth/setup.md +9 -91
- package/templates/tanstack-start/docs/library/prisma/cloudflare-d1.md +30 -358
- package/templates/tanstack-start/docs/library/prisma/config.md +27 -327
- package/templates/tanstack-start/docs/library/prisma/crud.md +46 -174
- package/templates/tanstack-start/docs/library/prisma/index.md +23 -113
- package/templates/tanstack-start/docs/library/prisma/relations.md +31 -153
- package/templates/tanstack-start/docs/library/prisma/schema.md +40 -217
- package/templates/tanstack-start/docs/library/prisma/setup.md +13 -113
- package/templates/tanstack-start/docs/library/prisma/transactions.md +20 -110
- package/templates/tanstack-start/docs/library/tanstack-query/index.md +12 -99
- package/templates/tanstack-start/docs/library/tanstack-query/invalidation.md +28 -107
- package/templates/tanstack-start/docs/library/tanstack-query/optimistic-updates.md +44 -146
- package/templates/tanstack-start/docs/library/tanstack-query/setup.md +11 -73
- package/templates/tanstack-start/docs/library/tanstack-query/use-mutation.md +33 -127
- package/templates/tanstack-start/docs/library/tanstack-query/use-query.md +49 -149
- package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +19 -112
- package/templates/tanstack-start/docs/library/tanstack-start/index.md +33 -80
- package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +28 -106
- package/templates/tanstack-start/docs/library/tanstack-start/routing.md +21 -118
- package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +41 -172
- package/templates/tanstack-start/docs/library/tanstack-start/setup.md +6 -39
- package/templates/tanstack-start/docs/library/zod/basic-types.md +33 -145
- package/templates/tanstack-start/docs/library/zod/complex-types.md +32 -156
- package/templates/tanstack-start/docs/library/zod/index.md +22 -150
- package/templates/tanstack-start/docs/library/zod/transforms.md +20 -129
- package/templates/tanstack-start/docs/library/zod/validation.md +39 -155
- package/templates/hono/docs/commands/git.md +0 -145
- package/templates/hono/docs/mcp/context7.md +0 -106
- package/templates/hono/docs/mcp/index.md +0 -176
- package/templates/hono/docs/mcp/sequential-thinking.md +0 -101
- package/templates/hono/docs/mcp/serena.md +0 -269
- package/templates/hono/docs/mcp/sgrep.md +0 -105
- package/templates/hono/docs/skills/gemini-review/SKILL.md +0 -220
- package/templates/hono/docs/skills/gemini-review/references/checklists.md +0 -136
- package/templates/hono/docs/skills/gemini-review/references/prompt-templates.md +0 -303
- package/templates/npx/docs/commands/git.md +0 -145
- package/templates/npx/docs/mcp/index.md +0 -60
- package/templates/npx/docs/skills/gemini-review/SKILL.md +0 -220
- package/templates/npx/docs/skills/gemini-review/references/checklists.md +0 -134
- package/templates/npx/docs/skills/gemini-review/references/prompt-templates.md +0 -301
- package/templates/tanstack-start/docs/commands/git.md +0 -145
- package/templates/tanstack-start/docs/mcp/context7.md +0 -204
- package/templates/tanstack-start/docs/mcp/index.md +0 -177
- package/templates/tanstack-start/docs/mcp/sequential-thinking.md +0 -180
- package/templates/tanstack-start/docs/mcp/serena.md +0 -269
- package/templates/tanstack-start/docs/mcp/sgrep.md +0 -174
- package/templates/tanstack-start/docs/skills/gemini-review/SKILL.md +0 -220
- package/templates/tanstack-start/docs/skills/gemini-review/references/checklists.md +0 -144
- package/templates/tanstack-start/docs/skills/gemini-review/references/prompt-templates.md +0 -292
|
@@ -1,148 +1,56 @@
|
|
|
1
1
|
# Zod - 변환
|
|
2
2
|
|
|
3
|
-
> **상위 문서**: [Zod](./index.md)
|
|
4
|
-
|
|
5
3
|
## Transform
|
|
6
4
|
|
|
7
|
-
입력값을 다른 형태로 변환합니다.
|
|
8
|
-
|
|
9
5
|
```typescript
|
|
10
6
|
const stringToLength = z.string().transform((val) => val.length)
|
|
7
|
+
stringToLength.parse('hello') // => 5
|
|
11
8
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
type MySchemaIn = z.input<typeof stringToLength> // string
|
|
15
|
-
type MySchemaOut = z.output<typeof stringToLength> // number
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
### 체인으로 변환
|
|
19
|
-
|
|
20
|
-
```typescript
|
|
21
|
-
const emailToLower = z.string()
|
|
22
|
-
.email()
|
|
23
|
-
.transform((email) => email.toLowerCase())
|
|
24
|
-
|
|
25
|
-
emailToLower.parse('User@Example.COM') // => "user@example.com"
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Pipe를 사용한 Transform
|
|
29
|
-
|
|
30
|
-
```typescript
|
|
31
|
-
const stringToLength = z.string().pipe(z.transform(val => val.length))
|
|
32
|
-
|
|
33
|
-
stringToLength.parse('hello') // => 5
|
|
9
|
+
type In = z.input<typeof stringToLength> // string
|
|
10
|
+
type Out = z.output<typeof stringToLength> // number
|
|
34
11
|
```
|
|
35
12
|
|
|
36
|
-
|
|
13
|
+
## Pipe (검증 후 변환)
|
|
37
14
|
|
|
38
15
|
```typescript
|
|
39
16
|
const stringToNumber = z.string()
|
|
40
17
|
.transform((val) => parseInt(val, 10))
|
|
41
18
|
.pipe(z.number().min(0).max(100))
|
|
42
19
|
|
|
43
|
-
stringToNumber.parse('50')
|
|
44
|
-
stringToNumber.parse('150') //
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Transform 내에서 검증
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
const coercedInt = z.transform((val, ctx) => {
|
|
51
|
-
try {
|
|
52
|
-
const parsed = Number.parseInt(String(val))
|
|
53
|
-
return parsed
|
|
54
|
-
} catch (e) {
|
|
55
|
-
ctx.issues.push({
|
|
56
|
-
code: 'custom',
|
|
57
|
-
message: 'Not a number',
|
|
58
|
-
input: val,
|
|
59
|
-
})
|
|
60
|
-
return z.NEVER // 타입에 영향 없이 에러 반환
|
|
61
|
-
}
|
|
62
|
-
})
|
|
20
|
+
stringToNumber.parse('50') // => 50
|
|
21
|
+
stringToNumber.parse('150') // throws
|
|
63
22
|
```
|
|
64
23
|
|
|
65
24
|
## Coerce (강제 변환)
|
|
66
25
|
|
|
67
|
-
입력값을 자동으로 해당 타입으로 변환합니다.
|
|
68
|
-
|
|
69
|
-
```typescript
|
|
70
|
-
z.coerce.string() // 모든 값을 문자열로
|
|
71
|
-
z.coerce.number() // 모든 값을 숫자로
|
|
72
|
-
z.coerce.boolean() // 모든 값을 불리언으로
|
|
73
|
-
z.coerce.date() // 모든 값을 날짜로
|
|
74
|
-
z.coerce.bigint() // 모든 값을 BigInt로
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### v4 Coerce 입력 타입 변경
|
|
78
|
-
|
|
79
26
|
```typescript
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
|
|
27
|
+
z.coerce.string() // 모든 값 → 문자열
|
|
28
|
+
z.coerce.number() // 모든 값 → 숫자
|
|
29
|
+
z.coerce.boolean() // 모든 값 → 불리언
|
|
30
|
+
z.coerce.date() // 모든 값 → 날짜
|
|
31
|
+
z.coerce.bigint() // 모든 값 → BigInt
|
|
85
32
|
|
|
86
|
-
|
|
33
|
+
z.coerce.number().parse("42") // => 42
|
|
34
|
+
z.coerce.date().parse("2021-01-01") // => Date
|
|
87
35
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
z.coerce.string().parse(123) // => "123"
|
|
91
|
-
z.coerce.string().parse(true) // => "true"
|
|
92
|
-
z.coerce.string().parse(null) // => "null"
|
|
93
|
-
|
|
94
|
-
// number coercion
|
|
95
|
-
z.coerce.number().parse("42") // => 42
|
|
96
|
-
z.coerce.number().parse(true) // => 1
|
|
97
|
-
z.coerce.number().parse(false) // => 0
|
|
98
|
-
|
|
99
|
-
// boolean coercion
|
|
100
|
-
z.coerce.boolean().parse("true") // => true
|
|
101
|
-
z.coerce.boolean().parse("") // => false
|
|
102
|
-
z.coerce.boolean().parse(1) // => true
|
|
103
|
-
|
|
104
|
-
// date coercion
|
|
105
|
-
z.coerce.date().parse("2021-01-01") // => Date
|
|
106
|
-
z.coerce.date().parse(1609459200000) // => Date
|
|
36
|
+
// ⚠️ v4: 입력 타입이 unknown으로 변경됨
|
|
37
|
+
type In = z.input<typeof z.coerce.string()> // unknown
|
|
107
38
|
```
|
|
108
39
|
|
|
109
40
|
### 환경변수 불리언 (v4 권장)
|
|
110
41
|
|
|
111
|
-
`z.coerce.boolean()` 대신 더 정교한 `z.stringbool()` 사용:
|
|
112
|
-
|
|
113
42
|
```typescript
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
strbool.parse("true") // => true
|
|
117
|
-
strbool.parse("yes") // => true
|
|
118
|
-
strbool.parse("1") // => true
|
|
119
|
-
strbool.parse("false") // => false
|
|
120
|
-
strbool.parse("no") // => false
|
|
121
|
-
strbool.parse("0") // => false
|
|
43
|
+
z.stringbool() // "true"/"yes"/"1" → true
|
|
44
|
+
// "false"/"no"/"0" → false
|
|
122
45
|
```
|
|
123
46
|
|
|
124
47
|
## Preprocess
|
|
125
48
|
|
|
126
|
-
검증 전에 데이터를 전처리합니다.
|
|
127
|
-
|
|
128
|
-
```typescript
|
|
129
|
-
const castToString = z.preprocess((val) => String(val), z.string())
|
|
130
|
-
|
|
131
|
-
castToString.parse(123) // => "123"
|
|
132
|
-
castToString.parse(null) // => "null"
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### Preprocess vs Coerce
|
|
136
|
-
|
|
137
49
|
```typescript
|
|
138
|
-
|
|
139
|
-
const trimmedString = z.preprocess(
|
|
50
|
+
const trimmed = z.preprocess(
|
|
140
51
|
(val) => typeof val === 'string' ? val.trim() : val,
|
|
141
52
|
z.string()
|
|
142
53
|
)
|
|
143
|
-
|
|
144
|
-
// coerce - 내장 변환만
|
|
145
|
-
const coercedString = z.coerce.string()
|
|
146
54
|
```
|
|
147
55
|
|
|
148
56
|
## 입력/출력 타입 분리
|
|
@@ -152,23 +60,6 @@ const Schema = z.object({
|
|
|
152
60
|
createdAt: z.string().transform((str) => new Date(str)),
|
|
153
61
|
})
|
|
154
62
|
|
|
155
|
-
type SchemaInput = z.input<typeof Schema>
|
|
156
|
-
// { createdAt:
|
|
157
|
-
|
|
158
|
-
type SchemaOutput = z.output<typeof Schema>
|
|
159
|
-
// { createdAt: Date }
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
## 조건부 변환
|
|
163
|
-
|
|
164
|
-
```typescript
|
|
165
|
-
const conditionalTransform = z.string().transform((val) => {
|
|
166
|
-
if (val === 'null') return null
|
|
167
|
-
if (val === 'undefined') return undefined
|
|
168
|
-
return val
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
conditionalTransform.parse('hello') // => "hello"
|
|
172
|
-
conditionalTransform.parse('null') // => null
|
|
173
|
-
conditionalTransform.parse('undefined') // => undefined
|
|
63
|
+
type SchemaInput = z.input<typeof Schema> // { createdAt: string }
|
|
64
|
+
type SchemaOutput = z.output<typeof Schema> // { createdAt: Date }
|
|
174
65
|
```
|
|
@@ -1,208 +1,92 @@
|
|
|
1
1
|
# Zod - 검증
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Refinement (커스텀 검증)
|
|
3
|
+
## Refinement
|
|
6
4
|
|
|
7
5
|
```typescript
|
|
8
|
-
// v4
|
|
6
|
+
// v4: message → error
|
|
9
7
|
const PasswordSchema = z.string()
|
|
10
8
|
.min(8)
|
|
11
|
-
.refine((val) => /[A-Z]/.test(val), {
|
|
12
|
-
|
|
13
|
-
})
|
|
14
|
-
.refine((val) => /[0-9]/.test(val), {
|
|
15
|
-
error: '숫자가 포함되어야 합니다',
|
|
16
|
-
})
|
|
17
|
-
```
|
|
9
|
+
.refine((val) => /[A-Z]/.test(val), { error: '대문자 필수' })
|
|
10
|
+
.refine((val) => /[0-9]/.test(val), { error: '숫자 필수' })
|
|
18
11
|
|
|
19
|
-
|
|
12
|
+
// v4: refinement 후 체이닝 가능
|
|
13
|
+
z.string().refine(val => val.includes("@")).min(5) // ✅
|
|
20
14
|
|
|
21
|
-
|
|
22
|
-
// v3 - ZodEffects로 래핑되어 .min() 호출 불가
|
|
23
|
-
z.string()
|
|
24
|
-
.refine(val => val.includes("@"))
|
|
25
|
-
.min(5) // ❌ 에러
|
|
26
|
-
|
|
27
|
-
// v4 - 스키마 내부에 저장되어 체이닝 가능
|
|
28
|
-
z.string()
|
|
29
|
-
.refine(val => val.includes("@"))
|
|
30
|
-
.min(5) // ✅ 정상 작동
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Async Refinement
|
|
34
|
-
|
|
35
|
-
```typescript
|
|
15
|
+
// Async
|
|
36
16
|
const schema = z.string().refine(async (val) => val.length <= 8)
|
|
37
|
-
|
|
38
|
-
await schema.parseAsync('hello') // => "hello"
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### 이메일 중복 검사 예시
|
|
42
|
-
|
|
43
|
-
```typescript
|
|
44
|
-
const EmailSchema = z.email() // v4 새 API
|
|
45
|
-
.refine(async (email) => {
|
|
46
|
-
const exists = await checkEmailExists(email)
|
|
47
|
-
return !exists
|
|
48
|
-
}, {
|
|
49
|
-
error: '이미 사용 중인 이메일입니다', // v4: message → error
|
|
50
|
-
})
|
|
17
|
+
await schema.parseAsync('hello')
|
|
51
18
|
```
|
|
52
19
|
|
|
53
|
-
## Superrefine (고급
|
|
54
|
-
|
|
55
|
-
여러 이슈를 추가하거나 경로를 지정할 수 있습니다.
|
|
56
|
-
|
|
57
|
-
> **v4 변경**: `ctx.path`는 더 이상 사용할 수 없습니다 (성능 향상을 위해 제거됨)
|
|
20
|
+
## Superrefine (고급)
|
|
58
21
|
|
|
59
22
|
```typescript
|
|
60
|
-
|
|
23
|
+
z.object({
|
|
61
24
|
password: z.string(),
|
|
62
25
|
confirmPassword: z.string(),
|
|
63
26
|
}).superRefine((data, ctx) => {
|
|
64
27
|
if (data.password !== data.confirmPassword) {
|
|
65
28
|
ctx.addIssue({
|
|
66
29
|
code: z.ZodIssueCode.custom,
|
|
67
|
-
message: '
|
|
30
|
+
message: '비밀번호 불일치',
|
|
68
31
|
path: ['confirmPassword'],
|
|
69
32
|
})
|
|
70
33
|
}
|
|
71
|
-
// ctx.path // ❌ v4에서 더 이상 사용 불가
|
|
72
34
|
})
|
|
35
|
+
// ⚠️ v4: ctx.path 사용 불가
|
|
73
36
|
```
|
|
74
37
|
|
|
75
|
-
|
|
38
|
+
## 커스텀 스키마
|
|
76
39
|
|
|
77
40
|
```typescript
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
age: z.number(),
|
|
82
|
-
}).superRefine((data, ctx) => {
|
|
83
|
-
// 여러 조건 검증
|
|
84
|
-
if (data.age < 13 && data.email.includes('work')) {
|
|
85
|
-
ctx.addIssue({
|
|
86
|
-
code: z.ZodIssueCode.custom,
|
|
87
|
-
message: '13세 미만은 업무용 이메일을 사용할 수 없습니다',
|
|
88
|
-
path: ['email'],
|
|
89
|
-
})
|
|
90
|
-
}
|
|
41
|
+
const px = z.custom<`${number}px`>((val) =>
|
|
42
|
+
typeof val === 'string' && /^\d+px$/.test(val)
|
|
43
|
+
)
|
|
91
44
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
code: z.ZodIssueCode.custom,
|
|
95
|
-
message: 'admin 사용자명은 18세 이상만 사용 가능합니다',
|
|
96
|
-
path: ['username'],
|
|
97
|
-
})
|
|
98
|
-
}
|
|
99
|
-
})
|
|
45
|
+
px.parse('42px') // ✅
|
|
46
|
+
px.parse('42vw') // throws
|
|
100
47
|
```
|
|
101
48
|
|
|
102
|
-
##
|
|
49
|
+
## 에러 처리
|
|
103
50
|
|
|
104
51
|
```typescript
|
|
105
|
-
const
|
|
106
|
-
return typeof val === 'string' ? /^\d+px$/.test(val) : false
|
|
107
|
-
})
|
|
52
|
+
const result = schema.safeParse(data)
|
|
108
53
|
|
|
109
|
-
|
|
54
|
+
if (!result.success) {
|
|
55
|
+
result.error.errors.forEach((err) => {
|
|
56
|
+
console.log(err.path, err.message, err.code)
|
|
57
|
+
})
|
|
110
58
|
|
|
111
|
-
|
|
112
|
-
|
|
59
|
+
// 평면화
|
|
60
|
+
const flat = result.error.flatten()
|
|
61
|
+
// { fieldErrors: { email: ['Invalid email'] } }
|
|
62
|
+
}
|
|
113
63
|
```
|
|
114
64
|
|
|
115
|
-
## TanStack Start
|
|
116
|
-
|
|
117
|
-
### Server Function 입력 검증
|
|
65
|
+
## TanStack Start 연동
|
|
118
66
|
|
|
119
67
|
```typescript
|
|
120
|
-
|
|
121
|
-
import { zodValidator } from '@tanstack/react-start/validators'
|
|
122
|
-
import { z } from 'zod'
|
|
123
|
-
|
|
124
|
-
const createUserSchema = z.object({
|
|
125
|
-
email: z.email(), // v4 새 API
|
|
126
|
-
name: z.string().min(1).max(100).trim(),
|
|
127
|
-
bio: z.string().max(500).optional(),
|
|
128
|
-
})
|
|
129
|
-
|
|
68
|
+
// Server Function
|
|
130
69
|
export const createUser = createServerFn({ method: 'POST' })
|
|
131
70
|
.inputValidator(zodValidator(createUserSchema))
|
|
132
|
-
.handler(async ({ data }) => {
|
|
133
|
-
// data는 타입 안전함
|
|
134
|
-
return prisma.user.create({ data })
|
|
135
|
-
})
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
### 환경 변수 검증
|
|
71
|
+
.handler(async ({ data }) => prisma.user.create({ data }))
|
|
139
72
|
|
|
140
|
-
|
|
141
|
-
const
|
|
73
|
+
// 환경 변수
|
|
74
|
+
const env = z.object({
|
|
142
75
|
NODE_ENV: z.enum(['development', 'production', 'test']),
|
|
143
76
|
DATABASE_URL: z.string().url(),
|
|
144
77
|
API_SECRET: z.string().min(32),
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
export const env = envSchema.parse(process.env)
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
### Middleware에서 사용
|
|
151
|
-
|
|
152
|
-
```typescript
|
|
153
|
-
import { createMiddleware } from '@tanstack/react-start'
|
|
154
|
-
import { zodValidator } from '@tanstack/react-start/validators'
|
|
155
|
-
import { z } from 'zod'
|
|
156
|
-
|
|
157
|
-
const mySchema = z.object({
|
|
158
|
-
workspaceId: z.string(),
|
|
159
|
-
})
|
|
78
|
+
}).parse(process.env)
|
|
160
79
|
|
|
80
|
+
// Middleware
|
|
161
81
|
const workspaceMiddleware = createMiddleware({ type: 'function' })
|
|
162
|
-
.inputValidator(zodValidator(
|
|
163
|
-
.server(({ next, data }) =>
|
|
164
|
-
console.log('Workspace ID:', data.workspaceId)
|
|
165
|
-
return next()
|
|
166
|
-
})
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
## 에러 처리
|
|
170
|
-
|
|
171
|
-
```typescript
|
|
172
|
-
const result = UserSchema.safeParse(data)
|
|
173
|
-
|
|
174
|
-
if (!result.success) {
|
|
175
|
-
// ZodError 객체
|
|
176
|
-
const errors = result.error.errors
|
|
177
|
-
|
|
178
|
-
errors.forEach((err) => {
|
|
179
|
-
console.log('Path:', err.path)
|
|
180
|
-
console.log('Message:', err.message)
|
|
181
|
-
console.log('Code:', err.code)
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
// 평면화된 에러
|
|
185
|
-
const flatErrors = result.error.flatten()
|
|
186
|
-
console.log(flatErrors.fieldErrors)
|
|
187
|
-
// { email: ['Invalid email'], name: ['Required'] }
|
|
188
|
-
}
|
|
82
|
+
.inputValidator(zodValidator(z.object({ workspaceId: z.string() })))
|
|
83
|
+
.server(({ next, data }) => next())
|
|
189
84
|
```
|
|
190
85
|
|
|
191
|
-
## Zod Mini (경량
|
|
192
|
-
|
|
193
|
-
v4에서 새롭게 추가된 경량 API:
|
|
86
|
+
## Zod Mini (v4 경량)
|
|
194
87
|
|
|
195
88
|
```typescript
|
|
196
89
|
import * as z from "zod/mini"
|
|
197
90
|
|
|
198
|
-
|
|
199
|
-
z.string().min(5).max(10).trim()
|
|
200
|
-
|
|
201
|
-
// Zod Mini - check 메서드로 통합
|
|
202
|
-
z.string().check(
|
|
203
|
-
z.minLength(5),
|
|
204
|
-
z.maxLength(10),
|
|
205
|
-
z.toLowerCase(),
|
|
206
|
-
z.trim(),
|
|
207
|
-
)
|
|
91
|
+
z.string().check(z.minLength(5), z.maxLength(10), z.trim())
|
|
208
92
|
```
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
현재 git 상태를 확인하고, 아래 규칙에 따라 작업을 진행해주세요.
|
|
2
|
-
|
|
3
|
-
**추가 지시사항**: $ARGUMENTS
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 실행 절차
|
|
8
|
-
|
|
9
|
-
### 추가 지시사항이 없는 경우 (기본 동작)
|
|
10
|
-
1. `git status`로 현재 상태 확인
|
|
11
|
-
2. `git diff`로 변경 내용 분석
|
|
12
|
-
3. 스테이징 안 된 변경사항 → `git add`
|
|
13
|
-
4. 커밋 안 된 변경사항 → 논리적 단위로 분리하여 `git commit`
|
|
14
|
-
5. 최종 `git status`로 완료 확인
|
|
15
|
-
|
|
16
|
-
### 추가 지시사항이 있는 경우
|
|
17
|
-
- 사용자의 지시사항을 우선적으로 따름
|
|
18
|
-
- 예: `/git push` → push 진행, `/git 특정파일만 커밋` → 해당 파일만 처리
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## ⛔ NEVER (절대 금지)
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
❌ 커밋에 "Generated with Claude Code" 포함
|
|
26
|
-
❌ 커밋에 "🤖" 또는 AI 관련 이모지 포함
|
|
27
|
-
❌ 커밋에 "Co-Authored-By:" 헤더 포함
|
|
28
|
-
❌ 커밋에 AI/봇이 작성했다는 어떤 표시도 포함
|
|
29
|
-
❌ 커밋 메시지 여러 줄 작성
|
|
30
|
-
❌ 커밋 메시지에 이모지 사용
|
|
31
|
-
❌ 커밋 메시지에 마침표(.) 사용
|
|
32
|
-
❌ 여러 작업을 하나의 커밋으로 퉁치기
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
## ✅ ALWAYS (필수)
|
|
38
|
-
|
|
39
|
-
### 커밋 형식
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
<prefix>: <설명>
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
**한 줄로 간결하게** 작성합니다. 본문이나 푸터는 작성하지 않습니다.
|
|
46
|
-
|
|
47
|
-
### ⭐ 커밋 분리 원칙
|
|
48
|
-
|
|
49
|
-
**하나의 커밋 = 하나의 논리적 변경 단위**
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
# ❌ 잘못된 방식: 모든 작업을 하나로 퉁침
|
|
53
|
-
git add .
|
|
54
|
-
git commit -m "feat: 여러 기능 추가"
|
|
55
|
-
|
|
56
|
-
# ✅ 올바른 방식: 논리적 단위로 분리
|
|
57
|
-
git add src/auth/
|
|
58
|
-
git commit -m "feat: 사용자 인증 기능 추가"
|
|
59
|
-
|
|
60
|
-
git add src/users/
|
|
61
|
-
git commit -m "feat: 사용자 관리 기능 추가"
|
|
62
|
-
|
|
63
|
-
git add docs/
|
|
64
|
-
git commit -m "docs: API 문서 업데이트"
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
---
|
|
68
|
-
|
|
69
|
-
## 🏷 Prefix 목록
|
|
70
|
-
|
|
71
|
-
| Prefix | 용도 | 예시 |
|
|
72
|
-
|--------|------|------|
|
|
73
|
-
| `feat` | 새로운 기능 | `feat: 사용자 인증 기능 추가` |
|
|
74
|
-
| `fix` | 버그 수정 | `fix: 토큰 검증 오류 수정` |
|
|
75
|
-
| `refactor` | 리팩토링 | `refactor: 인증 로직 분리` |
|
|
76
|
-
| `style` | 코드 스타일 | `style: prettier 적용` |
|
|
77
|
-
| `docs` | 문서 수정 | `docs: API 문서 업데이트` |
|
|
78
|
-
| `test` | 테스트 | `test: 인증 테스트 추가` |
|
|
79
|
-
| `chore` | 빌드/설정 | `chore: 의존성 업데이트` |
|
|
80
|
-
| `perf` | 성능 개선 | `perf: 쿼리 최적화` |
|
|
81
|
-
| `ci` | CI/CD | `ci: GitHub Actions 추가` |
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
## ✅ 올바른 예시
|
|
86
|
-
|
|
87
|
-
```bash
|
|
88
|
-
feat: 사용자 로그인 기능 추가
|
|
89
|
-
fix: 세션 만료 오류 수정
|
|
90
|
-
refactor: 서비스 클래스 구조 개선
|
|
91
|
-
docs: README 설치 가이드 추가
|
|
92
|
-
chore: 의존성 버전 업그레이드
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
---
|
|
96
|
-
|
|
97
|
-
## ❌ 잘못된 예시
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
# prefix 없음
|
|
101
|
-
사용자 인증 기능 추가함
|
|
102
|
-
|
|
103
|
-
# 마침표 불필요
|
|
104
|
-
feat: 사용자 인증 추가.
|
|
105
|
-
|
|
106
|
-
# 대문자 사용
|
|
107
|
-
FEAT: 사용자 인증 추가
|
|
108
|
-
|
|
109
|
-
# scope 불필요
|
|
110
|
-
feat(auth): 인증 추가
|
|
111
|
-
|
|
112
|
-
# AI 작성 표시 (절대 금지!)
|
|
113
|
-
feat: 로그인 기능 추가
|
|
114
|
-
|
|
115
|
-
🤖 Generated with Claude Code
|
|
116
|
-
|
|
117
|
-
# Co-Author 표시 (절대 금지!)
|
|
118
|
-
feat: 로그인 기능 추가
|
|
119
|
-
|
|
120
|
-
Co-Authored-By: Claude <noreply@anthropic.com>
|
|
121
|
-
|
|
122
|
-
# 여러 줄 본문 (금지)
|
|
123
|
-
feat: 로그인 기능 추가
|
|
124
|
-
|
|
125
|
-
- 이메일 인증 추가
|
|
126
|
-
- 세션 관리 구현
|
|
127
|
-
|
|
128
|
-
# 여러 작업을 하나로 퉁침 (금지)
|
|
129
|
-
feat: 로그인, 회원가입, 프로필 기능 추가
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
---
|
|
133
|
-
|
|
134
|
-
## 📦 커밋 분리 가이드
|
|
135
|
-
|
|
136
|
-
### 언제 커밋을 분리해야 하나요?
|
|
137
|
-
|
|
138
|
-
| 상황 | 커밋 분리 |
|
|
139
|
-
|------|----------|
|
|
140
|
-
| 서로 다른 기능 구현 | ✅ 분리 |
|
|
141
|
-
| 버그 수정 + 새 기능 | ✅ 분리 |
|
|
142
|
-
| 코드 변경 + 문서 변경 | ✅ 분리 |
|
|
143
|
-
| 리팩토링 + 기능 추가 | ✅ 분리 |
|
|
144
|
-
| 동일 기능의 관련 파일들 | 🔄 묶어도 됨 |
|
|
145
|
-
| 동일 기능의 타입 + 구현 | 🔄 묶어도 됨 |
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
# Context7
|
|
2
|
-
|
|
3
|
-
> 라이브러리 공식 문서 조회 도구
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 개요
|
|
8
|
-
|
|
9
|
-
Context7은 주요 라이브러리의 공식 문서를 조회하여 정확한 API 정보와 사용 패턴을 제공합니다.
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## 사용 시점
|
|
14
|
-
|
|
15
|
-
### ✅ 사용 권장
|
|
16
|
-
- **API 확인**: 라이브러리 함수/메서드 사용법
|
|
17
|
-
- **공식 패턴**: 권장되는 코드 패턴
|
|
18
|
-
- **버전별 차이**: 특정 버전의 API 확인
|
|
19
|
-
- **최신 정보**: 최신 릴리즈 기능 확인
|
|
20
|
-
|
|
21
|
-
### ❌ 사용 불필요
|
|
22
|
-
- 이미 알고 있는 기본 API
|
|
23
|
-
- 프로젝트 내부 코드 관련 질문
|
|
24
|
-
- 일반적인 프로그래밍 개념
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
## 지원 라이브러리
|
|
29
|
-
|
|
30
|
-
### 주요 지원
|
|
31
|
-
- **Hono**: 라우팅, 미들웨어, RPC
|
|
32
|
-
- **Zod**: 스키마 정의, 검증
|
|
33
|
-
- **Prisma**: ORM, 쿼리, 마이그레이션
|
|
34
|
-
- **TypeScript**: 타입 시스템
|
|
35
|
-
|
|
36
|
-
### 기타 지원
|
|
37
|
-
- React, Vue, Angular
|
|
38
|
-
- Express, Fastify
|
|
39
|
-
- 기타 주요 npm 패키지
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## 사용 예시
|
|
44
|
-
|
|
45
|
-
### Hono 문서 조회
|
|
46
|
-
```
|
|
47
|
-
"Hono의 zValidator 사용법 조회"
|
|
48
|
-
"Hono middleware 작성 패턴 조회"
|
|
49
|
-
"Hono RPC client 설정 방법 조회"
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Zod 문서 조회
|
|
53
|
-
```
|
|
54
|
-
"Zod v4의 z.email() 사용법 조회"
|
|
55
|
-
"Zod transform 패턴 조회"
|
|
56
|
-
"Zod discriminatedUnion 사용법 조회"
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
### Prisma 문서 조회
|
|
60
|
-
```
|
|
61
|
-
"Prisma v7 generator 설정 조회"
|
|
62
|
-
"Prisma transaction 패턴 조회"
|
|
63
|
-
"Prisma relation 쿼리 방법 조회"
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
---
|
|
67
|
-
|
|
68
|
-
## 장점
|
|
69
|
-
|
|
70
|
-
### 1. 정확한 정보
|
|
71
|
-
- 공식 문서 기반
|
|
72
|
-
- 검증된 코드 예시
|
|
73
|
-
|
|
74
|
-
### 2. 최신 정보
|
|
75
|
-
- 최신 버전 반영
|
|
76
|
-
- 업데이트된 API
|
|
77
|
-
|
|
78
|
-
### 3. 버전 특정
|
|
79
|
-
- 특정 버전 문서 조회
|
|
80
|
-
- 버전 간 차이 확인
|
|
81
|
-
|
|
82
|
-
---
|
|
83
|
-
|
|
84
|
-
## 워크플로우
|
|
85
|
-
|
|
86
|
-
```
|
|
87
|
-
1. 필요한 정보 파악
|
|
88
|
-
└─ 어떤 라이브러리의 어떤 기능?
|
|
89
|
-
|
|
90
|
-
2. Context7 조회
|
|
91
|
-
└─ 해당 라이브러리 문서 검색
|
|
92
|
-
|
|
93
|
-
3. 정보 확인
|
|
94
|
-
└─ API 시그니처, 사용 예시
|
|
95
|
-
|
|
96
|
-
4. 코드 적용
|
|
97
|
-
└─ 프로젝트에 맞게 적용
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
## 관련 문서
|
|
103
|
-
|
|
104
|
-
- [MCP 개요](./index.md)
|
|
105
|
-
- [sgrep](./sgrep.md)
|
|
106
|
-
- [Sequential Thinking](./sequential-thinking.md)
|