@kood/claude-code 0.5.4 → 0.5.6
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 +6 -2
- package/package.json +1 -1
- package/templates/.claude/agents/document-writer.md +2 -2
- package/templates/.claude/skills/docs-creator/SKILL.md +2 -2
- package/templates/.claude/skills/docs-refactor/SKILL.md +1 -1
- package/templates/.claude/skills/plan/SKILL.md +15 -15
- package/templates/.claude/skills/ralph/SKILL.md +425 -72
- package/templates/hono/CLAUDE.md +28 -28
- package/templates/hono/docs/architecture.md +24 -24
- package/templates/hono/docs/deployment/cloudflare.md +18 -18
- package/templates/hono/docs/deployment/docker.md +13 -13
- package/templates/hono/docs/deployment/index.md +19 -19
- package/templates/hono/docs/deployment/railway.md +32 -32
- package/templates/hono/docs/deployment/vercel.md +29 -29
- package/templates/hono/docs/guides/conventions.md +57 -57
- package/templates/hono/docs/guides/env-setup.md +47 -47
- package/templates/hono/docs/guides/getting-started.md +27 -27
- package/templates/hono/docs/library/hono/error-handling.md +11 -11
- package/templates/hono/docs/library/hono/index.md +4 -4
- package/templates/hono/docs/library/hono/middleware.md +18 -18
- package/templates/hono/docs/library/hono/rpc.md +7 -7
- package/templates/hono/docs/library/hono/validation.md +6 -6
- package/templates/hono/docs/library/prisma/cloudflare-d1.md +29 -29
- package/templates/hono/docs/library/prisma/config.md +16 -16
- package/templates/hono/docs/library/prisma/index.md +32 -32
- package/templates/hono/docs/library/t3-env/index.md +22 -22
- package/templates/hono/docs/library/zod/index.md +31 -31
- package/templates/nextjs/CLAUDE.md +54 -54
- package/templates/nextjs/docs/architecture.md +146 -146
- package/templates/nextjs/docs/design.md +183 -183
- package/templates/nextjs/docs/guides/conventions.md +86 -86
- package/templates/nextjs/docs/guides/getting-started.md +28 -28
- package/templates/nextjs/docs/guides/routes.md +32 -32
- package/templates/nextjs/docs/library/better-auth/index.md +70 -70
- package/templates/nextjs/docs/library/nextjs/app-router.md +43 -43
- package/templates/nextjs/docs/library/nextjs/caching.md +73 -73
- package/templates/nextjs/docs/library/nextjs/index.md +51 -51
- package/templates/nextjs/docs/library/nextjs/middleware.md +41 -41
- package/templates/nextjs/docs/library/nextjs/route-handlers.md +31 -31
- package/templates/nextjs/docs/library/nextjs/server-actions.md +34 -34
- package/templates/nextjs/docs/library/prisma/cloudflare-d1.md +20 -20
- package/templates/nextjs/docs/library/prisma/config.md +18 -18
- package/templates/nextjs/docs/library/prisma/crud.md +17 -17
- package/templates/nextjs/docs/library/prisma/index.md +18 -18
- package/templates/nextjs/docs/library/prisma/relations.md +16 -16
- package/templates/nextjs/docs/library/prisma/schema.md +23 -23
- package/templates/nextjs/docs/library/prisma/setup.md +6 -6
- package/templates/nextjs/docs/library/prisma/transactions.md +10 -10
- package/templates/nextjs/docs/library/tanstack-query/index.md +6 -6
- package/templates/nextjs/docs/library/tanstack-query/invalidation.md +20 -20
- package/templates/nextjs/docs/library/tanstack-query/optimistic-updates.md +4 -4
- package/templates/nextjs/docs/library/tanstack-query/use-mutation.md +15 -15
- package/templates/nextjs/docs/library/tanstack-query/use-query.md +22 -22
- package/templates/nextjs/docs/library/zod/complex-types.md +11 -11
- package/templates/nextjs/docs/library/zod/index.md +8 -8
- package/templates/nextjs/docs/library/zod/transforms.md +11 -11
- package/templates/nextjs/docs/library/zod/validation.md +9 -9
- package/templates/npx/CLAUDE.md +38 -38
- package/templates/npx/docs/library/commander/index.md +12 -12
- package/templates/npx/docs/library/fs-extra/index.md +9 -9
- package/templates/npx/docs/library/prompts/index.md +3 -3
- package/templates/npx/docs/references/patterns.md +12 -12
- package/templates/tanstack-start/CLAUDE.md +54 -54
- package/templates/tanstack-start/docs/architecture.md +128 -128
- package/templates/tanstack-start/docs/design.md +169 -169
- package/templates/tanstack-start/docs/guides/conventions.md +43 -43
- package/templates/tanstack-start/docs/guides/env-setup.md +35 -35
- package/templates/tanstack-start/docs/guides/getting-started.md +19 -19
- package/templates/tanstack-start/docs/guides/hooks.md +45 -45
- package/templates/tanstack-start/docs/guides/routes.md +54 -54
- package/templates/tanstack-start/docs/guides/services.md +45 -45
- package/templates/tanstack-start/docs/library/prisma/cloudflare-d1.md +19 -19
- package/templates/tanstack-start/docs/library/prisma/config.md +16 -16
- package/templates/tanstack-start/docs/library/prisma/crud.md +17 -17
- package/templates/tanstack-start/docs/library/prisma/relations.md +16 -16
- package/templates/tanstack-start/docs/library/prisma/schema.md +23 -23
- package/templates/tanstack-start/docs/library/prisma/setup.md +6 -6
- package/templates/tanstack-start/docs/library/prisma/transactions.md +10 -10
- package/templates/tanstack-start/docs/library/tanstack-query/invalidation.md +19 -19
- package/templates/tanstack-start/docs/library/tanstack-query/optimistic-updates.md +4 -4
- package/templates/tanstack-start/docs/library/tanstack-query/use-mutation.md +14 -14
- package/templates/tanstack-start/docs/library/tanstack-query/use-query.md +21 -21
- package/templates/tanstack-start/docs/library/tanstack-router/error-handling.md +9 -9
- package/templates/tanstack-start/docs/library/tanstack-router/hooks.md +11 -11
- package/templates/tanstack-start/docs/library/tanstack-router/navigation.md +17 -17
- package/templates/tanstack-start/docs/library/tanstack-router/route-context.md +5 -5
- package/templates/tanstack-start/docs/library/tanstack-router/search-params.md +10 -10
- package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +8 -8
- package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +9 -9
- package/templates/tanstack-start/docs/library/tanstack-start/routing.md +6 -6
- package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +18 -18
- package/templates/tanstack-start/docs/library/tanstack-start/setup.md +4 -4
- package/templates/tanstack-start/docs/library/zod/complex-types.md +11 -11
- package/templates/tanstack-start/docs/library/zod/transforms.md +11 -11
- package/templates/tanstack-start/docs/library/zod/validation.md +9 -9
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
# Prisma v7 - Database ORM
|
|
2
2
|
|
|
3
|
-
> Type-safe
|
|
3
|
+
> Type-safe 데이터베이스 ORM
|
|
4
4
|
|
|
5
5
|
@config.md
|
|
6
6
|
@cloudflare-d1.md
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## 버전 주의
|
|
11
11
|
|
|
12
12
|
```prisma
|
|
13
13
|
generator client {
|
|
14
|
-
provider = "prisma-client" // ✅ v7 (
|
|
15
|
-
output = "./generated/client" // ✅ output
|
|
14
|
+
provider = "prisma-client" // ✅ v7 (prisma-client-js 아님!)
|
|
15
|
+
output = "./generated/client" // ✅ output 필수
|
|
16
16
|
}
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
-
##
|
|
21
|
+
## 금지 사항
|
|
22
22
|
|
|
23
|
-
|
|
|
24
|
-
|
|
25
|
-
| `prisma db push` |
|
|
26
|
-
| `prisma migrate` |
|
|
27
|
-
| `prisma generate` |
|
|
28
|
-
|
|
|
23
|
+
| 명령 | 설명 |
|
|
24
|
+
|------|------|
|
|
25
|
+
| `prisma db push` | 자동 실행 금지 |
|
|
26
|
+
| `prisma migrate` | 자동 실행 금지 |
|
|
27
|
+
| `prisma generate` | 자동 실행 금지 |
|
|
28
|
+
| schema 변경 | 요청된 것만 |
|
|
29
29
|
|
|
30
30
|
---
|
|
31
31
|
|
|
32
|
-
##
|
|
32
|
+
## 설치
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
35
|
npm install prisma-client
|
|
@@ -38,20 +38,20 @@ npm install -D prisma
|
|
|
38
38
|
|
|
39
39
|
---
|
|
40
40
|
|
|
41
|
-
## Multi-File
|
|
41
|
+
## Multi-File 구조 (필수)
|
|
42
42
|
|
|
43
43
|
```
|
|
44
44
|
prisma/schema/
|
|
45
45
|
├── +base.prisma # datasource, generator
|
|
46
|
-
├── +enum.prisma # enum
|
|
47
|
-
├── user.prisma # User
|
|
48
|
-
└── post.prisma # Post
|
|
46
|
+
├── +enum.prisma # enum 정의
|
|
47
|
+
├── user.prisma # User 모델 (한글 주석 필수)
|
|
48
|
+
└── post.prisma # Post 모델
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
### +base.prisma
|
|
52
52
|
|
|
53
53
|
```prisma
|
|
54
|
-
// datasource, generator
|
|
54
|
+
// datasource, generator 설정
|
|
55
55
|
datasource db {
|
|
56
56
|
provider = "postgresql"
|
|
57
57
|
url = env("DATABASE_URL")
|
|
@@ -66,12 +66,12 @@ generator client {
|
|
|
66
66
|
### user.prisma
|
|
67
67
|
|
|
68
68
|
```prisma
|
|
69
|
-
//
|
|
69
|
+
// 사용자 모델
|
|
70
70
|
model User {
|
|
71
71
|
id String @id @default(cuid())
|
|
72
|
-
email String @unique //
|
|
73
|
-
name String? //
|
|
74
|
-
posts Post[] //
|
|
72
|
+
email String @unique // 로그인 이메일
|
|
73
|
+
name String? // 표시 이름
|
|
74
|
+
posts Post[] // 작성 게시글
|
|
75
75
|
createdAt DateTime @default(now())
|
|
76
76
|
updatedAt DateTime @updatedAt
|
|
77
77
|
}
|
|
@@ -110,7 +110,7 @@ const user = await prisma.user.create({
|
|
|
110
110
|
data: { email: 'user@example.com', name: 'John' },
|
|
111
111
|
})
|
|
112
112
|
|
|
113
|
-
//
|
|
113
|
+
// 관계와 함께
|
|
114
114
|
const userWithPosts = await prisma.user.create({
|
|
115
115
|
data: {
|
|
116
116
|
email: 'user@example.com',
|
|
@@ -131,7 +131,7 @@ const users = await prisma.user.findMany({
|
|
|
131
131
|
take: 10,
|
|
132
132
|
})
|
|
133
133
|
|
|
134
|
-
//
|
|
134
|
+
// 관계 포함
|
|
135
135
|
const userWithPosts = await prisma.user.findUnique({
|
|
136
136
|
where: { id },
|
|
137
137
|
include: { posts: { where: { published: true } } },
|
|
@@ -163,24 +163,24 @@ await prisma.user.deleteMany({ where: { email: { contains: '@test.com' } } })
|
|
|
163
163
|
|
|
164
164
|
---
|
|
165
165
|
|
|
166
|
-
##
|
|
166
|
+
## 필터링
|
|
167
167
|
|
|
168
168
|
```typescript
|
|
169
169
|
await prisma.user.findMany({
|
|
170
170
|
where: {
|
|
171
|
-
age: { gt: 18, lte: 65 }, //
|
|
172
|
-
email: { contains: '@gmail.com' }, //
|
|
171
|
+
age: { gt: 18, lte: 65 }, // 비교
|
|
172
|
+
email: { contains: '@gmail.com' }, // 문자열
|
|
173
173
|
AND: [{ email: { contains: '@' } }, { name: { not: null } }],
|
|
174
174
|
OR: [{ role: 'admin' }, { role: 'moderator' }],
|
|
175
|
-
id: { in: ['id1', 'id2'] }, //
|
|
176
|
-
posts: { some: { published: true } }, //
|
|
175
|
+
id: { in: ['id1', 'id2'] }, // 배열
|
|
176
|
+
posts: { some: { published: true } }, // 관계
|
|
177
177
|
},
|
|
178
178
|
})
|
|
179
179
|
```
|
|
180
180
|
|
|
181
181
|
---
|
|
182
182
|
|
|
183
|
-
##
|
|
183
|
+
## 트랜잭션
|
|
184
184
|
|
|
185
185
|
```typescript
|
|
186
186
|
// Sequential
|
|
@@ -199,7 +199,7 @@ const result = await prisma.$transaction(async (tx) => {
|
|
|
199
199
|
|
|
200
200
|
---
|
|
201
201
|
|
|
202
|
-
##
|
|
202
|
+
## Hono와 함께 사용
|
|
203
203
|
|
|
204
204
|
```typescript
|
|
205
205
|
import { Hono } from 'hono'
|
|
@@ -241,7 +241,7 @@ app.get('/users/:id', async (c) => {
|
|
|
241
241
|
|
|
242
242
|
---
|
|
243
243
|
|
|
244
|
-
##
|
|
244
|
+
## 관련 문서
|
|
245
245
|
|
|
246
|
-
- [Config
|
|
246
|
+
- [Config 파일](./config.md) - prisma.config.ts 설정
|
|
247
247
|
- [Cloudflare D1](./cloudflare-d1.md)
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# t3-env - Type-Safe Environment Variables
|
|
2
2
|
|
|
3
|
-
> Zod
|
|
3
|
+
> Zod 기반 타입 안전 환경 변수 관리
|
|
4
4
|
|
|
5
5
|
<context>
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
**용도:** 서버 환경 변수 검증, 런타임 타입 안전성
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
- Transform &
|
|
12
|
-
-
|
|
13
|
-
-
|
|
9
|
+
**특징:**
|
|
10
|
+
- Zod 스키마로 검증 + 타입 추론
|
|
11
|
+
- Transform & Default 값 지원
|
|
12
|
+
- 런타임 검증
|
|
13
|
+
- 프레임워크 무관
|
|
14
14
|
|
|
15
15
|
</context>
|
|
16
16
|
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
|
|
19
19
|
<forbidden>
|
|
20
20
|
|
|
21
|
-
|
|
|
22
|
-
|
|
23
|
-
|
|
|
24
|
-
|
|
|
25
|
-
|
|
|
21
|
+
| 분류 | 금지 |
|
|
22
|
+
|------|------|
|
|
23
|
+
| **직접 접근** | `process.env` 직접 사용 (env 객체 필수) |
|
|
24
|
+
| **타입** | any 타입으로 env 변수 접근 |
|
|
25
|
+
| **검증 우회** | 스키마 정의 없이 환경 변수 사용 |
|
|
26
26
|
|
|
27
27
|
</forbidden>
|
|
28
28
|
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
|
|
31
31
|
<required>
|
|
32
32
|
|
|
33
|
-
|
|
|
34
|
-
|
|
35
|
-
|
|
|
36
|
-
|
|
|
33
|
+
| 분류 | 필수 |
|
|
34
|
+
|------|------|
|
|
35
|
+
| **설치** | `@t3-oss/env-core zod` |
|
|
36
|
+
| **구조** | `src/env.ts` 파일 생성 |
|
|
37
37
|
| **Import** | `import { env } from '@/env'` |
|
|
38
38
|
|
|
39
39
|
</required>
|
|
@@ -114,7 +114,7 @@ import { env } from '@/env'
|
|
|
114
114
|
|
|
115
115
|
export const prisma = new PrismaClient({
|
|
116
116
|
datasourceUrl: env.DATABASE_URL,
|
|
117
|
-
// ^? string (
|
|
117
|
+
// ^? string (타입 안전)
|
|
118
118
|
})
|
|
119
119
|
```
|
|
120
120
|
|
|
@@ -329,7 +329,7 @@ import { createMiddleware } from 'hono/factory'
|
|
|
329
329
|
import { env } from '@/env'
|
|
330
330
|
|
|
331
331
|
export const envMiddleware = createMiddleware(async (c, next) => {
|
|
332
|
-
//
|
|
332
|
+
// env 객체가 초기화되었는지 확인
|
|
333
333
|
if (!env.DATABASE_URL) {
|
|
334
334
|
return c.json({ error: 'Server misconfigured' }, 500)
|
|
335
335
|
}
|
|
@@ -363,10 +363,10 @@ app.use(
|
|
|
363
363
|
|
|
364
364
|
## Tips
|
|
365
365
|
|
|
366
|
-
|
|
|
367
|
-
|
|
368
|
-
| **Cloudflare** |
|
|
369
|
-
| **Monorepo** |
|
|
366
|
+
| 상황 | 방법 |
|
|
367
|
+
|------|------|
|
|
368
|
+
| **Cloudflare** | `createWorkerEnv(env)` 패턴 사용 |
|
|
369
|
+
| **Monorepo** | 각 패키지마다 별도 `env.ts` |
|
|
370
370
|
| **Testing** | `.env.test` + `NODE_ENV=test` |
|
|
371
371
|
| **Docker** | `docker run -e DATABASE_URL=...` |
|
|
372
372
|
| **CI/CD** | GitHub Secrets → Environment Variables |
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
# Zod v4 - Schema Validation
|
|
2
2
|
|
|
3
|
-
> TypeScript-first
|
|
3
|
+
> TypeScript-first 스키마 검증
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## 버전 주의
|
|
8
8
|
|
|
9
9
|
```typescript
|
|
10
|
-
// ✅ v4
|
|
10
|
+
// ✅ v4 문법
|
|
11
11
|
z.email()
|
|
12
12
|
z.url()
|
|
13
13
|
z.uuid()
|
|
14
14
|
|
|
15
|
-
// ❌ v3
|
|
15
|
+
// ❌ v3 문법 (사용 금지)
|
|
16
16
|
z.string().email()
|
|
17
17
|
z.string().url()
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## 설치
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
25
|
npm install zod
|
|
@@ -27,7 +27,7 @@ npm install zod
|
|
|
27
27
|
|
|
28
28
|
---
|
|
29
29
|
|
|
30
|
-
##
|
|
30
|
+
## 기본 타입
|
|
31
31
|
|
|
32
32
|
```typescript
|
|
33
33
|
import { z } from 'zod'
|
|
@@ -40,28 +40,28 @@ z.undefined()
|
|
|
40
40
|
z.null()
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
###
|
|
43
|
+
### 문자열 (v4)
|
|
44
44
|
|
|
45
45
|
```typescript
|
|
46
|
-
z.email() //
|
|
46
|
+
z.email() // 이메일
|
|
47
47
|
z.url() // URL
|
|
48
48
|
z.uuid() // UUID
|
|
49
|
-
z.string().min(1).max(100) //
|
|
50
|
-
z.string().trim() //
|
|
51
|
-
z.string().regex(/^[a-z]+$/) //
|
|
49
|
+
z.string().min(1).max(100) // 길이
|
|
50
|
+
z.string().trim() // 공백 제거
|
|
51
|
+
z.string().regex(/^[a-z]+$/) // 정규식
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
###
|
|
54
|
+
### 숫자
|
|
55
55
|
|
|
56
56
|
```typescript
|
|
57
|
-
z.number().int() //
|
|
58
|
-
z.number().positive() //
|
|
57
|
+
z.number().int() // 정수
|
|
58
|
+
z.number().positive() // 양수
|
|
59
59
|
z.number().min(1).max(100)
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
---
|
|
63
63
|
|
|
64
|
-
##
|
|
64
|
+
## 객체
|
|
65
65
|
|
|
66
66
|
```typescript
|
|
67
67
|
const userSchema = z.object({
|
|
@@ -82,7 +82,7 @@ z.string().nullable() // string | null
|
|
|
82
82
|
z.string().nullish() // string | null | undefined
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
-
###
|
|
85
|
+
### 기본값
|
|
86
86
|
|
|
87
87
|
```typescript
|
|
88
88
|
z.string().default('Anonymous')
|
|
@@ -92,8 +92,8 @@ z.enum(['user', 'admin']).default('user')
|
|
|
92
92
|
### Partial / Pick / Omit
|
|
93
93
|
|
|
94
94
|
```typescript
|
|
95
|
-
userSchema.partial() //
|
|
96
|
-
userSchema.partial({ email: true }) //
|
|
95
|
+
userSchema.partial() // 모든 필드 optional
|
|
96
|
+
userSchema.partial({ email: true }) // 특정 필드만
|
|
97
97
|
userSchema.pick({ id: true, name: true })
|
|
98
98
|
userSchema.omit({ password: true })
|
|
99
99
|
```
|
|
@@ -118,7 +118,7 @@ z.discriminatedUnion('type', [
|
|
|
118
118
|
|
|
119
119
|
---
|
|
120
120
|
|
|
121
|
-
## Coerce (
|
|
121
|
+
## Coerce (타입 변환)
|
|
122
122
|
|
|
123
123
|
```typescript
|
|
124
124
|
z.coerce.number() // string → number
|
|
@@ -137,27 +137,27 @@ z.string().transform((s) => s.split(','))
|
|
|
137
137
|
|
|
138
138
|
---
|
|
139
139
|
|
|
140
|
-
## Refine (
|
|
140
|
+
## Refine (커스텀 검증)
|
|
141
141
|
|
|
142
142
|
```typescript
|
|
143
|
-
//
|
|
143
|
+
// 단일 필드
|
|
144
144
|
z.string().refine((val) => val.length >= 8, {
|
|
145
|
-
message: '
|
|
145
|
+
message: '8자 이상 필요',
|
|
146
146
|
})
|
|
147
147
|
|
|
148
|
-
//
|
|
148
|
+
// 객체 전체
|
|
149
149
|
z.object({
|
|
150
150
|
password: z.string().min(8),
|
|
151
151
|
confirmPassword: z.string(),
|
|
152
152
|
}).refine((data) => data.password === data.confirmPassword, {
|
|
153
|
-
message: '
|
|
153
|
+
message: '비밀번호 불일치',
|
|
154
154
|
path: ['confirmPassword'],
|
|
155
155
|
})
|
|
156
156
|
```
|
|
157
157
|
|
|
158
158
|
---
|
|
159
159
|
|
|
160
|
-
##
|
|
160
|
+
## 에러 처리
|
|
161
161
|
|
|
162
162
|
```typescript
|
|
163
163
|
const result = schema.safeParse(input)
|
|
@@ -170,16 +170,16 @@ if (result.success) {
|
|
|
170
170
|
}
|
|
171
171
|
```
|
|
172
172
|
|
|
173
|
-
###
|
|
173
|
+
### 커스텀 에러
|
|
174
174
|
|
|
175
175
|
```typescript
|
|
176
|
-
z.email({ message: '
|
|
177
|
-
z.string().min(1, { message: '
|
|
176
|
+
z.email({ message: '올바른 이메일 입력' })
|
|
177
|
+
z.string().min(1, { message: '필수 입력' })
|
|
178
178
|
```
|
|
179
179
|
|
|
180
180
|
---
|
|
181
181
|
|
|
182
|
-
##
|
|
182
|
+
## Hono와 함께
|
|
183
183
|
|
|
184
184
|
```typescript
|
|
185
185
|
import { zValidator } from '@hono/zod-validator'
|
|
@@ -204,6 +204,6 @@ app.post('/users',
|
|
|
204
204
|
|
|
205
205
|
---
|
|
206
206
|
|
|
207
|
-
##
|
|
207
|
+
## 관련 문서
|
|
208
208
|
|
|
209
|
-
- [Hono
|
|
209
|
+
- [Hono 검증](../hono/validation.md)
|
|
@@ -4,17 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
<context>
|
|
6
6
|
|
|
7
|
-
**Purpose:** Next.js App Router
|
|
7
|
+
**Purpose:** Next.js App Router 기반 웹 애플리케이션 개발 지침
|
|
8
8
|
|
|
9
|
-
**Scope:** Full-stack React
|
|
9
|
+
**Scope:** Full-stack React 애플리케이션 구현
|
|
10
10
|
|
|
11
11
|
**Key Features:**
|
|
12
12
|
- App Router (file-based routing)
|
|
13
|
-
- Server Actions (
|
|
13
|
+
- Server Actions (타입 안전 API)
|
|
14
14
|
- Server/Client Components
|
|
15
15
|
- Route Handlers (REST API)
|
|
16
16
|
- Middleware
|
|
17
|
-
- Built-in Optimization (
|
|
17
|
+
- Built-in Optimization (이미지, 폰트, 스크립트)
|
|
18
18
|
- Deployment (Vercel, Docker, Node.js)
|
|
19
19
|
|
|
20
20
|
</context>
|
|
@@ -35,14 +35,14 @@
|
|
|
35
35
|
|
|
36
36
|
<forbidden>
|
|
37
37
|
|
|
38
|
-
|
|
|
39
|
-
|
|
40
|
-
| **Git
|
|
41
|
-
| **Prisma** |
|
|
42
|
-
| **Server Actions** |
|
|
43
|
-
| **Route Handlers** |
|
|
44
|
-
|
|
|
45
|
-
|
|
|
38
|
+
| 분류 | 금지 행동 |
|
|
39
|
+
|------|----------|
|
|
40
|
+
| **Git 커밋** | AI 표시 (`Generated with Claude Code`, `🤖`, `Co-Authored-By:`), 여러 줄 메시지, 이모지 |
|
|
41
|
+
| **Prisma** | `db push/migrate/generate` 자동 실행, `schema.prisma` 무단 수정 |
|
|
42
|
+
| **Server Actions** | 클라이언트 컴포넌트에서 직접 정의, try-catch 없이 사용, Zod 검증 누락 (POST/PUT/PATCH) |
|
|
43
|
+
| **Route Handlers** | `/app/api/` 외부에 생성, Server Actions로 대체 가능한 경우 생성 |
|
|
44
|
+
| **클라이언트** | Server Action 직접 호출 (TanStack Query 사용), `"use client"` 누락 |
|
|
45
|
+
| **코드 검색** | Bash의 grep/rg/find 명령어 (ast-grep 또는 전용 도구 사용) |
|
|
46
46
|
|
|
47
47
|
</forbidden>
|
|
48
48
|
|
|
@@ -50,18 +50,18 @@
|
|
|
50
50
|
|
|
51
51
|
<required>
|
|
52
52
|
|
|
53
|
-
|
|
|
54
|
-
|
|
55
|
-
|
|
|
56
|
-
|
|
|
57
|
-
|
|
|
58
|
-
|
|
|
59
|
-
|
|
|
60
|
-
| **Server Actions** | `"use server"`
|
|
61
|
-
|
|
|
62
|
-
| **Custom Hook
|
|
63
|
-
|
|
|
64
|
-
| **Prisma** | Multi-File
|
|
53
|
+
| 작업 | 필수 행동 |
|
|
54
|
+
|------|----------|
|
|
55
|
+
| **작업 시작 전** | 관련 docs 읽기 (UI → design, API → nextjs, DB → prisma, 인증 → next-auth) |
|
|
56
|
+
| **문서 검색** | serena mcp 사용 (문서 인덱싱/검색, context 길이 최적화) |
|
|
57
|
+
| **코드 검색** | ast-grep 사용 (함수/컴포넌트/패턴 검색) |
|
|
58
|
+
| **복잡한 작업** | Sequential Thinking MCP (5+ 단계 작업) |
|
|
59
|
+
| **대규모 수정** | gemini-review (3+ 파일 변경, 아키텍처 결정) |
|
|
60
|
+
| **Server Actions** | `"use server"` 선언, Zod 검증 (POST/PUT/PATCH), try-catch + revalidatePath/redirect |
|
|
61
|
+
| **클라이언트 API** | TanStack Query (`useQuery`/`useMutation`)로 Server Action 호출 |
|
|
62
|
+
| **Custom Hook 순서** | State → Global Hooks (useParams, useRouter, useSearchParams) → React Query → Handlers → Memo → Effect |
|
|
63
|
+
| **코드 작성** | UTF-8 인코딩, 코드 묶음별 한글 주석, const 함수 선언 |
|
|
64
|
+
| **Prisma** | Multi-File 구조 (`prisma/schema/`), 모든 요소 한글 주석 필수 |
|
|
65
65
|
|
|
66
66
|
</required>
|
|
67
67
|
|
|
@@ -69,15 +69,15 @@
|
|
|
69
69
|
|
|
70
70
|
<tech_stack>
|
|
71
71
|
|
|
72
|
-
|
|
|
73
|
-
|
|
74
|
-
| Next.js | **15.x** | App Router
|
|
72
|
+
| 기술 | 버전 | 주의 |
|
|
73
|
+
|------|------|------|
|
|
74
|
+
| Next.js | **15.x** | App Router 전용 |
|
|
75
75
|
| React | **19.x** | Server Components |
|
|
76
76
|
| TypeScript | 5.x | strict |
|
|
77
77
|
| Tailwind CSS | 4.x | @theme |
|
|
78
|
-
| Prisma | **7.x** | `prisma-client`, output
|
|
78
|
+
| Prisma | **7.x** | `prisma-client`, output 필수 |
|
|
79
79
|
| Zod | **4.x** | `z.email()`, `z.url()` |
|
|
80
|
-
| NextAuth.js | **5.x** (Auth.js) | App Router
|
|
80
|
+
| NextAuth.js | **5.x** (Auth.js) | App Router 지원 |
|
|
81
81
|
| TanStack Query | 5.x | - |
|
|
82
82
|
|
|
83
83
|
</tech_stack>
|
|
@@ -92,41 +92,41 @@ src/
|
|
|
92
92
|
│ ├── page.tsx # Home page
|
|
93
93
|
│ ├── [slug]/
|
|
94
94
|
│ │ ├── page.tsx # Dynamic route
|
|
95
|
-
│ │ ├── _components/ #
|
|
96
|
-
│ │ ├── _hooks/ #
|
|
97
|
-
│ │ └── _actions/ #
|
|
95
|
+
│ │ ├── _components/ # 페이지 전용 컴포넌트 (필수)
|
|
96
|
+
│ │ ├── _hooks/ # 페이지 전용 훅 (필수)
|
|
97
|
+
│ │ └── _actions/ # 페이지 전용 Server Actions (필수)
|
|
98
98
|
│ ├── api/
|
|
99
99
|
│ │ └── [endpoint]/
|
|
100
100
|
│ │ └── route.ts # Route Handler (REST API)
|
|
101
|
-
│ └── _actions/ #
|
|
102
|
-
├── components/ui/ #
|
|
101
|
+
│ └── _actions/ # 공통 Server Actions
|
|
102
|
+
├── components/ui/ # 공통 UI 컴포넌트 (Server Components)
|
|
103
103
|
├── middleware.ts # Middleware
|
|
104
104
|
├── database/prisma.ts
|
|
105
105
|
└── lib/
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
-
|
|
110
|
-
- Custom
|
|
111
|
-
- Server Components
|
|
112
|
-
- Server Actions
|
|
113
|
-
- Route Handlers
|
|
108
|
+
**필수 규칙:**
|
|
109
|
+
- 페이지당 `_components/`, `_hooks/`, `_actions/` 폴더 필수 (줄 수 무관)
|
|
110
|
+
- Custom Hook은 페이지 크기와 무관하게 **반드시** `_hooks/` 폴더에 분리
|
|
111
|
+
- Server Components가 기본 → `"use client"` 명시 필요 시만 사용
|
|
112
|
+
- Server Actions는 글로벌(`app/_actions/`) 또는 페이지 전용(`[route]/_actions/`)에 분리
|
|
113
|
+
- Route Handlers는 `/app/api/` 경로에만 생성
|
|
114
114
|
</structure>
|
|
115
115
|
|
|
116
116
|
---
|
|
117
117
|
|
|
118
118
|
<conventions>
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
TypeScript: const
|
|
122
|
-
Import
|
|
120
|
+
파일명: kebab-case, Routes: `page.tsx`, `layout.tsx`, `[slug]/page.tsx`
|
|
121
|
+
TypeScript: const 선언, 명시적 return type, interface(객체)/type(유니온), any→unknown
|
|
122
|
+
Import 순서: 외부 → @/ → 상대경로 → type
|
|
123
123
|
|
|
124
124
|
Prisma Multi-File:
|
|
125
125
|
```
|
|
126
126
|
prisma/schema/
|
|
127
127
|
├── +base.prisma # datasource, generator
|
|
128
128
|
├── +enum.prisma # enum
|
|
129
|
-
└── [model].prisma #
|
|
129
|
+
└── [model].prisma # 모델별 (한글 주석!)
|
|
130
130
|
```
|
|
131
131
|
|
|
132
132
|
</conventions>
|
|
@@ -136,7 +136,7 @@ prisma/schema/
|
|
|
136
136
|
<quick_patterns>
|
|
137
137
|
|
|
138
138
|
```typescript
|
|
139
|
-
// Server Action (
|
|
139
|
+
// Server Action (파일 상단)
|
|
140
140
|
"use server"
|
|
141
141
|
|
|
142
142
|
export async function createPost(formData: FormData) {
|
|
@@ -150,7 +150,7 @@ export async function createPost(formData: FormData) {
|
|
|
150
150
|
return post
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
// Server Action (
|
|
153
|
+
// Server Action (인증)
|
|
154
154
|
"use server"
|
|
155
155
|
|
|
156
156
|
import { auth } from "@/lib/auth"
|
|
@@ -209,12 +209,12 @@ export default async function PostsPage() {
|
|
|
209
209
|
|
|
210
210
|
<ui_ux>
|
|
211
211
|
|
|
212
|
-
|
|
|
213
|
-
|
|
214
|
-
|
|
|
215
|
-
|
|
|
216
|
-
|
|
|
217
|
-
|
|
|
212
|
+
| 원칙 | 값 |
|
|
213
|
+
|------|------|
|
|
214
|
+
| 색상 | 60-30-10 (배경-보조-강조) |
|
|
215
|
+
| 간격 | 8px 그리드 |
|
|
216
|
+
| 접근성 | WCAG AA (대비 4.5:1+) |
|
|
217
|
+
| 폰트 | 2-3개 |
|
|
218
218
|
| Safe Area | tailwindcss-safe-area |
|
|
219
219
|
|
|
220
220
|
</ui_ux>
|
|
@@ -224,8 +224,8 @@ export default async function PostsPage() {
|
|
|
224
224
|
<docs_structure>
|
|
225
225
|
```
|
|
226
226
|
docs/
|
|
227
|
-
├── guides/ #
|
|
227
|
+
├── guides/ # 시작하기, 규칙, 패턴
|
|
228
228
|
├── library/ # nextjs, prisma, next-auth, tanstack-query, zod
|
|
229
|
-
└── design.md # UI/UX
|
|
229
|
+
└── design.md # UI/UX 가이드
|
|
230
230
|
```
|
|
231
231
|
</docs_structure>
|