@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
@@ -0,0 +1,110 @@
1
+ ---
2
+ title: Use pendingComponent for Route Loading States
3
+ impact: MEDIUM
4
+ impactDescription: eliminates layout shift during navigation
5
+ tags: routing, pendingComponent, loading, UX, transitions
6
+ ---
7
+
8
+ ## pendingComponent로 라우트 로딩 상태 처리
9
+
10
+ `pendingComponent`는 loader가 완료되기 전 보여주는 로딩 UI입니다. `pendingMs`/`pendingMinMs`로 플리커 없는 로딩 경험을 구현합니다.
11
+
12
+ **❌ 잘못된 예시 (로딩 상태 없음):**
13
+
14
+ ```tsx
15
+ export const Route = createFileRoute('/tasks')({
16
+ loader: async () => {
17
+ const tasks = await fetchTasks() // 2초 소요
18
+ return { tasks }
19
+ },
20
+ component: TasksPage,
21
+ // 로딩 UI 없음 → 사용자가 2초간 빈 화면 봄
22
+ })
23
+ ```
24
+
25
+ **✅ 올바른 예시 (pendingComponent + 타이밍 설정):**
26
+
27
+ ```tsx
28
+ export const Route = createFileRoute('/tasks')({
29
+ loader: async () => {
30
+ return { tasks: await fetchTasks() }
31
+ },
32
+ pendingComponent: () => (
33
+ <div className="p-4">
34
+ <div className="animate-pulse space-y-3">
35
+ <div className="h-8 bg-gray-200 rounded w-1/3" />
36
+ <div className="h-4 bg-gray-200 rounded" />
37
+ <div className="h-4 bg-gray-200 rounded" />
38
+ </div>
39
+ </div>
40
+ ),
41
+ pendingMs: 150, // 150ms 후에도 loader 미완료 시 로딩 UI 표시
42
+ pendingMinMs: 200, // 로딩 UI 최소 200ms 표시 (플리커 방지)
43
+ component: TasksPage,
44
+ })
45
+ ```
46
+
47
+ **타이밍 동작:**
48
+
49
+ ```
50
+ Time 0ms: 네비게이션 시작
51
+ Time 150ms: pendingMs 경과 → loader 미완료면 pendingComponent 표시
52
+ loader 완료면 즉시 컴포넌트 렌더링 (로딩 UI 없음)
53
+
54
+ pendingComponent 표시 후:
55
+ loader 완료 시 → 최소 200ms(pendingMinMs) 후 컴포넌트 전환
56
+ (짧은 플리커 방지)
57
+ ```
58
+
59
+ **Router 레벨 기본값:**
60
+
61
+ ```tsx
62
+ const router = createRouter({
63
+ routeTree,
64
+ defaultPendingComponent: () => <GlobalSpinner />,
65
+ defaultPendingMs: 150,
66
+ defaultPendingMinMs: 200,
67
+ })
68
+ ```
69
+
70
+ **pendingComponent vs Suspense:**
71
+
72
+ | 항목 | pendingComponent | Suspense |
73
+ |------|-----------------|----------|
74
+ | 대상 | 라우트 네비게이션 | 컴포넌트 내 비동기 |
75
+ | 트리거 | loader 미완료 | Promise throw |
76
+ | 타이밍 제어 | pendingMs/pendingMinMs | 없음 |
77
+ | 사용 시점 | 페이지 전환 | deferred data, lazy 컴포넌트 |
78
+
79
+ **조합 패턴 (pendingComponent + Suspense):**
80
+
81
+ ```tsx
82
+ export const Route = createFileRoute('/posts/$postId')({
83
+ loader: async ({ params }) => {
84
+ const post = await getPost(params.postId) // 빠른 데이터
85
+ const deferredComments = getComments(params.postId) // 느린 데이터
86
+ return { post, deferredComments }
87
+ },
88
+ // 페이지 전환 시 로딩 UI (post 로딩 중)
89
+ pendingComponent: () => <PostSkeleton />,
90
+ pendingMs: 150,
91
+ component: PostPage,
92
+ })
93
+
94
+ function PostPage() {
95
+ const { post, deferredComments } = Route.useLoaderData()
96
+ return (
97
+ <div>
98
+ <PostContent post={post} />
99
+ {/* 댓글은 별도 Suspense (이미 post는 로드됨) */}
100
+ <Suspense fallback={<CommentsSkeleton />}>
101
+ <Await promise={deferredComments}>
102
+ {(comments) => <Comments comments={comments} />}
103
+ </Await>
104
+ </Suspense>
105
+ </div>
106
+ )
107
+ }
108
+ ```
109
+
110
+ 참고: [Pending Component](https://tanstack.com/router/latest/docs/framework/react/guide/data-loading#pending-component)
@@ -0,0 +1,91 @@
1
+ ---
2
+ title: Preload Routes on User Intent for Instant Navigation
3
+ impact: MEDIUM-HIGH
4
+ impactDescription: eliminates perceived loading time on navigation
5
+ tags: routing, preload, performance, link, UX
6
+ ---
7
+
8
+ ## 사용자 의도 기반 라우트 프리로딩
9
+
10
+ `preload="intent"`로 hover/touch 시 라우트 데이터를 미리 로드하여 즉각적인 네비게이션을 구현합니다.
11
+
12
+ **❌ 잘못된 예시 (프리로딩 없음):**
13
+
14
+ ```tsx
15
+ // 클릭 후 loader 실행 → 사용자 대기
16
+ <Link to="/posts/$postId" params={{ postId: '123' }}>
17
+ View Post
18
+ </Link>
19
+ ```
20
+
21
+ **✅ 올바른 예시 (intent 프리로딩):**
22
+
23
+ ```tsx
24
+ // hover 시 미리 loader 실행 → 클릭 시 즉시 렌더링
25
+ <Link
26
+ to="/posts/$postId"
27
+ params={{ postId: '123' }}
28
+ preload="intent"
29
+ >
30
+ View Post
31
+ </Link>
32
+ ```
33
+
34
+ **Router 레벨 기본값 설정:**
35
+
36
+ ```tsx
37
+ const router = createRouter({
38
+ routeTree,
39
+ defaultPreload: 'intent', // 전역 기본값
40
+ defaultPreloadDelay: 50, // hover 후 50ms 대기
41
+ defaultPreloadStaleTime: 30_000, // 프리로드 데이터 30초간 fresh
42
+ })
43
+ ```
44
+
45
+ **프리로딩 모드:**
46
+
47
+ | 모드 | 트리거 | 사용 시점 |
48
+ |------|--------|---------|
49
+ | `'intent'` | hover/touch 50ms 후 | 일반적인 네비게이션 링크 (권장) |
50
+ | `'viewport'` | 뷰포트 진입 시 | 목록 페이지, 무한 스크롤 |
51
+ | `'render'` | 컴포넌트 마운트 시 | 확실히 이동할 링크 |
52
+ | `false` | 비활성 | 인증/외부 링크 |
53
+
54
+ **Link별 오버라이드:**
55
+
56
+ ```tsx
57
+ // 목록 아이템은 viewport 프리로딩
58
+ {posts.map(post => (
59
+ <Link
60
+ key={post.id}
61
+ to="/posts/$postId"
62
+ params={{ postId: post.id }}
63
+ preload="viewport"
64
+ >
65
+ {post.title}
66
+ </Link>
67
+ ))}
68
+
69
+ // 특정 링크는 프리로딩 비활성
70
+ <Link to="/settings" preload={false}>
71
+ Settings
72
+ </Link>
73
+ ```
74
+
75
+ **프로그래밍 방식 프리로딩:**
76
+
77
+ ```tsx
78
+ const router = useRouter()
79
+
80
+ // 검색 결과 hover 시 수동 프리로드
81
+ const handleMouseEnter = (postId: string) => {
82
+ router.preloadRoute({
83
+ to: '/posts/$postId',
84
+ params: { postId },
85
+ })
86
+ }
87
+ ```
88
+
89
+ **캐싱:** 프리로드된 데이터는 기본 30초(`defaultPreloadStaleTime`) 동안 fresh 상태로 유지됩니다.
90
+
91
+ 참고: [Preloading Guide](https://tanstack.com/router/latest/docs/framework/react/guide/preloading)
@@ -0,0 +1,120 @@
1
+ ---
2
+ title: Use Router Context for Dependency Injection
3
+ impact: MEDIUM-HIGH
4
+ impactDescription: enables type-safe shared state across all routes
5
+ tags: routing, context, createRootRouteWithContext, dependency-injection
6
+ ---
7
+
8
+ ## Router Context로 의존성 주입
9
+
10
+ `createRootRouteWithContext`로 QueryClient, 인증 상태 등을 타입 안전하게 모든 라우트에 전달합니다.
11
+
12
+ **❌ 잘못된 예시 (전역 변수/import):**
13
+
14
+ ```tsx
15
+ // 전역 import → 테스트 어려움, 타입 안전성 없음
16
+ import { queryClient } from '../lib/queryClient'
17
+ import { getAuth } from '../lib/auth'
18
+
19
+ export const Route = createFileRoute('/dashboard')({
20
+ loader: async () => {
21
+ const user = await getAuth() // 타입 추론 불가
22
+ return await queryClient.fetchQuery(...)
23
+ },
24
+ })
25
+ ```
26
+
27
+ **✅ 올바른 예시 (createRootRouteWithContext):**
28
+
29
+ ```tsx
30
+ // 1. Context 인터페이스 정의
31
+ interface RouterContext {
32
+ queryClient: QueryClient
33
+ auth: { user: User | null }
34
+ }
35
+
36
+ // 2. Root route에 context 타입 바인딩
37
+ // src/routes/__root.tsx
38
+ import { createRootRouteWithContext, Outlet } from '@tanstack/react-router'
39
+
40
+ export const Route = createRootRouteWithContext<RouterContext>()({
41
+ component: () => <Outlet />,
42
+ })
43
+
44
+ // 3. Router 생성 시 context 값 전달
45
+ // src/router.tsx
46
+ const router = createRouter({
47
+ routeTree,
48
+ context: {
49
+ queryClient: new QueryClient(),
50
+ auth: { user: null },
51
+ },
52
+ })
53
+
54
+ // 4. 하위 라우트에서 타입 안전하게 접근
55
+ export const Route = createFileRoute('/dashboard')({
56
+ beforeLoad: async ({ context }) => {
57
+ // context.queryClient: QueryClient ✅ 완전한 타입 추론
58
+ // context.auth: { user: User | null } ✅
59
+ if (!context.auth.user) {
60
+ throw redirect({ to: '/login' })
61
+ }
62
+ },
63
+ loader: async ({ context }) => {
64
+ return context.queryClient.ensureQueryData({
65
+ queryKey: ['dashboard'],
66
+ queryFn: fetchDashboard,
67
+ })
68
+ },
69
+ })
70
+ ```
71
+
72
+ **beforeLoad에서 context 확장:**
73
+
74
+ ```tsx
75
+ // 부모 라우트에서 context 확장 → 자식 라우트에서 접근
76
+ export const Route = createFileRoute('/admin')({
77
+ beforeLoad: async ({ context }) => {
78
+ const permissions = await fetchPermissions(context.auth.user!.id)
79
+ return { permissions } // context에 병합됨
80
+ },
81
+ })
82
+
83
+ // 자식 라우트
84
+ export const Route = createFileRoute('/admin/users')({
85
+ beforeLoad: async ({ context }) => {
86
+ // context.permissions 접근 가능 (부모에서 추가됨)
87
+ if (!context.permissions.includes('manage_users')) {
88
+ throw redirect({ to: '/admin' })
89
+ }
90
+ },
91
+ })
92
+ ```
93
+
94
+ **컴포넌트에서 context 접근:**
95
+
96
+ ```tsx
97
+ function Dashboard() {
98
+ // useRouteContext로 접근
99
+ const { queryClient, auth } = Route.useRouteContext()
100
+
101
+ // 또는 getRouteApi 사용 (코드 스플릿)
102
+ const routeApi = getRouteApi('/dashboard')
103
+ const context = routeApi.useRouteContext()
104
+ }
105
+ ```
106
+
107
+ **useRouterState (라우터 전역 상태):**
108
+
109
+ ```tsx
110
+ // 라우터 상태 반응형 구독
111
+ const status = useRouterState({ select: (s) => s.status })
112
+ // 'idle' | 'pending' → 전역 로딩 인디케이터에 사용
113
+
114
+ const location = useRouterState({ select: (s) => s.location })
115
+ // 현재 URL 정보
116
+
117
+ // ⚠️ useRouter().state는 반응형이 아님 → useRouterState 사용
118
+ ```
119
+
120
+ 참고: [Router Context](https://tanstack.com/router/latest/docs/framework/react/guide/router-context)
@@ -0,0 +1,114 @@
1
+ ---
2
+ title: Validate Search Params with Zod for Type Safety
3
+ impact: HIGH
4
+ impactDescription: prevents invalid URL state and runtime errors
5
+ tags: routing, search-params, useSearch, zod, validation, type-safety
6
+ ---
7
+
8
+ ## Zod로 Search Params 타입 안전하게 검증
9
+
10
+ TanStack Router의 `validateSearch`로 URL search params를 스키마 기반으로 검증하고, `useSearch`로 타입 안전하게 접근합니다.
11
+
12
+ **❌ 잘못된 예시 (타입 없는 search params):**
13
+
14
+ ```tsx
15
+ function PostsPage() {
16
+ const searchParams = new URLSearchParams(window.location.search)
17
+ const page = Number(searchParams.get('page')) || 1 // 타입 안전성 없음
18
+ const sort = searchParams.get('sort') ?? 'date' // 유효성 검증 없음
19
+ }
20
+ ```
21
+
22
+ **✅ 올바른 예시 (Zod 스키마 + validateSearch):**
23
+
24
+ ```tsx
25
+ import { createFileRoute } from '@tanstack/react-router'
26
+ import { z } from 'zod'
27
+ import { zodValidator, fallback } from '@tanstack/zod-adapter'
28
+
29
+ const postsSearchSchema = z.object({
30
+ page: fallback(z.number().int().positive(), 1),
31
+ sort: fallback(z.enum(['date', 'title', 'author']), 'date'),
32
+ q: fallback(z.string().optional(), undefined),
33
+ limit: fallback(z.number().int().min(1).max(100), 20),
34
+ })
35
+
36
+ export const Route = createFileRoute('/posts')({
37
+ validateSearch: zodValidator(postsSearchSchema),
38
+ component: PostsPage,
39
+ })
40
+
41
+ function PostsPage() {
42
+ // 모든 타입이 스키마에서 자동 추론
43
+ const { page, sort, q, limit } = Route.useSearch()
44
+
45
+ return <div>Page {page}, sorted by {sort}</div>
46
+ }
47
+ ```
48
+
49
+ **useSearch에서 select로 리렌더 최적화:**
50
+
51
+ ```tsx
52
+ // ❌ 전체 search 구독 - 아무 param 변경 시 리렌더
53
+ function Pagination() {
54
+ const { page, sort, q, limit } = Route.useSearch()
55
+ return <div>Page {page}</div> // page만 사용하는데 전체 리렌더
56
+ }
57
+
58
+ // ✅ select로 필요한 값만 구독
59
+ function Pagination() {
60
+ const page = useSearch({
61
+ from: '/posts',
62
+ select: (search) => search.page,
63
+ })
64
+ return <div>Page {page}</div> // page 변경 시에만 리렌더
65
+ }
66
+ ```
67
+
68
+ **네비게이션에서 search params 업데이트:**
69
+
70
+ ```tsx
71
+ function PostsFilter() {
72
+ const navigate = useNavigate({ from: '/posts' })
73
+ const { sort, q } = Route.useSearch()
74
+
75
+ const handleSortChange = (newSort: string) => {
76
+ navigate({
77
+ search: (prev) => ({ ...prev, sort: newSort, page: 1 }),
78
+ })
79
+ }
80
+
81
+ const clearFilters = () => {
82
+ navigate({
83
+ search: { page: 1, sort: 'date', limit: 20 }, // 전체 초기화
84
+ })
85
+ }
86
+
87
+ return (
88
+ <div>
89
+ <select value={sort} onChange={(e) => handleSortChange(e.target.value)}>
90
+ <option value="date">Date</option>
91
+ <option value="title">Title</option>
92
+ </select>
93
+ <button onClick={clearFilters}>Clear</button>
94
+ </div>
95
+ )
96
+ }
97
+ ```
98
+
99
+ **복잡한 스키마 패턴:**
100
+
101
+ ```tsx
102
+ const filterSchema = z.object({
103
+ search: z.string().trim().optional(),
104
+ page: z.coerce.number().int().min(1).default(1),
105
+ sort: z.enum(['name', 'date', 'popularity']).default('date'),
106
+ order: z.enum(['asc', 'desc']).default('asc'),
107
+ inStock: z.coerce.boolean().default(true),
108
+ categories: z.array(z.string()).default([]),
109
+ })
110
+ ```
111
+
112
+ **주의:** `@tanstack/zod-adapter`는 별도 패키지입니다. Valibot 사용 시 `@tanstack/valibot-adapter`.
113
+
114
+ 참고: [Search Params Guide](https://tanstack.com/router/latest/docs/framework/react/guide/search-params)
@@ -64,4 +64,4 @@ function PostPage() {
64
64
 
65
65
  페이지가 3초 대신 50ms에 렌더링됩니다. 댓글은 준비되면 스트리밍. 다음에 사용: 분석, 추천, 사용자 활동, 소셜 기능.
66
66
 
67
- 참고: [TanStack Router Deferred Data Loading](https://tanstack.com/router/v1/docs/framework/react/guide/deferred-data-loading)
67
+ 참고: [TanStack Router Deferred Data Loading](https://tanstack.com/router/latest/docs/framework/react/guide/deferred-data-loading)
@@ -0,0 +1,79 @@
1
+ ---
2
+ title: Use Route-Level Error Boundaries
3
+ impact: HIGH
4
+ impactDescription: graceful error recovery per route
5
+ tags: server, error-handling, error-boundary, tanstack-router
6
+ ---
7
+
8
+ ## 라우트 레벨 에러 바운더리
9
+
10
+ TanStack Router는 라우트별 `errorComponent`를 지원합니다. 전역 에러 페이지 대신 라우트 단위 에러 처리로 사용자 경험을 개선하세요.
11
+
12
+ **❌ 잘못된 예시 (에러 처리 없음):**
13
+
14
+ ```typescript
15
+ export const Route = createFileRoute('/posts/$postId')({
16
+ loader: async ({ params }) => {
17
+ const post = await getPost(params.postId)
18
+ return { post } // post가 null이면 런타임 에러
19
+ },
20
+ component: PostPage
21
+ })
22
+
23
+ function PostPage() {
24
+ const { post } = Route.useLoaderData()
25
+ return <div>{post.title}</div> // 💥 Cannot read property 'title' of null
26
+ }
27
+ ```
28
+
29
+ **✅ 올바른 예시 (라우트별 에러 처리):**
30
+
31
+ ```typescript
32
+ export const Route = createFileRoute('/posts/$postId')({
33
+ loader: async ({ params }) => {
34
+ const post = await getPost(params.postId)
35
+ if (!post) throw new Error('Post not found')
36
+ return { post }
37
+ },
38
+ errorComponent: ({ error, reset }) => (
39
+ <div>
40
+ <h2>오류가 발생했습니다</h2>
41
+ <p>{error.message}</p>
42
+ <button onClick={reset}>다시 시도</button>
43
+ </div>
44
+ ),
45
+ component: PostPage
46
+ })
47
+ ```
48
+
49
+ **전역 기본 에러 컴포넌트 설정:**
50
+
51
+ ```typescript
52
+ import { createRouter } from '@tanstack/react-router'
53
+
54
+ const router = createRouter({
55
+ routeTree,
56
+ defaultErrorComponent: ({ error, reset }) => (
57
+ <div>
58
+ <h1>예기치 못한 오류</h1>
59
+ <p>{error.message}</p>
60
+ <button onClick={reset}>재시도</button>
61
+ </div>
62
+ )
63
+ })
64
+ ```
65
+
66
+ **notFoundComponent로 404 처리:**
67
+
68
+ ```typescript
69
+ export const Route = createFileRoute('/posts/$postId')({
70
+ loader: async ({ params }) => {
71
+ const post = await getPost(params.postId)
72
+ if (!post) throw notFound()
73
+ return { post }
74
+ },
75
+ notFoundComponent: () => <div>게시글을 찾을 수 없습니다</div>
76
+ })
77
+ ```
78
+
79
+ **원칙:** loader에서 예외를 명시적으로 throw하고, errorComponent/notFoundComponent로 처리합니다. TanStack Router가 자동으로 Suspense와 ErrorBoundary를 래핑합니다.
@@ -0,0 +1,85 @@
1
+ ---
2
+ title: Use Middleware for Cross-Cutting Concerns
3
+ impact: HIGH
4
+ impactDescription: centralizes auth, logging, validation
5
+ tags: server, middleware, createMiddleware, authentication, tanstack-start
6
+ ---
7
+
8
+ ## 크로스 커팅 관심사에 Middleware 사용
9
+
10
+ `createMiddleware()`로 인증, 로깅, 에러 처리 등 공통 로직을 중앙화합니다. 각 Server Function에 반복 코드를 작성하지 마세요.
11
+
12
+ **❌ 잘못된 예시 (모든 Server Function에 인증 로직 반복):**
13
+
14
+ ```typescript
15
+ import { createServerFn } from '@tanstack/react-start'
16
+
17
+ const getTodos = createServerFn().handler(async () => {
18
+ const session = await getSession()
19
+ if (!session?.user) throw new Error('Unauthorized')
20
+ return await db.todo.findMany({ where: { userId: session.user.id } })
21
+ })
22
+
23
+ const createTodo = createServerFn({ method: 'POST' })
24
+ .handler(async (data) => {
25
+ const session = await getSession()
26
+ if (!session?.user) throw new Error('Unauthorized')
27
+ return await db.todo.create({ data: { ...data, userId: session.user.id } })
28
+ })
29
+ ```
30
+
31
+ **✅ 올바른 예시 (Middleware로 인증 중앙화):**
32
+
33
+ ```typescript
34
+ import { createServerFn } from '@tanstack/react-start'
35
+ import { createMiddleware } from '@tanstack/react-start'
36
+
37
+ // 인증 미들웨어 정의 (재사용 가능)
38
+ const authMiddleware = createMiddleware()
39
+ .server(async ({ next }) => {
40
+ const session = await getSession()
41
+ if (!session?.user) {
42
+ throw redirect({ to: '/login' })
43
+ }
44
+ return next({ context: { user: session.user } })
45
+ })
46
+
47
+ // Server Functions에 미들웨어 적용
48
+ const getTodos = createServerFn()
49
+ .middleware([authMiddleware])
50
+ .handler(async ({ context }) => {
51
+ return await db.todo.findMany({ where: { userId: context.user.id } })
52
+ })
53
+
54
+ const createTodo = createServerFn({ method: 'POST' })
55
+ .middleware([authMiddleware])
56
+ .inputValidator((d: unknown) => TodoSchema.parse(d))
57
+ .handler(async ({ data, context }) => {
58
+ return await db.todo.create({ data: { ...data, userId: context.user.id } })
59
+ })
60
+ ```
61
+
62
+ **미들웨어 체이닝:**
63
+
64
+ ```typescript
65
+ const loggingMiddleware = createMiddleware()
66
+ .server(async ({ next }) => {
67
+ const start = Date.now()
68
+ const result = await next()
69
+ console.log(`Duration: ${Date.now() - start}ms`)
70
+ return result
71
+ })
72
+
73
+ // 여러 미들웨어 조합 (배열 순서대로 실행)
74
+ const protectedAction = createServerFn({ method: 'POST' })
75
+ .middleware([loggingMiddleware, authMiddleware])
76
+ .handler(async ({ context }) => { /* ... */ })
77
+ ```
78
+
79
+ **실행 순서:** inputValidator → middleware (배열 순서) → handler
80
+
81
+ **주의사항:**
82
+ - 미들웨어 코드가 클라이언트 번들에 포함될 수 있으므로, DB 연결/API 키 등 민감 정보는 handler 내에서만 사용
83
+ - `redirect()` 사용 시 직렬화 에러가 발생할 수 있으므로 `throw redirect()` 패턴 사용
84
+
85
+ 참고: [Middleware Guide](https://tanstack.com/start/latest/docs/framework/react/guide/middleware)