@kood/claude-code 0.5.4 → 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 +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/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,15 +1,15 @@
|
|
|
1
1
|
# Prisma - Cloudflare D1
|
|
2
2
|
|
|
3
|
-
> SQLite
|
|
3
|
+
> SQLite 기반 서버리스 데이터베이스
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## 주의사항
|
|
8
8
|
|
|
9
9
|
```
|
|
10
|
-
D1
|
|
11
|
-
prisma migrate dev
|
|
12
|
-
Prisma ORM D1
|
|
10
|
+
D1은 트랜잭션 미지원 (ACID 보장 X)
|
|
11
|
+
prisma migrate dev 사용 불가 → wrangler CLI 사용
|
|
12
|
+
Prisma ORM D1 지원은 Preview 상태
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
---
|
|
@@ -22,11 +22,11 @@ Prisma ORM D1 support is in Preview
|
|
|
22
22
|
generator client {
|
|
23
23
|
provider = "prisma-client"
|
|
24
24
|
output = "../src/generated/prisma"
|
|
25
|
-
runtime = "cloudflare" //
|
|
25
|
+
runtime = "cloudflare" // D1 필수
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
datasource db {
|
|
29
|
-
provider = "sqlite" // D1
|
|
29
|
+
provider = "sqlite" // D1은 SQLite 기반
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
model User {
|
|
@@ -59,7 +59,7 @@ export default app
|
|
|
59
59
|
|
|
60
60
|
---
|
|
61
61
|
|
|
62
|
-
##
|
|
62
|
+
## 설치
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
65
|
npm install hono @prisma/client @prisma/adapter-d1
|
|
@@ -69,7 +69,7 @@ npx prisma init --datasource-provider sqlite
|
|
|
69
69
|
|
|
70
70
|
---
|
|
71
71
|
|
|
72
|
-
##
|
|
72
|
+
## D1 데이터베이스 생성
|
|
73
73
|
|
|
74
74
|
```bash
|
|
75
75
|
npx wrangler d1 create my-database
|
|
@@ -93,29 +93,29 @@ npx wrangler d1 create my-database
|
|
|
93
93
|
|
|
94
94
|
---
|
|
95
95
|
|
|
96
|
-
##
|
|
96
|
+
## 마이그레이션 워크플로우
|
|
97
97
|
|
|
98
98
|
```bash
|
|
99
|
-
# 1.
|
|
99
|
+
# 1. 마이그레이션 파일 생성
|
|
100
100
|
npx wrangler d1 migrations create my-database create_user_table
|
|
101
101
|
|
|
102
|
-
# 2.
|
|
102
|
+
# 2. SQL 생성 (초기)
|
|
103
103
|
npx prisma migrate diff \
|
|
104
104
|
--from-empty \
|
|
105
105
|
--to-schema-datamodel prisma/schema.prisma \
|
|
106
106
|
--script \
|
|
107
107
|
--output prisma/migrations/0001_create_user_table.sql
|
|
108
108
|
|
|
109
|
-
# 3.
|
|
109
|
+
# 3. 로컬 적용
|
|
110
110
|
npx wrangler d1 migrations apply my-database --local
|
|
111
111
|
|
|
112
|
-
# 4.
|
|
112
|
+
# 4. 원격 적용
|
|
113
113
|
npx wrangler d1 migrations apply my-database --remote
|
|
114
114
|
```
|
|
115
115
|
|
|
116
116
|
---
|
|
117
117
|
|
|
118
|
-
##
|
|
118
|
+
## 완전한 CRUD API
|
|
119
119
|
|
|
120
120
|
```typescript
|
|
121
121
|
import { Hono } from 'hono'
|
|
@@ -130,7 +130,7 @@ type Variables = { prisma: PrismaClient }
|
|
|
130
130
|
|
|
131
131
|
const app = new Hono<{ Bindings: Bindings; Variables: Variables }>()
|
|
132
132
|
|
|
133
|
-
// Prisma
|
|
133
|
+
// Prisma 미들웨어
|
|
134
134
|
app.use('*', async (c, next) => {
|
|
135
135
|
const adapter = new PrismaD1(c.env.DB)
|
|
136
136
|
c.set('prisma', new PrismaClient({ adapter }))
|
|
@@ -161,20 +161,20 @@ export default app
|
|
|
161
161
|
|
|
162
162
|
---
|
|
163
163
|
|
|
164
|
-
##
|
|
164
|
+
## 로컬 개발
|
|
165
165
|
|
|
166
166
|
```bash
|
|
167
|
-
#
|
|
167
|
+
# Worker 실행
|
|
168
168
|
npx wrangler dev
|
|
169
169
|
|
|
170
|
-
#
|
|
170
|
+
# D1 조회
|
|
171
171
|
npx wrangler d1 execute my-database --local \
|
|
172
172
|
--command "SELECT * FROM User;"
|
|
173
173
|
```
|
|
174
174
|
|
|
175
175
|
---
|
|
176
176
|
|
|
177
|
-
##
|
|
177
|
+
## 배포
|
|
178
178
|
|
|
179
179
|
```bash
|
|
180
180
|
npx prisma generate
|
|
@@ -184,17 +184,17 @@ npx wrangler deploy
|
|
|
184
184
|
|
|
185
185
|
---
|
|
186
186
|
|
|
187
|
-
##
|
|
187
|
+
## 제한사항
|
|
188
188
|
|
|
189
|
-
|
|
|
190
|
-
|
|
191
|
-
|
|
|
192
|
-
|
|
|
193
|
-
|
|
|
189
|
+
| 항목 | D1 |
|
|
190
|
+
|------|-----|
|
|
191
|
+
| 트랜잭션 | ❌ 미지원 |
|
|
192
|
+
| 마이그레이션 | wrangler 사용 |
|
|
193
|
+
| 접속 방식 | HTTP (어댑터) |
|
|
194
194
|
|
|
195
195
|
---
|
|
196
196
|
|
|
197
|
-
##
|
|
197
|
+
## 관련 문서
|
|
198
198
|
|
|
199
|
-
- [Prisma
|
|
200
|
-
- [Cloudflare
|
|
199
|
+
- [Prisma 개요](./index.md)
|
|
200
|
+
- [Cloudflare 배포](../../deployment/cloudflare.md)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# Prisma - Config
|
|
1
|
+
# Prisma - Config 파일
|
|
2
2
|
|
|
3
|
-
> prisma.config.ts
|
|
3
|
+
> prisma.config.ts 설정 (v7)
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
## Multi-File
|
|
7
|
+
## Multi-File 스키마 필수 설정
|
|
8
8
|
|
|
9
9
|
```typescript
|
|
10
10
|
// prisma.config.ts
|
|
@@ -12,7 +12,7 @@ import path from 'node:path'
|
|
|
12
12
|
import { defineConfig, env } from 'prisma/config'
|
|
13
13
|
|
|
14
14
|
export default defineConfig({
|
|
15
|
-
schema: path.join('prisma', 'schema'), //
|
|
15
|
+
schema: path.join('prisma', 'schema'), // 폴더 경로
|
|
16
16
|
datasource: {
|
|
17
17
|
url: env('DATABASE_URL'),
|
|
18
18
|
},
|
|
@@ -21,13 +21,13 @@ export default defineConfig({
|
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
24
|
-
##
|
|
24
|
+
## 파일 위치
|
|
25
25
|
|
|
26
26
|
```
|
|
27
|
-
|
|
28
|
-
├── prisma.config.ts #
|
|
27
|
+
프로젝트/
|
|
28
|
+
├── prisma.config.ts # 프로젝트 루트
|
|
29
29
|
├── prisma/
|
|
30
|
-
│ ├── schema/ # Multi-File
|
|
30
|
+
│ ├── schema/ # Multi-File 스키마
|
|
31
31
|
│ │ ├── +base.prisma
|
|
32
32
|
│ │ ├── +enum.prisma
|
|
33
33
|
│ │ └── user.prisma
|
|
@@ -37,7 +37,7 @@ project/
|
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
40
|
-
##
|
|
40
|
+
## 전체 설정 예시
|
|
41
41
|
|
|
42
42
|
```typescript
|
|
43
43
|
// prisma.config.ts
|
|
@@ -69,14 +69,14 @@ datasource db {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
generator client {
|
|
72
|
-
provider = "prisma-client" // v7
|
|
72
|
+
provider = "prisma-client" // v7 필수
|
|
73
73
|
output = "../../generated/prisma"
|
|
74
74
|
}
|
|
75
75
|
```
|
|
76
76
|
|
|
77
77
|
---
|
|
78
78
|
|
|
79
|
-
##
|
|
79
|
+
## 시드 스크립트
|
|
80
80
|
|
|
81
81
|
```typescript
|
|
82
82
|
// prisma/seed.ts
|
|
@@ -86,7 +86,7 @@ const prisma = new PrismaClient()
|
|
|
86
86
|
|
|
87
87
|
async function main() {
|
|
88
88
|
await prisma.user.create({
|
|
89
|
-
data: { email: 'admin@example.com', name: '
|
|
89
|
+
data: { email: 'admin@example.com', name: '관리자' },
|
|
90
90
|
})
|
|
91
91
|
}
|
|
92
92
|
|
|
@@ -104,18 +104,18 @@ main()
|
|
|
104
104
|
generator client {
|
|
105
105
|
provider = "prisma-client"
|
|
106
106
|
output = "../../generated/prisma"
|
|
107
|
-
runtime = "workerd" // Workers
|
|
107
|
+
runtime = "workerd" // Workers 런타임
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
datasource db {
|
|
111
|
-
provider = "sqlite" // D1
|
|
111
|
+
provider = "sqlite" // D1은 SQLite
|
|
112
112
|
url = env("DATABASE_URL")
|
|
113
113
|
}
|
|
114
114
|
```
|
|
115
115
|
|
|
116
116
|
---
|
|
117
117
|
|
|
118
|
-
##
|
|
118
|
+
## 관련 문서
|
|
119
119
|
|
|
120
|
-
- [Prisma
|
|
120
|
+
- [Prisma 개요](./index.md)
|
|
121
121
|
- [Cloudflare D1](./cloudflare-d1.md)
|
|
@@ -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)
|