@kood/claude-code 0.6.6 → 0.7.0

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 (170) hide show
  1. package/dist/index.js +7 -1
  2. package/package.json +1 -1
  3. package/templates/.claude/agents/analyst.md +5 -0
  4. package/templates/.claude/agents/architect.md +5 -0
  5. package/templates/.claude/agents/build-fixer.md +1 -0
  6. package/templates/.claude/agents/code-reviewer.md +1 -0
  7. package/templates/.claude/agents/critic.md +4 -0
  8. package/templates/.claude/agents/deep-executor.md +1 -0
  9. package/templates/.claude/agents/dependency-manager.md +2 -0
  10. package/templates/.claude/agents/deployment-validator.md +2 -0
  11. package/templates/.claude/agents/designer.md +2 -0
  12. package/templates/.claude/agents/document-writer.md +3 -0
  13. package/templates/.claude/agents/explore.md +1 -0
  14. package/templates/.claude/agents/git-operator.md +2 -0
  15. package/templates/.claude/agents/implementation-executor.md +2 -0
  16. package/templates/.claude/agents/ko-to-en-translator.md +3 -0
  17. package/templates/.claude/agents/lint-fixer.md +2 -0
  18. package/templates/.claude/agents/planner.md +3 -0
  19. package/templates/.claude/agents/pm.md +349 -0
  20. package/templates/.claude/agents/qa-tester.md +1 -0
  21. package/templates/.claude/agents/refactor-advisor.md +4 -0
  22. package/templates/.claude/agents/researcher.md +9 -1
  23. package/templates/.claude/agents/scientist.md +1 -0
  24. package/templates/.claude/agents/security-reviewer.md +1 -0
  25. package/templates/.claude/agents/tdd-guide.md +1 -0
  26. package/templates/.claude/agents/vision.md +1 -0
  27. package/templates/.claude/instructions/agent-patterns/agent-teams-usage.md +376 -0
  28. package/templates/.claude/instructions/sourcing/reliable-search.md +49 -2
  29. package/templates/.claude/scripts/agent-teams/check-availability.sh +238 -0
  30. package/templates/.claude/scripts/agent-teams/setup-tmux.sh +125 -0
  31. package/templates/.claude/skills/agent-teams-setup/SKILL.md +460 -0
  32. package/templates/.claude/skills/brainstorm/SKILL.md +1 -0
  33. package/templates/.claude/skills/bug-fix/SKILL.md +1 -0
  34. package/templates/.claude/skills/crawler/SKILL.md +2 -0
  35. package/templates/.claude/skills/docs-creator/SKILL.md +1 -0
  36. package/templates/.claude/skills/docs-fetch/SKILL.md +6 -4
  37. package/templates/.claude/skills/docs-refactor/SKILL.md +1 -0
  38. package/templates/.claude/skills/elon-musk/SKILL.md +1 -0
  39. package/templates/.claude/skills/execute/SKILL.md +1 -0
  40. package/templates/.claude/skills/feedback/SKILL.md +1 -0
  41. package/templates/.claude/skills/figma-to-code/SKILL.md +1 -0
  42. package/templates/.claude/skills/genius-thinking/SKILL.md +1 -0
  43. package/templates/.claude/skills/global-uiux-design/SKILL.md +1 -0
  44. package/templates/.claude/skills/korea-uiux-design/SKILL.md +1 -0
  45. package/templates/.claude/skills/nextjs-react-best-practices/SKILL.md +1 -0
  46. package/templates/.claude/skills/plan/SKILL.md +1 -0
  47. package/templates/.claude/skills/prd/SKILL.md +1 -0
  48. package/templates/.claude/skills/project-optimizer/AGENTS.md +275 -0
  49. package/templates/.claude/skills/project-optimizer/SKILL.md +375 -0
  50. package/templates/.claude/skills/project-optimizer/rules/arch-config-centralize.md +66 -0
  51. package/templates/.claude/skills/project-optimizer/rules/arch-hot-path.md +35 -0
  52. package/templates/.claude/skills/project-optimizer/rules/arch-interface-segregation.md +51 -0
  53. package/templates/.claude/skills/project-optimizer/rules/arch-module-boundary.md +42 -0
  54. package/templates/.claude/skills/project-optimizer/rules/build-cache.md +57 -0
  55. package/templates/.claude/skills/project-optimizer/rules/build-code-split.md +56 -0
  56. package/templates/.claude/skills/project-optimizer/rules/build-incremental.md +65 -0
  57. package/templates/.claude/skills/project-optimizer/rules/build-minify.md +61 -0
  58. package/templates/.claude/skills/project-optimizer/rules/build-tree-shake.md +60 -0
  59. package/templates/.claude/skills/project-optimizer/rules/code-complexity.md +65 -0
  60. package/templates/.claude/skills/project-optimizer/rules/code-dead-elimination.md +32 -0
  61. package/templates/.claude/skills/project-optimizer/rules/code-duplication.md +54 -0
  62. package/templates/.claude/skills/project-optimizer/rules/code-error-handling.md +75 -0
  63. package/templates/.claude/skills/project-optimizer/rules/code-naming.md +52 -0
  64. package/templates/.claude/skills/project-optimizer/rules/concurrency-defer-await.md +54 -0
  65. package/templates/.claude/skills/project-optimizer/rules/concurrency-parallel.md +90 -0
  66. package/templates/.claude/skills/project-optimizer/rules/concurrency-pipeline.md +68 -0
  67. package/templates/.claude/skills/project-optimizer/rules/concurrency-pool.md +68 -0
  68. package/templates/.claude/skills/project-optimizer/rules/deps-lightweight-alt.md +37 -0
  69. package/templates/.claude/skills/project-optimizer/rules/deps-peer-align.md +44 -0
  70. package/templates/.claude/skills/project-optimizer/rules/deps-security-audit.md +45 -0
  71. package/templates/.claude/skills/project-optimizer/rules/deps-unused-removal.md +25 -0
  72. package/templates/.claude/skills/project-optimizer/rules/deps-version-pin.md +40 -0
  73. package/templates/.claude/skills/project-optimizer/rules/dx-ci-speed.md +47 -0
  74. package/templates/.claude/skills/project-optimizer/rules/dx-dev-server.md +35 -0
  75. package/templates/.claude/skills/project-optimizer/rules/dx-lint-config.md +36 -0
  76. package/templates/.claude/skills/project-optimizer/rules/dx-test-coverage.md +34 -0
  77. package/templates/.claude/skills/project-optimizer/rules/dx-type-safety.md +49 -0
  78. package/templates/.claude/skills/project-optimizer/rules/io-batch-queries.md +67 -0
  79. package/templates/.claude/skills/project-optimizer/rules/io-cache-layer.md +67 -0
  80. package/templates/.claude/skills/project-optimizer/rules/io-connection-reuse.md +67 -0
  81. package/templates/.claude/skills/project-optimizer/rules/io-serialize-minimal.md +61 -0
  82. package/templates/.claude/skills/project-optimizer/rules/io-stream.md +75 -0
  83. package/templates/.claude/skills/project-optimizer/rules/memory-bounded-cache.md +65 -0
  84. package/templates/.claude/skills/project-optimizer/rules/memory-large-data.md +64 -0
  85. package/templates/.claude/skills/project-optimizer/rules/memory-lazy-init.md +78 -0
  86. package/templates/.claude/skills/project-optimizer/rules/memory-leak-prevention.md +79 -0
  87. package/templates/.claude/skills/project-optimizer/rules/memory-pool-reuse.md +70 -0
  88. package/templates/.claude/skills/ralph/SKILL.md +1 -0
  89. package/templates/.claude/skills/refactor/SKILL.md +1 -0
  90. package/templates/.claude/skills/research/SKILL.md +1 -0
  91. package/templates/.claude/skills/sql-optimizer/SKILL.md +438 -0
  92. package/templates/.claude/skills/sql-optimizer/orm-patterns.md +218 -0
  93. package/templates/.claude/skills/startup-validator/SKILL.md +1 -0
  94. package/templates/.claude/skills/tanstack-start-react-best-practices/AGENTS.md +53 -14
  95. package/templates/.claude/skills/tanstack-start-react-best-practices/SKILL.md +94 -27
  96. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-defer-third-party.md +42 -19
  97. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-optimistic-updates.md +109 -0
  98. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-suspense-query.md +74 -0
  99. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-use-hook.md +81 -0
  100. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-react-compiler.md +81 -0
  101. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-beforeload-auth.md +121 -0
  102. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-file-conventions.md +104 -0
  103. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-link-navigation.md +119 -0
  104. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-nested-layouts.md +155 -0
  105. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-path-params.md +89 -0
  106. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-pending-component.md +110 -0
  107. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-preload-strategy.md +91 -0
  108. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-router-context.md +120 -0
  109. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-search-params.md +114 -0
  110. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-deferred-data.md +1 -1
  111. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-error-boundaries.md +79 -0
  112. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-middleware.md +85 -0
  113. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-serialization.md +56 -21
  114. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-streaming.md +84 -0
  115. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-validator.md +71 -0
  116. package/templates/.claude/skills/tauri-react-best-practices/AGENTS.md +527 -0
  117. package/templates/.claude/skills/tauri-react-best-practices/SKILL.md +571 -0
  118. package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-barrel-imports.md +140 -0
  119. package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-cargo-profile.md +96 -0
  120. package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-frontend-treeshake.md +242 -0
  121. package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-lazy-components.md +255 -0
  122. package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-remove-unused-commands.md +160 -0
  123. package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-ci-pipeline.md +269 -0
  124. package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-signing.md +207 -0
  125. package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-updater.md +226 -0
  126. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-async-commands.md +172 -0
  127. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-batch-commands.md +133 -0
  128. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-binary-response.md +198 -0
  129. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-channel-streaming.md +186 -0
  130. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-error-handling.md +250 -0
  131. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-type-safe.md +227 -0
  132. package/templates/.claude/skills/tauri-react-best-practices/rules/perf-derived-state.md +231 -0
  133. package/templates/.claude/skills/tauri-react-best-practices/rules/perf-functional-setstate.md +191 -0
  134. package/templates/.claude/skills/tauri-react-best-practices/rules/perf-index-maps.md +276 -0
  135. package/templates/.claude/skills/tauri-react-best-practices/rules/perf-lazy-state-init.md +196 -0
  136. package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-lifecycle.md +265 -0
  137. package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-mobile-compat.md +199 -0
  138. package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-permission-scope.md +193 -0
  139. package/templates/.claude/skills/tauri-react-best-practices/rules/react-error-boundary.md +239 -0
  140. package/templates/.claude/skills/tauri-react-best-practices/rules/react-event-listener.md +151 -0
  141. package/templates/.claude/skills/tauri-react-best-practices/rules/react-file-src.md +155 -0
  142. package/templates/.claude/skills/tauri-react-best-practices/rules/react-invoke-hook.md +139 -0
  143. package/templates/.claude/skills/tauri-react-best-practices/rules/react-optimistic-update.md +211 -0
  144. package/templates/.claude/skills/tauri-react-best-practices/rules/security-capability-split.md +205 -0
  145. package/templates/.claude/skills/tauri-react-best-practices/rules/security-csp.md +207 -0
  146. package/templates/.claude/skills/tauri-react-best-practices/rules/security-least-privilege.md +106 -0
  147. package/templates/.claude/skills/tauri-react-best-practices/rules/security-no-wildcard.md +253 -0
  148. package/templates/.claude/skills/tauri-react-best-practices/rules/security-scope-paths.md +160 -0
  149. package/templates/.claude/skills/tauri-react-best-practices/rules/state-async-mutex.md +270 -0
  150. package/templates/.claude/skills/tauri-react-best-practices/rules/state-mutex-pattern.md +265 -0
  151. package/templates/.claude/skills/tauri-react-best-practices/rules/state-react-sync.md +375 -0
  152. package/templates/.claude/skills/tauri-react-best-practices/rules/state-single-container.md +275 -0
  153. package/templates/tanstack-start/docs/architecture.md +238 -167
  154. package/templates/tanstack-start/docs/library/tanstack-router/error-handling.md +777 -38
  155. package/templates/tanstack-start/docs/library/tanstack-router/hooks.md +549 -37
  156. package/templates/tanstack-start/docs/library/tanstack-router/index.md +895 -111
  157. package/templates/tanstack-start/docs/library/tanstack-router/navigation.md +641 -43
  158. package/templates/tanstack-start/docs/library/tanstack-router/route-context.md +889 -38
  159. package/templates/tanstack-start/docs/library/tanstack-router/search-params.md +891 -29
  160. package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +972 -36
  161. package/templates/tanstack-start/docs/library/tanstack-start/index.md +1525 -881
  162. package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +1099 -20
  163. package/templates/tanstack-start/docs/library/tanstack-start/routing.md +796 -30
  164. package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +953 -35
  165. package/templates/tanstack-start/docs/library/tanstack-start/setup.md +371 -15
  166. package/templates/tauri/CLAUDE.md +189 -0
  167. package/templates/tauri/docs/guides/distribution.md +261 -0
  168. package/templates/tauri/docs/guides/getting-started.md +302 -0
  169. package/templates/tauri/docs/guides/mobile.md +288 -0
  170. package/templates/tauri/docs/library/tauri/index.md +510 -0
@@ -1,59 +1,825 @@
1
1
  # TanStack Start - Routing
2
2
 
3
- <patterns>
3
+ > File-based routing with TanStack Router (v1.159.4)
4
+
5
+ ---
6
+
7
+ <overview>
8
+
9
+ ## File-based Routing
10
+
11
+ TanStack Start는 TanStack Router 위에 구축되어 있으며, Router의 모든 기능을 사용할 수 있습니다. 파일 시스템 구조로 라우팅이 자동 생성됩니다.
12
+
13
+ | 개념 | 설명 |
14
+ |------|------|
15
+ | **File-based** | 파일 경로 = URL 경로 |
16
+ | **Dynamic Routes** | `$param.tsx` = `/:param` |
17
+ | **Nested Routes** | 폴더 구조 = 계층 라우트 |
18
+ | **Server Routes** | API 엔드포인트 (Server Functions 대신) |
19
+ | **Loader** | 라우트 로드 시 데이터 사전 로드 |
20
+ | **SSR** | 서버 사이드 렌더링 옵션 (true/false/'data-only') |
21
+ | **Pathless Layout** | URL 경로 없이 레이아웃/로직 적용 |
22
+ | **Non-Nested** | 부모 경로에서 언네스팅 |
23
+ | **Grouped** | 디렉토리 그룹핑 (경로 계층 영향 없음) |
24
+
25
+ </overview>
26
+
27
+ ---
28
+
29
+ <router_config>
30
+
31
+ ## Router 설정
32
+
33
+ `src/router.tsx` 파일에서 라우터 동작을 설정합니다.
34
+
35
+ ```typescript
36
+ // src/router.tsx
37
+ import { createRouter } from '@tanstack/react-router'
38
+ import { routeTree } from './routeTree.gen'
39
+
40
+ // 매번 새 router 인스턴스를 반환하는 함수 export
41
+ export function getRouter() {
42
+ const router = createRouter({
43
+ routeTree,
44
+ scrollRestoration: true,
45
+ })
46
+
47
+ return router
48
+ }
49
+ ```
50
+
51
+ > **참고:** `routeTree.gen.ts`는 `npm run dev` 또는 `npm run start` 실행 시 자동 생성됩니다. TanStack Start의 타입 안전성은 이 파일에 의존합니다.
52
+
53
+ </router_config>
54
+
55
+ ---
56
+
57
+ <file_structure>
58
+
59
+ ## 파일 구조 -> URL 매핑
60
+
61
+ | 파일 경로 | URL | 타입 |
62
+ |----------|-----|------|
63
+ | `routes/index.tsx` | `/` | Index Route |
64
+ | `routes/about.tsx` | `/about` | Static Route |
65
+ | `routes/posts.tsx` | `/posts` | "Layout" Route |
66
+ | `routes/posts/index.tsx` | `/posts/` | Index Route |
67
+ | `routes/posts/$postId.tsx` | `/posts/:postId` | Dynamic Route |
68
+ | `routes/rest/$.tsx` | `/rest/*` | Wildcard Route |
69
+ | `routes/__root.tsx` | - | Root layout (모든 라우트 부모) |
70
+ | `routes/_authed.tsx` | - | Pathless Layout (인증 레이아웃 등) |
71
+ | `routes/dashboard/_layout.tsx` | - | 중첩 레이아웃 |
72
+
73
+ ### 라우트 타입 정리
74
+
75
+ | 타입 | 설명 | 예시 |
76
+ |------|------|------|
77
+ | **Index Routes** | URL이 정확히 일치 | `index.tsx` |
78
+ | **Dynamic Routes** | URL 일부를 변수로 캡처 | `$postId.tsx` |
79
+ | **Wildcard/Splat** | URL 전체를 캡처 | `$.tsx` |
80
+ | **Pathless Layout** | URL 없이 레이아웃 적용 | `_authed.tsx` |
81
+ | **Non-Nested** | 부모에서 독립 | 별도 컴포넌트 트리 |
82
+ | **Grouped** | 디렉토리 정리용 | 경로 계층 영향 없음 |
83
+
84
+ </file_structure>
85
+
86
+ ---
87
+
88
+ <root_route>
89
+
90
+ ## Root Route (__root.tsx)
91
+
92
+ Root Route는 라우트 트리 최상위이며, 모든 라우트를 감쌉니다.
93
+
94
+ ```tsx
95
+ // src/routes/__root.tsx
96
+ import type { ReactNode } from 'react'
97
+ import {
98
+ Outlet,
99
+ createRootRoute,
100
+ HeadContent,
101
+ Scripts,
102
+ } from '@tanstack/react-router'
103
+
104
+ export const Route = createRootRoute({
105
+ head: () => ({
106
+ meta: [
107
+ { charSet: 'utf-8' },
108
+ { name: 'viewport', content: 'width=device-width, initial-scale=1' },
109
+ { title: 'TanStack Start Starter' },
110
+ ],
111
+ }),
112
+ component: RootComponent,
113
+ })
114
+
115
+ function RootComponent() {
116
+ return (
117
+ <RootDocument>
118
+ <Outlet />
119
+ </RootDocument>
120
+ )
121
+ }
122
+
123
+ function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
124
+ return (
125
+ <html>
126
+ <head>
127
+ <HeadContent />
128
+ </head>
129
+ <body>
130
+ {children}
131
+ <Scripts />
132
+ </body>
133
+ </html>
134
+ )
135
+ }
136
+ ```
137
+
138
+ **특징:**
139
+ - 경로 없음 - **항상** 매칭
140
+ - 컴포넌트가 **항상** 렌더링
141
+ - document shell (`<html>`, `<body>`) 렌더링 장소
142
+ - 전역 로직 처리에 적합
143
+
144
+ **핵심 컴포넌트:**
145
+ | 컴포넌트 | 위치 | 역할 |
146
+ |---------|------|------|
147
+ | `<HeadContent />` | `<head>` 안 | head/title/meta/link/script 렌더링 |
148
+ | `<Outlet />` | 어디든 | 다음 매칭 자식 라우트 렌더링 |
149
+ | `<Scripts />` | `<body>` 안 | 클라이언트 JavaScript 로드 (필수) |
150
+
151
+ </root_route>
152
+
153
+ ---
154
+
155
+ <basic_routes>
156
+
157
+ ## 기본 라우트
158
+
159
+ ### 정적 라우트
4
160
 
5
161
  ```tsx
6
- // 기본
7
- export const Route = createFileRoute('/about')({ component: AboutPage })
162
+ // routes/about.tsx
163
+ import { createFileRoute } from '@tanstack/react-router'
164
+
165
+ export const Route = createFileRoute('/about')({
166
+ component: AboutPage,
167
+ })
168
+
169
+ const AboutPage = (): JSX.Element => {
170
+ return (
171
+ <div>
172
+ <h1>About</h1>
173
+ <p>This is the about page</p>
174
+ </div>
175
+ )
176
+ }
177
+ ```
178
+
179
+ ### 인덱스 라우트
8
180
 
9
- // Loader
181
+ ```tsx
182
+ // routes/index.tsx
10
183
  export const Route = createFileRoute('/')({
11
- component: Page,
12
- loader: async () => fetch('/api/posts').then(r => r.json()),
184
+ component: HomePage,
185
+ })
186
+
187
+ const HomePage = (): JSX.Element => {
188
+ return <h1>Welcome Home</h1>
189
+ }
190
+ ```
191
+
192
+ > **참고:** `createFileRoute`에 전달하는 경로 문자열은 TanStack Router Bundler Plugin이 **자동으로 작성/관리**합니다. 파일 이동이나 이름 변경 시 자동 업데이트됩니다.
193
+
194
+ </basic_routes>
195
+
196
+ ---
197
+
198
+ <nested_routing>
199
+
200
+ ## 중첩 라우팅 (Nested Routing)
201
+
202
+ TanStack Router는 URL을 올바른 컴포넌트 트리에 매칭합니다.
203
+
204
+ ```
205
+ routes/
206
+ ├── __root.tsx # <Root> 렌더링
207
+ ├── posts.tsx # <Posts> 렌더링
208
+ ├── posts/$postId.tsx # <Post> 렌더링
209
+ ```
210
+
211
+ URL: `/posts/123` -> 컴포넌트 트리:
212
+
213
+ ```
214
+ <Root>
215
+ <Posts>
216
+ <Post />
217
+ </Posts>
218
+ </Root>
219
+ ```
220
+
221
+ </nested_routing>
222
+
223
+ ---
224
+
225
+ <loaders>
226
+
227
+ ## Loader: 데이터 사전 로드
228
+
229
+ ### 기본 Loader
230
+
231
+ ```tsx
232
+ // routes/posts/index.tsx
233
+ export const Route = createFileRoute('/posts')({
234
+ loader: async (): Promise<{ posts: Post[] }> => {
235
+ const posts = await getPosts()
236
+ return { posts }
237
+ },
238
+ component: PostsPage,
13
239
  })
14
- const Page = () => {
15
- const posts = Route.useLoaderData()
16
- return <ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>
240
+
241
+ const PostsPage = (): JSX.Element => {
242
+ const { posts } = Route.useLoaderData()
243
+
244
+ return (
245
+ <ul>
246
+ {posts.map((post) => (
247
+ <li key={post.id}>
248
+ <h2>{post.title}</h2>
249
+ </li>
250
+ ))}
251
+ </ul>
252
+ )
17
253
  }
254
+ ```
255
+
256
+ ### Server Function으로 데이터 로드
257
+
258
+ ```tsx
259
+ export const Route = createFileRoute('/dashboard')({
260
+ loader: async (): Promise<{ dashboard: DashboardData }> => {
261
+ const dashboard = await getDashboardData()
262
+ return { dashboard }
263
+ },
264
+ component: DashboardPage,
265
+ })
266
+ ```
267
+
268
+ ### 로더에서 에러 처리
269
+
270
+ ```tsx
271
+ export const Route = createFileRoute('/items/$id')({
272
+ loader: async ({ params }): Promise<{ item: Item }> => {
273
+ try {
274
+ const item = await getItemById(params.id)
275
+ if (!item) {
276
+ throw new Error('Item not found')
277
+ }
278
+ return { item }
279
+ } catch (error) {
280
+ throw redirect({ to: '/items' })
281
+ }
282
+ },
283
+ component: ItemDetailPage,
284
+ })
285
+ ```
286
+
287
+ </loaders>
288
+
289
+ ---
290
+
291
+ <dynamic_routes>
18
292
 
19
- // 동적 라우트
293
+ ## 동적 라우트 ($param)
294
+
295
+ ### 단일 파라미터
296
+
297
+ ```tsx
298
+ // routes/users/$id.tsx
20
299
  export const Route = createFileRoute('/users/$id')({
21
- loader: async ({ params }) => ({ user: await getUserById(params.id) }),
22
- component: () => {
23
- const { user } = Route.useLoaderData()
24
- return <h1>{user.name}</h1>
300
+ loader: async ({ params }): Promise<{ user: User }> => {
301
+ const user = await getUserById(params.id)
302
+ if (!user) {
303
+ throw redirect({ to: '/users' })
304
+ }
305
+ return { user }
306
+ },
307
+ component: UserDetailPage,
308
+ })
309
+
310
+ const UserDetailPage = (): JSX.Element => {
311
+ const { user } = Route.useLoaderData()
312
+ const { id } = Route.useParams()
313
+
314
+ return (
315
+ <div>
316
+ <h1>{user.name}</h1>
317
+ <p>ID: {id}</p>
318
+ </div>
319
+ )
320
+ }
321
+ ```
322
+
323
+ ### 다중 파라미터
324
+
325
+ ```tsx
326
+ // routes/blog/$year/$month/$day.tsx
327
+ export const Route = createFileRoute('/blog/$year/$month/$day')({
328
+ loader: async ({ params }): Promise<{ posts: Post[] }> => {
329
+ const posts = await getPostsByDate(params.year, params.month, params.day)
330
+ return { posts }
331
+ },
332
+ component: BlogArchivePage,
333
+ })
334
+ ```
335
+
336
+ ### Catch-all ($.tsx)
337
+
338
+ ```tsx
339
+ // routes/search/$.tsx
340
+ export const Route = createFileRoute('/search/$')({
341
+ loader: async ({ params }): Promise<{ query: string }> => {
342
+ return { query: params._ }
343
+ },
344
+ component: SearchPage,
345
+ })
346
+ ```
347
+
348
+ </dynamic_routes>
349
+
350
+ ---
351
+
352
+ <ssr_options>
353
+
354
+ ## SSR (Server-Side Rendering) 옵션
355
+
356
+ ### Selective SSR
357
+
358
+ `ssr` 속성으로 라우트별 SSR 동작을 제어합니다. 기본값은 `true`입니다.
359
+
360
+ ```typescript
361
+ // src/start.ts에서 전역 기본값 변경 가능
362
+ import { createStart } from '@tanstack/react-start'
363
+
364
+ export const startInstance = createStart(() => ({
365
+ defaultSsr: false, // 기본적으로 SSR 비활성화
366
+ }))
367
+ ```
368
+
369
+ ### ssr: true (기본값)
370
+
371
+ 초기 요청 시:
372
+ 1. `beforeLoad` 서버에서 실행, context를 클라이언트에 전송
373
+ 2. `loader` 서버에서 실행, 데이터를 클라이언트에 전송
374
+ 3. 컴포넌트 서버에서 렌더링, HTML을 클라이언트에 전송
375
+
376
+ ```tsx
377
+ export const Route = createFileRoute('/products')({
378
+ ssr: true, // 기본값 (생략 가능)
379
+ loader: async () => {
380
+ const products = await getProducts()
381
+ return { products }
382
+ },
383
+ component: ProductsPage,
384
+ })
385
+ ```
386
+
387
+ ### ssr: false
388
+
389
+ 서버 사이드 `beforeLoad`/`loader` 실행 및 컴포넌트 렌더링 비활성화.
390
+
391
+ ```tsx
392
+ export const Route = createFileRoute('/dashboard')({
393
+ ssr: false, // 클라이언트에서만 렌더링
394
+ beforeLoad: () => {
395
+ console.log('클라이언트 hydration 중에만 실행')
25
396
  },
397
+ component: DashboardPage,
26
398
  })
399
+ // 인증 필요한 페이지, 브라우저 전용 API 사용 시 적합
400
+ ```
401
+
402
+ ### ssr: 'data-only'
403
+
404
+ `beforeLoad`와 `loader`는 서버에서 실행하지만, 컴포넌트 렌더링은 클라이언트에서만.
405
+
406
+ ```tsx
407
+ export const Route = createFileRoute('/items')({
408
+ ssr: 'data-only',
409
+ loader: async () => {
410
+ // 서버에서 실행 (DB 접근 가능)
411
+ const items = await getItems()
412
+ return { items }
413
+ },
414
+ component: ItemsPage,
415
+ })
416
+ // 무거운 컴포넌트 + 서버 데이터 조합에 적합
417
+ ```
27
418
 
28
- // SSR 옵션
29
- ssr: true // 전체 SSR (기본값)
30
- ssr: false // 클라이언트만
31
- ssr: 'data-only' // 데이터만 서버
419
+ </ssr_options>
32
420
 
33
- // Server Routes (API)
421
+ ---
422
+
423
+ <before_load>
424
+
425
+ ## beforeLoad: 라우트 진입 전 검증
426
+
427
+ ### 인증 체크
428
+
429
+ ```tsx
430
+ export const Route = createFileRoute('/dashboard')({
431
+ beforeLoad: async ({ location }): Promise<{ user: User }> => {
432
+ const user = await getCurrentUser()
433
+
434
+ if (!user) {
435
+ throw redirect({
436
+ to: '/login',
437
+ search: { redirect: location.href },
438
+ })
439
+ }
440
+
441
+ return { user }
442
+ },
443
+ component: DashboardPage,
444
+ })
445
+
446
+ const DashboardPage = (): JSX.Element => {
447
+ const { user } = Route.useRouteContext()
448
+ return <h1>Welcome, {user.name}!</h1>
449
+ }
450
+ ```
451
+
452
+ ### 권한 체크
453
+
454
+ ```tsx
455
+ export const Route = createFileRoute('/admin')({
456
+ beforeLoad: async ({ context }): Promise<{ user: User }> => {
457
+ const user = await getCurrentUser()
458
+
459
+ if (!user || user.role !== 'ADMIN') {
460
+ throw redirect({ to: '/' })
461
+ }
462
+
463
+ return { user }
464
+ },
465
+ component: AdminPage,
466
+ })
467
+ ```
468
+
469
+ ### 데이터 검증
470
+
471
+ ```tsx
472
+ export const Route = createFileRoute('/items/$id')({
473
+ beforeLoad: async ({ params }): Promise<{ valid: boolean }> => {
474
+ const isValidId = await validateItemId(params.id)
475
+
476
+ if (!isValidId) {
477
+ throw redirect({ to: '/items' })
478
+ }
479
+
480
+ return { valid: true }
481
+ },
482
+ loader: async ({ params }) => {
483
+ // beforeLoad가 성공한 후 실행
484
+ return { item: await getItemById(params.id) }
485
+ },
486
+ component: ItemDetailPage,
487
+ })
488
+ ```
489
+
490
+ </before_load>
491
+
492
+ ---
493
+
494
+ <server_routes>
495
+
496
+ ## Server Routes: API 엔드포인트
497
+
498
+ **주의:** Server Functions 사용 권장. Server Routes는 복잡한 요청/응답이 필요할 때만 사용.
499
+
500
+ ### 기본 Server Route
501
+
502
+ ```tsx
503
+ // routes/api/hello.tsx
34
504
  export const Route = createFileRoute('/api/hello')({
35
505
  server: {
36
506
  handlers: {
37
- GET: async () => new Response('Hello'),
38
- POST: async ({ request }) => {
507
+ GET: async (): Promise<Response> => {
508
+ return new Response('Hello World', {
509
+ headers: { 'Content-Type': 'text/plain' },
510
+ })
511
+ },
512
+ },
513
+ },
514
+ })
515
+ ```
516
+
517
+ ### 여러 메서드
518
+
519
+ ```tsx
520
+ export const Route = createFileRoute('/api/users')({
521
+ server: {
522
+ handlers: {
523
+ GET: async (): Promise<Response> => {
524
+ const users = await prisma.user.findMany()
525
+ return Response.json(users)
526
+ },
527
+ POST: async ({ request }): Promise<Response> => {
39
528
  const body = await request.json()
40
- return json({ name: body.name })
529
+ const user = await prisma.user.create({ data: body })
530
+ return Response.json(user, { status: 201 })
531
+ },
532
+ },
533
+ },
534
+ })
535
+ ```
536
+
537
+ ### 미들웨어 + Server Route
538
+
539
+ ```tsx
540
+ export const Route = createFileRoute('/api/protected')({
541
+ server: {
542
+ middleware: [authMiddleware, adminMiddleware],
543
+ handlers: {
544
+ GET: async ({ request }): Promise<Response> => {
545
+ return Response.json({ data: 'admin only' })
41
546
  },
42
547
  },
43
548
  },
44
549
  })
45
550
  ```
46
551
 
47
- </patterns>
552
+ </server_routes>
553
+
554
+ ---
555
+
556
+ <catch_all>
557
+
558
+ ## Catch-all Route (404)
559
+
560
+ ```tsx
561
+ // routes/$.tsx
562
+ export const Route = createFileRoute('/$')({
563
+ component: NotFoundPage,
564
+ })
48
565
 
49
- <structure>
566
+ const NotFoundPage = (): JSX.Element => {
567
+ const { _splat } = Route.useParams()
50
568
 
569
+ return (
570
+ <div style={{ textAlign: 'center', padding: '2rem' }}>
571
+ <h1>404 - Page Not Found</h1>
572
+ <p>The page "{_splat}" does not exist.</p>
573
+ <a href="/">Go Home</a>
574
+ </div>
575
+ )
576
+ }
51
577
  ```
52
- routes/
53
- ├── __root.tsx # Root layout
54
- ├── index.tsx # /
55
- ├── users/$id.tsx # /users/:id
56
- ├── $.tsx # Catch-all (404)
578
+
579
+ ### Error Boundary
580
+
581
+ ```tsx
582
+ // routes/__root.tsx
583
+ export const Route = createRootRoute({
584
+ component: RootLayout,
585
+ errorComponent: ({ error }) => (
586
+ <div>
587
+ <h1>Error</h1>
588
+ <p>{error.message}</p>
589
+ </div>
590
+ ),
591
+ })
57
592
  ```
58
593
 
59
- </structure>
594
+ </catch_all>
595
+
596
+ ---
597
+
598
+ <nested_layouts>
599
+
600
+ ## 중첩 레이아웃
601
+
602
+ ### Pathless Layout (_authed 패턴)
603
+
604
+ URL 경로에 영향 없이 레이아웃과 로직을 그룹에 적용:
605
+
606
+ ```tsx
607
+ // routes/_authed.tsx (pathless layout - URL에 _authed 없음)
608
+ export const Route = createFileRoute('/_authed')({
609
+ beforeLoad: async ({ location }) => {
610
+ const user = await getCurrentUser()
611
+ if (!user) {
612
+ throw redirect({
613
+ to: '/login',
614
+ search: { redirect: location.href },
615
+ })
616
+ }
617
+ return { user }
618
+ },
619
+ component: AuthedLayout,
620
+ })
621
+
622
+ function AuthedLayout() {
623
+ return (
624
+ <div>
625
+ <Outlet />
626
+ </div>
627
+ )
628
+ }
629
+
630
+ // routes/_authed/dashboard.tsx -> /dashboard
631
+ export const Route = createFileRoute('/_authed/dashboard')({
632
+ component: DashboardPage,
633
+ })
634
+
635
+ // routes/_authed/settings.tsx -> /settings
636
+ export const Route = createFileRoute('/_authed/settings')({
637
+ component: SettingsPage,
638
+ })
639
+ ```
640
+
641
+ ### 중첩 레이아웃 (Dashboard)
642
+
643
+ ```tsx
644
+ // routes/dashboard/_layout.tsx
645
+ export const Route = createFileRoute('/dashboard')({
646
+ component: DashboardLayout,
647
+ loader: async () => {
648
+ const user = await getCurrentUser()
649
+ return { user }
650
+ },
651
+ })
652
+
653
+ const DashboardLayout = (): JSX.Element => {
654
+ const { user } = Route.useLoaderData()
655
+
656
+ return (
657
+ <div style={{ display: 'flex' }}>
658
+ <aside>
659
+ <p>Welcome, {user.name}</p>
660
+ </aside>
661
+ <main>
662
+ <Outlet />
663
+ </main>
664
+ </div>
665
+ )
666
+ }
667
+
668
+ // routes/dashboard/index.tsx
669
+ export const Route = createFileRoute('/dashboard/')({
670
+ component: () => <h1>Dashboard Home</h1>,
671
+ })
672
+
673
+ // routes/dashboard/analytics.tsx
674
+ export const Route = createFileRoute('/dashboard/analytics')({
675
+ component: () => <h1>Analytics</h1>,
676
+ })
677
+ ```
678
+
679
+ ### Context 전달
680
+
681
+ ```tsx
682
+ // 부모 라우트의 loader/beforeLoad에서 반환한 데이터는
683
+ // 자식 라우트에서 useRouteContext()로 접근 가능
684
+ const DashboardPage = (): JSX.Element => {
685
+ const { user } = Route.useRouteContext()
686
+ return <h1>Welcome, {user.name}!</h1>
687
+ }
688
+ ```
689
+
690
+ </nested_layouts>
691
+
692
+ ---
693
+
694
+ <search_params>
695
+
696
+ ## Search Parameters (Query String)
697
+
698
+ ```tsx
699
+ // routes/search.tsx
700
+ export const Route = createFileRoute('/search')({
701
+ validateSearch: (search): { q: string; page: number } => {
702
+ return {
703
+ q: (search.q as string) || '',
704
+ page: (search.page as number) || 1,
705
+ }
706
+ },
707
+ loader: async ({ search }) => {
708
+ const results = await searchItems(search.q, search.page)
709
+ return { results }
710
+ },
711
+ component: SearchPage,
712
+ })
713
+
714
+ const SearchPage = (): JSX.Element => {
715
+ const navigate = useNavigate({ from: '/search' })
716
+ const search = Route.useSearch()
717
+ const { results } = Route.useLoaderData()
718
+
719
+ return (
720
+ <div>
721
+ <input
722
+ value={search.q}
723
+ onChange={(e) => {
724
+ navigate({
725
+ search: { q: e.target.value, page: 1 },
726
+ })
727
+ }}
728
+ />
729
+ <div>Page: {search.page}</div>
730
+ </div>
731
+ )
732
+ }
733
+ ```
734
+
735
+ </search_params>
736
+
737
+ ---
738
+
739
+ <navigation>
740
+
741
+ ## 네비게이션
742
+
743
+ ```tsx
744
+ import { Link, useNavigate } from '@tanstack/react-router'
745
+
746
+ // Link 컴포넌트
747
+ const HomePage = (): JSX.Element => {
748
+ return (
749
+ <div>
750
+ <Link to="/about">About</Link>
751
+ <Link to="/users/$id" params={{ id: '123' }}>
752
+ User Detail
753
+ </Link>
754
+ </div>
755
+ )
756
+ }
757
+
758
+ // useNavigate 훅
759
+ const LoginPage = (): JSX.Element => {
760
+ const navigate = useNavigate()
761
+
762
+ const handleLogin = () => {
763
+ navigate({ to: '/dashboard' })
764
+ }
765
+
766
+ return <button onClick={handleLogin}>Login</button>
767
+ }
768
+ ```
769
+
770
+ </navigation>
771
+
772
+ ---
773
+
774
+ <project_structure>
775
+
776
+ ## 권장 프로젝트 구조
777
+
778
+ ```
779
+ src/
780
+ ├── routes/
781
+ │ ├── __root.tsx # Root layout (html/body/scripts)
782
+ │ ├── index.tsx # /
783
+ │ ├── $.tsx # Catch-all (404)
784
+ │ ├── about.tsx # /about
785
+ │ ├── _authed.tsx # Pathless layout (인증 필요 페이지)
786
+ │ ├── _authed/
787
+ │ │ ├── dashboard.tsx # /dashboard (인증 필요)
788
+ │ │ └── settings.tsx # /settings (인증 필요)
789
+ │ ├── api/
790
+ │ │ └── hello.tsx # /api/hello (Server Routes)
791
+ │ ├── users/
792
+ │ │ ├── index.tsx # /users
793
+ │ │ ├── $id.tsx # /users/:id
794
+ │ │ └── -components/ # 페이지 전용
795
+ │ └── dashboard/
796
+ │ ├── _layout.tsx # 레이아웃
797
+ │ ├── index.tsx # /dashboard
798
+ │ └── analytics.tsx # /dashboard/analytics
799
+ ├── router.tsx # Router 설정
800
+ ├── routeTree.gen.ts # 자동 생성
801
+ ├── functions/ # 공통 Server Functions
802
+ ├── middleware/ # 공통 Middleware
803
+ └── components/
804
+ ```
805
+
806
+ </project_structure>
807
+
808
+ ---
809
+
810
+ <version_info>
811
+
812
+ **Version:** TanStack Start/Router v1.159.4
813
+
814
+ **Key Features:**
815
+ - File-based routing (zero-config, 자동 경로 관리)
816
+ - Type-safe route parameters (routeTree.gen.ts 기반)
817
+ - Selective SSR (true/false/'data-only', 라우트별 설정)
818
+ - createStart에서 defaultSsr 전역 설정
819
+ - beforeLoad for auth/validation
820
+ - Server Routes for API endpoints (메서드별 미들웨어 가능)
821
+ - Nested layouts, Pathless layouts, Grouped routes
822
+ - HeadContent/Scripts 컴포넌트 (Root Route 필수)
823
+ - scrollRestoration 기본 지원
824
+
825
+ </version_info>