@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,211 @@
1
+ # useOptimistic으로 IPC 대기 시간 마스킹
2
+
3
+ ## 왜 중요한가
4
+
5
+ Tauri Command 호출은 Rust ↔ JS 직렬화 오버헤드가 있어 최소 수십 ms 지연이 발생합니다. React 19의 `useOptimistic`을 사용하면 서버 응답 대기 없이 UI를 즉시 업데이트하여 사용자 경험을 개선할 수 있습니다.
6
+
7
+ ## ❌ 잘못된 패턴
8
+
9
+ ```tsx
10
+ import { invoke } from '@tauri-apps/api/core'
11
+ import { useState } from 'react'
12
+
13
+ function TodoList({ initialTodos }: { initialTodos: Todo[] }) {
14
+ const [todos, setTodos] = useState(initialTodos)
15
+ const [loading, setLoading] = useState(false)
16
+
17
+ const addTodo = async (title: string) => {
18
+ setLoading(true)
19
+ // ❌ invoke 응답까지 사용자는 대기해야 함
20
+ const newTodo = await invoke<Todo>('create_todo', { title })
21
+ setTodos(prev => [...prev, newTodo])
22
+ setLoading(false)
23
+ }
24
+
25
+ return (
26
+ <div>
27
+ {loading && <Spinner />}
28
+ {todos.map(todo => <TodoItem key={todo.id} todo={todo} />)}
29
+ <button onClick={() => addTodo('New Task')}>Add</button>
30
+ </div>
31
+ )
32
+ }
33
+ ```
34
+
35
+ **문제점:**
36
+ - 사용자는 Rust 응답까지 대기 (느린 UX)
37
+ - 네트워크/IPC 지연이 체감됨
38
+ - 로딩 스피너로 인한 UI 깜빡임
39
+
40
+ ## ✅ 올바른 패턴
41
+
42
+ ```tsx
43
+ import { invoke } from '@tauri-apps/api/core'
44
+ import { useOptimistic, startTransition, useState } from 'react'
45
+
46
+ type Todo = {
47
+ id: string
48
+ title: string
49
+ completed: boolean
50
+ pending?: boolean
51
+ }
52
+
53
+ function TodoList({ initialTodos }: { initialTodos: Todo[] }) {
54
+ const [todos, setTodos] = useState(initialTodos)
55
+ const [optimisticTodos, addOptimistic] = useOptimistic(
56
+ todos,
57
+ (current, newTodo: Todo) => [...current, { ...newTodo, pending: true }]
58
+ )
59
+
60
+ const addTodo = async (title: string) => {
61
+ const tempTodo: Todo = {
62
+ id: crypto.randomUUID(),
63
+ title,
64
+ completed: false
65
+ }
66
+
67
+ startTransition(async () => {
68
+ addOptimistic(tempTodo) // ✅ 즉시 UI에 반영
69
+
70
+ try {
71
+ const savedTodo = await invoke<Todo>('create_todo', { title })
72
+ setTodos(prev => [...prev, savedTodo])
73
+ } catch (error) {
74
+ // 실패 시 자동 롤백됨
75
+ console.error('Failed to create todo:', error)
76
+ }
77
+ })
78
+ }
79
+
80
+ return (
81
+ <div>
82
+ {optimisticTodos.map(todo => (
83
+ <TodoItem
84
+ key={todo.id}
85
+ todo={todo}
86
+ style={{ opacity: todo.pending ? 0.5 : 1 }}
87
+ />
88
+ ))}
89
+ <button onClick={() => addTodo('New Task')}>Add</button>
90
+ </div>
91
+ )
92
+ }
93
+ ```
94
+
95
+ **좋아요/투표 UI 예시:**
96
+
97
+ ```tsx
98
+ import { invoke } from '@tauri-apps/api/core'
99
+ import { useOptimistic, startTransition } from 'react'
100
+
101
+ function LikeButton({ postId, liked, count }: {
102
+ postId: string
103
+ liked: boolean
104
+ count: number
105
+ }) {
106
+ const [optimistic, setOptimistic] = useOptimistic(
107
+ { liked, count },
108
+ (curr) => ({
109
+ liked: !curr.liked,
110
+ count: curr.liked ? curr.count - 1 : curr.count + 1
111
+ })
112
+ )
113
+
114
+ const toggleLike = () => {
115
+ startTransition(async () => {
116
+ setOptimistic(null) // ✅ 즉시 UI 토글
117
+
118
+ try {
119
+ await invoke('toggle_like', { postId })
120
+ } catch (error) {
121
+ // 실패 시 자동 롤백
122
+ console.error('Failed to toggle like:', error)
123
+ }
124
+ })
125
+ }
126
+
127
+ return (
128
+ <button onClick={toggleLike}>
129
+ {optimistic.liked ? '❤️' : '🤍'} {optimistic.count}
130
+ </button>
131
+ )
132
+ }
133
+ ```
134
+
135
+ **삭제 액션 예시:**
136
+
137
+ ```tsx
138
+ import { invoke } from '@tauri-apps/api/core'
139
+ import { useOptimistic, startTransition, useState } from 'react'
140
+
141
+ function FileList({ initialFiles }: { initialFiles: File[] }) {
142
+ const [files, setFiles] = useState(initialFiles)
143
+ const [optimisticFiles, removeOptimistic] = useOptimistic(
144
+ files,
145
+ (current, fileIdToRemove: string) =>
146
+ current.filter(f => f.id !== fileIdToRemove)
147
+ )
148
+
149
+ const deleteFile = (fileId: string) => {
150
+ startTransition(async () => {
151
+ removeOptimistic(fileId) // ✅ 즉시 제거
152
+
153
+ try {
154
+ await invoke('delete_file', { fileId })
155
+ setFiles(prev => prev.filter(f => f.id !== fileId))
156
+ } catch (error) {
157
+ // 실패 시 자동 롤백
158
+ alert('Failed to delete file')
159
+ }
160
+ })
161
+ }
162
+
163
+ return (
164
+ <div>
165
+ {optimisticFiles.map(file => (
166
+ <div key={file.id}>
167
+ {file.name}
168
+ <button onClick={() => deleteFile(file.id)}>Delete</button>
169
+ </div>
170
+ ))}
171
+ </div>
172
+ )
173
+ }
174
+ ```
175
+
176
+ ## 추가 컨텍스트
177
+
178
+ **사용 시점:**
179
+ - 좋아요/투표 버튼
180
+ - 댓글 추가/삭제
181
+ - 장바구니 아이템 추가/제거
182
+ - 토글 스위치 (완료/미완료)
183
+ - 파일 업로드/삭제
184
+
185
+ **주의사항:**
186
+ - `startTransition` 내에서 사용해야 자동 롤백 작동
187
+ - 복잡한 데이터 구조는 `immer` 같은 라이브러리 활용
188
+ - 에러 발생 시 사용자에게 피드백 제공 (toast, alert)
189
+
190
+ **React 19 미만 환경:**
191
+ ```tsx
192
+ // React 18 이하에서는 수동 롤백 구현
193
+ const [tempState, setTempState] = useState(null)
194
+
195
+ const addTodo = async (title: string) => {
196
+ const tempTodo = { id: 'temp', title }
197
+ setTempState(tempTodo)
198
+
199
+ try {
200
+ const saved = await invoke('create_todo', { title })
201
+ setTodos(prev => [...prev, saved])
202
+ } catch {
203
+ // 수동 롤백
204
+ setTempState(null)
205
+ }
206
+ }
207
+ ```
208
+
209
+ **참고:** [React 19 useOptimistic](https://react.dev/reference/react/useOptimistic)
210
+
211
+ 영향도: MEDIUM-HIGH - 사용자 체감 응답 속도, UX 품질
@@ -0,0 +1,205 @@
1
+ # 윈도우별 Capability 분리
2
+
3
+ ## 왜 중요한가
4
+
5
+ Tauri 애플리케이션은 여러 윈도우를 가질 수 있으며, 각 윈도우는 서로 다른 목적과 신뢰 수준을 가집니다. 모든 윈도우에 동일한 권한을 부여하면, 덜 신뢰할 수 있는 콘텐츠를 표시하는 윈도우(예: 외부 웹뷰, 플러그인 UI)가 과도한 권한을 갖게 됩니다. 윈도우별로 Capability를 분리하면 권한 상승 공격(Privilege Escalation)을 방지할 수 있습니다.
6
+
7
+ ## ❌ 잘못된 패턴
8
+
9
+ ```json
10
+ // src-tauri/capabilities/default.json
11
+ {
12
+ "$schema": "../gen/schemas/desktop-schema.json",
13
+ "identifier": "default",
14
+ "description": "모든 윈도우에 동일한 권한",
15
+ "windows": ["main", "worker", "external-viewer"],
16
+ "permissions": [
17
+ "core:default",
18
+ "fs:allow-read-text-file",
19
+ "fs:allow-write-text-file",
20
+ "shell:allow-execute",
21
+ "http:allow-fetch"
22
+ ]
23
+ }
24
+ ```
25
+
26
+ ```rust
27
+ // src-tauri/src/main.rs
28
+ fn main() {
29
+ tauri::Builder::default()
30
+ .setup(|app| {
31
+ // 외부 콘텐츠를 표시하는 윈도우도 동일한 권한
32
+ tauri::window::WindowBuilder::new(
33
+ app,
34
+ "external-viewer",
35
+ tauri::WindowUrl::External("https://untrusted.com".parse().unwrap())
36
+ ).build()?;
37
+ Ok(())
38
+ })
39
+ .run(tauri::generate_context!())
40
+ .expect("error while running tauri application");
41
+ }
42
+ ```
43
+
44
+ **문제점:**
45
+ - 외부 웹사이트를 표시하는 윈도우가 파일 시스템, 셸 실행 권한을 갖음
46
+ - XSS 공격 시 `shell:allow-execute`로 임의 명령 실행 가능
47
+ - 신뢰할 수 없는 콘텐츠가 로컬 파일 읽기/쓰기 가능
48
+ - 모든 윈도우가 동일한 공격 표면을 가짐
49
+
50
+ ## ✅ 올바른 패턴
51
+
52
+ ```json
53
+ // src-tauri/capabilities/main-window.json
54
+ {
55
+ "$schema": "../gen/schemas/desktop-schema.json",
56
+ "identifier": "main-window",
57
+ "description": "메인 윈도우 전체 권한",
58
+ "windows": ["main"],
59
+ "permissions": [
60
+ "core:default",
61
+ "core:window:allow-close",
62
+ "core:window:allow-minimize",
63
+ {
64
+ "identifier": "fs:allow-read-text-file",
65
+ "allow": [{ "path": "$APPDATA/my-app/*" }]
66
+ },
67
+ {
68
+ "identifier": "fs:allow-write-text-file",
69
+ "allow": [{ "path": "$APPDATA/my-app/*" }]
70
+ },
71
+ "shell:allow-open",
72
+ "http:allow-fetch"
73
+ ]
74
+ }
75
+ ```
76
+
77
+ ```json
78
+ // src-tauri/capabilities/worker-window.json
79
+ {
80
+ "$schema": "../gen/schemas/desktop-schema.json",
81
+ "identifier": "worker-window",
82
+ "description": "백그라운드 작업 윈도우 (읽기 전용)",
83
+ "windows": ["worker"],
84
+ "permissions": [
85
+ "core:default",
86
+ {
87
+ "identifier": "fs:allow-read-text-file",
88
+ "allow": [{ "path": "$APPDATA/my-app/queue/*" }]
89
+ },
90
+ "http:allow-fetch"
91
+ ]
92
+ }
93
+ ```
94
+
95
+ ```json
96
+ // src-tauri/capabilities/external-viewer.json
97
+ {
98
+ "$schema": "../gen/schemas/desktop-schema.json",
99
+ "identifier": "external-viewer",
100
+ "description": "외부 콘텐츠 뷰어 (최소 권한)",
101
+ "windows": ["external-viewer"],
102
+ "permissions": [
103
+ "core:default",
104
+ "core:window:allow-close"
105
+ ]
106
+ }
107
+ ```
108
+
109
+ ```rust
110
+ // src-tauri/src/main.rs
111
+ fn main() {
112
+ tauri::Builder::default()
113
+ .setup(|app| {
114
+ // 각 윈도우는 자신의 capability를 가짐
115
+ tauri::window::WindowBuilder::new(
116
+ app,
117
+ "external-viewer",
118
+ tauri::WindowUrl::External("https://untrusted.com".parse().unwrap())
119
+ ).build()?;
120
+ Ok(())
121
+ })
122
+ .run(tauri::generate_context!())
123
+ .expect("error while running tauri application");
124
+ }
125
+ ```
126
+
127
+ **장점:**
128
+ - 각 윈도우는 필요한 최소 권한만 가짐
129
+ - 외부 콘텐츠 윈도우는 시스템 접근 불가
130
+ - 백그라운드 워커는 쓰기 권한 없음 (데이터 손상 방지)
131
+ - 공격 성공 시 피해 범위 제한
132
+
133
+ ## 추가 컨텍스트
134
+
135
+ **Capability 병합 규칙:**
136
+
137
+ Tauri는 여러 capability 파일을 자동으로 병합합니다. 윈도우는 자신의 이름이 `windows` 배열에 포함된 모든 capability의 권한을 받습니다.
138
+
139
+ ```json
140
+ // capabilities/base.json
141
+ {
142
+ "identifier": "base",
143
+ "windows": ["main", "worker"],
144
+ "permissions": ["core:default"]
145
+ }
146
+
147
+ // capabilities/main-only.json
148
+ {
149
+ "identifier": "main-only",
150
+ "windows": ["main"],
151
+ "permissions": ["fs:allow-write-text-file"]
152
+ }
153
+ ```
154
+
155
+ 결과:
156
+ - `main` 윈도우: `core:default` + `fs:allow-write-text-file`
157
+ - `worker` 윈도우: `core:default`만
158
+
159
+ **일반적인 윈도우 타입별 권한 예시:**
160
+
161
+ | 윈도우 타입 | 설명 | 필요한 권한 |
162
+ |-----------|------|-----------|
163
+ | `main` | 메인 애플리케이션 UI | 전체 파일 시스템, HTTP, 일부 셸 |
164
+ | `settings` | 설정 창 | 설정 파일 읽기/쓰기만 |
165
+ | `worker` | 백그라운드 작업 | HTTP, 임시 파일 읽기/쓰기 |
166
+ | `preview` | 파일 미리보기 | 읽기 전용 파일 시스템 |
167
+ | `external` | 외부 웹 콘텐츠 | 윈도우 제어만 (close/minimize) |
168
+ | `admin` | 관리자 기능 | 전체 권한 (추가 인증 필요) |
169
+
170
+ **보안 설계 패턴:**
171
+
172
+ 1. **신뢰 경계 식별**
173
+ ```
174
+ 신뢰도: main > settings > worker > preview > external
175
+ 권한: 많음 ←------------------------→ 적음
176
+ ```
177
+
178
+ 2. **기본 권한 + 확장 패턴**
179
+ ```json
180
+ // base.json: 모든 윈도우에 기본 권한
181
+ { "windows": ["*"], "permissions": ["core:default"] }
182
+
183
+ // main.json: 메인 윈도우만 확장
184
+ { "windows": ["main"], "permissions": ["fs:allow-*"] }
185
+ ```
186
+
187
+ 3. **명시적 윈도우 나열**
188
+ ```json
189
+ // ❌ 와일드카드 사용
190
+ { "windows": ["*"], "permissions": ["fs:allow-write-text-file"] }
191
+
192
+ // ✅ 필요한 윈도우만 명시
193
+ { "windows": ["main", "settings"], "permissions": ["fs:allow-write-text-file"] }
194
+ ```
195
+
196
+ **체크리스트:**
197
+ - [ ] 각 윈도우의 신뢰 수준을 평가함
198
+ - [ ] 외부 콘텐츠를 표시하는 윈도우는 최소 권한만
199
+ - [ ] 백그라운드 워커는 쓰기 권한 최소화
200
+ - [ ] 관리자 기능은 별도 윈도우로 분리
201
+ - [ ] Capability 파일 이름이 윈도우 이름과 일치 (가독성)
202
+
203
+ **참조:**
204
+ - [Tauri Multi-Window Security](https://tauri.app/v2/security/#multi-window-applications)
205
+ - [Capability Configuration](https://tauri.app/v2/core/capability/)
@@ -0,0 +1,207 @@
1
+ # Content Security Policy 설정
2
+
3
+ ## 왜 중요한가
4
+
5
+ Content Security Policy(CSP)는 웹 애플리케이션에서 실행 가능한 스크립트의 출처를 제한하여 XSS(Cross-Site Scripting) 공격을 방지합니다. Tauri 애플리케이션은 로컬 파일로 실행되지만, 외부 API 호출이나 사용자 입력을 처리할 때 여전히 XSS 위험이 있습니다. 강력한 CSP는 악의적인 스크립트가 실행되는 것을 원천 차단합니다.
6
+
7
+ ## ❌ 잘못된 패턴
8
+
9
+ ```html
10
+ <!-- index.html: CSP 미설정 -->
11
+ <!DOCTYPE html>
12
+ <html>
13
+ <head>
14
+ <meta charset="UTF-8" />
15
+ <title>My App</title>
16
+ </head>
17
+ <body>
18
+ <div id="root"></div>
19
+ <script type="module" src="/src/main.tsx"></script>
20
+ </body>
21
+ </html>
22
+ ```
23
+
24
+ ```html
25
+ <!-- index.html: 너무 관대한 CSP -->
26
+ <!DOCTYPE html>
27
+ <html>
28
+ <head>
29
+ <meta charset="UTF-8" />
30
+ <meta http-equiv="Content-Security-Policy"
31
+ content="default-src *; script-src * 'unsafe-inline' 'unsafe-eval'; style-src * 'unsafe-inline';" />
32
+ <title>My App</title>
33
+ </head>
34
+ <body>
35
+ <div id="root"></div>
36
+ <script type="module" src="/src/main.tsx"></script>
37
+ </body>
38
+ </html>
39
+ ```
40
+
41
+ **문제점:**
42
+ - CSP 미설정: 모든 출처의 스크립트 실행 가능
43
+ - `unsafe-eval`: `eval()`, `Function()` 사용 가능 (동적 코드 실행)
44
+ - `unsafe-inline`: 인라인 스크립트/스타일 허용 (XSS 주입 가능)
45
+ - `default-src *`: 모든 리소스 출처 허용
46
+ - 공격자가 임의의 스크립트를 주입하여 Tauri API 호출 가능
47
+
48
+ ## ✅ 올바른 패턴
49
+
50
+ ```html
51
+ <!-- index.html: 기본 Tauri CSP -->
52
+ <!DOCTYPE html>
53
+ <html>
54
+ <head>
55
+ <meta charset="UTF-8" />
56
+ <meta http-equiv="Content-Security-Policy"
57
+ content="default-src 'self' tauri:; script-src 'self' tauri:; style-src 'self' tauri: 'unsafe-inline'; img-src 'self' tauri: data: https:;" />
58
+ <title>My App</title>
59
+ </head>
60
+ <body>
61
+ <div id="root"></div>
62
+ <script type="module" src="/src/main.tsx"></script>
63
+ </body>
64
+ </html>
65
+ ```
66
+
67
+ **장점:**
68
+ - `default-src 'self' tauri:`: 로컬 리소스와 Tauri 프로토콜만 허용
69
+ - `script-src 'self' tauri:`: 외부 스크립트 차단
70
+ - `img-src ... https:`: 이미지는 HTTPS 외부 출처 허용
71
+ - `style-src ... 'unsafe-inline'`: CSS-in-JS 라이브러리 호환 (필요 시)
72
+ - 인라인 스크립트 차단으로 XSS 방어
73
+
74
+ **추가 예시 (외부 API 사용):**
75
+
76
+ ```html
77
+ <!-- index.html: 외부 API와 nonce 사용 -->
78
+ <!DOCTYPE html>
79
+ <html>
80
+ <head>
81
+ <meta charset="UTF-8" />
82
+ <meta http-equiv="Content-Security-Policy"
83
+ content="default-src 'self' tauri:;
84
+ script-src 'self' tauri: 'nonce-random123';
85
+ connect-src 'self' https://api.example.com;
86
+ style-src 'self' tauri: 'unsafe-inline';
87
+ img-src 'self' tauri: data: https:;" />
88
+ <title>My App</title>
89
+ </head>
90
+ <body>
91
+ <div id="root"></div>
92
+ <script type="module" nonce="random123" src="/src/main.tsx"></script>
93
+ </body>
94
+ </html>
95
+ ```
96
+
97
+ **추가 예시 (프로덕션 환경):**
98
+
99
+ ```json
100
+ // tauri.conf.json
101
+ {
102
+ "app": {
103
+ "security": {
104
+ "csp": "default-src 'self' tauri:; script-src 'self' tauri:; style-src 'self' tauri: 'unsafe-inline'; img-src 'self' tauri: data: https:; connect-src 'self' https://api.example.com"
105
+ }
106
+ }
107
+ }
108
+ ```
109
+
110
+ ## 추가 컨텍스트
111
+
112
+ **CSP 지시자 설명:**
113
+
114
+ | 지시자 | 설명 | Tauri 권장값 |
115
+ |-------|------|-------------|
116
+ | `default-src` | 모든 리소스의 기본 정책 | `'self' tauri:` |
117
+ | `script-src` | JavaScript 출처 | `'self' tauri:` (nonce 추가 가능) |
118
+ | `style-src` | CSS 출처 | `'self' tauri: 'unsafe-inline'` |
119
+ | `img-src` | 이미지 출처 | `'self' tauri: data: https:` |
120
+ | `font-src` | 폰트 출처 | `'self' tauri: data:` |
121
+ | `connect-src` | AJAX, WebSocket 출처 | `'self' https://api.example.com` |
122
+ | `media-src` | 오디오/비디오 출처 | `'self' tauri:` |
123
+
124
+ **특수 키워드:**
125
+
126
+ | 키워드 | 의미 | 사용 권장 |
127
+ |-------|------|----------|
128
+ | `'self'` | 현재 도메인 (tauri://localhost) | ✅ 필수 |
129
+ | `tauri:` | Tauri 프로토콜 (`asset:`, `ipc:`) | ✅ 필수 |
130
+ | `'unsafe-inline'` | 인라인 스크립트/스타일 허용 | ❌ script-src에는 금지 |
131
+ | `'unsafe-eval'` | eval() 허용 | ❌ 절대 금지 |
132
+ | `'nonce-xxx'` | 특정 nonce를 가진 스크립트만 | ✅ 동적 스크립트 시 권장 |
133
+ | `data:` | data: URI 허용 | ⚠️ img-src, font-src만 |
134
+ | `https:` | 모든 HTTPS 출처 | ⚠️ img-src만 허용 |
135
+
136
+ **React 앱 호환성:**
137
+
138
+ ```html
139
+ <!-- Vite + React + Tauri -->
140
+ <!DOCTYPE html>
141
+ <html>
142
+ <head>
143
+ <meta charset="UTF-8" />
144
+ <!-- Vite는 빌드 시 모듈 스크립트로 변환 -->
145
+ <meta http-equiv="Content-Security-Policy"
146
+ content="default-src 'self' tauri:;
147
+ script-src 'self' tauri:;
148
+ style-src 'self' tauri: 'unsafe-inline';
149
+ img-src 'self' tauri: data: https:;
150
+ connect-src 'self' https://api.example.com;" />
151
+ <title>My App</title>
152
+ </head>
153
+ <body>
154
+ <div id="root"></div>
155
+ <!-- 모듈 스크립트는 기본적으로 안전 -->
156
+ <script type="module" src="/src/main.tsx"></script>
157
+ </body>
158
+ </html>
159
+ ```
160
+
161
+ **CSP 위반 디버깅:**
162
+
163
+ ```typescript
164
+ // src/main.tsx
165
+ // CSP 위반 시 콘솔에 에러 출력
166
+ window.addEventListener('securitypolicyviolation', (e) => {
167
+ console.error('CSP Violation:', {
168
+ blockedURI: e.blockedURI,
169
+ violatedDirective: e.violatedDirective,
170
+ originalPolicy: e.originalPolicy,
171
+ });
172
+ });
173
+ ```
174
+
175
+ **점진적 강화 전략:**
176
+
177
+ 1. **개발 단계**: 관대한 CSP로 시작
178
+ ```
179
+ default-src 'self' tauri:;
180
+ script-src 'self' tauri: 'unsafe-inline';
181
+ style-src 'self' tauri: 'unsafe-inline';
182
+ ```
183
+
184
+ 2. **테스트 단계**: `unsafe-inline` 제거, nonce 추가
185
+ ```
186
+ script-src 'self' tauri: 'nonce-${random}';
187
+ ```
188
+
189
+ 3. **프로덕션**: 최소 권한 CSP
190
+ ```
191
+ default-src 'self' tauri:;
192
+ script-src 'self' tauri:;
193
+ connect-src 'self' https://api.example.com;
194
+ ```
195
+
196
+ **체크리스트:**
197
+ - [ ] CSP 헤더가 설정되어 있음
198
+ - [ ] `unsafe-eval` 사용 안 함
199
+ - [ ] `script-src`에 `unsafe-inline` 사용 안 함 (또는 nonce 사용)
200
+ - [ ] `connect-src`로 API 엔드포인트 명시
201
+ - [ ] 개발자 도구에서 CSP 위반 확인
202
+ - [ ] 프로덕션 빌드에서 CSP 테스트
203
+
204
+ **참조:**
205
+ - [Tauri Security CSP Guide](https://tauri.app/v2/security/#content-security-policy)
206
+ - [MDN CSP Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
207
+ - [CSP Evaluator](https://csp-evaluator.withgoogle.com/)