@kood/claude-code 0.5.3 → 0.5.5
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 +552 -340
- package/package.json +1 -1
- package/templates/.claude/agents/document-writer.md +73 -306
- package/templates/.claude/instructions/agent-patterns/index.md +7 -7
- package/templates/.claude/instructions/document-templates/ralph-templates.md +71 -0
- package/templates/.claude/instructions/index.md +14 -14
- package/templates/.claude/instructions/multi-agent/agent-roster.md +14 -14
- package/templates/.claude/instructions/multi-agent/index.md +4 -4
- package/templates/.claude/skills/docs-creator/AGENTS.md +54 -176
- package/templates/.claude/skills/docs-creator/SKILL.md +98 -464
- package/templates/.claude/skills/docs-refactor/AGENTS.md +61 -190
- package/templates/.claude/skills/docs-refactor/SKILL.md +67 -443
- package/templates/.claude/skills/execute/SKILL.md +540 -13
- package/templates/.claude/skills/plan/SKILL.md +84 -18
- package/templates/.claude/skills/ralph/SKILL.md +17 -14
- package/templates/.claude/skills/refactor/AGENTS.md +269 -0
- package/templates/.claude/skills/refactor/SKILL.md +424 -66
- package/templates/.claude/skills/stitch-design/README.md +34 -0
- package/templates/.claude/skills/stitch-design/SKILL.md +213 -0
- package/templates/.claude/skills/stitch-design/examples/DESIGN.md +154 -0
- package/templates/.claude/skills/stitch-loop/README.md +54 -0
- package/templates/.claude/skills/stitch-loop/SKILL.md +316 -0
- package/templates/.claude/skills/stitch-loop/examples/SITE.md +73 -0
- package/templates/.claude/skills/stitch-loop/examples/next-prompt.md +25 -0
- package/templates/.claude/skills/stitch-loop/resources/baton-schema.md +61 -0
- package/templates/.claude/skills/stitch-loop/resources/site-template.md +104 -0
- package/templates/.claude/skills/stitch-react/README.md +36 -0
- package/templates/.claude/skills/stitch-react/SKILL.md +323 -0
- package/templates/.claude/skills/stitch-react/examples/gold-standard-card.tsx +88 -0
- package/templates/.claude/skills/stitch-react/package-lock.json +231 -0
- package/templates/.claude/skills/stitch-react/package.json +16 -0
- package/templates/.claude/skills/stitch-react/resources/architecture-checklist.md +15 -0
- package/templates/.claude/skills/stitch-react/resources/component-template.tsx +37 -0
- package/templates/.claude/skills/stitch-react/resources/stitch-api-reference.md +14 -0
- package/templates/.claude/skills/stitch-react/resources/style-guide.json +24 -0
- package/templates/.claude/skills/stitch-react/scripts/fetch-stitch.sh +30 -0
- package/templates/.claude/skills/stitch-react/scripts/validate.js +77 -0
- 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,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 라우트 구조
|
|
2
2
|
|
|
3
|
-
> TanStack Start
|
|
3
|
+
> TanStack Start 파일 기반 라우팅
|
|
4
4
|
|
|
5
5
|
<instructions>
|
|
6
6
|
@../library/tanstack-router/index.md
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
<route_structure>
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## 라우트 폴더 구조
|
|
14
14
|
|
|
15
15
|
```
|
|
16
16
|
routes/
|
|
@@ -19,28 +19,28 @@ routes/
|
|
|
19
19
|
├── users/
|
|
20
20
|
│ ├── index.tsx # /users (List)
|
|
21
21
|
│ ├── $id.tsx # /users/:id (Detail)
|
|
22
|
-
│ ├── -components/ #
|
|
23
|
-
│ ├── -hooks/ #
|
|
24
|
-
│ ├── -functions/ #
|
|
25
|
-
│ └── -sections/ #
|
|
22
|
+
│ ├── -components/ # 페이지 전용 컴포넌트 (필수)
|
|
23
|
+
│ ├── -hooks/ # 페이지 전용 Hook (필수)
|
|
24
|
+
│ ├── -functions/ # 페이지 전용 Server Functions (필수)
|
|
25
|
+
│ └── -sections/ # 섹션 분리 (선택, 복잡한 경우만)
|
|
26
26
|
└── posts/
|
|
27
27
|
├── index.tsx
|
|
28
28
|
├── $slug.tsx
|
|
29
|
-
├── -components/ #
|
|
30
|
-
├── -hooks/ #
|
|
31
|
-
└── -functions/ #
|
|
29
|
+
├── -components/ # 필수
|
|
30
|
+
├── -hooks/ # 필수
|
|
31
|
+
└── -functions/ # 필수
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
|
|
|
35
|
-
|
|
36
|
-
| `-` |
|
|
37
|
-
| `$` |
|
|
38
|
-
| `_` | Pathless Layout | ✅
|
|
34
|
+
| 접두사 | 용도 | 라우트 생성 |
|
|
35
|
+
|--------|------|-----------|
|
|
36
|
+
| `-` | 라우트 제외 폴더 | ❌ 제외 |
|
|
37
|
+
| `$` | 동적 파라미터 | ✅ 생성 |
|
|
38
|
+
| `_` | Pathless Layout | ✅ 생성 (경로 없음) |
|
|
39
39
|
|
|
40
|
-
**⚠️
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
- `-sections
|
|
40
|
+
**⚠️ 필수 규칙:**
|
|
41
|
+
- 모든 페이지에 `-components/`, `-hooks/`, `-functions/` 폴더 **필수**
|
|
42
|
+
- 페이지 크기(줄 수)와 **무관**하게 Custom Hook은 반드시 `-hooks/` 폴더에 분리
|
|
43
|
+
- `-sections/`는 200줄 이상 복잡한 페이지에서만 선택적 사용
|
|
44
44
|
|
|
45
45
|
</route_structure>
|
|
46
46
|
|
|
@@ -48,17 +48,17 @@ routes/
|
|
|
48
48
|
|
|
49
49
|
<file_naming>
|
|
50
50
|
|
|
51
|
-
##
|
|
51
|
+
## 라우트 파일명 규칙
|
|
52
52
|
|
|
53
|
-
|
|
|
54
|
-
|
|
55
|
-
| `/` | `index.tsx` |
|
|
56
|
-
| `/users` | `users/index.tsx` |
|
|
57
|
-
| `/users/:id` | `users/$id.tsx` |
|
|
58
|
-
| `/posts/:slug` | `posts/$slug.tsx` | URL
|
|
59
|
-
| `/dashboard/*` | `dashboard/$.tsx` | Catch-all
|
|
60
|
-
| Layout | `__root.tsx` | Root
|
|
61
|
-
| Pathless | `_layout.tsx` |
|
|
53
|
+
| 경로 | 파일명 | 설명 |
|
|
54
|
+
|------|--------|------|
|
|
55
|
+
| `/` | `index.tsx` | 인덱스 라우트 |
|
|
56
|
+
| `/users` | `users/index.tsx` | 목록 페이지 |
|
|
57
|
+
| `/users/:id` | `users/$id.tsx` | 동적 파라미터 |
|
|
58
|
+
| `/posts/:slug` | `posts/$slug.tsx` | URL 파라미터 |
|
|
59
|
+
| `/dashboard/*` | `dashboard/$.tsx` | Catch-all 라우트 |
|
|
60
|
+
| Layout | `__root.tsx` | Root 레이아웃 |
|
|
61
|
+
| Pathless | `_layout.tsx` | 경로 없는 레이아웃 |
|
|
62
62
|
|
|
63
63
|
</file_naming>
|
|
64
64
|
|
|
@@ -66,7 +66,7 @@ routes/
|
|
|
66
66
|
|
|
67
67
|
<patterns>
|
|
68
68
|
|
|
69
|
-
##
|
|
69
|
+
## 기본 라우트 패턴
|
|
70
70
|
|
|
71
71
|
```tsx
|
|
72
72
|
// routes/users/index.tsx
|
|
@@ -89,7 +89,7 @@ const UsersPage = (): JSX.Element => {
|
|
|
89
89
|
}
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
##
|
|
92
|
+
## 동적 라우트 + Loader
|
|
93
93
|
|
|
94
94
|
```tsx
|
|
95
95
|
// routes/users/$id.tsx
|
|
@@ -188,7 +188,7 @@ const DashboardPage = (): JSX.Element => {
|
|
|
188
188
|
}
|
|
189
189
|
```
|
|
190
190
|
|
|
191
|
-
## Section
|
|
191
|
+
## Section 패턴
|
|
192
192
|
|
|
193
193
|
```tsx
|
|
194
194
|
// routes/users/-sections/user-list-section.tsx
|
|
@@ -217,7 +217,7 @@ export const UserListSection = (): JSX.Element => {
|
|
|
217
217
|
}
|
|
218
218
|
```
|
|
219
219
|
|
|
220
|
-
##
|
|
220
|
+
## 컴포넌트 패턴
|
|
221
221
|
|
|
222
222
|
```tsx
|
|
223
223
|
// routes/users/-components/user-card.tsx
|
|
@@ -268,21 +268,21 @@ export const UserCard = ({
|
|
|
268
268
|
|
|
269
269
|
<folder_structure_rules>
|
|
270
270
|
|
|
271
|
-
##
|
|
271
|
+
## 폴더 구조 규칙
|
|
272
272
|
|
|
273
|
-
**⚠️
|
|
274
|
-
- `-components/`:
|
|
275
|
-
- `-hooks/`:
|
|
276
|
-
- `-functions/`:
|
|
273
|
+
**⚠️ 모든 페이지에 필수:**
|
|
274
|
+
- `-components/`: 페이지 전용 컴포넌트
|
|
275
|
+
- `-hooks/`: 페이지 전용 Custom Hook (줄 수 무관)
|
|
276
|
+
- `-functions/`: 페이지 전용 Server Functions
|
|
277
277
|
|
|
278
|
-
|
|
279
|
-
- `-sections/`:
|
|
278
|
+
**선택적 사용:**
|
|
279
|
+
- `-sections/`: 200줄+ 복잡한 페이지에서만 사용
|
|
280
280
|
|
|
281
|
-
|
|
|
282
|
-
|
|
283
|
-
| ~100
|
|
284
|
-
| 100-200
|
|
285
|
-
| 200
|
|
281
|
+
| 페이지 크기 | 필수 | 선택 |
|
|
282
|
+
|------------|------|------|
|
|
283
|
+
| ~100줄 | `-components/`, `-hooks/`, `-functions/` | - |
|
|
284
|
+
| 100-200줄 | `-components/`, `-hooks/`, `-functions/` | - |
|
|
285
|
+
| 200줄+ | `-components/`, `-hooks/`, `-functions/` | `-sections/` |
|
|
286
286
|
|
|
287
287
|
</folder_structure_rules>
|
|
288
288
|
|
|
@@ -290,23 +290,23 @@ export const UserCard = ({
|
|
|
290
290
|
|
|
291
291
|
<loader_execution>
|
|
292
292
|
|
|
293
|
-
## Loader
|
|
293
|
+
## Loader 실행 순서
|
|
294
294
|
|
|
295
|
-
|
|
|
296
|
-
|
|
297
|
-
| 1. `beforeLoad` |
|
|
298
|
-
| 2. `loader` |
|
|
295
|
+
| 단계 | 실행 방식 | 설명 |
|
|
296
|
+
|------|----------|------|
|
|
297
|
+
| 1. `beforeLoad` | 순차 (outermost → innermost) | 인증 체크, 컨텍스트 설정 |
|
|
298
|
+
| 2. `loader` | 병렬 (모든 loader 동시) | 데이터 페칭 |
|
|
299
299
|
|
|
300
300
|
```tsx
|
|
301
301
|
// Parent Route
|
|
302
302
|
export const Route = createFileRoute('/dashboard')({
|
|
303
303
|
beforeLoad: async () => {
|
|
304
|
-
// 1.
|
|
304
|
+
// 1. 먼저 실행 (순차)
|
|
305
305
|
const auth = await checkAuth()
|
|
306
306
|
return { auth }
|
|
307
307
|
},
|
|
308
308
|
loader: async () => {
|
|
309
|
-
// 2.
|
|
309
|
+
// 2. 나중에 실행 (병렬)
|
|
310
310
|
return getDashboardData()
|
|
311
311
|
},
|
|
312
312
|
})
|
|
@@ -314,11 +314,11 @@ export const Route = createFileRoute('/dashboard')({
|
|
|
314
314
|
// Child Route
|
|
315
315
|
export const Route = createFileRoute('/dashboard/users')({
|
|
316
316
|
beforeLoad: async () => {
|
|
317
|
-
// 1.
|
|
317
|
+
// 1. Parent beforeLoad 다음 실행
|
|
318
318
|
return {}
|
|
319
319
|
},
|
|
320
320
|
loader: async () => {
|
|
321
|
-
// 2.
|
|
321
|
+
// 2. Parent loader와 병렬 실행
|
|
322
322
|
return getUsers()
|
|
323
323
|
},
|
|
324
324
|
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Server Functions
|
|
2
2
|
|
|
3
|
-
> TanStack Start
|
|
3
|
+
> TanStack Start 데이터 레이어 (Server Functions)
|
|
4
4
|
|
|
5
5
|
<instructions>
|
|
6
6
|
@../library/tanstack-start/index.md
|
|
@@ -10,15 +10,15 @@
|
|
|
10
10
|
|
|
11
11
|
<api_naming>
|
|
12
12
|
|
|
13
|
-
## API
|
|
13
|
+
## API 이름 (중요)
|
|
14
14
|
|
|
15
|
-
| ✅
|
|
16
|
-
|
|
17
|
-
| `.inputValidator()` | ~~`.validator()`~~ | TanStack Start
|
|
18
|
-
| `.middleware()` | - | Middleware
|
|
19
|
-
| `.handler()` | - |
|
|
15
|
+
| ✅ 올바른 API | ❌ 잘못된 API | 설명 |
|
|
16
|
+
|-------------|-------------|------|
|
|
17
|
+
| `.inputValidator()` | ~~`.validator()`~~ | TanStack Start는 `inputValidator`만 지원 |
|
|
18
|
+
| `.middleware()` | - | Middleware 체이닝 |
|
|
19
|
+
| `.handler()` | - | 최종 handler 함수 |
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
**주의:** `validator`는 존재하지 않는 API입니다. 반드시 `inputValidator`를 사용하세요.
|
|
22
22
|
|
|
23
23
|
</api_naming>
|
|
24
24
|
|
|
@@ -26,15 +26,15 @@
|
|
|
26
26
|
|
|
27
27
|
<folder_structure>
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## 서비스 폴더 구조
|
|
30
30
|
|
|
31
31
|
```
|
|
32
32
|
services/
|
|
33
33
|
├── user/
|
|
34
|
-
│ ├── index.ts #
|
|
35
|
-
│ ├── schemas.ts # Zod
|
|
36
|
-
│ ├── queries.ts # GET (
|
|
37
|
-
│ └── mutations.ts # POST (
|
|
34
|
+
│ ├── index.ts # 진입점 (re-export)
|
|
35
|
+
│ ├── schemas.ts # Zod 스키마
|
|
36
|
+
│ ├── queries.ts # GET (읽기)
|
|
37
|
+
│ └── mutations.ts # POST (쓰기)
|
|
38
38
|
├── auth/
|
|
39
39
|
│ ├── index.ts
|
|
40
40
|
│ ├── schemas.ts
|
|
@@ -47,12 +47,12 @@ services/
|
|
|
47
47
|
└── mutations.ts
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
|
|
|
51
|
-
|
|
52
|
-
| `index.ts` |
|
|
53
|
-
| `schemas.ts` | Zod
|
|
54
|
-
| `queries.ts` | GET
|
|
55
|
-
| `mutations.ts` | POST/PUT/DELETE (
|
|
50
|
+
| 파일 | 용도 |
|
|
51
|
+
|------|------|
|
|
52
|
+
| `index.ts` | 모든 함수 re-export |
|
|
53
|
+
| `schemas.ts` | Zod 검증 스키마 |
|
|
54
|
+
| `queries.ts` | GET 요청 (읽기) |
|
|
55
|
+
| `mutations.ts` | POST/PUT/DELETE (쓰기) |
|
|
56
56
|
|
|
57
57
|
</folder_structure>
|
|
58
58
|
|
|
@@ -60,7 +60,7 @@ services/
|
|
|
60
60
|
|
|
61
61
|
<patterns>
|
|
62
62
|
|
|
63
|
-
## Schemas
|
|
63
|
+
## Schemas 파일
|
|
64
64
|
|
|
65
65
|
```typescript
|
|
66
66
|
// services/user/schemas.ts
|
|
@@ -81,7 +81,7 @@ export type CreateUserInput = z.infer<typeof createUserSchema>
|
|
|
81
81
|
export type UpdateUserInput = z.infer<typeof updateUserSchema>
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
## Queries
|
|
84
|
+
## Queries 파일 (GET)
|
|
85
85
|
|
|
86
86
|
```typescript
|
|
87
87
|
// services/user/queries.ts
|
|
@@ -108,7 +108,7 @@ export const getUserByEmail = createServerFn({ method: 'GET' })
|
|
|
108
108
|
})
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
-
## Mutations
|
|
111
|
+
## Mutations 파일 (POST)
|
|
112
112
|
|
|
113
113
|
```typescript
|
|
114
114
|
// services/user/mutations.ts
|
|
@@ -135,7 +135,7 @@ export const deleteUser = createServerFn({ method: 'POST' })
|
|
|
135
135
|
})
|
|
136
136
|
```
|
|
137
137
|
|
|
138
|
-
##
|
|
138
|
+
## 진입점 파일
|
|
139
139
|
|
|
140
140
|
```typescript
|
|
141
141
|
// services/user/index.ts
|
|
@@ -144,7 +144,7 @@ export * from './queries'
|
|
|
144
144
|
export * from './mutations'
|
|
145
145
|
```
|
|
146
146
|
|
|
147
|
-
## Database
|
|
147
|
+
## Database 파일
|
|
148
148
|
|
|
149
149
|
```typescript
|
|
150
150
|
// database/prisma.ts
|
|
@@ -171,7 +171,7 @@ if (process.env.NODE_ENV !== 'production') {
|
|
|
171
171
|
|
|
172
172
|
<middleware>
|
|
173
173
|
|
|
174
|
-
## Middleware
|
|
174
|
+
## Middleware 패턴
|
|
175
175
|
|
|
176
176
|
```typescript
|
|
177
177
|
// middleware/auth.ts
|
|
@@ -234,7 +234,7 @@ export const deleteUser = createServerFn({ method: 'POST' })
|
|
|
234
234
|
|
|
235
235
|
<usage>
|
|
236
236
|
|
|
237
|
-
## TanStack Query
|
|
237
|
+
## TanStack Query 연동
|
|
238
238
|
|
|
239
239
|
```typescript
|
|
240
240
|
// routes/users/-hooks/use-users.ts
|
|
@@ -274,7 +274,7 @@ export const useUsers = () => {
|
|
|
274
274
|
}
|
|
275
275
|
```
|
|
276
276
|
|
|
277
|
-
## Form
|
|
277
|
+
## Form 연동
|
|
278
278
|
|
|
279
279
|
```tsx
|
|
280
280
|
// routes/users/-components/create-user-form.tsx
|
|
@@ -331,23 +331,23 @@ export const CreateUserForm = (): JSX.Element => {
|
|
|
331
331
|
|
|
332
332
|
<method_chaining>
|
|
333
333
|
|
|
334
|
-
## Method Chaining
|
|
334
|
+
## Method Chaining 순서
|
|
335
335
|
|
|
336
336
|
```typescript
|
|
337
|
-
// ✅
|
|
337
|
+
// ✅ 올바른 순서
|
|
338
338
|
createServerFn({ method: 'POST' })
|
|
339
|
-
.middleware([authMiddleware]) // 1. middleware (
|
|
340
|
-
.inputValidator(createUserSchema) // 2. inputValidator (
|
|
341
|
-
.handler(async ({ data }) => {}) // 3. handler (
|
|
339
|
+
.middleware([authMiddleware]) // 1. middleware (선택)
|
|
340
|
+
.inputValidator(createUserSchema) // 2. inputValidator (선택)
|
|
341
|
+
.handler(async ({ data }) => {}) // 3. handler (필수)
|
|
342
342
|
|
|
343
|
-
// ❌
|
|
343
|
+
// ❌ 잘못된 순서 (TypeScript 에러)
|
|
344
344
|
createServerFn({ method: 'POST' })
|
|
345
|
-
.handler(async () => {}) // ❌ handler
|
|
346
|
-
.inputValidator(schema) // ❌ inputValidator
|
|
345
|
+
.handler(async () => {}) // ❌ handler가 먼저
|
|
346
|
+
.inputValidator(schema) // ❌ inputValidator가 나중에
|
|
347
347
|
|
|
348
|
-
// ❌
|
|
348
|
+
// ❌ 잘못된 API 이름 (존재하지 않음)
|
|
349
349
|
createServerFn({ method: 'POST' })
|
|
350
|
-
.validator(schema) // ❌ validator
|
|
350
|
+
.validator(schema) // ❌ validator는 없음! inputValidator 사용
|
|
351
351
|
.handler(async ({ data }) => {})
|
|
352
352
|
```
|
|
353
353
|
|
|
@@ -357,14 +357,14 @@ createServerFn({ method: 'POST' })
|
|
|
357
357
|
|
|
358
358
|
<best_practices>
|
|
359
359
|
|
|
360
|
-
|
|
|
361
|
-
|
|
362
|
-
|
|
|
363
|
-
|
|
|
364
|
-
| **Validation** |
|
|
365
|
-
| **Middleware** |
|
|
366
|
-
| **TanStack Query** |
|
|
367
|
-
|
|
|
360
|
+
| 원칙 | 설명 |
|
|
361
|
+
|------|------|
|
|
362
|
+
| **파일 분리** | schemas, queries, mutations 분리 필수 |
|
|
363
|
+
| **진입점** | index.ts에서 모든 함수 re-export |
|
|
364
|
+
| **Validation** | POST/PUT/DELETE는 inputValidator 필수 |
|
|
365
|
+
| **Middleware** | 인증/권한은 middleware 사용 |
|
|
366
|
+
| **TanStack Query** | 클라이언트에서 직접 호출 금지, Query/Mutation 사용 |
|
|
367
|
+
| **에러 처리** | 명확한 에러 메시지 throw |
|
|
368
368
|
|
|
369
369
|
</best_practices>
|
|
370
370
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# Prisma - Cloudflare D1
|
|
2
2
|
|
|
3
|
-
SQLite
|
|
3
|
+
SQLite 기반 서버리스 DB. 일반 Prisma 마이그레이션과 다른 워크플로우.
|
|
4
4
|
|
|
5
|
-
⚠️
|
|
5
|
+
⚠️ 트랜잭션 미지원 | prisma migrate 불가 - wrangler 사용 | Preview 상태
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## 설정
|
|
8
8
|
|
|
9
9
|
```prisma
|
|
10
10
|
// schema.prisma
|
|
11
11
|
generator client {
|
|
12
12
|
provider = "prisma-client"
|
|
13
13
|
output = "../src/generated/prisma"
|
|
14
|
-
runtime = "cloudflare" //
|
|
14
|
+
runtime = "cloudflare" // 필수
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
datasource db {
|
|
@@ -26,7 +26,7 @@ datasource db {
|
|
|
26
26
|
}
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## 사용법
|
|
30
30
|
|
|
31
31
|
```typescript
|
|
32
32
|
import { PrismaClient } from './generated/prisma'
|
|
@@ -44,33 +44,33 @@ export default {
|
|
|
44
44
|
}
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
##
|
|
47
|
+
## 마이그레이션 워크플로우
|
|
48
48
|
|
|
49
49
|
```bash
|
|
50
|
-
# 1.
|
|
50
|
+
# 1. D1 생성
|
|
51
51
|
npx wrangler d1 create my-database
|
|
52
52
|
|
|
53
|
-
# 2.
|
|
53
|
+
# 2. 마이그레이션 생성
|
|
54
54
|
npx wrangler d1 migrations create my-database init
|
|
55
55
|
|
|
56
|
-
# 3.
|
|
56
|
+
# 3. SQL 생성 (초기)
|
|
57
57
|
npx prisma migrate diff --from-empty --to-schema-datamodel prisma/schema.prisma --script --output prisma/migrations/0001.sql
|
|
58
58
|
|
|
59
|
-
# 4.
|
|
59
|
+
# 4. SQL 생성 (후속)
|
|
60
60
|
npx prisma migrate diff --from-local-d1 --to-schema-datamodel prisma/schema.prisma --script
|
|
61
61
|
|
|
62
|
-
# 5.
|
|
63
|
-
npx wrangler d1 migrations apply my-database --local #
|
|
64
|
-
npx wrangler d1 migrations apply my-database --remote #
|
|
62
|
+
# 5. 적용
|
|
63
|
+
npx wrangler d1 migrations apply my-database --local # 로컬
|
|
64
|
+
npx wrangler d1 migrations apply my-database --remote # 프로덕션
|
|
65
65
|
|
|
66
|
-
# 6.
|
|
66
|
+
# 6. Client 생성
|
|
67
67
|
npx prisma generate
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
##
|
|
70
|
+
## 제한사항
|
|
71
71
|
|
|
72
|
-
|
|
|
72
|
+
| 항목 | 일반 SQLite | D1 |
|
|
73
73
|
|------|-------------|-----|
|
|
74
|
-
|
|
|
75
|
-
|
|
|
76
|
-
|
|
|
74
|
+
| 마이그레이션 | prisma migrate | wrangler d1 |
|
|
75
|
+
| 트랜잭션 | ✅ | ❌ |
|
|
76
|
+
| 접속 | 직접 | HTTP 어댑터 |
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# Prisma - Config
|
|
1
|
+
# Prisma - Config 파일
|
|
2
2
|
|
|
3
|
-
Prisma v7 `prisma.config.ts`
|
|
3
|
+
Prisma v7 `prisma.config.ts` 설정.
|
|
4
4
|
|
|
5
|
-
## Multi-File
|
|
5
|
+
## Multi-File 스키마 (필수)
|
|
6
6
|
|
|
7
7
|
```typescript
|
|
8
8
|
// prisma.config.ts
|
|
@@ -11,7 +11,7 @@ import path from 'node:path'
|
|
|
11
11
|
import { defineConfig, env } from 'prisma/config'
|
|
12
12
|
|
|
13
13
|
export default defineConfig({
|
|
14
|
-
schema: path.join('prisma', 'schema'), //
|
|
14
|
+
schema: path.join('prisma', 'schema'), // 폴더 경로!
|
|
15
15
|
migrations: {
|
|
16
16
|
path: 'prisma/migrations',
|
|
17
17
|
seed: 'tsx prisma/seed.ts',
|
|
@@ -22,16 +22,16 @@ export default defineConfig({
|
|
|
22
22
|
})
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
##
|
|
25
|
+
## 폴더 구조
|
|
26
26
|
|
|
27
27
|
```
|
|
28
|
-
|
|
28
|
+
프로젝트/
|
|
29
29
|
├── prisma.config.ts
|
|
30
30
|
├── prisma/
|
|
31
31
|
│ ├── schema/
|
|
32
32
|
│ │ ├── +base.prisma # datasource, generator
|
|
33
|
-
│ │ ├── +enum.prisma # enum
|
|
34
|
-
│ │ └── user.prisma #
|
|
33
|
+
│ │ ├── +enum.prisma # enum 정의
|
|
34
|
+
│ │ └── user.prisma # 모델
|
|
35
35
|
│ └── migrations/
|
|
36
36
|
```
|
|
37
37
|
|
|
@@ -49,17 +49,17 @@ generator client {
|
|
|
49
49
|
}
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
##
|
|
52
|
+
## 설정 옵션
|
|
53
53
|
|
|
54
|
-
|
|
|
54
|
+
| 옵션 | 설명 |
|
|
55
55
|
|------|------|
|
|
56
|
-
| `schema` |
|
|
57
|
-
| `datasource.url` | DB URL (
|
|
56
|
+
| `schema` | 스키마 폴더 경로 |
|
|
57
|
+
| `datasource.url` | DB URL (필수) |
|
|
58
58
|
| `datasource.shadowDatabaseUrl` | Shadow DB URL |
|
|
59
|
-
| `migrations.path` |
|
|
60
|
-
| `migrations.seed` |
|
|
59
|
+
| `migrations.path` | 마이그레이션 폴더 |
|
|
60
|
+
| `migrations.seed` | 시드 명령어 |
|
|
61
61
|
|
|
62
|
-
##
|
|
62
|
+
## 시드 파일
|
|
63
63
|
|
|
64
64
|
```typescript
|
|
65
65
|
// prisma/seed.ts
|
|
@@ -69,7 +69,7 @@ const prisma = new PrismaClient()
|
|
|
69
69
|
|
|
70
70
|
async function main() {
|
|
71
71
|
await prisma.user.create({
|
|
72
|
-
data: { email: 'admin@example.com', name: '
|
|
72
|
+
data: { email: 'admin@example.com', name: '관리자', role: 'ADMIN' },
|
|
73
73
|
})
|
|
74
74
|
}
|
|
75
75
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
# Prisma - CRUD
|
|
1
|
+
# Prisma - CRUD 작업
|
|
2
2
|
|
|
3
3
|
## Create
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
|
-
//
|
|
6
|
+
// 단일
|
|
7
7
|
const user = await prisma.user.create({
|
|
8
8
|
data: { email: 'alice@prisma.io', name: 'Alice' },
|
|
9
9
|
})
|
|
10
10
|
|
|
11
|
-
//
|
|
11
|
+
// 관계 포함
|
|
12
12
|
const user = await prisma.user.create({
|
|
13
13
|
data: {
|
|
14
14
|
email: 'bob@prisma.io',
|
|
@@ -27,22 +27,22 @@ posts: { create: [{
|
|
|
27
27
|
## Read
|
|
28
28
|
|
|
29
29
|
```typescript
|
|
30
|
-
//
|
|
30
|
+
// 단일
|
|
31
31
|
const user = await prisma.user.findUnique({ where: { email } })
|
|
32
32
|
|
|
33
|
-
//
|
|
33
|
+
// 다중
|
|
34
34
|
const users = await prisma.user.findMany({ where: { name: 'Alice' } })
|
|
35
35
|
|
|
36
|
-
//
|
|
36
|
+
// 관계 포함
|
|
37
37
|
const users = await prisma.user.findMany({ where: { role: 'ADMIN' }, include: { posts: true } })
|
|
38
38
|
|
|
39
|
-
//
|
|
39
|
+
// 필드 선택
|
|
40
40
|
const user = await prisma.user.findUnique({
|
|
41
41
|
where: { email },
|
|
42
42
|
select: { email: true, posts: { select: { title: true } } },
|
|
43
43
|
})
|
|
44
44
|
|
|
45
|
-
//
|
|
45
|
+
// 관계로 필터
|
|
46
46
|
const users = await prisma.user.findMany({
|
|
47
47
|
where: { posts: { some: { published: false } } },
|
|
48
48
|
})
|
|
@@ -51,10 +51,10 @@ const users = await prisma.user.findMany({
|
|
|
51
51
|
## Update
|
|
52
52
|
|
|
53
53
|
```typescript
|
|
54
|
-
//
|
|
54
|
+
// 단일
|
|
55
55
|
const user = await prisma.user.update({ where: { id }, data: { name: 'Updated' } })
|
|
56
56
|
|
|
57
|
-
//
|
|
57
|
+
// 다중
|
|
58
58
|
await prisma.user.updateMany({ where: { role: 'USER' }, data: { role: 'ADMIN' } })
|
|
59
59
|
|
|
60
60
|
// Upsert
|
|
@@ -69,22 +69,22 @@ const user = await prisma.user.upsert({
|
|
|
69
69
|
|
|
70
70
|
```typescript
|
|
71
71
|
await prisma.user.delete({ where: { id } })
|
|
72
|
-
await prisma.user.deleteMany({}) //
|
|
73
|
-
await prisma.post.deleteMany({ where: { published: false } }) //
|
|
72
|
+
await prisma.user.deleteMany({}) // 전체
|
|
73
|
+
await prisma.post.deleteMany({ where: { published: false } }) // 조건부
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
##
|
|
76
|
+
## 필터 연산자
|
|
77
77
|
|
|
78
78
|
```typescript
|
|
79
|
-
//
|
|
79
|
+
// 문자열
|
|
80
80
|
{ contains: 'prisma', startsWith: 'A', endsWith: 'io' }
|
|
81
81
|
|
|
82
|
-
//
|
|
82
|
+
// 숫자
|
|
83
83
|
{ gt: 18, gte: 18, lt: 65, lte: 65 }
|
|
84
84
|
|
|
85
|
-
//
|
|
85
|
+
// 배열
|
|
86
86
|
{ in: [1, 2, 3], notIn: [4, 5] }
|
|
87
87
|
|
|
88
|
-
//
|
|
88
|
+
// 논리
|
|
89
89
|
{ OR: [...], AND: [...], NOT: {...} }
|
|
90
90
|
```
|