@kood/claude-code 0.1.7 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/index.js +137 -3
  2. package/package.json +8 -2
  3. package/templates/hono/CLAUDE.md +53 -326
  4. package/templates/hono/docs/architecture/architecture.md +93 -747
  5. package/templates/hono/docs/deployment/cloudflare.md +59 -513
  6. package/templates/hono/docs/deployment/docker.md +41 -356
  7. package/templates/hono/docs/deployment/index.md +49 -190
  8. package/templates/hono/docs/deployment/railway.md +36 -306
  9. package/templates/hono/docs/deployment/vercel.md +49 -434
  10. package/templates/hono/docs/library/ai-sdk/index.md +53 -290
  11. package/templates/hono/docs/library/ai-sdk/openrouter.md +19 -387
  12. package/templates/hono/docs/library/ai-sdk/providers.md +28 -394
  13. package/templates/hono/docs/library/ai-sdk/streaming.md +52 -353
  14. package/templates/hono/docs/library/ai-sdk/structured-output.md +63 -395
  15. package/templates/hono/docs/library/ai-sdk/tools.md +62 -431
  16. package/templates/hono/docs/library/hono/env-setup.md +24 -313
  17. package/templates/hono/docs/library/hono/error-handling.md +34 -295
  18. package/templates/hono/docs/library/hono/index.md +24 -122
  19. package/templates/hono/docs/library/hono/middleware.md +21 -188
  20. package/templates/hono/docs/library/hono/rpc.md +40 -341
  21. package/templates/hono/docs/library/hono/validation.md +35 -195
  22. package/templates/hono/docs/library/pino/index.md +42 -333
  23. package/templates/hono/docs/library/prisma/cloudflare-d1.md +64 -367
  24. package/templates/hono/docs/library/prisma/config.md +19 -260
  25. package/templates/hono/docs/library/prisma/index.md +64 -320
  26. package/templates/hono/docs/library/zod/index.md +53 -257
  27. package/templates/npx/CLAUDE.md +58 -276
  28. package/templates/npx/docs/references/patterns.md +160 -0
  29. package/templates/tanstack-start/CLAUDE.md +0 -4
  30. package/templates/tanstack-start/docs/architecture/architecture.md +44 -589
  31. package/templates/tanstack-start/docs/design/index.md +119 -12
  32. package/templates/tanstack-start/docs/guides/conventions.md +103 -0
  33. package/templates/tanstack-start/docs/guides/env-setup.md +34 -340
  34. package/templates/tanstack-start/docs/guides/getting-started.md +22 -209
  35. package/templates/tanstack-start/docs/guides/hooks.md +166 -0
  36. package/templates/tanstack-start/docs/guides/routes.md +166 -0
  37. package/templates/tanstack-start/docs/guides/services.md +143 -0
  38. package/templates/tanstack-start/docs/library/tanstack-query/index.md +18 -2
  39. package/templates/tanstack-start/docs/library/zod/index.md +16 -1
  40. package/templates/tanstack-start/docs/design/accessibility.md +0 -163
  41. package/templates/tanstack-start/docs/design/color.md +0 -93
  42. package/templates/tanstack-start/docs/design/spacing.md +0 -122
  43. package/templates/tanstack-start/docs/design/typography.md +0 -80
  44. package/templates/tanstack-start/docs/guides/best-practices.md +0 -950
  45. package/templates/tanstack-start/docs/guides/husky-lint-staged.md +0 -303
  46. package/templates/tanstack-start/docs/guides/prettier.md +0 -189
  47. package/templates/tanstack-start/docs/guides/project-templates.md +0 -710
  48. package/templates/tanstack-start/docs/library/tanstack-query/setup.md +0 -48
  49. package/templates/tanstack-start/docs/library/zod/basic-types.md +0 -74
@@ -1,909 +1,255 @@
1
- # Architecture
1
+ # Hono 서버 아키텍처
2
2
 
3
- Hono 서버 애플리케이션의 기술 아키텍처 가이드입니다.
3
+ > 레이어 기반 아키텍처
4
4
 
5
- ## System Overview
5
+ ---
6
+
7
+ ## 시스템 개요
6
8
 
7
9
  ```
8
- ┌─────────────────────────────────────────────────────────────────┐
9
- │ Client (Browser/App) │
10
- │ │
11
- │ ┌────────────────┐ ┌────────────────┐ ┌───────────────┐ │
12
- │ │ HTTP Client │───▶│ hono/client │───▶│ React UI │ │
13
- │ │ (fetch/axios) │◀───│ (RPC Client) │◀───│ (Components) │ │
14
- │ └────────────────┘ └───────┬────────┘ └───────────────┘ │
15
- │ │ │
16
- └────────────────────────────────┼─────────────────────────────────┘
17
-
18
-
19
- ┌─────────────────────────────────────────────────────────────────┐
20
- │ Hono Server │
21
- │ │
22
- │ ┌────────────────────────────────────────────────────────────┐ │
23
- │ │ Middleware Stack │ │
24
- │ │ - logger → 요청 로깅 │ │
25
- │ │ - cors → CORS 설정 │ │
26
- │ │ - secureHeaders → 보안 헤더 │ │
27
- │ │ - authMiddleware → 인증 처리 │ │
28
- │ └────────────────────────┬───────────────────────────────────┘ │
29
- │ │ │
30
- │ ┌────────────────────────▼───────────────────────────────────┐ │
31
- │ │ Routes Layer │ │
32
- │ │ - routes/users.ts → /users/* │ │
33
- │ │ - routes/posts.ts → /posts/* │ │
34
- │ │ - routes/auth.ts → /auth/* │ │
35
- │ └────────────────────────┬───────────────────────────────────┘ │
36
- │ │ │
37
- │ ┌────────────────────────▼───────────────────────────────────┐ │
38
- │ │ Validation Layer │ │
39
- │ │ - @hono/zod-validator → 요청 검증 │ │
40
- │ │ - Zod v4 Schemas → 타입 안전 검증 │ │
41
- │ └────────────────────────┬───────────────────────────────────┘ │
42
- │ │ │
43
- │ ┌────────────────────────▼───────────────────────────────────┐ │
44
- │ │ Services Layer │ │
45
- │ │ - Business Logic │ │
46
- │ │ - Data Transformation │ │
47
- │ │ - Error Handling (HTTPException) │ │
48
- │ └────────────────────────┬───────────────────────────────────┘ │
49
- │ │ │
50
- └───────────────────────────┼──────────────────────────────────────┘
51
-
52
-
53
- ┌─────────────────────────────────────────────────────────────────┐
54
- │ Database Layer │
55
- │ │
56
- │ ┌────────────────┐ ┌────────────────┐ ┌───────────────┐ │
57
- │ │ Prisma Client │───▶│ PostgreSQL │ │ Cloudflare │ │
58
- │ │ (ORM v7) │ │ (Primary) │ │ D1/KV/R2 │ │
59
- │ └────────────────┘ └────────────────┘ └───────────────┘ │
60
- │ │
61
- └─────────────────────────────────────────────────────────────────┘
10
+ Client → Middleware → Routes → Validation → Services → Database
62
11
  ```
63
12
 
64
- ## Project Structure
13
+ ---
14
+
15
+ ## 프로젝트 구조
65
16
 
66
17
  ```
67
- my-app/
68
- ├── src/
69
- ├── index.ts # Entry point & App 설정
70
- ├── routes/ # 라우트 모듈
71
- │ │ ├── index.ts # 라우트 통합 (re-export)
72
- │ │ ├── users.ts # /users/* 라우트
73
- │ ├── posts.ts # /posts/* 라우트
74
- │ └── auth.ts # /auth/* 라우트
75
- ├── middleware/ # 커스텀 미들웨어
76
- │ │ ├── index.ts # re-export
77
- │ │ ├── auth.ts # 인증 미들웨어
78
- │ │ ├── logger.ts # 로깅 미들웨어
79
- │ │ └── rate-limit.ts # 레이트 리밋 미들웨어
80
- │ ├── validators/ # Zod 스키마 정의
81
- │ │ ├── index.ts # re-export
82
- │ │ ├── user.ts # 사용자 스키마
83
- │ │ ├── post.ts # 게시글 스키마
84
- │ │ └── common.ts # 공통 스키마 (pagination 등)
85
- │ ├── services/ # 비즈니스 로직 레이어
86
- │ │ ├── user/
87
- │ │ │ ├── index.ts # re-export
88
- │ │ │ ├── queries.ts # 조회 로직
89
- │ │ │ └── mutations.ts # 생성/수정/삭제 로직
90
- │ │ └── post/
91
- │ │ ├── index.ts
92
- │ │ ├── queries.ts
93
- │ │ └── mutations.ts
94
- │ ├── database/ # 데이터베이스 연결
95
- │ │ └── prisma.ts # Prisma Client 싱글톤
96
- │ ├── types/ # 타입 정의
97
- │ │ ├── index.ts # re-export
98
- │ │ ├── env.d.ts # 환경변수 타입
99
- │ │ └── bindings.ts # Cloudflare Bindings 타입
100
- │ └── lib/ # 공통 유틸리티
101
- │ ├── errors.ts # 커스텀 에러 클래스
102
- │ ├── jwt.ts # JWT 유틸리티
103
- │ └── utils.ts # 범용 유틸리티
104
- ├── prisma/
105
- │ ├── schema.prisma # Prisma 스키마
106
- │ └── generated/ # Prisma Client 출력
107
- │ └── client/
108
- ├── wrangler.toml # Cloudflare Workers 설정
109
- ├── .dev.vars # 로컬 환경변수
110
- ├── package.json
111
- └── tsconfig.json
18
+ src/
19
+ ├── index.ts # Entry point
20
+ ├── routes/ # 라우트 모듈
21
+ ├── middleware/ # 커스텀 미들웨어
22
+ ├── validators/ # Zod 스키마
23
+ ├── services/ # 비즈니스 로직
24
+ └── user/
25
+ ├── queries.ts # 조회
26
+ └── mutations.ts # 생성/수정/삭제
27
+ ├── database/ # Prisma Client
28
+ ├── types/ # 타입 정의
29
+ └── lib/ # 유틸리티
112
30
  ```
113
31
 
114
- ## Layer Architecture
115
-
116
- ### 1. Entry Point (src/index.ts)
32
+ ---
117
33
 
118
- 애플리케이션의 진입점으로, 전역 설정과 라우트 마운트를 담당합니다.
34
+ ## Entry Point
119
35
 
120
36
  ```typescript
121
37
  // src/index.ts
122
38
  import { Hono } from 'hono'
123
39
  import { logger } from 'hono/logger'
124
40
  import { cors } from 'hono/cors'
125
- import { secureHeaders } from 'hono/secure-headers'
126
41
  import { HTTPException } from 'hono/http-exception'
127
42
  import { users } from './routes/users'
128
- import { posts } from './routes/posts'
129
- import { auth } from './routes/auth'
130
-
131
- type Bindings = {
132
- DATABASE_URL: string
133
- JWT_SECRET: string
134
- NODE_ENV: string
135
- }
136
43
 
137
- type Variables = {
138
- userId: string
139
- }
44
+ type Bindings = { DATABASE_URL: string; JWT_SECRET: string }
45
+ type Variables = { userId: string }
140
46
 
141
47
  const app = new Hono<{ Bindings: Bindings; Variables: Variables }>()
142
48
 
143
- // 글로벌 미들웨어
144
49
  app.use(logger())
145
- app.use(secureHeaders())
146
50
  app.use('/api/*', cors())
147
51
 
148
- // 글로벌 에러 핸들러
149
52
  app.onError((err, c) => {
150
53
  if (err instanceof HTTPException) {
151
54
  return c.json({ error: err.message }, err.status)
152
55
  }
153
- console.error(err)
154
56
  return c.json({ error: 'Internal Server Error' }, 500)
155
57
  })
156
58
 
157
- // 404 핸들러
158
- app.notFound((c) => {
159
- return c.json({ error: 'Not Found', path: c.req.path }, 404)
160
- })
59
+ app.notFound((c) => c.json({ error: 'Not Found' }, 404))
161
60
 
162
- // 라우트 마운트
163
61
  app.route('/api/users', users)
164
- app.route('/api/posts', posts)
165
- app.route('/api/auth', auth)
166
-
167
- // Health Check
168
62
  app.get('/health', (c) => c.json({ status: 'ok' }))
169
63
 
170
64
  export default app
171
65
  ```
172
66
 
173
- ### 2. Routes Layer (Presentation)
174
-
175
- 파일 기반으로 라우트를 모듈화하여 관리합니다.
176
-
177
- ```
178
- routes/
179
- ├── index.ts # 라우트 통합
180
- ├── users.ts # /users 라우트
181
- ├── posts.ts # /posts 라우트
182
- └── auth.ts # /auth 라우트
183
- ```
67
+ ---
184
68
 
185
- **특징**:
186
- - 각 파일은 독립적인 Hono 인스턴스
187
- - zValidator로 요청 검증
188
- - 미들웨어 적용 가능
189
- - RPC 타입 추론 지원
69
+ ## Routes Layer
190
70
 
191
71
  ```typescript
192
72
  // routes/users.ts
193
73
  import { Hono } from 'hono'
194
74
  import { zValidator } from '@hono/zod-validator'
195
75
  import { authMiddleware } from '@/middleware/auth'
196
- import { createUserSchema, updateUserSchema, userIdSchema } from '@/validators/user'
197
- import { paginationSchema } from '@/validators/common'
198
- import { getUsers, getUserById, createUser, updateUser, deleteUser } from '@/services/user'
76
+ import { createUserSchema, userIdSchema } from '@/validators/user'
77
+ import { getUsers, createUser } from '@/services/user'
199
78
 
200
79
  const users = new Hono()
201
80
 
202
- // 목록 조회 (공개)
203
81
  users.get('/', zValidator('query', paginationSchema), async (c) => {
204
82
  const { page, limit } = c.req.valid('query')
205
- const result = await getUsers({ page, limit })
206
- return c.json(result)
83
+ return c.json(await getUsers({ page, limit }))
207
84
  })
208
85
 
209
- // 단일 조회 (공개)
210
- users.get('/:id', zValidator('param', userIdSchema), async (c) => {
211
- const { id } = c.req.valid('param')
212
- const user = await getUserById(id)
213
- return c.json({ user })
86
+ users.post('/', authMiddleware, zValidator('json', createUserSchema), async (c) => {
87
+ const data = c.req.valid('json')
88
+ return c.json({ user: await createUser(data) }, 201)
214
89
  })
215
90
 
216
- // 생성 (인증 필요)
217
- users.post(
218
- '/',
219
- authMiddleware,
220
- zValidator('json', createUserSchema),
221
- async (c) => {
222
- const data = c.req.valid('json')
223
- const user = await createUser(data)
224
- return c.json({ user }, 201)
225
- }
226
- )
227
-
228
- // 수정 (인증 필요)
229
- users.put(
230
- '/:id',
231
- authMiddleware,
232
- zValidator('param', userIdSchema),
233
- zValidator('json', updateUserSchema),
234
- async (c) => {
235
- const { id } = c.req.valid('param')
236
- const data = c.req.valid('json')
237
- const user = await updateUser(id, data)
238
- return c.json({ user })
239
- }
240
- )
241
-
242
- // 삭제 (인증 필요)
243
- users.delete(
244
- '/:id',
245
- authMiddleware,
246
- zValidator('param', userIdSchema),
247
- async (c) => {
248
- const { id } = c.req.valid('param')
249
- await deleteUser(id)
250
- return c.json({ success: true })
251
- }
252
- )
253
-
254
91
  export { users }
255
92
  ```
256
93
 
257
- ### 3. Middleware Layer
258
-
259
- 요청/응답 파이프라인을 처리합니다.
260
-
261
- ```
262
- middleware/
263
- ├── index.ts # re-export
264
- ├── auth.ts # 인증 미들웨어
265
- ├── logger.ts # 로깅 미들웨어
266
- └── rate-limit.ts # 레이트 리밋
267
- ```
94
+ ---
268
95
 
269
- **규칙**:
270
- - `createMiddleware`로 타입 안전 미들웨어 작성
271
- - `HTTPException`으로 에러 처리
272
- - `c.set()`으로 변수 전달
96
+ ## Middleware Layer
273
97
 
274
98
  ```typescript
275
99
  // middleware/auth.ts
276
100
  import { createMiddleware } from 'hono/factory'
277
101
  import { HTTPException } from 'hono/http-exception'
278
- import { verifyToken } from '@/lib/jwt'
279
102
 
280
103
  type Env = {
281
- Bindings: {
282
- JWT_SECRET: string
283
- }
284
- Variables: {
285
- userId: string
286
- }
104
+ Bindings: { JWT_SECRET: string }
105
+ Variables: { userId: string }
287
106
  }
288
107
 
289
108
  export const authMiddleware = createMiddleware<Env>(async (c, next) => {
290
109
  const token = c.req.header('Authorization')?.replace('Bearer ', '')
110
+ if (!token) throw new HTTPException(401, { message: 'Unauthorized' })
291
111
 
292
- if (!token) {
293
- throw new HTTPException(401, { message: 'Unauthorized' })
294
- }
295
-
296
- try {
297
- const payload = await verifyToken(token, c.env.JWT_SECRET)
298
- c.set('userId', payload.sub)
299
- await next()
300
- } catch {
301
- throw new HTTPException(401, { message: 'Invalid token' })
302
- }
112
+ const payload = await verifyToken(token, c.env.JWT_SECRET)
113
+ c.set('userId', payload.sub)
114
+ await next()
303
115
  })
304
116
  ```
305
117
 
306
- ### 4. Validators Layer (Input Validation)
118
+ ---
307
119
 
308
- Zod v4를 사용한 타입 안전 요청 검증을 담당합니다.
309
-
310
- ```
311
- validators/
312
- ├── index.ts # re-export
313
- ├── user.ts # 사용자 스키마
314
- ├── post.ts # 게시글 스키마
315
- └── common.ts # 공통 스키마
316
- ```
317
-
318
- **Zod v4 문법**:
120
+ ## Validators Layer
319
121
 
320
122
  ```typescript
321
123
  // validators/user.ts
322
124
  import { z } from 'zod'
323
125
 
324
- // ✅ Zod v4 문법
325
126
  export const createUserSchema = z.object({
326
- email: z.email(), // v4: z.email()
327
- name: z.string().min(1).max(100).trim(),
127
+ email: z.email(), // Zod v4
128
+ name: z.string().min(1).trim(),
328
129
  password: z.string().min(8),
329
- website: z.url().optional(), // ✅ v4: z.url()
330
130
  })
331
131
 
332
- export const updateUserSchema = createUserSchema.partial().omit({ password: true })
333
-
334
- export const userIdSchema = z.object({
335
- id: z.string().uuid(),
336
- })
337
-
338
- // 타입 추출
339
- export type CreateUserInput = z.infer<typeof createUserSchema>
340
- export type UpdateUserInput = z.infer<typeof updateUserSchema>
341
- ```
342
-
343
- ```typescript
344
- // validators/common.ts
345
- import { z } from 'zod'
346
-
347
132
  export const paginationSchema = z.object({
348
- page: z.coerce.number().positive().optional().default(1),
349
- limit: z.coerce.number().min(1).max(100).optional().default(10),
350
- })
351
-
352
- export const searchSchema = z.object({
353
- q: z.string().min(1),
354
- page: z.coerce.number().positive().optional(),
355
- limit: z.coerce.number().max(100).optional(),
133
+ page: z.coerce.number().positive().default(1),
134
+ limit: z.coerce.number().max(100).default(10),
356
135
  })
357
136
 
358
- export type PaginationInput = z.infer<typeof paginationSchema>
137
+ export type CreateUserInput = z.infer<typeof createUserSchema>
359
138
  ```
360
139
 
361
- ### 5. Services Layer (Business Logic)
362
-
363
- 비즈니스 로직을 라우트와 분리하여 관리합니다.
140
+ ---
364
141
 
365
- ```
366
- services/
367
- ├── user/
368
- │ ├── index.ts # re-export
369
- │ ├── queries.ts # 조회 로직
370
- │ └── mutations.ts # 생성/수정/삭제 로직
371
- └── post/
372
- ├── index.ts
373
- ├── queries.ts
374
- └── mutations.ts
375
- ```
142
+ ## Services Layer
376
143
 
377
- **Queries** - 읽기 작업:
144
+ ### Queries
378
145
 
379
146
  ```typescript
380
147
  // services/user/queries.ts
381
148
  import { HTTPException } from 'hono/http-exception'
382
149
  import { prisma } from '@/database/prisma'
383
- import type { PaginationInput } from '@/validators/common'
384
150
 
385
- export const getUsers = async ({ page, limit }: PaginationInput) => {
151
+ export const getUsers = async ({ page, limit }) => {
386
152
  const [users, total] = await Promise.all([
387
153
  prisma.user.findMany({
388
154
  skip: (page - 1) * limit,
389
155
  take: limit,
390
- orderBy: { createdAt: 'desc' },
391
- select: {
392
- id: true,
393
- email: true,
394
- name: true,
395
- createdAt: true,
396
- },
156
+ select: { id: true, email: true, name: true },
397
157
  }),
398
158
  prisma.user.count(),
399
159
  ])
400
-
401
- return {
402
- users,
403
- pagination: {
404
- page,
405
- limit,
406
- total,
407
- totalPages: Math.ceil(total / limit),
408
- },
409
- }
160
+ return { users, pagination: { page, limit, total } }
410
161
  }
411
162
 
412
163
  export const getUserById = async (id: string) => {
413
- const user = await prisma.user.findUnique({
414
- where: { id },
415
- include: { posts: true },
416
- })
417
-
418
- if (!user) {
419
- throw new HTTPException(404, { message: 'User not found' })
420
- }
421
-
164
+ const user = await prisma.user.findUnique({ where: { id } })
165
+ if (!user) throw new HTTPException(404, { message: 'User not found' })
422
166
  return user
423
167
  }
424
168
  ```
425
169
 
426
- **Mutations** - 쓰기 작업:
170
+ ### Mutations
427
171
 
428
172
  ```typescript
429
173
  // services/user/mutations.ts
430
174
  import { HTTPException } from 'hono/http-exception'
431
175
  import { prisma } from '@/database/prisma'
432
- import type { CreateUserInput, UpdateUserInput } from '@/validators/user'
433
176
 
434
177
  export const createUser = async (data: CreateUserInput) => {
435
- // 중복 체크
436
- const existing = await prisma.user.findUnique({
437
- where: { email: data.email },
438
- })
439
-
440
- if (existing) {
441
- throw new HTTPException(409, { message: 'Email already exists' })
442
- }
443
-
444
- // 비밀번호 해싱 (실제로는 bcrypt 사용)
445
- const hashedPassword = await hashPassword(data.password)
178
+ const existing = await prisma.user.findUnique({ where: { email: data.email } })
179
+ if (existing) throw new HTTPException(409, { message: 'Email already exists' })
446
180
 
447
181
  return prisma.user.create({
448
- data: {
449
- ...data,
450
- password: hashedPassword,
451
- },
452
- select: {
453
- id: true,
454
- email: true,
455
- name: true,
456
- createdAt: true,
457
- },
182
+ data: { ...data, password: await hashPassword(data.password) },
183
+ select: { id: true, email: true, name: true },
458
184
  })
459
185
  }
460
-
461
- export const updateUser = async (id: string, data: UpdateUserInput) => {
462
- const user = await prisma.user.findUnique({ where: { id } })
463
-
464
- if (!user) {
465
- throw new HTTPException(404, { message: 'User not found' })
466
- }
467
-
468
- return prisma.user.update({
469
- where: { id },
470
- data,
471
- select: {
472
- id: true,
473
- email: true,
474
- name: true,
475
- updatedAt: true,
476
- },
477
- })
478
- }
479
-
480
- export const deleteUser = async (id: string) => {
481
- const user = await prisma.user.findUnique({ where: { id } })
482
-
483
- if (!user) {
484
- throw new HTTPException(404, { message: 'User not found' })
485
- }
486
-
487
- await prisma.user.delete({ where: { id } })
488
- }
489
186
  ```
490
187
 
491
- ### 6. Database Layer (Data Access)
188
+ ---
492
189
 
493
- Prisma v7을 통한 데이터베이스 액세스를 담당합니다.
190
+ ## Database Layer
494
191
 
495
192
  ```typescript
496
193
  // database/prisma.ts
497
194
  import { PrismaClient } from '../../prisma/generated/client'
498
195
 
499
- const globalForPrisma = globalThis as unknown as {
500
- prisma: PrismaClient | undefined
501
- }
196
+ const globalForPrisma = globalThis as { prisma?: PrismaClient }
502
197
 
503
- export const prisma =
504
- globalForPrisma.prisma ??
505
- new PrismaClient({
506
- log: process.env.NODE_ENV === 'development' ? ['query'] : [],
507
- })
198
+ export const prisma = globalForPrisma.prisma ?? new PrismaClient()
508
199
 
509
200
  if (process.env.NODE_ENV !== 'production') {
510
201
  globalForPrisma.prisma = prisma
511
202
  }
512
203
  ```
513
204
 
514
- ## Data Flow
515
-
516
- ### Query Flow (읽기)
517
-
518
- ```
519
- 1. Client sends GET request
520
-
521
-
522
- ┌─────────────────┐
523
- │ Middleware │ ← logger, cors, secureHeaders
524
- │ Stack │
525
- └────────┬────────┘
526
-
527
-
528
- ┌─────────────────┐
529
- │ Route Handler │ ← zValidator('query', schema)
530
- └────────┬────────┘
531
-
532
-
533
- ┌─────────────────┐
534
- │ Service Query │ ← getUsers(), getUserById()
535
- └────────┬────────┘
536
-
537
-
538
- ┌─────────────────┐
539
- │ Prisma Client │ ← findMany(), findUnique()
540
- └────────┬────────┘
541
-
542
-
543
- ┌─────────────────┐
544
- │ Database │
545
- └─────────────────┘
546
- ```
547
-
548
- ### Mutation Flow (쓰기)
549
-
550
- ```
551
- 1. Client sends POST/PUT/DELETE request
552
-
553
-
554
- ┌─────────────────┐
555
- │ Middleware │ ← authMiddleware (인증)
556
- │ Stack │
557
- └────────┬────────┘
558
-
559
-
560
- ┌─────────────────┐
561
- │ Zod Validation │ ← zValidator('json', schema)
562
- └────────┬────────┘
563
- │ Valid
564
-
565
- ┌─────────────────┐
566
- │ Service │ ← createUser(), updateUser()
567
- │ Mutation │
568
- └────────┬────────┘
569
-
570
-
571
- ┌─────────────────┐
572
- │ Business Logic │ ← 중복 체크, 권한 검증
573
- └────────┬────────┘
574
-
575
-
576
- ┌─────────────────┐
577
- │ Prisma Mutation│ ← create(), update(), delete()
578
- └────────┬────────┘
579
-
580
-
581
- ┌─────────────────┐
582
- │ Database │
583
- └─────────────────┘
584
- ```
585
-
586
- ### Error Flow
587
-
588
- ```
589
- 1. Error occurs anywhere
590
-
591
-
592
- ┌─────────────────┐
593
- │ HTTPException │ ← 비즈니스 에러
594
- │ throw │
595
- └────────┬────────┘
596
-
597
-
598
- ┌─────────────────┐
599
- │ app.onError() │ ← 글로벌 에러 핸들러
600
- └────────┬────────┘
601
-
602
-
603
- ┌─────────────────┐
604
- │ JSON Response │ ← { error: message }
605
- └─────────────────┘
606
- ```
607
-
608
- ## RPC Pattern (Type-safe Client)
205
+ ---
609
206
 
610
- ### Server 설정
207
+ ## RPC Pattern
611
208
 
612
209
  ```typescript
613
- // src/index.ts
210
+ // server
614
211
  const app = new Hono()
615
212
  .route('/api/users', users)
616
- .route('/api/posts', posts)
617
213
 
618
214
  export type AppType = typeof app
619
- export default app
620
- ```
621
215
 
622
- ### Client 사용
623
-
624
- ```typescript
625
- // client.ts
216
+ // client
626
217
  import { hc } from 'hono/client'
627
218
  import type { AppType } from './server'
628
219
 
629
220
  const client = hc<AppType>('http://localhost:8787')
630
221
 
631
- // Type-safe API 호출
632
- const getUsers = async () => {
633
- const res = await client.api.users.$get({
634
- query: { page: '1', limit: '10' },
635
- })
636
- return res.json()
637
- }
638
-
639
- const createUser = async (data: CreateUserInput) => {
640
- const res = await client.api.users.$post({
641
- json: data,
642
- })
643
- return res.json()
644
- }
645
- ```
646
-
647
- ## Technology Stack
648
-
649
- ### Core Framework
650
-
651
- | Technology | Purpose | Version |
652
- |------------|---------|---------|
653
- | Hono | Web Standards 서버 프레임워크 | latest |
654
- | TypeScript | 타입 안전 개발 | 5.x |
655
-
656
- ### Validation
657
-
658
- | Technology | Purpose | Version |
659
- |------------|---------|---------|
660
- | Zod | 스키마 검증 | **4.x** |
661
- | @hono/zod-validator | Zod 미들웨어 | latest |
662
-
663
- ### Database
664
-
665
- | Technology | Purpose | Version |
666
- |------------|---------|---------|
667
- | Prisma | ORM | **7.x** |
668
- | PostgreSQL | Primary Database | - |
669
- | Cloudflare D1 | Edge Database | - |
670
-
671
- ### Runtime
672
-
673
- | Technology | Purpose |
674
- |------------|---------|
675
- | Cloudflare Workers | Edge Runtime |
676
- | Node.js | 로컬 개발 |
677
- | Bun | 대안 런타임 |
678
-
679
- ## TypeScript Configuration
680
-
681
- ```json
682
- {
683
- "compilerOptions": {
684
- "target": "ES2022",
685
- "lib": ["ES2022"],
686
- "module": "ESNext",
687
- "moduleResolution": "bundler",
688
- "jsx": "react-jsx",
689
- "jsxImportSource": "hono/jsx",
690
- "strict": true,
691
- "noUnusedLocals": true,
692
- "noUnusedParameters": true,
693
- "types": ["@cloudflare/workers-types"],
694
- "paths": {
695
- "@/*": ["./src/*"]
696
- }
697
- },
698
- "include": ["src/**/*"]
699
- }
700
- ```
701
-
702
- ## Deployment Architecture
703
-
704
- ### Cloudflare Workers
705
-
706
- ```
707
- ┌─────────────────────────────────────┐
708
- │ Cloudflare Edge Network │
709
- │ │
710
- │ ┌─────────────┐ ┌─────────────┐ │
711
- │ │ Workers │ │ KV │ │
712
- │ │ (Hono App) │ │ (Cache) │ │
713
- │ └──────┬──────┘ └─────────────┘ │
714
- │ │ │
715
- │ ┌──────▼──────┐ ┌─────────────┐ │
716
- │ │ D1 │ │ R2 │ │
717
- │ │ (Database) │ │ (Storage) │ │
718
- │ └─────────────┘ └─────────────┘ │
719
- │ │
720
- └─────────────────────────────────────┘
721
- ```
722
-
723
- ### Node.js / Bun
724
-
725
- ```
726
- ┌─────────────────────────────────────┐
727
- │ Server (Node/Bun) │
728
- │ │
729
- │ ┌─────────────────────────────┐ │
730
- │ │ Hono App │ │
731
- │ │ (Full-stack Server) │ │
732
- │ └─────────────────────────────┘ │
733
- │ │
734
- └───────────────────┬─────────────────┘
735
-
736
-
737
- ┌───────────────┐
738
- │ Database │
739
- │ (PostgreSQL) │
740
- └───────────────┘
741
- ```
742
-
743
- ## Documentation Structure
744
-
745
- ```
746
- docs/
747
- ├── library/ # 라이브러리 레퍼런스
748
- │ ├── hono/ # Hono 가이드
749
- │ │ ├── index.md # 기본 사용법
750
- │ │ ├── middleware.md # 미들웨어
751
- │ │ ├── validation.md # Zod 검증
752
- │ │ ├── error-handling.md # 에러 처리
753
- │ │ └── rpc.md # RPC Client
754
- │ ├── prisma/ # Prisma 가이드
755
- │ │ ├── index.md # 기본 사용법
756
- │ │ └── cloudflare-d1.md # D1 연동
757
- │ └── zod/ # Zod 가이드
758
- │ └── index.md
759
- ├── deployment/ # 배포 가이드
760
- │ ├── index.md # 배포 개요
761
- │ └── cloudflare.md # Cloudflare 배포
762
- ├── mcp/ # MCP 도구 가이드
763
- │ ├── index.md
764
- │ ├── sgrep.md
765
- │ ├── sequential-thinking.md
766
- │ └── context7.md
767
- ├── skills/ # 스킬 가이드
768
- │ └── gemini-review/
769
- ├── git/ # Git 규칙
770
- │ └── index.md
771
- └── architecture/ # 아키텍처
772
- └── architecture.md # 시스템 아키텍처
773
- ```
774
-
775
- ## Security Considerations
776
-
777
- ### Input Validation
778
-
779
- 모든 라우트에서 Zod를 통한 입력 검증:
780
-
781
- ```typescript
782
- // ✅ 올바른 패턴: zValidator 사용
783
- app.post(
784
- '/users',
785
- zValidator('json', createUserSchema), // 자동 검증
786
- (c) => {
787
- const data = c.req.valid('json') // data는 이미 검증됨
788
- // ...
789
- }
790
- )
791
-
792
- // ❌ 잘못된 패턴: 수동 검증 금지
793
- app.post('/users', async (c) => {
794
- const body = await c.req.json()
795
- if (!body.email) { // ❌ 이렇게 하지 마세요
796
- return c.json({ error: 'Email required' }, 400)
797
- }
798
- })
799
- ```
800
-
801
- ### Error Handling
802
-
803
- HTTPException을 통한 안전한 에러 처리:
804
-
805
- ```typescript
806
- // ✅ 올바른 패턴
807
- import { HTTPException } from 'hono/http-exception'
808
-
809
- if (!user) {
810
- throw new HTTPException(404, { message: 'User not found' })
811
- }
812
-
813
- // ❌ 잘못된 패턴
814
- if (!user) {
815
- throw new Error('User not found') // ❌ HTTPException 사용해야 함
816
- }
222
+ const res = await client.api.users.$get({ query: { page: '1' } })
223
+ const data = await res.json()
817
224
  ```
818
225
 
819
- ### Authentication
820
-
821
- 미들웨어를 통한 인증 처리:
226
+ ---
822
227
 
823
- ```typescript
824
- // ✅ 올바른 패턴: 미들웨어 사용
825
- app.post('/protected', authMiddleware, (c) => {
826
- const userId = c.get('userId')
827
- // ...
828
- })
228
+ ## Tech Stack
829
229
 
830
- // 잘못된 패턴: 핸들러 내부에서 인증
831
- app.post('/protected', async (c) => {
832
- const token = c.req.header('Authorization') // 미들웨어 사용해야 함
833
- // ...
834
- })
835
- ```
230
+ | 분류 | 기술 | 버전 |
231
+ |------|------|------|
232
+ | Framework | Hono | latest |
233
+ | Validation | Zod | **4.x** |
234
+ | ORM | Prisma | **7.x** |
235
+ | Runtime | Cloudflare Workers, Node.js, Bun | - |
836
236
 
837
- ### Environment Variables
237
+ ---
838
238
 
839
- ```typescript
840
- // types/env.d.ts
841
- type Bindings = {
842
- DATABASE_URL: string
843
- JWT_SECRET: string
844
- NODE_ENV: 'development' | 'production'
845
- }
239
+ ## 패턴 요약
846
240
 
847
- // 사용
848
- const app = new Hono<{ Bindings: Bindings }>()
241
+ | 레이어 | 역할 | 파일 |
242
+ |--------|------|------|
243
+ | Routes | HTTP 라우팅 | `routes/*.ts` |
244
+ | Middleware | 요청/응답 처리 | `middleware/*.ts` |
245
+ | Validators | 입력 검증 | `validators/*.ts` |
246
+ | Services | 비즈니스 로직 | `services/*/*.ts` |
247
+ | Database | 데이터 액세스 | `database/prisma.ts` |
849
248
 
850
- app.get('/', (c) => {
851
- const secret = c.env.JWT_SECRET // 타입 안전
852
- })
853
- ```
854
-
855
- ## Performance Considerations
856
-
857
- ### Middleware Optimization
858
-
859
- ```typescript
860
- // 필요한 경로에만 미들웨어 적용
861
- app.use('/api/*', cors()) // API 전용
862
- app.use('/api/protected/*', authMiddleware) // 인증 필요 경로만
863
-
864
- // 불필요한 미들웨어 중복 적용 금지
865
- ```
866
-
867
- ### Database Optimization
868
-
869
- ```typescript
870
- // 필요한 필드만 선택
871
- const users = await prisma.user.findMany({
872
- select: { // ✅ select 사용
873
- id: true,
874
- name: true,
875
- email: true,
876
- },
877
- take: 20, // ✅ 페이지네이션
878
- skip: (page - 1) * 20,
879
- })
880
-
881
- // 병렬 쿼리 실행
882
- const [users, total] = await Promise.all([
883
- prisma.user.findMany({ take: 20 }),
884
- prisma.user.count(),
885
- ])
886
- ```
887
-
888
- ### Response Optimization
889
-
890
- ```typescript
891
- // 적절한 상태 코드 사용
892
- app.post('/users', (c) => {
893
- return c.json({ user }, 201) // Created
894
- })
895
-
896
- // 불필요한 데이터 제외
897
- const { password, ...safeUser } = user
898
- return c.json({ user: safeUser })
899
- ```
249
+ ---
900
250
 
901
- ## Related Documentation
251
+ ## 관련 문서
902
252
 
903
- - [Hono 기본 사용법](../library/hono/index.md)
904
- - [미들웨어](../library/hono/middleware.md)
905
- - [Zod 검증](../library/hono/validation.md)
906
- - [에러 처리](../library/hono/error-handling.md)
907
- - [RPC Client](../library/hono/rpc.md)
908
- - [Prisma v7](../library/prisma/index.md)
253
+ - [Hono](../library/hono/index.md)
254
+ - [Prisma](../library/prisma/index.md)
909
255
  - [Cloudflare 배포](../deployment/cloudflare.md)