@kood/claude-code 0.1.7 → 0.1.9

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 +118 -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
package/dist/index.js CHANGED
@@ -136,6 +136,60 @@ var listAvailableTemplates = async () => {
136
136
  }
137
137
  return templates;
138
138
  };
139
+ var copySkills = async (templates, targetDir) => {
140
+ const counter = { files: 0, directories: 0 };
141
+ const targetSkillsDir = path.join(targetDir, ".claude", "skills");
142
+ for (const template of templates) {
143
+ const templatePath = getTemplatePath(template);
144
+ const skillsSrc = path.join(templatePath, "docs", "skills");
145
+ if (await fs.pathExists(skillsSrc)) {
146
+ await fs.ensureDir(targetSkillsDir);
147
+ await copyRecursive(skillsSrc, targetSkillsDir, counter);
148
+ }
149
+ }
150
+ return counter;
151
+ };
152
+ var copyCommands = async (templates, targetDir) => {
153
+ const counter = { files: 0, directories: 0 };
154
+ const targetCommandsDir = path.join(targetDir, ".claude", "commands");
155
+ for (const template of templates) {
156
+ const templatePath = getTemplatePath(template);
157
+ const commandsSrc = path.join(templatePath, "docs", "commands");
158
+ if (await fs.pathExists(commandsSrc)) {
159
+ await fs.ensureDir(targetCommandsDir);
160
+ await copyRecursive(commandsSrc, targetCommandsDir, counter);
161
+ }
162
+ }
163
+ return counter;
164
+ };
165
+ var checkSkillsAndCommandsExist = async (templates) => {
166
+ let hasSkills = false;
167
+ let hasCommands = false;
168
+ for (const template of templates) {
169
+ const templatePath = getTemplatePath(template);
170
+ const skillsSrc = path.join(templatePath, "docs", "skills");
171
+ const commandsSrc = path.join(templatePath, "docs", "commands");
172
+ if (await fs.pathExists(skillsSrc)) {
173
+ hasSkills = true;
174
+ }
175
+ if (await fs.pathExists(commandsSrc)) {
176
+ hasCommands = true;
177
+ }
178
+ }
179
+ return { hasSkills, hasCommands };
180
+ };
181
+ var checkExistingClaudeFiles = async (targetDir) => {
182
+ const existingFiles = [];
183
+ const skillsDir = path.join(targetDir, ".claude", "skills");
184
+ const commandsDir = path.join(targetDir, ".claude", "commands");
185
+ if (await fs.pathExists(skillsDir)) {
186
+ existingFiles.push(".claude/skills/");
187
+ }
188
+ if (await fs.pathExists(commandsDir)) {
189
+ existingFiles.push(".claude/commands/");
190
+ }
191
+ return existingFiles;
192
+ };
139
193
 
140
194
  // src/commands/init.ts
141
195
  var TEMPLATE_DESCRIPTIONS = {
@@ -227,10 +281,69 @@ var init = async (options) => {
227
281
  }
228
282
  logger.blank();
229
283
  logger.success(`Total: ${totalFiles} files, ${totalDirectories} directories`);
284
+ if (options.skills || options.commands) {
285
+ const { hasSkills, hasCommands } = await checkSkillsAndCommandsExist(templates);
286
+ const existingClaudeFiles = await checkExistingClaudeFiles(targetDir);
287
+ if (existingClaudeFiles.length > 0 && !options.force) {
288
+ logger.warn("The following .claude files/folders already exist:");
289
+ existingClaudeFiles.forEach((f) => logger.step(f));
290
+ logger.blank();
291
+ const response = await prompts({
292
+ type: "confirm",
293
+ name: "overwrite",
294
+ message: "Overwrite existing .claude files?",
295
+ initial: false
296
+ });
297
+ if (!response.overwrite) {
298
+ logger.info("Skipping skills/commands installation.");
299
+ } else {
300
+ await installSkillsAndCommands();
301
+ }
302
+ } else {
303
+ await installSkillsAndCommands();
304
+ }
305
+ async function installSkillsAndCommands() {
306
+ if (options.skills && hasSkills) {
307
+ logger.blank();
308
+ logger.info("Installing skills...");
309
+ const skillsResult = await copySkills(templates, targetDir);
310
+ totalFiles += skillsResult.files;
311
+ totalDirectories += skillsResult.directories;
312
+ logger.success(
313
+ `Skills: ${skillsResult.files} files, ${skillsResult.directories} directories`
314
+ );
315
+ } else if (options.skills && !hasSkills) {
316
+ logger.warn("No skills found in selected templates.");
317
+ }
318
+ if (options.commands && hasCommands) {
319
+ logger.blank();
320
+ logger.info("Installing commands...");
321
+ const commandsResult = await copyCommands(templates, targetDir);
322
+ totalFiles += commandsResult.files;
323
+ totalDirectories += commandsResult.directories;
324
+ logger.success(
325
+ `Commands: ${commandsResult.files} files, ${commandsResult.directories} directories`
326
+ );
327
+ } else if (options.commands && !hasCommands) {
328
+ logger.warn("No commands found in selected templates.");
329
+ }
330
+ }
331
+ }
332
+ logger.blank();
230
333
  logger.success("Claude Code documentation installed!");
231
334
  logger.blank();
232
335
  logger.info("Installed templates:");
233
336
  templates.forEach((t) => logger.step(t));
337
+ if (options.skills || options.commands) {
338
+ logger.blank();
339
+ logger.info("Installed extras:");
340
+ if (options.skills) {
341
+ logger.step("Skills \u2192 .claude/skills/");
342
+ }
343
+ if (options.commands) {
344
+ logger.step("Commands \u2192 .claude/commands/");
345
+ }
346
+ }
234
347
  logger.blank();
235
348
  logger.info("Next steps:");
236
349
  logger.step("Read CLAUDE.md for project guidelines");
@@ -240,11 +353,11 @@ var init = async (options) => {
240
353
 
241
354
  // src/index.ts
242
355
  var program = new Command();
243
- program.name("claude-code").description("Claude Code documentation installer for projects").version("0.1.7");
356
+ program.name("claude-code").description("Claude Code documentation installer for projects").version("0.1.9");
244
357
  program.option(
245
358
  "-t, --template <names>",
246
359
  "template names (comma-separated: tanstack-start,hono)"
247
- ).option("-f, --force", "overwrite existing files without prompting").option("--cwd <path>", "target directory (default: current directory)").option("--list", "list available templates").action(async (options) => {
360
+ ).option("-f, --force", "overwrite existing files without prompting").option("--cwd <path>", "target directory (default: current directory)").option("--list", "list available templates").option("-s, --skills", "install skills to .claude/skills/").option("-c, --commands", "install commands to .claude/commands/").action(async (options) => {
248
361
  banner();
249
362
  if (options.list) {
250
363
  const templates = await listAvailableTemplates();
@@ -256,7 +369,9 @@ program.option(
256
369
  await init({
257
370
  templates: options.template?.split(",").map((t) => t.trim()),
258
371
  force: options.force,
259
- cwd: options.cwd
372
+ cwd: options.cwd,
373
+ skills: options.skills,
374
+ commands: options.commands
260
375
  });
261
376
  });
262
377
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kood/claude-code",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Claude Code documentation installer for projects",
5
5
  "type": "module",
6
6
  "bin": "./dist/index.js",
@@ -12,6 +12,8 @@
12
12
  "copy-templates": "node scripts/copy-templates.js",
13
13
  "build": "tsup && npm run copy-templates",
14
14
  "dev": "npm run build && node dist/index.js",
15
+ "lint": "eslint src/",
16
+ "lint:fix": "eslint src/ --fix",
15
17
  "prepublishOnly": "npm run build"
16
18
  },
17
19
  "keywords": [
@@ -38,10 +40,14 @@
38
40
  "@types/fs-extra": "^11.0.4",
39
41
  "@types/node": "^22.10.0",
40
42
  "@types/prompts": "^2.4.9",
43
+ "@typescript-eslint/eslint-plugin": "^8.50.1",
44
+ "@typescript-eslint/parser": "^8.50.1",
45
+ "eslint": "^9.39.2",
46
+ "globals": "^16.5.0",
41
47
  "tsup": "^8.3.5",
42
48
  "typescript": "^5.7.2"
43
49
  },
44
50
  "engines": {
45
51
  "node": ">=18"
46
52
  }
47
- }
53
+ }
@@ -1,6 +1,6 @@
1
- # CLAUDE.md - Claude Code Instructions
1
+ # CLAUDE.md - Hono Server Framework
2
2
 
3
- > Hono 서버 프레임워크 프로젝트 작업 지침
3
+ > Web Standards 기반 초경량 서버 프레임워크
4
4
 
5
5
  ## Instructions
6
6
 
@@ -12,213 +12,53 @@
12
12
 
13
13
  ---
14
14
 
15
- ## 🚨 STOP - 작업 전 필수 확인
15
+ ## STOP - 금지 사항
16
16
 
17
- ```
18
- ┌─────────────────────────────────────────────────────────────┐
19
- │ 이 프로젝트에서 작업하기 전에 문서를 끝까지 읽으세요. │
20
- │ 특히 NEVER DO 섹션의 규칙은 절대 위반하지 마세요. │
21
- │ │
22
- │ 📖 작업 유형별 상세 문서: docs/ 폴더 참조 │
23
- └─────────────────────────────────────────────────────────────┘
24
- ```
25
-
26
- ---
27
-
28
- ## ⛔ NEVER DO (절대 금지 - 예외 없음)
29
-
30
- ### Git 커밋 금지 사항
31
- ```
32
- ❌ "Generated with Claude Code" 포함 금지
33
- ❌ "🤖" 또는 AI 관련 이모지 포함 금지
34
- ❌ "Co-Authored-By:" 헤더 포함 금지
35
- ❌ AI/봇이 작성했다는 어떤 표시도 금지
36
- ❌ 커밋 메시지 여러 줄 작성 금지
37
- ❌ 커밋 메시지에 이모지 사용 금지
38
- ```
39
-
40
- ### Prisma 금지 사항
41
- ```
42
- ❌ prisma db push 자동 실행 금지
43
- ❌ prisma migrate 자동 실행 금지
44
- ❌ prisma generate 자동 실행 금지
45
- ❌ schema.prisma 임의 변경 금지 (요청된 것만)
46
- ```
47
-
48
- ### API 구현 금지 사항
49
- ```
50
- ❌ handler 내부에서 수동 검증 금지 (zValidator 사용)
51
- ❌ handler 내부에서 수동 인증 체크 금지 (middleware 사용)
52
- ❌ app.onError 없이 에러 처리 금지
53
- ❌ HTTPException 없이 에러 throw 금지
54
- ```
55
-
56
- ### 코드 검색 금지 사항
57
- ```
58
- ❌ grep, rg 등 기본 검색 도구 사용 금지
59
- ❌ find 명령어로 코드 검색 금지
60
- ✅ 코드베이스 검색 시 sgrep 사용 필수
61
- ```
62
-
63
- ### 코드 작성 규칙
64
- ```
65
- ✅ 모든 한글 텍스트는 UTF-8 인코딩 유지
66
- ✅ 코드 묶음 단위로 한글 주석 작성 (너무 세세하게 X)
67
- ✅ Prisma Multi-File 모든 요소에 한글 주석 필수
68
- ```
69
-
70
- ### Prisma Multi-File 구조 (필수)
71
- ```
72
- prisma/
73
- ├── schema/
74
- │ ├── +base.prisma # datasource, generator 설정
75
- │ ├── +enum.prisma # 모든 enum 정의
76
- │ ├── user.prisma # User 모델
77
- │ ├── post.prisma # Post 모델
78
- │ └── ... # 기타 모델별 파일
79
- ```
80
-
81
- ---
82
-
83
- ## ✅ ALWAYS DO (필수 실행)
84
-
85
- ### 1. 작업 전: 관련 문서 읽기
86
- ```
87
- API 작업 → docs/library/hono/ 읽기
88
- DB 작업 → docs/library/prisma/ 읽기
89
- 검증 작업 → docs/library/zod/ 읽기
90
- 배포 작업 → docs/deployment/ 읽기
91
- ```
92
-
93
- ### 2. MCP 도구 적극 활용
94
- ```
95
- 코드베이스 검색 → sgrep 사용 (grep/rg 금지)
96
- 복잡한 분석/디버깅 → Sequential Thinking 사용
97
- 라이브러리 문서 → Context7 사용
98
- ```
99
- **상세**: `docs/mcp/` 참고
100
-
101
- ### 3. 복잡한 작업 시: Gemini Review 실행
102
- ```
103
- 아키텍처 설계/변경 → gemini-review (architecture)
104
- 구현 계획 검증 → gemini-review (plan)
105
- 복잡한 코드 리뷰 → gemini-review (code)
106
- ```
107
-
108
- **실행 조건**:
109
- - 3개 이상 파일 수정하는 기능 구현
110
- - 새로운 아키텍처 패턴 도입
111
- - 보안 관련 코드 (인증, 권한, 암호화)
112
- - 성능 크리티컬 코드
113
-
114
- ### 4. 작업 완료 후: Git 커밋
115
- ```bash
116
- git add .
117
- git commit -m "<prefix>: <설명>"
118
- ```
119
-
120
- **커밋 형식**: `<prefix>: <설명>` (한 줄, 본문 없음)
121
-
122
- **Prefix**: `feat` | `fix` | `refactor` | `style` | `docs` | `test` | `chore` | `perf` | `ci`
123
-
124
- **예시**:
125
- ```bash
126
- feat: 사용자 인증 API 추가
127
- fix: JWT 토큰 검증 오류 수정
128
- docs: API 문서 업데이트
129
- ```
17
+ | 분류 | 금지 항목 |
18
+ |------|----------|
19
+ | **Git** | `Generated with Claude Code`, `🤖`, `Co-Authored-By:`, 여러 줄 커밋, 이모지 |
20
+ | **Prisma** | `db push`, `migrate`, `generate` 자동 실행, schema 임의 변경 |
21
+ | **API** | handler 내부 수동 검증 (→ zValidator), 수동 인증 (→ middleware), 일반 Error throw (→ HTTPException) |
22
+ | **검색** | grep, rg, find (→ ast-grep 사용) |
130
23
 
131
24
  ---
132
25
 
133
- ## 📚 문서 참조 테이블
26
+ ## ALWAYS - 필수 사항
134
27
 
135
- | 작업 | 문서 경로 | 필독 여부 |
136
- |------|----------|----------|
137
- | **Git 규칙** | `../../commands/git.md` | 🔴 필수 |
138
- | **API 개발** | `docs/library/hono/` | 🔴 필수 |
139
- | **DB** | `docs/library/prisma/` | 🟡 해당 |
140
- | **검증** | `docs/library/zod/` | 🟡 해당 |
141
- | **배포** | `docs/deployment/` | 🟡 해당 |
28
+ | 작업 | 필수 |
29
+ |------|------|
30
+ | 작업 | 관련 docs 읽기 |
31
+ | 코드 검색 | ast-grep 사용 |
32
+ | 복잡한 분석 | Sequential Thinking MCP |
33
+ | 3+ 파일 수정 | gemini-review 실행 |
34
+ | 코드 작성 | UTF-8, 코드 묶음별 한글 주석 |
35
+ | Prisma | Multi-File 구조, 모든 요소 한글 주석 |
142
36
 
143
37
  ---
144
38
 
145
- ## 🛠 Tech Stack (버전 주의)
39
+ ## Tech Stack
146
40
 
147
41
  | 기술 | 버전 | 주의사항 |
148
42
  |------|------|----------|
149
- | Hono | 최신 | Web Standards 기반 서버 프레임워크 |
43
+ | Hono | 최신 | Web Standards 기반 |
150
44
  | TypeScript | 5.x | strict mode |
151
- | Prisma | **7.x** | `prisma-client` (js 아님), output 필수 |
152
- | Zod | **4.x** | `z.email()`, `z.url()` (string().email() 아님) |
153
- | @hono/zod-validator | 최신 | Zod 검증 미들웨어 |
45
+ | Prisma | **7.x** | `prisma-client`, output 필수 |
46
+ | Zod | **4.x** | `z.email()`, `z.url()` (v4 문법) |
154
47
 
155
48
  ---
156
49
 
157
- ## 📁 Directory Structure
158
-
159
- ```
160
- src/
161
- ├── index.ts # Entry point
162
- ├── routes/ # 라우트 모듈
163
- │ ├── index.ts # 라우트 통합
164
- │ ├── users.ts # /users 라우트
165
- │ └── posts.ts # /posts 라우트
166
- ├── middleware/ # 미들웨어
167
- │ ├── auth.ts # 인증 미들웨어
168
- │ └── logger.ts # 로깅 미들웨어
169
- ├── validators/ # Zod 스키마
170
- │ ├── user.ts # 사용자 스키마
171
- │ └── post.ts # 게시글 스키마
172
- ├── services/ # 비즈니스 로직
173
- │ └── user.service.ts # 사용자 서비스
174
- ├── database/ # DB 연결
175
- │ └── prisma.ts # Prisma Client
176
- ├── types/ # 타입 정의
177
- │ └── env.d.ts # 환경변수 타입
178
- └── lib/ # 유틸리티
179
- └── errors.ts # 커스텀 에러
180
- ```
181
-
182
- ---
183
-
184
- ## 🔧 Code Conventions
185
-
186
- ### File Naming
187
- - **kebab-case**: `user-service.ts`, `auth-middleware.ts`
188
- - **라우트 파일**: `users.ts`, `posts.ts`
189
-
190
- ### TypeScript
191
- - `const` 선언 사용 (function 대신)
192
- - 명시적 return type
193
- - `interface` (객체) / `type` (유니온)
194
- - `any` 금지 → `unknown` 사용
195
-
196
- ### Import
197
- ```typescript
198
- // @/ → ./src/
199
- import { prisma } from '@/database/prisma'
200
- import { userSchema } from '@/validators/user'
201
- ```
202
-
203
- **순서**: 외부 → 내부(@/) → 상대경로 → type imports
204
-
205
- ---
50
+ ## Quick Patterns
206
51
 
207
- ## 📝 Quick Patterns (복사용)
52
+ ### App + 에러 핸들러
208
53
 
209
- ### App 설정
210
54
  ```typescript
211
55
  import { Hono } from 'hono'
212
56
  import { HTTPException } from 'hono/http-exception'
213
57
 
214
- type Bindings = {
215
- DATABASE_URL: string
216
- JWT_SECRET: string
217
- }
58
+ type Bindings = { DATABASE_URL: string; JWT_SECRET: string }
218
59
 
219
60
  const app = new Hono<{ Bindings: Bindings }>()
220
61
 
221
- // 글로벌 에러 핸들러
222
62
  app.onError((err, c) => {
223
63
  if (err instanceof HTTPException) {
224
64
  return c.json({ error: err.message }, err.status)
@@ -227,172 +67,59 @@ app.onError((err, c) => {
227
67
  return c.json({ error: 'Internal Server Error' }, 500)
228
68
  })
229
69
 
230
- // 404 핸들러
231
- app.notFound((c) => {
232
- return c.json({ error: 'Not Found', path: c.req.path }, 404)
233
- })
70
+ app.notFound((c) => c.json({ error: 'Not Found' }, 404))
234
71
 
235
72
  export default app
236
73
  ```
237
74
 
238
- ### 라우트 + Zod 검증 (GET)
239
- ```typescript
240
- import { Hono } from 'hono'
241
- import { zValidator } from '@hono/zod-validator'
242
- import { z } from 'zod'
243
-
244
- const app = new Hono()
75
+ ### Zod 검증 (v4 문법)
245
76
 
246
- // ✅ 올바른 패턴: zValidator 사용
247
- const querySchema = z.object({
248
- page: z.coerce.number().positive().optional(),
249
- limit: z.coerce.number().max(100).optional(),
250
- })
251
-
252
- app.get('/users', zValidator('query', querySchema), (c) => {
253
- const { page = 1, limit = 10 } = c.req.valid('query')
254
- return c.json({ page, limit, users: [] })
255
- })
256
- ```
257
-
258
- ### 라우트 + Zod 검증 (POST)
259
77
  ```typescript
260
78
  import { zValidator } from '@hono/zod-validator'
261
79
  import { z } from 'zod'
262
80
 
263
- // Zod v4 문법
264
- const createUserSchema = z.object({
265
- email: z.email(), // ✅ v4
81
+ const schema = z.object({
82
+ email: z.email(), // ✅ v4
266
83
  name: z.string().min(1).trim(),
267
- website: z.url().optional(), // ✅ v4
84
+ website: z.url().optional() // ✅ v4
268
85
  })
269
86
 
270
- app.post('/users', zValidator('json', createUserSchema), async (c) => {
87
+ app.post('/users', zValidator('json', schema), (c) => {
271
88
  const data = c.req.valid('json')
272
- // prisma.user.create({ data })
273
89
  return c.json({ user: data }, 201)
274
90
  })
275
91
  ```
276
92
 
277
- ### 잘못된 패턴 (금지)
278
- ```typescript
279
- // ❌ handler 내부에서 수동 검증 금지
280
- app.post('/users', async (c) => {
281
- const body = await c.req.json()
282
- // ❌ 이렇게 하지 마세요!
283
- if (!body.email) {
284
- return c.json({ error: 'Email required' }, 400)
285
- }
286
- })
93
+ ### Prisma Multi-File 구조
287
94
 
288
- // ❌ 일반 Error throw 금지
289
- app.get('/user/:id', async (c) => {
290
- throw new Error('Not found') // ❌ HTTPException 사용해야 함
291
- })
292
95
  ```
293
-
294
- ### HTTPException 사용
295
- ```typescript
296
- import { HTTPException } from 'hono/http-exception'
297
-
298
- app.get('/users/:id', async (c) => {
299
- const id = c.req.param('id')
300
- const user = await prisma.user.findUnique({ where: { id } })
301
-
302
- if (!user) {
303
- throw new HTTPException(404, { message: 'User not found' })
304
- }
305
-
306
- return c.json({ user })
307
- })
96
+ prisma/schema/
97
+ ├── +base.prisma # datasource, generator
98
+ ├── +enum.prisma # enum 정의
99
+ ├── user.prisma # User 모델 (한글 주석 필수)
100
+ └── post.prisma # Post 모델
308
101
  ```
309
102
 
310
- ### 인증 미들웨어
311
- ```typescript
312
- import { createMiddleware } from 'hono/factory'
313
- import { HTTPException } from 'hono/http-exception'
314
-
315
- type Env = {
316
- Variables: {
317
- userId: string
318
- }
103
+ ```prisma
104
+ // +base.prisma
105
+ generator client {
106
+ provider = "prisma-client" // v7
107
+ output = "./generated/client" // ✅ 필수
319
108
  }
320
-
321
- export const authMiddleware = createMiddleware<Env>(async (c, next) => {
322
- const token = c.req.header('Authorization')?.replace('Bearer ', '')
323
-
324
- if (!token) {
325
- throw new HTTPException(401, { message: 'Unauthorized' })
326
- }
327
-
328
- // JWT 검증 로직
329
- const payload = verifyToken(token)
330
- c.set('userId', payload.sub)
331
-
332
- await next()
333
- })
334
-
335
- // 사용
336
- app.get('/me', authMiddleware, (c) => {
337
- const userId = c.get('userId')
338
- return c.json({ userId })
339
- })
340
109
  ```
341
110
 
342
- ### Zod Schema (v4 문법!)
343
- ```typescript
344
- import { z } from 'zod'
111
+ ---
345
112
 
346
- const schema = z.object({
347
- email: z.email(), // ✅ v4
348
- name: z.string().min(1).trim(),
349
- website: z.url().optional(), // ✅ v4
350
- age: z.number().min(0),
351
- })
113
+ ## 문서 구조
352
114
 
353
- // 커스텀 에러 핸들링
354
- app.post(
355
- '/users',
356
- zValidator('json', schema, (result, c) => {
357
- if (!result.success) {
358
- return c.json({ errors: result.error.flatten() }, 400)
359
- }
360
- }),
361
- (c) => {
362
- const data = c.req.valid('json')
363
- return c.json({ user: data }, 201)
364
- }
365
- )
366
115
  ```
367
-
368
- ### RPC Client (Type-safe)
369
- ```typescript
370
- // server.ts
371
- const app = new Hono()
372
- .get('/users', (c) => c.json({ users: [] }))
373
- .post('/users', zValidator('json', createUserSchema), (c) => {
374
- const data = c.req.valid('json')
375
- return c.json({ user: data }, 201)
376
- })
377
-
378
- export type AppType = typeof app
379
-
380
- // client.ts
381
- import { hc } from 'hono/client'
382
- import type { AppType } from './server'
383
-
384
- const client = hc<AppType>('http://localhost:8787/')
385
-
386
- // Type-safe API 호출
387
- const res = await client.users.$get()
388
- const data = await res.json() // { users: [] }
116
+ docs/
117
+ ├── library/
118
+ │ ├── hono/ # 라우팅, 미들웨어, 검증, RPC
119
+ │ ├── prisma/ # CRUD, 관계, D1 연동
120
+ │ ├── zod/ # v4 문법, 검증 패턴
121
+ │ ├── ai-sdk/ # LLM 통합 (streaming, tools)
122
+ │ └── pino/ # 로깅
123
+ ├── deployment/ # Docker, Railway, Vercel, Cloudflare
124
+ └── architecture/ # 아키텍처 패턴
389
125
  ```
390
-
391
- ---
392
-
393
- ## 🔗 Quick Links
394
-
395
- - [Hono 가이드](./docs/library/hono/index.md)
396
- - [Git 규칙](../../commands/git.md)
397
- - [MCP 가이드](./docs/mcp/index.md)
398
- - [배포 가이드](./docs/deployment/index.md)