@kood/claude-code 0.6.6 → 0.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +7 -1
- package/package.json +1 -1
- package/templates/.claude/agents/researcher.md +8 -1
- package/templates/.claude/instructions/sourcing/reliable-search.md +49 -2
- package/templates/.claude/skills/docs-fetch/SKILL.md +5 -4
- package/templates/.claude/skills/project-optimizer/AGENTS.md +275 -0
- package/templates/.claude/skills/project-optimizer/SKILL.md +374 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-config-centralize.md +66 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-hot-path.md +35 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-interface-segregation.md +51 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-module-boundary.md +42 -0
- package/templates/.claude/skills/project-optimizer/rules/build-cache.md +57 -0
- package/templates/.claude/skills/project-optimizer/rules/build-code-split.md +56 -0
- package/templates/.claude/skills/project-optimizer/rules/build-incremental.md +65 -0
- package/templates/.claude/skills/project-optimizer/rules/build-minify.md +61 -0
- package/templates/.claude/skills/project-optimizer/rules/build-tree-shake.md +60 -0
- package/templates/.claude/skills/project-optimizer/rules/code-complexity.md +65 -0
- package/templates/.claude/skills/project-optimizer/rules/code-dead-elimination.md +32 -0
- package/templates/.claude/skills/project-optimizer/rules/code-duplication.md +54 -0
- package/templates/.claude/skills/project-optimizer/rules/code-error-handling.md +75 -0
- package/templates/.claude/skills/project-optimizer/rules/code-naming.md +52 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-defer-await.md +54 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-parallel.md +90 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-pipeline.md +68 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-pool.md +68 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-lightweight-alt.md +37 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-peer-align.md +44 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-security-audit.md +45 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-unused-removal.md +25 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-version-pin.md +40 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-ci-speed.md +47 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-dev-server.md +35 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-lint-config.md +36 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-test-coverage.md +34 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-type-safety.md +49 -0
- package/templates/.claude/skills/project-optimizer/rules/io-batch-queries.md +67 -0
- package/templates/.claude/skills/project-optimizer/rules/io-cache-layer.md +67 -0
- package/templates/.claude/skills/project-optimizer/rules/io-connection-reuse.md +67 -0
- package/templates/.claude/skills/project-optimizer/rules/io-serialize-minimal.md +61 -0
- package/templates/.claude/skills/project-optimizer/rules/io-stream.md +75 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-bounded-cache.md +65 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-large-data.md +64 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-lazy-init.md +78 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-leak-prevention.md +79 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-pool-reuse.md +70 -0
- package/templates/.claude/skills/sql-optimizer/SKILL.md +437 -0
- package/templates/.claude/skills/sql-optimizer/orm-patterns.md +218 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/AGENTS.md +53 -14
- package/templates/.claude/skills/tanstack-start-react-best-practices/SKILL.md +93 -27
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-defer-third-party.md +42 -19
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-optimistic-updates.md +109 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-suspense-query.md +74 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-use-hook.md +81 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-react-compiler.md +81 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-beforeload-auth.md +121 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-file-conventions.md +104 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-link-navigation.md +119 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-nested-layouts.md +155 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-path-params.md +89 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-pending-component.md +110 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-preload-strategy.md +91 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-router-context.md +120 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-search-params.md +114 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-deferred-data.md +1 -1
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-error-boundaries.md +79 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-middleware.md +85 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-serialization.md +56 -21
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-streaming.md +84 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-validator.md +71 -0
- package/templates/.claude/skills/tauri-react-best-practices/AGENTS.md +527 -0
- package/templates/.claude/skills/tauri-react-best-practices/SKILL.md +570 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-barrel-imports.md +140 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-cargo-profile.md +96 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-frontend-treeshake.md +242 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-lazy-components.md +255 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-remove-unused-commands.md +160 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-ci-pipeline.md +269 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-signing.md +207 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-updater.md +226 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-async-commands.md +172 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-batch-commands.md +133 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-binary-response.md +198 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-channel-streaming.md +186 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-error-handling.md +250 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-type-safe.md +227 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-derived-state.md +231 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-functional-setstate.md +191 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-index-maps.md +276 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-lazy-state-init.md +196 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-lifecycle.md +265 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-mobile-compat.md +199 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-permission-scope.md +193 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-error-boundary.md +239 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-event-listener.md +151 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-file-src.md +155 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-invoke-hook.md +139 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-optimistic-update.md +211 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-capability-split.md +205 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-csp.md +207 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-least-privilege.md +106 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-no-wildcard.md +253 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-scope-paths.md +160 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-async-mutex.md +270 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-mutex-pattern.md +265 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-react-sync.md +375 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-single-container.md +275 -0
- package/templates/tanstack-start/docs/architecture.md +238 -167
- package/templates/tanstack-start/docs/library/tanstack-router/error-handling.md +777 -38
- package/templates/tanstack-start/docs/library/tanstack-router/hooks.md +549 -37
- package/templates/tanstack-start/docs/library/tanstack-router/index.md +895 -111
- package/templates/tanstack-start/docs/library/tanstack-router/navigation.md +641 -43
- package/templates/tanstack-start/docs/library/tanstack-router/route-context.md +889 -38
- package/templates/tanstack-start/docs/library/tanstack-router/search-params.md +891 -29
- package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +972 -36
- package/templates/tanstack-start/docs/library/tanstack-start/index.md +1525 -881
- package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +1099 -20
- package/templates/tanstack-start/docs/library/tanstack-start/routing.md +796 -30
- package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +953 -35
- package/templates/tanstack-start/docs/library/tanstack-start/setup.md +371 -15
- package/templates/tauri/CLAUDE.md +189 -0
- package/templates/tauri/docs/guides/distribution.md +261 -0
- package/templates/tauri/docs/guides/getting-started.md +302 -0
- package/templates/tauri/docs/guides/mobile.md +288 -0
- package/templates/tauri/docs/library/tauri/index.md +510 -0
|
@@ -1,52 +1,408 @@
|
|
|
1
1
|
# TanStack Start - 설치 및 설정
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> v1.159.4 기준
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<installation>
|
|
8
|
+
|
|
9
|
+
## 패키지 설치
|
|
4
10
|
|
|
5
11
|
```bash
|
|
6
|
-
|
|
7
|
-
|
|
12
|
+
npm install @tanstack/react-start @tanstack/react-router react react-dom
|
|
13
|
+
npm install -D vite @vitejs/plugin-react vite-tsconfig-paths typescript @types/react @types/react-dom @types/node
|
|
8
14
|
```
|
|
9
15
|
|
|
10
|
-
|
|
16
|
+
**vinxi 사용 금지**: TanStack Start v1은 Vite를 직접 사용합니다.
|
|
17
|
+
|
|
18
|
+
| 패키지 | 버전 | 용도 |
|
|
19
|
+
|--------|------|------|
|
|
20
|
+
| `@tanstack/react-start` | 최신 | Full-stack framework |
|
|
21
|
+
| `@tanstack/react-router` | 최신 | File-based routing |
|
|
22
|
+
| `react`, `react-dom` | 19+ | React 라이브러리 |
|
|
23
|
+
| `vite` | 7+ | Build tool |
|
|
24
|
+
| `@vitejs/plugin-react` | 최신 | React JSX 처리 |
|
|
25
|
+
| `vite-tsconfig-paths` | 최신 | Path alias 지원 |
|
|
26
|
+
|
|
27
|
+
> **참고:** `@vitejs/plugin-react` 대신 `@vitejs/plugin-react-oxc` 또는 `@vitejs/plugin-react-swc`도 사용 가능합니다.
|
|
28
|
+
|
|
29
|
+
### 프로젝트 생성 (자동)
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm create @tanstack/start@latest my-app
|
|
33
|
+
cd my-app
|
|
34
|
+
npm install
|
|
35
|
+
npm run dev
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
</installation>
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
<vite_config>
|
|
43
|
+
|
|
44
|
+
## vite.config.ts
|
|
11
45
|
|
|
12
46
|
```typescript
|
|
13
|
-
// vite.config.ts
|
|
14
47
|
import { defineConfig } from 'vite'
|
|
15
48
|
import tsConfigPaths from 'vite-tsconfig-paths'
|
|
16
49
|
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
|
|
17
50
|
import viteReact from '@vitejs/plugin-react'
|
|
18
51
|
|
|
19
52
|
export default defineConfig({
|
|
20
|
-
server: {
|
|
21
|
-
|
|
53
|
+
server: {
|
|
54
|
+
port: 3000,
|
|
55
|
+
},
|
|
56
|
+
plugins: [
|
|
57
|
+
tsConfigPaths(),
|
|
58
|
+
tanstackStart(),
|
|
59
|
+
// react 플러그인은 반드시 start 플러그인 뒤에 위치해야 함
|
|
60
|
+
viteReact(),
|
|
61
|
+
],
|
|
62
|
+
})
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**플러그인 순서 (중요):**
|
|
66
|
+
1. `tsConfigPaths()` - Path alias
|
|
67
|
+
2. `tanstackStart()` - Server Functions, SSR
|
|
68
|
+
3. `viteReact()` - JSX 처리 (반드시 start 뒤에!)
|
|
69
|
+
|
|
70
|
+
### Server Function ID 커스터마이징 (실험적)
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { defineConfig } from 'vite'
|
|
74
|
+
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
|
|
75
|
+
import viteReact from '@vitejs/plugin-react'
|
|
76
|
+
|
|
77
|
+
export default defineConfig({
|
|
78
|
+
plugins: [
|
|
79
|
+
tanstackStart({
|
|
80
|
+
serverFns: {
|
|
81
|
+
generateFunctionId: ({ filename, functionName }) => {
|
|
82
|
+
return crypto
|
|
83
|
+
.createHash('sha1')
|
|
84
|
+
.update(`${filename}--${functionName}`)
|
|
85
|
+
.digest('hex')
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
}),
|
|
89
|
+
viteReact(),
|
|
90
|
+
],
|
|
22
91
|
})
|
|
23
92
|
```
|
|
24
93
|
|
|
94
|
+
</vite_config>
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
<typescript_config>
|
|
99
|
+
|
|
100
|
+
## tsconfig.json
|
|
101
|
+
|
|
25
102
|
```json
|
|
26
|
-
// tsconfig.json
|
|
27
103
|
{
|
|
28
104
|
"compilerOptions": {
|
|
29
105
|
"target": "ES2022",
|
|
30
106
|
"module": "ESNext",
|
|
31
|
-
"moduleResolution": "
|
|
107
|
+
"moduleResolution": "Bundler",
|
|
32
108
|
"strict": true,
|
|
33
109
|
"jsx": "react-jsx",
|
|
34
|
-
"
|
|
110
|
+
"strictNullChecks": true,
|
|
111
|
+
"skipLibCheck": true,
|
|
112
|
+
"paths": {
|
|
113
|
+
"@/*": ["./src/*"]
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"include": ["src"],
|
|
117
|
+
"exclude": ["node_modules"]
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**주의사항:**
|
|
122
|
+
- `strictNullChecks: true` - null/undefined 체크 필수
|
|
123
|
+
- `jsx: "react-jsx"` - React 17+ 문법
|
|
124
|
+
- `moduleResolution: "Bundler"` - Vite와 호환 (대소문자 주의)
|
|
125
|
+
- `verbatimModuleSyntax` **사용 금지** - 서버 번들이 클라이언트 번들로 유출될 수 있음
|
|
126
|
+
- `skipLibCheck: true` 권장
|
|
127
|
+
|
|
128
|
+
</typescript_config>
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
<package_json>
|
|
133
|
+
|
|
134
|
+
## package.json Scripts
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"type": "module",
|
|
139
|
+
"scripts": {
|
|
140
|
+
"dev": "vite dev",
|
|
141
|
+
"build": "vite build",
|
|
142
|
+
"start": "node .output/server/index.mjs",
|
|
143
|
+
"preview": "vite preview",
|
|
144
|
+
"type-check": "tsc --noEmit"
|
|
35
145
|
}
|
|
36
146
|
}
|
|
37
147
|
```
|
|
38
148
|
|
|
39
|
-
|
|
149
|
+
| Script | 명령 | 설명 |
|
|
150
|
+
|--------|------|------|
|
|
151
|
+
| `dev` | `vite dev` | 개발 서버 (Hot reload) |
|
|
152
|
+
| `build` | `vite build` | 프로덕션 빌드 (`.output/` 생성) |
|
|
153
|
+
| `start` | `node .output/server/index.mjs` | 프로덕션 서버 |
|
|
154
|
+
|
|
155
|
+
> **참고:** `package.json`에 `"type": "module"` 설정이 필요합니다.
|
|
156
|
+
|
|
157
|
+
</package_json>
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
<required_files>
|
|
162
|
+
|
|
163
|
+
## 필수 파일
|
|
164
|
+
|
|
165
|
+
TanStack Start 사용에 필요한 최소 파일:
|
|
166
|
+
|
|
167
|
+
### 1. Router 설정 (src/router.tsx)
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
// src/router.tsx
|
|
171
|
+
import { createRouter } from '@tanstack/react-router'
|
|
172
|
+
import { routeTree } from './routeTree.gen'
|
|
173
|
+
|
|
174
|
+
// 매번 새 router 인스턴스를 반환하는 함수를 export해야 합니다
|
|
175
|
+
export function getRouter() {
|
|
176
|
+
const router = createRouter({
|
|
177
|
+
routeTree,
|
|
178
|
+
scrollRestoration: true,
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
return router
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### 2. Root Route (src/routes/__root.tsx)
|
|
186
|
+
|
|
187
|
+
```tsx
|
|
188
|
+
// src/routes/__root.tsx
|
|
189
|
+
/// <reference types="vite/client" />
|
|
190
|
+
import type { ReactNode } from 'react'
|
|
191
|
+
import {
|
|
192
|
+
Outlet,
|
|
193
|
+
createRootRoute,
|
|
194
|
+
HeadContent,
|
|
195
|
+
Scripts,
|
|
196
|
+
} from '@tanstack/react-router'
|
|
197
|
+
|
|
198
|
+
export const Route = createRootRoute({
|
|
199
|
+
head: () => ({
|
|
200
|
+
meta: [
|
|
201
|
+
{ charSet: 'utf-8' },
|
|
202
|
+
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
|
203
|
+
{ title: 'My App' },
|
|
204
|
+
],
|
|
205
|
+
}),
|
|
206
|
+
component: RootComponent,
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
function RootComponent() {
|
|
210
|
+
return (
|
|
211
|
+
<RootDocument>
|
|
212
|
+
<Outlet />
|
|
213
|
+
</RootDocument>
|
|
214
|
+
)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
|
|
218
|
+
return (
|
|
219
|
+
<html>
|
|
220
|
+
<head>
|
|
221
|
+
<HeadContent />
|
|
222
|
+
</head>
|
|
223
|
+
<body>
|
|
224
|
+
{children}
|
|
225
|
+
<Scripts />
|
|
226
|
+
</body>
|
|
227
|
+
</html>
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**핵심 컴포넌트:**
|
|
233
|
+
- `<HeadContent />` - `<head>` 태그 안에 배치, meta/title/link 렌더링
|
|
234
|
+
- `<Outlet />` - 자식 라우트 렌더링
|
|
235
|
+
- `<Scripts />` - `<body>` 태그 안에 배치, 클라이언트 JavaScript 로드 (필수)
|
|
236
|
+
|
|
237
|
+
### 3. Route Tree (src/routeTree.gen.ts)
|
|
238
|
+
|
|
239
|
+
이 파일은 `npm run dev` 또는 `npm run build` 실행 시 **자동 생성**됩니다. 수동으로 생성하지 마세요.
|
|
240
|
+
|
|
241
|
+
### 4. Start 설정 (src/start.ts) - 선택적
|
|
242
|
+
|
|
243
|
+
전역 미들웨어나 Start 레벨 옵션 설정 시 필요:
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
// src/start.ts
|
|
247
|
+
import { createStart } from '@tanstack/react-start'
|
|
248
|
+
|
|
249
|
+
export const startInstance = createStart(() => ({
|
|
250
|
+
// 전역 미들웨어, SSR 기본값 등 설정
|
|
251
|
+
}))
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
</required_files>
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
<environment_variables>
|
|
259
|
+
|
|
260
|
+
## 환경 변수 설정
|
|
261
|
+
|
|
262
|
+
### .env (프로젝트 루트)
|
|
263
|
+
|
|
264
|
+
```env
|
|
265
|
+
# 데이터베이스
|
|
266
|
+
DATABASE_URL=postgresql://user:password@localhost:5432/myapp
|
|
267
|
+
|
|
268
|
+
# 서버
|
|
269
|
+
API_SECRET=your-secret-key-min-32-characters-long
|
|
270
|
+
|
|
271
|
+
# 클라이언트 (VITE_ prefix)
|
|
272
|
+
VITE_API_BASEURL=http://localhost:3000
|
|
273
|
+
VITE_ENVIRONMENT=development
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### lib/env.ts (Zod 검증)
|
|
40
277
|
|
|
41
278
|
```typescript
|
|
42
|
-
// lib/env.ts
|
|
43
279
|
import { z } from 'zod'
|
|
44
280
|
|
|
45
|
-
|
|
46
|
-
|
|
281
|
+
// 서버 환경변수 (process.env)
|
|
282
|
+
const serverEnvSchema = z.object({
|
|
283
|
+
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
|
|
47
284
|
DATABASE_URL: z.string().url(),
|
|
48
285
|
API_SECRET: z.string().min(32),
|
|
49
286
|
})
|
|
50
287
|
|
|
51
|
-
export const
|
|
288
|
+
export const serverEnv = serverEnvSchema.parse(process.env)
|
|
289
|
+
|
|
290
|
+
// 클라이언트 환경변수 (import.meta.env)
|
|
291
|
+
const clientEnvSchema = z.object({
|
|
292
|
+
VITE_API_BASEURL: z.string().url().default('http://localhost:3000'),
|
|
293
|
+
VITE_ENVIRONMENT: z.enum(['development', 'production']).default('development'),
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
export const clientEnv = clientEnvSchema.parse(import.meta.env)
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**보안 규칙:**
|
|
300
|
+
- Server Function에서만 `serverEnv` 사용
|
|
301
|
+
- Loader에서 `process.env` 직접 접근 금지 (클라이언트 노출)
|
|
302
|
+
- 클라이언트에서는 `clientEnv` 사용
|
|
303
|
+
- `VITE_` prefix로 시작하는 환경변수만 클라이언트 노출
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
// 올바른 방식: Server Function에서 검증
|
|
307
|
+
export const getSecretConfig = createServerFn({ method: 'GET' })
|
|
308
|
+
.middleware([authMiddleware])
|
|
309
|
+
.handler(async () => {
|
|
310
|
+
return { secret: serverEnv.API_SECRET }
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
// 잘못된 방식: Loader에서 직접 사용
|
|
314
|
+
export const Route = createFileRoute('/config')({
|
|
315
|
+
loader: () => {
|
|
316
|
+
const secret = process.env.API_SECRET // 클라이언트에 노출!
|
|
317
|
+
return { secret }
|
|
318
|
+
},
|
|
319
|
+
})
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
</environment_variables>
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
<project_structure>
|
|
327
|
+
|
|
328
|
+
## 초기 프로젝트 구조
|
|
329
|
+
|
|
52
330
|
```
|
|
331
|
+
my-app/
|
|
332
|
+
├── src/
|
|
333
|
+
│ ├── routes/
|
|
334
|
+
│ │ ├── __root.tsx # Root layout (html/body)
|
|
335
|
+
│ │ ├── index.tsx # /
|
|
336
|
+
│ │ └── $.tsx # Catch-all (404)
|
|
337
|
+
│ ├── router.tsx # Router 설정
|
|
338
|
+
│ ├── routeTree.gen.ts # 자동 생성 (수정 금지)
|
|
339
|
+
│ ├── functions/ # 공통 Server Functions
|
|
340
|
+
│ ├── middleware/ # 공통 Middleware
|
|
341
|
+
│ ├── components/ # UI 컴포넌트
|
|
342
|
+
│ ├── lib/
|
|
343
|
+
│ │ └── env.ts # 환경변수 검증
|
|
344
|
+
│ └── database/ # Prisma
|
|
345
|
+
├── vite.config.ts
|
|
346
|
+
├── tsconfig.json
|
|
347
|
+
├── package.json
|
|
348
|
+
└── .env
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### Server Function 파일 조직 패턴
|
|
352
|
+
|
|
353
|
+
```
|
|
354
|
+
src/utils/
|
|
355
|
+
├── users.functions.ts # Server Function 래퍼 (createServerFn) - 어디서든 import 가능
|
|
356
|
+
├── users.server.ts # 서버 전용 헬퍼 (DB 쿼리 등) - handler 안에서만 import
|
|
357
|
+
└── schemas.ts # 공유 검증 스키마 (클라이언트 안전)
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
> **참고:** Server Function은 정적 import가 안전합니다. 빌드 프로세스가 클라이언트 번들에서 서버 구현을 RPC 스텁으로 교체합니다. 단, 동적 import는 피하세요.
|
|
361
|
+
|
|
362
|
+
</project_structure>
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
<verification>
|
|
367
|
+
|
|
368
|
+
## 설정 확인
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
# 1. 개발 서버 시작
|
|
372
|
+
npm run dev
|
|
373
|
+
|
|
374
|
+
# 2. http://localhost:3000 접속
|
|
375
|
+
|
|
376
|
+
# 3. 타입 체크
|
|
377
|
+
npm run type-check
|
|
378
|
+
|
|
379
|
+
# 4. 프로덕션 빌드
|
|
380
|
+
npm run build
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
성공 기준:
|
|
384
|
+
- 개발 서버 실행
|
|
385
|
+
- Hot reload 작동
|
|
386
|
+
- TypeScript 에러 없음
|
|
387
|
+
- `vite build` 성공 (`.output/` 생성)
|
|
388
|
+
- `routeTree.gen.ts` 자동 생성됨
|
|
389
|
+
|
|
390
|
+
</verification>
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
<version_info>
|
|
395
|
+
|
|
396
|
+
**Version:** TanStack Start/Router v1.159.4
|
|
397
|
+
|
|
398
|
+
**Key Points:**
|
|
399
|
+
- Vite 7+ 필수 (vinxi 사용 안함)
|
|
400
|
+
- `.inputValidator()` 사용 (`.validator()` deprecated)
|
|
401
|
+
- `verbatimModuleSyntax` 사용 금지
|
|
402
|
+
- TypeScript `strict: true` 필수
|
|
403
|
+
- `package.json`에 `"type": "module"` 필수
|
|
404
|
+
- React 플러그인은 반드시 Start 플러그인 뒤에 위치
|
|
405
|
+
- `routeTree.gen.ts`는 자동 생성 (수동 생성 금지)
|
|
406
|
+
- Server Function 정적 import 안전, 동적 import 금지
|
|
407
|
+
|
|
408
|
+
</version_info>
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# CLAUDE.md - Tauri
|
|
2
|
+
|
|
3
|
+
> Cross-platform Desktop & Mobile App Framework
|
|
4
|
+
|
|
5
|
+
<context>
|
|
6
|
+
|
|
7
|
+
**Purpose:** Tauri v2 프레임워크로 데스크톱/모바일 크로스플랫폼 애플리케이션 개발을 위한 작업 지침
|
|
8
|
+
|
|
9
|
+
**Scope:** Rust 백엔드 + React + TypeScript + Vite 프론트엔드 기반 크로스플랫폼 앱 (iOS, Android, Windows, macOS)
|
|
10
|
+
|
|
11
|
+
**Key Features:**
|
|
12
|
+
- Rust 백엔드 + 시스템 WebView (작은 바이너리 사이즈)
|
|
13
|
+
- React + TypeScript + Vite 프론트엔드
|
|
14
|
+
- IPC (Commands + Events) 기반 프론트엔드-백엔드 통신
|
|
15
|
+
- Capabilities/Permissions 보안 모델
|
|
16
|
+
- Plugin 시스템 (데스크톱 + 모바일 네이티브 확장)
|
|
17
|
+
- iOS, Android, Windows, macOS, Linux 빌드
|
|
18
|
+
|
|
19
|
+
</context>
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
<instructions>
|
|
24
|
+
@docs/library/tauri/index.md
|
|
25
|
+
@docs/guides/getting-started.md
|
|
26
|
+
@docs/guides/mobile.md
|
|
27
|
+
@docs/guides/distribution.md
|
|
28
|
+
</instructions>
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
<forbidden>
|
|
33
|
+
|
|
34
|
+
| 분류 | 금지 행동 |
|
|
35
|
+
|------|----------|
|
|
36
|
+
| **보안** | Capabilities 없이 Command 노출, CSP 비활성화, `'unsafe-eval'` 무분별 사용 |
|
|
37
|
+
| **IPC** | 프론트엔드에서 Rust 함수 직접 호출 (invoke 사용), 민감 데이터 Event로 브로드캐스트 |
|
|
38
|
+
| **상태관리** | Arc 래핑 (State<T>가 내부 처리), 비동기 코드에서 await 걸쳐 Mutex lock 유지 |
|
|
39
|
+
| **모바일** | iOS 개발을 macOS 외 플랫폼에서 시도, Android 메인 스레드에서 블로킹 I/O |
|
|
40
|
+
| **빌드** | `--no-verify` 또는 보안 검증 우회, WebView2 설치 skip |
|
|
41
|
+
| **v1 API** | allowlist 사용 (capabilities 사용), `@tauri-apps/api/tauri` import (core 사용), Window 타입 (WebviewWindow 사용) |
|
|
42
|
+
|
|
43
|
+
</forbidden>
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
<required>
|
|
48
|
+
|
|
49
|
+
| 작업 | 필수 행동 |
|
|
50
|
+
|------|----------|
|
|
51
|
+
| **Command 정의** | `#[tauri::command]` 어노테이션, `tauri::generate_handler!` 등록 |
|
|
52
|
+
| **프론트엔드 호출** | `invoke()` from `@tauri-apps/api/core` 사용 |
|
|
53
|
+
| **보안** | Capabilities 파일 정의 (`src-tauri/capabilities/`), Permission 명시 |
|
|
54
|
+
| **상태관리** | `app.manage()` + `State<T>` 패턴, 가변 상태 → `Mutex<T>` |
|
|
55
|
+
| **모바일 빌드** | `tauri android init` / `tauri ios init` 먼저 실행 |
|
|
56
|
+
| **Plugin 사용** | Plugin별 Permission 추가 (`src-tauri/capabilities/`) |
|
|
57
|
+
| **타입 안전성** | Command 인자/반환 → `serde::Serialize`/`Deserialize` |
|
|
58
|
+
| **에러 처리** | Command → `Result<T, E>` 반환, Error 타입 직렬화 가능 |
|
|
59
|
+
|
|
60
|
+
</required>
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
<tech_stack>
|
|
65
|
+
|
|
66
|
+
| 기술 | 버전 | 주의 |
|
|
67
|
+
|------|------|------|
|
|
68
|
+
| Tauri | 2.x | CLI: @tauri-apps/cli@latest |
|
|
69
|
+
| Rust | stable | MSVC 툴체인 (Windows) |
|
|
70
|
+
| React | 19.x | - |
|
|
71
|
+
| TypeScript | 5.x | strict |
|
|
72
|
+
| Vite | 6.x | strictPort: true |
|
|
73
|
+
| @tauri-apps/api | 2.x | core, webviewWindow |
|
|
74
|
+
|
|
75
|
+
</tech_stack>
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
<structure>
|
|
80
|
+
```
|
|
81
|
+
my-tauri-app/
|
|
82
|
+
├── src/ # React + TypeScript 프론트엔드
|
|
83
|
+
│ ├── App.tsx
|
|
84
|
+
│ ├── main.tsx
|
|
85
|
+
│ └── components/
|
|
86
|
+
├── src-tauri/ # Rust 백엔드
|
|
87
|
+
│ ├── src/
|
|
88
|
+
│ │ ├── main.rs # 앱 엔트리, Command 등록
|
|
89
|
+
│ │ ├── lib.rs # 라이브러리 (모바일 지원)
|
|
90
|
+
│ │ └── commands/ # Command 모듈
|
|
91
|
+
│ ├── capabilities/ # 보안 Capabilities
|
|
92
|
+
│ │ └── default.json
|
|
93
|
+
│ ├── Cargo.toml
|
|
94
|
+
│ ├── tauri.conf.json # Tauri 설정
|
|
95
|
+
│ ├── tauri.android.conf.json # Android 설정
|
|
96
|
+
│ └── tauri.ios.conf.json # iOS 설정
|
|
97
|
+
├── package.json
|
|
98
|
+
├── vite.config.ts
|
|
99
|
+
└── tsconfig.json
|
|
100
|
+
```
|
|
101
|
+
</structure>
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
<conventions>
|
|
106
|
+
|
|
107
|
+
파일명: kebab-case (TS), snake_case (Rust)
|
|
108
|
+
Command: snake_case (Rust) → camelCase (JS invoke)
|
|
109
|
+
Config: `tauri.conf.json` (메인), `tauri.[platform].conf.json` (플랫폼별)
|
|
110
|
+
Capabilities: `src-tauri/capabilities/` (JSON/TOML)
|
|
111
|
+
Permissions: `<plugin>:allow-<command>`, `<plugin>:deny-<command>`
|
|
112
|
+
|
|
113
|
+
</conventions>
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
<quick_patterns>
|
|
118
|
+
|
|
119
|
+
```rust
|
|
120
|
+
// Rust Command 정의
|
|
121
|
+
#[tauri::command]
|
|
122
|
+
async fn greet(name: String) -> Result<String, String> {
|
|
123
|
+
Ok(format!("Hello, {}!", name))
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// State 사용
|
|
127
|
+
#[tauri::command]
|
|
128
|
+
async fn increment(state: State<'_, Mutex<AppState>>) -> Result<u32, String> {
|
|
129
|
+
let mut s = state.lock().unwrap();
|
|
130
|
+
s.counter += 1;
|
|
131
|
+
Ok(s.counter)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// main.rs에 등록
|
|
135
|
+
fn main() {
|
|
136
|
+
tauri::Builder::default()
|
|
137
|
+
.plugin(tauri_plugin_shell::init())
|
|
138
|
+
.setup(|app| {
|
|
139
|
+
app.manage(Mutex::new(AppState { counter: 0 }));
|
|
140
|
+
Ok(())
|
|
141
|
+
})
|
|
142
|
+
.invoke_handler(tauri::generate_handler![greet, increment])
|
|
143
|
+
.run(tauri::generate_context!())
|
|
144
|
+
.expect("error while running tauri application");
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
// 프론트엔드 invoke
|
|
150
|
+
import { invoke } from '@tauri-apps/api/core';
|
|
151
|
+
|
|
152
|
+
const greeting = await invoke<string>('greet', { name: 'World' });
|
|
153
|
+
|
|
154
|
+
// Event 리스닝
|
|
155
|
+
import { listen } from '@tauri-apps/api/event';
|
|
156
|
+
const unlisten = await listen<string>('download-progress', (event) => {
|
|
157
|
+
console.log(event.payload);
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
// src-tauri/capabilities/default.json
|
|
163
|
+
{
|
|
164
|
+
"identifier": "default",
|
|
165
|
+
"description": "기본 앱 권한",
|
|
166
|
+
"windows": ["main"],
|
|
167
|
+
"permissions": [
|
|
168
|
+
"core:default",
|
|
169
|
+
"shell:allow-open"
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
</quick_patterns>
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
<docs_structure>
|
|
179
|
+
```
|
|
180
|
+
docs/
|
|
181
|
+
├── guides/
|
|
182
|
+
│ ├── getting-started.md # 설치, 프로젝트 생성, 개발 시작
|
|
183
|
+
│ ├── mobile.md # iOS/Android 개발 가이드
|
|
184
|
+
│ └── distribution.md # 빌드, 코드 서명, 배포
|
|
185
|
+
└── library/
|
|
186
|
+
└── tauri/
|
|
187
|
+
└── index.md # Tauri 핵심 API + IPC + Security
|
|
188
|
+
```
|
|
189
|
+
</docs_structure>
|