@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.
- package/dist/index.js +7 -1
- package/package.json +1 -1
- package/templates/.claude/agents/analyst.md +5 -0
- package/templates/.claude/agents/architect.md +5 -0
- package/templates/.claude/agents/build-fixer.md +1 -0
- package/templates/.claude/agents/code-reviewer.md +1 -0
- package/templates/.claude/agents/critic.md +4 -0
- package/templates/.claude/agents/deep-executor.md +1 -0
- package/templates/.claude/agents/dependency-manager.md +2 -0
- package/templates/.claude/agents/deployment-validator.md +2 -0
- package/templates/.claude/agents/designer.md +2 -0
- package/templates/.claude/agents/document-writer.md +3 -0
- package/templates/.claude/agents/explore.md +1 -0
- package/templates/.claude/agents/git-operator.md +2 -0
- package/templates/.claude/agents/implementation-executor.md +2 -0
- package/templates/.claude/agents/ko-to-en-translator.md +3 -0
- package/templates/.claude/agents/lint-fixer.md +2 -0
- package/templates/.claude/agents/planner.md +3 -0
- package/templates/.claude/agents/pm.md +349 -0
- package/templates/.claude/agents/qa-tester.md +1 -0
- package/templates/.claude/agents/refactor-advisor.md +4 -0
- package/templates/.claude/agents/researcher.md +9 -1
- package/templates/.claude/agents/scientist.md +1 -0
- package/templates/.claude/agents/security-reviewer.md +1 -0
- package/templates/.claude/agents/tdd-guide.md +1 -0
- package/templates/.claude/agents/vision.md +1 -0
- package/templates/.claude/instructions/agent-patterns/agent-teams-usage.md +376 -0
- package/templates/.claude/instructions/sourcing/reliable-search.md +49 -2
- package/templates/.claude/scripts/agent-teams/check-availability.sh +238 -0
- package/templates/.claude/scripts/agent-teams/setup-tmux.sh +125 -0
- package/templates/.claude/skills/agent-teams-setup/SKILL.md +460 -0
- package/templates/.claude/skills/brainstorm/SKILL.md +1 -0
- package/templates/.claude/skills/bug-fix/SKILL.md +1 -0
- package/templates/.claude/skills/crawler/SKILL.md +2 -0
- package/templates/.claude/skills/docs-creator/SKILL.md +1 -0
- package/templates/.claude/skills/docs-fetch/SKILL.md +6 -4
- package/templates/.claude/skills/docs-refactor/SKILL.md +1 -0
- package/templates/.claude/skills/elon-musk/SKILL.md +1 -0
- package/templates/.claude/skills/execute/SKILL.md +1 -0
- package/templates/.claude/skills/feedback/SKILL.md +1 -0
- package/templates/.claude/skills/figma-to-code/SKILL.md +1 -0
- package/templates/.claude/skills/genius-thinking/SKILL.md +1 -0
- package/templates/.claude/skills/global-uiux-design/SKILL.md +1 -0
- package/templates/.claude/skills/korea-uiux-design/SKILL.md +1 -0
- package/templates/.claude/skills/nextjs-react-best-practices/SKILL.md +1 -0
- package/templates/.claude/skills/plan/SKILL.md +1 -0
- package/templates/.claude/skills/prd/SKILL.md +1 -0
- package/templates/.claude/skills/project-optimizer/AGENTS.md +275 -0
- package/templates/.claude/skills/project-optimizer/SKILL.md +375 -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/ralph/SKILL.md +1 -0
- package/templates/.claude/skills/refactor/SKILL.md +1 -0
- package/templates/.claude/skills/research/SKILL.md +1 -0
- package/templates/.claude/skills/sql-optimizer/SKILL.md +438 -0
- package/templates/.claude/skills/sql-optimizer/orm-patterns.md +218 -0
- package/templates/.claude/skills/startup-validator/SKILL.md +1 -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 +94 -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 +571 -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
|
@@ -18,9 +18,10 @@
|
|
|
18
18
|
| **라우트** | Flat 파일 라우트 (`routes/users.tsx`) |
|
|
19
19
|
| **Route Export** | `export const IndexRoute`, `const Route` (export 안함) |
|
|
20
20
|
| **API** | `/api` 라우터 생성 (Server Functions 사용) |
|
|
21
|
-
| **레이어** |
|
|
21
|
+
| **레이어** | Features 건너뛰기, Routes에서 직접 DB 접근 |
|
|
22
22
|
| **검증** | Handler 내부 수동 검증, 인증 로직 분산 |
|
|
23
|
-
| **Barrel Export** | `functions/index.ts` 생성 (Tree Shaking
|
|
23
|
+
| **Barrel Export** | `functions/index.ts` 생성 (Tree Shaking 실패) |
|
|
24
|
+
| **폴더 구조** | `lib/db`, `lib/store` (→ `database/`, `stores/` 사용) |
|
|
24
25
|
|
|
25
26
|
</forbidden>
|
|
26
27
|
|
|
@@ -32,9 +33,10 @@
|
|
|
32
33
|
|------|------|
|
|
33
34
|
| **라우트 구조** | 페이지마다 폴더 생성 (`routes/users/index.tsx`) |
|
|
34
35
|
| **Route Export** | `export const Route = createFileRoute(...)` 필수 |
|
|
35
|
-
| **계층 구조** | Routes → Server Functions →
|
|
36
|
+
| **계층 구조** | Routes → Server Functions → Features → Database |
|
|
36
37
|
| **Route Group** | 목록 → `(main)/`, 생성/편집 → 외부 |
|
|
37
38
|
| **페이지 분리** | 100줄+ → `-components`, 200줄+ → `-sections` |
|
|
39
|
+
| **컴포넌트 분리** | 로직 있는 컴포넌트 → `-components/-hooks/`로 훅 분리 |
|
|
38
40
|
| **beforeLoad** | 인증 체크, Context 전달, 리다이렉트 |
|
|
39
41
|
| **loader** | 데이터 로딩 (beforeLoad 완료 후 병렬 실행) |
|
|
40
42
|
| **Server Fn** | `createServerFn` 기본 사용 |
|
|
@@ -58,17 +60,29 @@
|
|
|
58
60
|
│ │ React Router │───▶│ TanStack Query │───▶│ React UI │ │
|
|
59
61
|
│ │ (Navigation) │◀───│ (Caching) │◀───│ (Components) │ │
|
|
60
62
|
│ └────────────────┘ └───────┬────────┘ └───────────────┘ │
|
|
63
|
+
│ ┌─────────────────────────────┴─────────────────────────────┐ │
|
|
64
|
+
│ │ State: TanStack Query + Zustand │ │
|
|
65
|
+
│ └───────────────────────────────────────────────────────────┘ │
|
|
61
66
|
└────────────────────────────────┼─────────────────────────────────┘
|
|
62
67
|
▼
|
|
63
68
|
┌─────────────────────────────────────────────────────────────────┐
|
|
64
69
|
│ TanStack Start Server │
|
|
65
70
|
│ ┌────────────────────────────────────────────────────────────┐ │
|
|
71
|
+
│ │ Security: CSP | Rate Limit | CORS │ │
|
|
72
|
+
│ └────────────────────────────┬───────────────────────────────┘ │
|
|
73
|
+
│ ┌────────────────────────────▼───────────────────────────────┐ │
|
|
66
74
|
│ │ Server Functions │ │
|
|
67
|
-
│ │
|
|
75
|
+
│ │ routes/-functions/ (페이지) | functions/ (글로벌) │ │
|
|
76
|
+
│ └────────────────────────────┬───────────────────────────────┘ │
|
|
77
|
+
│ ┌────────────────────────────▼───────────────────────────────┐ │
|
|
78
|
+
│ │ Features (내부 도메인) | Services (외부 SDK) │ │
|
|
79
|
+
│ │ Prisma 쿼리, 스키마 | Stripe, S3, SendGrid │ │
|
|
80
|
+
│ └────────────────────────────┬───────────────────────────────┘ │
|
|
81
|
+
│ ┌────────────────────────────▼───────────────────────────────┐ │
|
|
82
|
+
│ │ Caching: Redis (분산) | Query (로컬) | CDN │ │
|
|
68
83
|
│ └────────────────────────────┬───────────────────────────────┘ │
|
|
69
84
|
│ ┌────────────────────────────▼───────────────────────────────┐ │
|
|
70
|
-
│ │
|
|
71
|
-
│ │ Zod Validation | Business Logic | Data Transformation │ │
|
|
85
|
+
│ │ Monitoring: Sentry (에러) | OpenTelemetry │ │
|
|
72
86
|
│ └────────────────────────────┬───────────────────────────────┘ │
|
|
73
87
|
└───────────────────────────────┼──────────────────────────────────┘
|
|
74
88
|
▼
|
|
@@ -84,6 +98,61 @@
|
|
|
84
98
|
|
|
85
99
|
---
|
|
86
100
|
|
|
101
|
+
<folder_structure>
|
|
102
|
+
|
|
103
|
+
## Folder Structure
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
src/
|
|
107
|
+
├── routes/ # 라우팅 (파일 기반)
|
|
108
|
+
├── components/ # UI 컴포넌트
|
|
109
|
+
│ ├── ui/ # shadcn/ui
|
|
110
|
+
│ ├── layout/ # Header, Sidebar, Footer
|
|
111
|
+
│ └── shared/ # 공용 컴포넌트
|
|
112
|
+
├── features/ # 내부 도메인 (DB 레이어)
|
|
113
|
+
│ └── <domain>/
|
|
114
|
+
│ ├── schemas.ts
|
|
115
|
+
│ ├── queries.ts
|
|
116
|
+
│ └── mutations.ts
|
|
117
|
+
├── services/ # 외부 SDK 연동
|
|
118
|
+
│ ├── stripe/
|
|
119
|
+
│ ├── sendgrid/
|
|
120
|
+
│ ├── s3/
|
|
121
|
+
│ └── openai/
|
|
122
|
+
├── functions/ # 글로벌 Server Functions
|
|
123
|
+
│ └── middlewares/
|
|
124
|
+
├── database/ # Prisma Client
|
|
125
|
+
├── stores/ # Zustand 스토어
|
|
126
|
+
├── hooks/ # 글로벌 훅
|
|
127
|
+
├── types/ # 전역 타입
|
|
128
|
+
├── env/ # 환경 변수 검증 (t3-env)
|
|
129
|
+
├── styles/ # CSS
|
|
130
|
+
├── config/ # 설정
|
|
131
|
+
│ ├── auth.ts
|
|
132
|
+
│ ├── query-client.ts
|
|
133
|
+
│ └── sentry.ts
|
|
134
|
+
└── lib/ # 유틸리티
|
|
135
|
+
├── utils/
|
|
136
|
+
├── constants/
|
|
137
|
+
└── validators/
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 폴더 역할
|
|
141
|
+
|
|
142
|
+
| 폴더 | 역할 | 예시 |
|
|
143
|
+
|------|------|------|
|
|
144
|
+
| **features/** | 내부 도메인, Prisma 쿼리 | users, projects, billing |
|
|
145
|
+
| **services/** | 외부 SDK 래퍼 | Stripe, SendGrid, S3, OpenAI |
|
|
146
|
+
| **functions/** | Server Functions | API 레이어 |
|
|
147
|
+
| **database/** | Prisma Client | 싱글톤 인스턴스 |
|
|
148
|
+
| **stores/** | Zustand 스토어 | 클라이언트 전역 상태 |
|
|
149
|
+
| **config/** | 설정 파일 | auth, query-client, sentry |
|
|
150
|
+
| **lib/** | 유틸리티 | utils, constants, validators |
|
|
151
|
+
|
|
152
|
+
</folder_structure>
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
87
156
|
<route_export_rule>
|
|
88
157
|
|
|
89
158
|
## Route Export 규칙
|
|
@@ -91,8 +160,6 @@
|
|
|
91
160
|
> ⚠️ **`export const Route` 필수**
|
|
92
161
|
>
|
|
93
162
|
> TanStack Router는 모든 라우트 파일에서 **정확히 `Route`라는 이름**으로 내보내야 합니다.
|
|
94
|
-
>
|
|
95
|
-
> `tsr generate` 및 `tsr watch` 명령어가 자동으로 경로를 생성하고 업데이트합니다.
|
|
96
163
|
|
|
97
164
|
| ❌ 금지 | ✅ 필수 |
|
|
98
165
|
|--------|--------|
|
|
@@ -101,16 +168,6 @@
|
|
|
101
168
|
| `export default createFileRoute(...)` | `export const Route = createFileRoute(...)` |
|
|
102
169
|
|
|
103
170
|
```typescript
|
|
104
|
-
// ❌ 금지: export 없음
|
|
105
|
-
const Route = createFileRoute('/users')({
|
|
106
|
-
component: UsersPage,
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
// ❌ 금지: 다른 이름
|
|
110
|
-
export const UsersRoute = createFileRoute('/users')({
|
|
111
|
-
component: UsersPage,
|
|
112
|
-
})
|
|
113
|
-
|
|
114
171
|
// ✅ 필수: 정확히 'Route' 이름으로 export
|
|
115
172
|
export const Route = createFileRoute('/users')({
|
|
116
173
|
component: UsersPage,
|
|
@@ -129,10 +186,6 @@ export const Route = createFileRoute('/users')({
|
|
|
129
186
|
|
|
130
187
|
> ⚠️ **페이지마다 폴더 생성 필수**
|
|
131
188
|
>
|
|
132
|
-
> 모든 페이지는 **반드시 폴더 구조**로 만들어야 합니다. Flat 파일 방식(`routes/users.tsx`)은 금지됩니다.
|
|
133
|
-
>
|
|
134
|
-
> **이유:** -components/, -functions/, -hooks/ 등 페이지 전용 리소스를 체계적으로 관리하기 위함입니다.
|
|
135
|
-
>
|
|
136
189
|
> | ❌ 금지 | ✅ 필수 |
|
|
137
190
|
> |--------|--------|
|
|
138
191
|
> | `routes/users.tsx` | `routes/users/index.tsx` |
|
|
@@ -143,117 +196,174 @@ routes/<route-name>/
|
|
|
143
196
|
├── (main)/ # route group (목록 페이지)
|
|
144
197
|
│ ├── index.tsx # 페이지 컴포넌트
|
|
145
198
|
│ ├── -components/ # 페이지 전용 컴포넌트
|
|
146
|
-
│ ├── -sections/ # UI 섹션 분리 (200줄+
|
|
147
|
-
│ ├── -tabs/ # 탭 콘텐츠 분리
|
|
199
|
+
│ ├── -sections/ # UI 섹션 분리 (200줄+)
|
|
148
200
|
│ ├── -hooks/ # 페이지 전용 훅
|
|
149
201
|
│ └── -utils/ # 상수, 헬퍼
|
|
150
|
-
├── new/ # 생성 페이지
|
|
202
|
+
├── new/ # 생성 페이지
|
|
151
203
|
│ └── index.tsx
|
|
152
|
-
├── route.tsx #
|
|
204
|
+
├── route.tsx # 레이아웃 (loader, beforeLoad)
|
|
153
205
|
└── -functions/ # 페이지 전용 서버 함수
|
|
154
206
|
```
|
|
155
207
|
|
|
156
|
-
| 패턴 |
|
|
157
|
-
|
|
158
|
-
| **Route Group
|
|
159
|
-
| **-components/** |
|
|
160
|
-
| **-sections/** |
|
|
161
|
-
|
|
|
162
|
-
| **route.tsx** | 레이아웃 | 하위 경로 공통 레이아웃 |
|
|
208
|
+
| 패턴 | 용도 |
|
|
209
|
+
|------|------|
|
|
210
|
+
| **Route Group `()`** | URL 미포함, 레이아웃 공유 |
|
|
211
|
+
| **-components/** | 페이지 전용 컴포넌트 (100줄+) |
|
|
212
|
+
| **-sections/** | 논리적 섹션 분리 (200줄+) |
|
|
213
|
+
| **route.tsx** | 하위 경로 공통 레이아웃 |
|
|
163
214
|
|
|
164
|
-
####
|
|
215
|
+
#### Component + Hook 분리
|
|
165
216
|
|
|
166
|
-
>
|
|
167
|
-
>
|
|
168
|
-
> `route.tsx`는 하위 경로의 공통 레이아웃 역할을 합니다.
|
|
169
|
-
> `index.tsx`는 Route Group `()`으로 묶어야 합니다.
|
|
170
|
-
>
|
|
171
|
-
> **필수:** `route.tsx`는 반드시 `component`를 export해야 합니다.
|
|
172
|
-
>
|
|
173
|
-
> | ❌ 금지 | ✅ 필수 |
|
|
174
|
-
> |--------|--------|
|
|
175
|
-
> | `export const Route = createFileRoute(...)({})` | `export const Route = createFileRoute(...)({ component: ... })` |
|
|
217
|
+
> 컴포넌트에 로직(서버 연동, 상태 관리)이 있으면 폴더로 묶고 훅 분리
|
|
176
218
|
|
|
177
219
|
```
|
|
178
|
-
|
|
179
|
-
├──
|
|
180
|
-
│ ├──
|
|
181
|
-
│
|
|
182
|
-
│
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
220
|
+
-components/
|
|
221
|
+
├── user-card/
|
|
222
|
+
│ ├── index.tsx # UI만
|
|
223
|
+
│ └── -hooks/
|
|
224
|
+
│ └── use-user-card.ts # 서버 연동, 상태 로직
|
|
225
|
+
└── user-form/
|
|
226
|
+
├── index.tsx # UI만
|
|
227
|
+
└── -hooks/
|
|
228
|
+
└── use-user-form.ts # 폼 로직, mutation
|
|
187
229
|
```
|
|
188
230
|
|
|
189
231
|
```typescript
|
|
190
|
-
//
|
|
191
|
-
export
|
|
192
|
-
|
|
193
|
-
|
|
232
|
+
// -components/user-form/-hooks/use-user-form.ts
|
|
233
|
+
export function useUserForm(userId?: string) {
|
|
234
|
+
const queryClient = useQueryClient()
|
|
235
|
+
|
|
236
|
+
const { data: user } = useQuery({
|
|
237
|
+
queryKey: ['user', userId],
|
|
238
|
+
queryFn: () => getUser(userId!),
|
|
239
|
+
enabled: !!userId,
|
|
240
|
+
})
|
|
194
241
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
242
|
+
const mutation = useMutation({
|
|
243
|
+
mutationFn: userId ? updateUser : createUser,
|
|
244
|
+
onSuccess: () => {
|
|
245
|
+
queryClient.invalidateQueries({ queryKey: ['users'] })
|
|
246
|
+
},
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
return { user, mutation, isLoading: mutation.isPending }
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// -components/user-form/index.tsx
|
|
253
|
+
export function UserForm({ userId }: Props) {
|
|
254
|
+
const { user, mutation, isLoading } = useUserForm(userId)
|
|
255
|
+
|
|
256
|
+
return (
|
|
257
|
+
<form onSubmit={(e) => mutation.mutate(formData)}>
|
|
258
|
+
{/* UI만 */}
|
|
259
|
+
</form>
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
| 분리 기준 | 컴포넌트 (`index.tsx`) | 훅 (`-hooks/`) |
|
|
265
|
+
|----------|----------------------|----------------|
|
|
266
|
+
| **역할** | UI 렌더링 | 로직 처리 |
|
|
267
|
+
| **내용** | JSX, 스타일 | useQuery, useMutation, 상태 |
|
|
204
268
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
269
|
+
### 2. Features Layer
|
|
270
|
+
|
|
271
|
+
> 내부 도메인 로직, Prisma 쿼리
|
|
272
|
+
|
|
273
|
+
```
|
|
274
|
+
features/<domain>/
|
|
275
|
+
├── schemas.ts # Zod 스키마
|
|
276
|
+
├── queries.ts # TanStack Query 옵션
|
|
277
|
+
└── mutations.ts # useMutation 옵션
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
// features/users/schemas.ts
|
|
282
|
+
export const createUserSchema = z.object({
|
|
283
|
+
email: z.email(),
|
|
284
|
+
name: z.string().min(1),
|
|
208
285
|
})
|
|
209
286
|
|
|
210
|
-
//
|
|
211
|
-
export const
|
|
212
|
-
|
|
287
|
+
// features/users/queries.ts
|
|
288
|
+
export const userQueryOptions = queryOptions({
|
|
289
|
+
queryKey: ['users'],
|
|
290
|
+
queryFn: getUsers,
|
|
291
|
+
staleTime: 5 * 60 * 1000,
|
|
213
292
|
})
|
|
214
293
|
```
|
|
215
294
|
|
|
216
|
-
###
|
|
295
|
+
### 3. Services Layer
|
|
296
|
+
|
|
297
|
+
> 외부 SDK 연동
|
|
217
298
|
|
|
218
299
|
```
|
|
219
|
-
services/<
|
|
220
|
-
├──
|
|
221
|
-
├──
|
|
222
|
-
|
|
223
|
-
|
|
300
|
+
services/<provider>/
|
|
301
|
+
├── client.ts # SDK 클라이언트
|
|
302
|
+
├── types.ts # 타입 정의
|
|
303
|
+
└── utils.ts # 헬퍼 함수
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
// services/stripe/client.ts
|
|
308
|
+
import Stripe from 'stripe'
|
|
309
|
+
|
|
310
|
+
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)
|
|
311
|
+
|
|
312
|
+
// services/stripe/utils.ts
|
|
313
|
+
export async function createCheckoutSession(priceId: string) {
|
|
314
|
+
return stripe.checkout.sessions.create({
|
|
315
|
+
mode: 'subscription',
|
|
316
|
+
line_items: [{ price: priceId, quantity: 1 }],
|
|
317
|
+
})
|
|
318
|
+
}
|
|
224
319
|
```
|
|
225
320
|
|
|
226
|
-
###
|
|
321
|
+
### 4. Server Functions Layer
|
|
227
322
|
|
|
228
323
|
```
|
|
229
|
-
functions/ # 글로벌
|
|
230
|
-
├── <function-name>.ts
|
|
324
|
+
functions/ # 글로벌
|
|
325
|
+
├── <function-name>.ts
|
|
231
326
|
└── middlewares/
|
|
232
|
-
|
|
327
|
+
├── auth.ts
|
|
328
|
+
└── logging.ts
|
|
233
329
|
|
|
234
330
|
routes/<route>/-functions/ # 페이지 전용
|
|
235
331
|
└── <function-name>.ts
|
|
236
332
|
```
|
|
237
333
|
|
|
238
|
-
> ⚠️ **`functions/index.ts` 생성 금지**
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
> // ❌ functions/index.ts 만들지 말 것
|
|
248
|
-
> export * from './get-users'
|
|
249
|
-
> export * from './create-post' // pg import → 클라이언트 빌드 실패
|
|
250
|
-
>
|
|
251
|
-
> // ✅ 개별 파일에서 직접 import
|
|
252
|
-
> import { getUsers } from '@/functions/get-users'
|
|
253
|
-
> import { createPost } from '@/functions/create-post'
|
|
254
|
-
> ```
|
|
334
|
+
> ⚠️ **`functions/index.ts` 생성 금지** - Tree Shaking 실패, Client 번들 오염
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
// ✅ 개별 파일에서 직접 import
|
|
338
|
+
import { getUsers } from '@/functions/get-users'
|
|
339
|
+
import { createPost } from '@/functions/create-post'
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### 5. State Management Layer
|
|
255
343
|
|
|
256
|
-
|
|
344
|
+
| 상태 유형 | 도구 | 사용 |
|
|
345
|
+
|----------|------|------|
|
|
346
|
+
| **서버 상태** | TanStack Query | API 데이터, 캐싱 (80%) |
|
|
347
|
+
| **클라이언트 상태** | Zustand | UI 상태, 설정 (20%) |
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
// stores/app.ts
|
|
351
|
+
import { create } from 'zustand'
|
|
352
|
+
import { persist } from 'zustand/middleware'
|
|
353
|
+
|
|
354
|
+
export const useAppStore = create(
|
|
355
|
+
persist(
|
|
356
|
+
(set) => ({
|
|
357
|
+
theme: 'dark' as 'light' | 'dark',
|
|
358
|
+
sidebarOpen: true,
|
|
359
|
+
setTheme: (theme) => set({ theme }),
|
|
360
|
+
}),
|
|
361
|
+
{ name: 'app-store' }
|
|
362
|
+
)
|
|
363
|
+
)
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### 6. Database Layer
|
|
257
367
|
|
|
258
368
|
```typescript
|
|
259
369
|
// database/prisma.ts
|
|
@@ -282,16 +392,7 @@ if (process.env.NODE_ENV !== 'production') {
|
|
|
282
392
|
|------|-----------|--------|
|
|
283
393
|
| **실행 순서** | 순차 (outermost → innermost) | 병렬 (beforeLoad 완료 후) |
|
|
284
394
|
| **용도** | 인증, Context 전달, 리다이렉트 | 데이터 로딩 |
|
|
285
|
-
|
|
|
286
|
-
| **성능 영향** | ⚠️ 높음 | ✅ 낮음 |
|
|
287
|
-
|
|
288
|
-
```
|
|
289
|
-
1. Parent beforeLoad (순차) ──┐
|
|
290
|
-
2. Child beforeLoad (순차) ──┼→ 완료 후
|
|
291
|
-
3. All loaders (병렬) ────────┘
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
### 코드 패턴
|
|
395
|
+
| **성능 영향** | ⚠️ 높음 (블로킹) | ✅ 낮음 (병렬) |
|
|
295
396
|
|
|
296
397
|
```typescript
|
|
297
398
|
// ✅ beforeLoad: 인증 & Context
|
|
@@ -311,11 +412,6 @@ loader: async () => {
|
|
|
311
412
|
}
|
|
312
413
|
```
|
|
313
414
|
|
|
314
|
-
| ❌ 금지 | ✅ 권장 |
|
|
315
|
-
|--------|--------|
|
|
316
|
-
| beforeLoad에서 데이터 로딩 | loader에서 데이터 로딩 |
|
|
317
|
-
| loader 차단 | 병렬 실행 |
|
|
318
|
-
|
|
319
415
|
</route_lifecycle>
|
|
320
416
|
|
|
321
417
|
---
|
|
@@ -340,22 +436,14 @@ export const Route = createRootRouteWithContext<RouterContext>()({
|
|
|
340
436
|
beforeLoad: async () => ({ user: await getUser() }),
|
|
341
437
|
})
|
|
342
438
|
|
|
343
|
-
// 2.
|
|
439
|
+
// 2. 확장
|
|
344
440
|
beforeLoad: async ({ context }) => ({
|
|
345
441
|
...context,
|
|
346
442
|
permissions: await getPermissions(context.user.id),
|
|
347
443
|
})
|
|
348
444
|
|
|
349
|
-
// 3.
|
|
445
|
+
// 3. 사용
|
|
350
446
|
const { user, permissions } = useRouteContext({ from: '/dashboard' })
|
|
351
|
-
|
|
352
|
-
// 4. 사용: Loader
|
|
353
|
-
loader: async ({ context }) => {
|
|
354
|
-
if (!context.permissions.includes('users:read')) {
|
|
355
|
-
throw new Error('Unauthorized')
|
|
356
|
-
}
|
|
357
|
-
return { users: await getUsers() }
|
|
358
|
-
}
|
|
359
447
|
```
|
|
360
448
|
|
|
361
449
|
</context_management>
|
|
@@ -369,17 +457,14 @@ loader: async ({ context }) => {
|
|
|
369
457
|
### Query Flow (읽기)
|
|
370
458
|
|
|
371
459
|
```
|
|
372
|
-
Page → useQuery → Server Function → Prisma → Database
|
|
460
|
+
Page → useQuery → Server Function → Features → Prisma → Database
|
|
373
461
|
↑
|
|
374
462
|
TanStack Query (Cache)
|
|
375
463
|
```
|
|
376
464
|
|
|
377
465
|
```typescript
|
|
378
466
|
// Page
|
|
379
|
-
const { data } = useQuery(
|
|
380
|
-
queryKey: ['users'],
|
|
381
|
-
queryFn: getUsers,
|
|
382
|
-
})
|
|
467
|
+
const { data } = useQuery(userQueryOptions)
|
|
383
468
|
|
|
384
469
|
// Server Function
|
|
385
470
|
export const getUsers = createServerFn()
|
|
@@ -390,13 +475,9 @@ export const getUsers = createServerFn()
|
|
|
390
475
|
### Mutation Flow (쓰기)
|
|
391
476
|
|
|
392
477
|
```
|
|
393
|
-
Form → useMutation → Server Function
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
↓
|
|
397
|
-
Prisma → Database
|
|
398
|
-
↓
|
|
399
|
-
invalidateQueries
|
|
478
|
+
Form → useMutation → Server Function → inputValidator → Features → Database
|
|
479
|
+
↓
|
|
480
|
+
invalidateQueries
|
|
400
481
|
```
|
|
401
482
|
|
|
402
483
|
```typescript
|
|
@@ -425,18 +506,16 @@ export const createUser = createServerFn({ method: 'POST' })
|
|
|
425
506
|
|
|
426
507
|
### Server Functions 타입
|
|
427
508
|
|
|
428
|
-
| 타입 | 실행 위치 | 사용
|
|
429
|
-
|
|
430
|
-
| **createServerFn** | 서버 | DB 접근,
|
|
509
|
+
| 타입 | 실행 위치 | 사용 |
|
|
510
|
+
|------|----------|------|
|
|
511
|
+
| **createServerFn** | 서버 | DB 접근, 비밀키 (기본) |
|
|
431
512
|
| createClientOnlyFn | 클라이언트 | localStorage, window |
|
|
432
513
|
| createIsomorphicFn | 양쪽 | 환경별 구현 |
|
|
433
514
|
|
|
434
|
-
**기본 규칙**: 별도 요청 없으면 `createServerFn` 사용
|
|
435
|
-
|
|
436
515
|
### Middleware 패턴
|
|
437
516
|
|
|
438
517
|
```typescript
|
|
439
|
-
//
|
|
518
|
+
// functions/middlewares/auth.ts
|
|
440
519
|
export const authMiddleware = createMiddleware()
|
|
441
520
|
.server(async ({ next, context }) => {
|
|
442
521
|
const session = await getSession()
|
|
@@ -444,9 +523,19 @@ export const authMiddleware = createMiddleware()
|
|
|
444
523
|
return next({ context: { ...context, user: session.user } })
|
|
445
524
|
})
|
|
446
525
|
|
|
447
|
-
//
|
|
526
|
+
// functions/middlewares/logging.ts
|
|
527
|
+
export const loggingMiddleware = createMiddleware()
|
|
528
|
+
.server(async ({ next }) => {
|
|
529
|
+
const start = Date.now()
|
|
530
|
+
const traceId = crypto.randomUUID()
|
|
531
|
+
const result = await next({ context: { traceId } })
|
|
532
|
+
console.log({ traceId, duration: Date.now() - start })
|
|
533
|
+
return result
|
|
534
|
+
})
|
|
535
|
+
|
|
536
|
+
// 사용
|
|
448
537
|
export const createPost = createServerFn({ method: 'POST' })
|
|
449
|
-
.middleware([authMiddleware])
|
|
538
|
+
.middleware([loggingMiddleware, authMiddleware])
|
|
450
539
|
.inputValidator(createPostSchema)
|
|
451
540
|
.handler(async ({ data, context }) => {
|
|
452
541
|
return prisma.post.create({
|
|
@@ -482,27 +571,6 @@ export const Route = createRootRoute({
|
|
|
482
571
|
export const Route = createFileRoute('/dashboard')({
|
|
483
572
|
errorComponent: ({ error }) => <div>{error.message}</div>,
|
|
484
573
|
})
|
|
485
|
-
|
|
486
|
-
// Loader 에러
|
|
487
|
-
loader: async () => {
|
|
488
|
-
try {
|
|
489
|
-
return { users: await getUsers() }
|
|
490
|
-
} catch (error) {
|
|
491
|
-
throw new Error('데이터 로딩 실패')
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
// Server Function 에러
|
|
496
|
-
.handler(async ({ data }) => {
|
|
497
|
-
try {
|
|
498
|
-
return await prisma.user.create({ data })
|
|
499
|
-
} catch (error) {
|
|
500
|
-
if (error.code === 'P2002') {
|
|
501
|
-
throw new Error('이미 존재하는 이메일')
|
|
502
|
-
}
|
|
503
|
-
throw new Error('사용자 생성 실패')
|
|
504
|
-
}
|
|
505
|
-
})
|
|
506
574
|
```
|
|
507
575
|
|
|
508
576
|
</error_handling>
|
|
@@ -518,9 +586,12 @@ loader: async () => {
|
|
|
518
586
|
| Framework | TanStack Start | latest |
|
|
519
587
|
| Router | TanStack Router | latest |
|
|
520
588
|
| Data | TanStack Query | latest |
|
|
589
|
+
| State | Zustand | latest |
|
|
521
590
|
| ORM | Prisma | 7.x |
|
|
522
591
|
| Validation | Zod | 4.x |
|
|
523
592
|
| Database | PostgreSQL | - |
|
|
524
|
-
|
|
|
593
|
+
| Cache | Redis | - |
|
|
594
|
+
| Monitoring | Sentry | latest |
|
|
595
|
+
| UI | React 19+ | - |
|
|
525
596
|
|
|
526
597
|
</tech_stack>
|