@kood/claude-code 0.3.5 → 0.3.7

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 (35) hide show
  1. package/dist/index.js +1 -1
  2. package/package.json +1 -1
  3. package/templates/nextjs/CLAUDE.md +228 -0
  4. package/templates/nextjs/docs/design.md +558 -0
  5. package/templates/nextjs/docs/guides/conventions.md +343 -0
  6. package/templates/nextjs/docs/guides/getting-started.md +367 -0
  7. package/templates/nextjs/docs/guides/routes.md +342 -0
  8. package/templates/nextjs/docs/library/better-auth/index.md +541 -0
  9. package/templates/nextjs/docs/library/nextjs/app-router.md +269 -0
  10. package/templates/nextjs/docs/library/nextjs/caching.md +351 -0
  11. package/templates/nextjs/docs/library/nextjs/index.md +291 -0
  12. package/templates/nextjs/docs/library/nextjs/middleware.md +391 -0
  13. package/templates/nextjs/docs/library/nextjs/route-handlers.md +382 -0
  14. package/templates/nextjs/docs/library/nextjs/server-actions.md +366 -0
  15. package/templates/nextjs/docs/library/prisma/cloudflare-d1.md +76 -0
  16. package/templates/nextjs/docs/library/prisma/config.md +77 -0
  17. package/templates/nextjs/docs/library/prisma/crud.md +90 -0
  18. package/templates/nextjs/docs/library/prisma/index.md +73 -0
  19. package/templates/nextjs/docs/library/prisma/relations.md +69 -0
  20. package/templates/nextjs/docs/library/prisma/schema.md +98 -0
  21. package/templates/nextjs/docs/library/prisma/setup.md +49 -0
  22. package/templates/nextjs/docs/library/prisma/transactions.md +50 -0
  23. package/templates/nextjs/docs/library/tanstack-query/index.md +66 -0
  24. package/templates/nextjs/docs/library/tanstack-query/invalidation.md +54 -0
  25. package/templates/nextjs/docs/library/tanstack-query/optimistic-updates.md +77 -0
  26. package/templates/nextjs/docs/library/tanstack-query/use-mutation.md +63 -0
  27. package/templates/nextjs/docs/library/tanstack-query/use-query.md +70 -0
  28. package/templates/nextjs/docs/library/zod/complex-types.md +61 -0
  29. package/templates/nextjs/docs/library/zod/index.md +56 -0
  30. package/templates/nextjs/docs/library/zod/transforms.md +51 -0
  31. package/templates/nextjs/docs/library/zod/validation.md +70 -0
  32. package/templates/tanstack-start/CLAUDE.md +7 -3
  33. package/templates/tanstack-start/docs/architecture.md +38 -7
  34. package/templates/tanstack-start/docs/guides/hooks.md +28 -0
  35. package/templates/tanstack-start/docs/guides/routes.md +29 -10
@@ -0,0 +1,342 @@
1
+ # Routes
2
+
3
+ > Next.js App Router 라우팅 패턴
4
+
5
+ ---
6
+
7
+ ## 기본 라우팅
8
+
9
+ | 파일 | 라우트 |
10
+ |------|--------|
11
+ | `app/page.tsx` | `/` |
12
+ | `app/about/page.tsx` | `/about` |
13
+ | `app/blog/page.tsx` | `/blog` |
14
+ | `app/blog/[slug]/page.tsx` | `/blog/:slug` |
15
+
16
+ ---
17
+
18
+ ## 동적 라우트
19
+
20
+ ### 단일 파라미터
21
+
22
+ ```typescript
23
+ // app/posts/[id]/page.tsx
24
+ interface PageProps {
25
+ params: { id: string }
26
+ }
27
+
28
+ export default async function PostPage({ params }: PageProps) {
29
+ const post = await prisma.post.findUnique({ where: { id: params.id } })
30
+
31
+ if (!post) notFound()
32
+
33
+ return <article>{post.title}</article>
34
+ }
35
+
36
+ // 정적 생성
37
+ export async function generateStaticParams() {
38
+ const posts = await prisma.post.findMany({ select: { id: true } })
39
+ return posts.map(post => ({ id: post.id }))
40
+ }
41
+ ```
42
+
43
+ ### Catch-all
44
+
45
+ ```typescript
46
+ // app/docs/[...slug]/page.tsx
47
+ interface PageProps {
48
+ params: { slug: string[] }
49
+ }
50
+
51
+ export default function DocsPage({ params }: PageProps) {
52
+ // /docs/a/b/c → params.slug = ["a", "b", "c"]
53
+ const path = params.slug.join("/")
54
+ return <div>{path}</div>
55
+ }
56
+ ```
57
+
58
+ ---
59
+
60
+ ## 레이아웃
61
+
62
+ ### Root Layout (필수)
63
+
64
+ ```typescript
65
+ // app/layout.tsx
66
+ import { Providers } from "./providers"
67
+
68
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
69
+ return (
70
+ <html lang="ko">
71
+ <body>
72
+ <Providers>{children}</Providers>
73
+ </body>
74
+ </html>
75
+ )
76
+ }
77
+ ```
78
+
79
+ ### 중첩 Layout
80
+
81
+ ```typescript
82
+ // app/dashboard/layout.tsx
83
+ import { auth } from "@/lib/auth"
84
+ import { headers } from "next/headers"
85
+ import { redirect } from "next/navigation"
86
+
87
+ export default async function DashboardLayout({ children }: { children: React.ReactNode }) {
88
+ // 인증 체크
89
+ const session = await auth.api.getSession({ headers: headers() })
90
+ if (!session?.user) redirect("/login")
91
+
92
+ return (
93
+ <div>
94
+ <nav>Dashboard Nav</nav>
95
+ <main>{children}</main>
96
+ </div>
97
+ )
98
+ }
99
+ ```
100
+
101
+ ---
102
+
103
+ ## Route Groups
104
+
105
+ ```
106
+ app/
107
+ ├── (marketing)/
108
+ │ ├── layout.tsx # Marketing layout
109
+ │ ├── page.tsx # /
110
+ │ └── about/
111
+ │ └── page.tsx # /about
112
+ └── (shop)/
113
+ ├── layout.tsx # Shop layout
114
+ └── products/
115
+ └── page.tsx # /products
116
+ ```
117
+
118
+ **용도:** URL에 영향 없이 다른 레이아웃 적용
119
+
120
+ ---
121
+
122
+ ## Loading & Error
123
+
124
+ ### Loading UI
125
+
126
+ ```typescript
127
+ // app/posts/loading.tsx
128
+ export default function Loading() {
129
+ return <div>Loading posts...</div>
130
+ }
131
+ ```
132
+
133
+ ### Error UI
134
+
135
+ ```typescript
136
+ // app/posts/error.tsx
137
+ "use client"
138
+
139
+ export default function Error({ error, reset }: { error: Error; reset: () => void }) {
140
+ return (
141
+ <div>
142
+ <h2>오류 발생: {error.message}</h2>
143
+ <button onClick={reset}>다시 시도</button>
144
+ </div>
145
+ )
146
+ }
147
+ ```
148
+
149
+ ### Not Found
150
+
151
+ ```typescript
152
+ // app/posts/[id]/not-found.tsx
153
+ export default function NotFound() {
154
+ return <div>게시글을 찾을 수 없습니다</div>
155
+ }
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Metadata
161
+
162
+ ### 정적
163
+
164
+ ```typescript
165
+ // app/about/page.tsx
166
+ import type { Metadata } from "next"
167
+
168
+ export const metadata: Metadata = {
169
+ title: "About Us",
170
+ description: "Learn more about our company",
171
+ }
172
+
173
+ export default function AboutPage() {
174
+ return <div>About</div>
175
+ }
176
+ ```
177
+
178
+ ### 동적
179
+
180
+ ```typescript
181
+ // app/posts/[id]/page.tsx
182
+ import type { Metadata } from "next"
183
+
184
+ export async function generateMetadata({ params }: { params: { id: string } }): Promise<Metadata> {
185
+ const post = await prisma.post.findUnique({ where: { id: params.id } })
186
+
187
+ if (!post) {
188
+ return {
189
+ title: "Post Not Found",
190
+ }
191
+ }
192
+
193
+ return {
194
+ title: post.title,
195
+ description: post.excerpt,
196
+ openGraph: {
197
+ title: post.title,
198
+ description: post.excerpt,
199
+ images: [post.image],
200
+ },
201
+ }
202
+ }
203
+ ```
204
+
205
+ ---
206
+
207
+ ## 네비게이션
208
+
209
+ ### Link
210
+
211
+ ```typescript
212
+ import Link from "next/link"
213
+
214
+ export function Navigation() {
215
+ return (
216
+ <nav>
217
+ <Link href="/">Home</Link>
218
+ <Link href="/about">About</Link>
219
+ <Link href="/posts">Posts</Link>
220
+ </nav>
221
+ )
222
+ }
223
+ ```
224
+
225
+ ### useRouter
226
+
227
+ ```typescript
228
+ "use client"
229
+
230
+ import { useRouter } from "next/navigation"
231
+
232
+ export function LoginButton() {
233
+ const router = useRouter()
234
+
235
+ return (
236
+ <button onClick={() => router.push("/login")}>
237
+ Login
238
+ </button>
239
+ )
240
+ }
241
+ ```
242
+
243
+ ---
244
+
245
+ ## 인증 보호
246
+
247
+ ### Layout에서 체크
248
+
249
+ ```typescript
250
+ // app/dashboard/layout.tsx
251
+ import { auth } from "@/lib/auth"
252
+ import { headers } from "next/headers"
253
+ import { redirect } from "next/navigation"
254
+
255
+ export default async function DashboardLayout({ children }: { children: React.ReactNode }) {
256
+ const session = await auth.api.getSession({ headers: headers() })
257
+
258
+ if (!session?.user) {
259
+ redirect("/login")
260
+ }
261
+
262
+ return <div>{children}</div>
263
+ }
264
+ ```
265
+
266
+ ### Middleware에서 체크
267
+
268
+ ```typescript
269
+ // middleware.ts
270
+ import { auth } from "@/lib/auth"
271
+ import { NextResponse } from "next/server"
272
+ import type { NextRequest } from "next/server"
273
+
274
+ export async function middleware(request: NextRequest) {
275
+ const session = await auth.api.getSession({ headers: request.headers })
276
+
277
+ if (!session?.user) {
278
+ return NextResponse.redirect(new URL("/login", request.url))
279
+ }
280
+
281
+ return NextResponse.next()
282
+ }
283
+
284
+ export const config = {
285
+ matcher: ["/dashboard/:path*", "/profile/:path*"],
286
+ }
287
+ ```
288
+
289
+ ---
290
+
291
+ ## 베스트 프랙티스
292
+
293
+ ### ✅ DO
294
+
295
+ ```typescript
296
+ // 1. Server Component에서 직접 데이터 페칭
297
+ export default async function PostsPage() {
298
+ const posts = await prisma.post.findMany()
299
+ return <PostsList posts={posts} />
300
+ }
301
+
302
+ // 2. 레이아웃에서 인증 체크
303
+ export default async function DashboardLayout({ children }) {
304
+ const session = await auth.api.getSession({ headers: headers() })
305
+ if (!session?.user) redirect("/login")
306
+ return <div>{children}</div>
307
+ }
308
+
309
+ // 3. generateStaticParams로 정적 생성
310
+ export async function generateStaticParams() {
311
+ const posts = await prisma.post.findMany({ select: { id: true } })
312
+ return posts.map(post => ({ id: post.id }))
313
+ }
314
+ ```
315
+
316
+ ### ❌ DON'T
317
+
318
+ ```typescript
319
+ // 1. Client Component에서 async/await
320
+ "use client"
321
+ export default async function PostsPage() { // ❌
322
+ const posts = await prisma.post.findMany()
323
+ return <PostsList posts={posts} />
324
+ }
325
+
326
+ // 2. 페이지마다 인증 체크 반복
327
+ export default async function Page1() {
328
+ const session = await auth.api.getSession({ headers: headers() }) // ❌ 중복
329
+ if (!session) redirect("/login")
330
+ }
331
+
332
+ // 3. 하드코딩된 경로
333
+ <Link href="/posts/123">Post</Link> // ❌ 하드코딩
334
+ ```
335
+
336
+ ---
337
+
338
+ ## 참조
339
+
340
+ - [App Router](../library/nextjs/app-router.md)
341
+ - [Server Actions](server-actions.md)
342
+ - [Client Components](client-components.md)