@kood/claude-code 0.5.1 → 0.5.3
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 +163 -28
- package/package.json +1 -1
- package/templates/.claude/agents/analyst.md +6 -14
- package/templates/.claude/agents/architect.md +6 -14
- package/templates/.claude/agents/code-reviewer.md +8 -14
- package/templates/.claude/agents/dependency-manager.md +8 -14
- package/templates/.claude/agents/deployment-validator.md +8 -14
- package/templates/.claude/agents/designer.md +8 -0
- package/templates/.claude/agents/document-writer.md +6 -14
- package/templates/.claude/agents/explore.md +8 -3
- package/templates/.claude/agents/git-operator.md +63 -17
- package/templates/.claude/agents/implementation-executor.md +14 -37
- package/templates/.claude/agents/ko-to-en-translator.md +8 -13
- package/templates/.claude/agents/lint-fixer.md +8 -172
- package/templates/.claude/agents/planner.md +6 -14
- package/templates/.claude/agents/refactor-advisor.md +8 -14
- package/templates/.claude/commands/git-all.md +3 -167
- package/templates/.claude/commands/git-session.md +3 -71
- package/templates/.claude/commands/lint-fix.md +119 -82
- package/templates/.claude/commands/lint-init.md +2 -54
- package/templates/.claude/commands/pre-deploy.md +143 -82
- package/templates/.claude/commands/version-update.md +171 -66
- package/templates/.claude/instructions/agent-patterns/agent-coordination.md +208 -0
- package/templates/.claude/instructions/agent-patterns/index.md +264 -0
- package/templates/.claude/instructions/agent-patterns/model-routing.md +167 -0
- package/templates/.claude/instructions/agent-patterns/parallel-execution.md +91 -0
- package/templates/.claude/instructions/agent-patterns/read-parallelization.md +106 -0
- package/templates/.claude/instructions/index.md +350 -0
- package/templates/.claude/instructions/multi-agent/agent-roster.md +811 -0
- package/templates/.claude/{PARALLEL_AGENTS.md → instructions/multi-agent/coordination-guide.md} +27 -336
- package/templates/.claude/instructions/{parallel-agent-execution.md → multi-agent/execution-patterns.md} +127 -438
- package/templates/.claude/instructions/multi-agent/index.md +282 -0
- package/templates/.claude/instructions/multi-agent/performance-optimization.md +456 -0
- package/templates/.claude/instructions/tech-stack/design-standards.md +282 -0
- package/templates/.claude/instructions/tech-stack/index.md +70 -0
- package/templates/.claude/instructions/tech-stack/prisma-patterns.md +352 -0
- package/templates/.claude/instructions/tech-stack/tanstack-patterns.md +275 -0
- package/templates/.claude/instructions/validation/forbidden-patterns.md +281 -0
- package/templates/.claude/instructions/validation/index.md +32 -0
- package/templates/.claude/instructions/validation/required-behaviors.md +331 -0
- package/templates/.claude/instructions/validation/verification-checklist.md +318 -0
- package/templates/.claude/instructions/workflow-patterns/index.md +18 -0
- package/templates/.claude/instructions/workflow-patterns/phase-based-workflow.md +250 -0
- package/templates/.claude/instructions/workflow-patterns/sequential-thinking.md +217 -0
- package/templates/.claude/instructions/workflow-patterns/todowrite-pattern.md +215 -0
- package/templates/.claude/skills/bug-fix/SKILL.md +972 -0
- package/templates/.claude/skills/docs-creator/AGENTS.md +4 -1
- package/templates/.claude/skills/docs-creator/SKILL.md +258 -0
- package/templates/.claude/skills/docs-refactor/AGENTS.md +4 -1
- package/templates/.claude/skills/docs-refactor/SKILL.md +145 -0
- package/templates/.claude/skills/execute/SKILL.md +15 -242
- package/templates/.claude/skills/figma-to-code/AGENTS.md +4 -1
- package/templates/.claude/skills/figma-to-code/SKILL.md +306 -0
- package/templates/.claude/skills/global-uiux-design/AGENTS.md +4 -1
- package/templates/.claude/skills/global-uiux-design/SKILL.md +455 -125
- package/templates/.claude/skills/korea-uiux-design/AGENTS.md +4 -1
- package/templates/.claude/skills/korea-uiux-design/SKILL.md +461 -116
- package/templates/.claude/skills/nextjs-react-best-practices/SKILL.md +177 -0
- package/templates/.claude/skills/plan/SKILL.md +1102 -98
- package/templates/.claude/skills/prd/SKILL.md +367 -66
- package/templates/.claude/skills/ralph/AGENTS.md +4 -1
- package/templates/.claude/skills/ralph/SKILL.md +83 -0
- package/templates/.claude/skills/refactor/SKILL.md +1214 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/SKILL.md +149 -0
- package/templates/.claude/commands/bug-fix.md +0 -510
- package/templates/.claude/commands/refactor.md +0 -788
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# TanStack Patterns
|
|
2
|
+
|
|
3
|
+
**목적**: TanStack Start, Router, Query 사용 패턴
|
|
4
|
+
|
|
5
|
+
## TanStack Start
|
|
6
|
+
|
|
7
|
+
### Server Functions
|
|
8
|
+
|
|
9
|
+
**기본 패턴:**
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { createServerFn } from '@tanstack/start'
|
|
13
|
+
|
|
14
|
+
// GET 메서드
|
|
15
|
+
export const getUsers = createServerFn({ method: 'GET' })
|
|
16
|
+
.handler(async () => {
|
|
17
|
+
return prisma.user.findMany()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
// POST 메서드 + inputValidator
|
|
21
|
+
export const createUser = createServerFn({ method: 'POST' })
|
|
22
|
+
.inputValidator(createUserSchema)
|
|
23
|
+
.handler(async ({ data }) => {
|
|
24
|
+
return prisma.user.create({ data })
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
// 인증 + inputValidator
|
|
28
|
+
export const updateUser = createServerFn({ method: 'PUT' })
|
|
29
|
+
.middleware([authMiddleware])
|
|
30
|
+
.inputValidator(updateUserSchema)
|
|
31
|
+
.handler(async ({ data, context }) => {
|
|
32
|
+
return prisma.user.update({
|
|
33
|
+
where: { id: context.userId },
|
|
34
|
+
data
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**필수 규칙:**
|
|
40
|
+
|
|
41
|
+
- [ ] POST/PUT/PATCH는 `inputValidator` 필수
|
|
42
|
+
- [ ] 인증 필요 시 `middleware` 필수
|
|
43
|
+
- [ ] handler 내부에서 수동 검증/인증 금지
|
|
44
|
+
|
|
45
|
+
### Route 구조
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
// routes/users/index.tsx
|
|
49
|
+
import { createFileRoute } from '@tanstack/react-router'
|
|
50
|
+
|
|
51
|
+
export const Route = createFileRoute('/users')({
|
|
52
|
+
component: UsersPage,
|
|
53
|
+
loader: async () => {
|
|
54
|
+
const users = await getUsers()
|
|
55
|
+
return { users }
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
function UsersPage() {
|
|
60
|
+
const { users } = Route.useLoaderData()
|
|
61
|
+
return <UserList users={users} />
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**필수 규칙:**
|
|
66
|
+
|
|
67
|
+
- [ ] loader로 초기 데이터 로드
|
|
68
|
+
- [ ] `Route.useLoaderData()` 사용
|
|
69
|
+
|
|
70
|
+
## TanStack Router
|
|
71
|
+
|
|
72
|
+
### File-based Routing
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
src/routes/
|
|
76
|
+
├── __root.tsx # Root layout
|
|
77
|
+
├── index.tsx # /
|
|
78
|
+
├── $slug.tsx # /:slug
|
|
79
|
+
└── users/
|
|
80
|
+
├── index.tsx # /users
|
|
81
|
+
├── $id.tsx # /users/:id
|
|
82
|
+
├── -components/ # 페이지 전용 컴포넌트
|
|
83
|
+
└── -hooks/ # 페이지 전용 훅
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**파일명 규칙:**
|
|
87
|
+
|
|
88
|
+
- `__root.tsx`: Root layout
|
|
89
|
+
- `index.tsx`: Index route
|
|
90
|
+
- `$param.tsx`: Dynamic parameter
|
|
91
|
+
- `-folder/`: Private (번들 제외)
|
|
92
|
+
|
|
93
|
+
### Navigation
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { useNavigate, useParams } from '@tanstack/react-router'
|
|
97
|
+
|
|
98
|
+
function Component() {
|
|
99
|
+
const navigate = useNavigate()
|
|
100
|
+
const params = useParams({ from: '/users/$id' })
|
|
101
|
+
|
|
102
|
+
const handleClick = () => {
|
|
103
|
+
navigate({ to: '/users/$id', params: { id: '123' } })
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return <div>{params.id}</div>
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**필수 규칙:**
|
|
111
|
+
|
|
112
|
+
- [ ] `useNavigate` 사용 (Link 컴포넌트도 가능)
|
|
113
|
+
- [ ] `useParams`로 경로 파라미터 접근
|
|
114
|
+
|
|
115
|
+
## TanStack Query
|
|
116
|
+
|
|
117
|
+
### useQuery
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { useQuery } from '@tanstack/react-query'
|
|
121
|
+
|
|
122
|
+
function Users() {
|
|
123
|
+
const { data, isLoading, error } = useQuery({
|
|
124
|
+
queryKey: ['users'],
|
|
125
|
+
queryFn: getUsers
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
if (isLoading) return <div>Loading...</div>
|
|
129
|
+
if (error) return <div>Error: {error.message}</div>
|
|
130
|
+
|
|
131
|
+
return <UserList users={data} />
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**필수 규칙:**
|
|
136
|
+
|
|
137
|
+
- [ ] `queryKey` 배열 형식
|
|
138
|
+
- [ ] `queryFn`에 Server Function 사용
|
|
139
|
+
- [ ] 로딩/에러 상태 처리
|
|
140
|
+
|
|
141
|
+
### useMutation
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
|
145
|
+
|
|
146
|
+
function CreateUserForm() {
|
|
147
|
+
const queryClient = useQueryClient()
|
|
148
|
+
|
|
149
|
+
const mutation = useMutation({
|
|
150
|
+
mutationFn: createUser,
|
|
151
|
+
onSuccess: () => {
|
|
152
|
+
// 캐시 무효화
|
|
153
|
+
queryClient.invalidateQueries({ queryKey: ['users'] })
|
|
154
|
+
}
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
const handleSubmit = (data) => {
|
|
158
|
+
mutation.mutate(data)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return <form onSubmit={handleSubmit}>...</form>
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**필수 규칙:**
|
|
166
|
+
|
|
167
|
+
- [ ] `onSuccess`에서 `invalidateQueries` 호출
|
|
168
|
+
- [ ] `mutationFn`에 Server Function 사용
|
|
169
|
+
- [ ] 직접 Server Function 호출 금지
|
|
170
|
+
|
|
171
|
+
### Optimistic Updates
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
const mutation = useMutation({
|
|
175
|
+
mutationFn: updateUser,
|
|
176
|
+
onMutate: async (newData) => {
|
|
177
|
+
// 진행 중인 쿼리 취소
|
|
178
|
+
await queryClient.cancelQueries({ queryKey: ['users'] })
|
|
179
|
+
|
|
180
|
+
// 이전 데이터 백업
|
|
181
|
+
const previous = queryClient.getQueryData(['users'])
|
|
182
|
+
|
|
183
|
+
// 낙관적 업데이트
|
|
184
|
+
queryClient.setQueryData(['users'], (old) => {
|
|
185
|
+
return old.map((user) =>
|
|
186
|
+
user.id === newData.id ? { ...user, ...newData } : user
|
|
187
|
+
)
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
return { previous }
|
|
191
|
+
},
|
|
192
|
+
onError: (err, newData, context) => {
|
|
193
|
+
// 롤백
|
|
194
|
+
queryClient.setQueryData(['users'], context.previous)
|
|
195
|
+
},
|
|
196
|
+
onSettled: () => {
|
|
197
|
+
// 재검증
|
|
198
|
+
queryClient.invalidateQueries({ queryKey: ['users'] })
|
|
199
|
+
}
|
|
200
|
+
})
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## 통합 예시
|
|
204
|
+
|
|
205
|
+
### 전체 흐름
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
// 1. Server Function 정의 (src/functions/users.ts)
|
|
209
|
+
export const getUsers = createServerFn({ method: 'GET' })
|
|
210
|
+
.handler(async () => prisma.user.findMany())
|
|
211
|
+
|
|
212
|
+
export const createUser = createServerFn({ method: 'POST' })
|
|
213
|
+
.middleware([authMiddleware])
|
|
214
|
+
.inputValidator(createUserSchema)
|
|
215
|
+
.handler(async ({ data }) => prisma.user.create({ data }))
|
|
216
|
+
|
|
217
|
+
// 2. Route 정의 (src/routes/users/index.tsx)
|
|
218
|
+
export const Route = createFileRoute('/users')({
|
|
219
|
+
component: UsersPage,
|
|
220
|
+
loader: async () => ({ users: await getUsers() })
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
// 3. 컴포넌트 (src/routes/users/-components/UserList.tsx)
|
|
224
|
+
function UsersPage() {
|
|
225
|
+
const { users: initialUsers } = Route.useLoaderData()
|
|
226
|
+
const queryClient = useQueryClient()
|
|
227
|
+
|
|
228
|
+
// useQuery로 실시간 데이터
|
|
229
|
+
const { data: users } = useQuery({
|
|
230
|
+
queryKey: ['users'],
|
|
231
|
+
queryFn: getUsers,
|
|
232
|
+
initialData: initialUsers // loader 데이터를 초기값으로
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
// useMutation으로 생성
|
|
236
|
+
const createMutation = useMutation({
|
|
237
|
+
mutationFn: createUser,
|
|
238
|
+
onSuccess: () => {
|
|
239
|
+
queryClient.invalidateQueries({ queryKey: ['users'] })
|
|
240
|
+
}
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
return (
|
|
244
|
+
<div>
|
|
245
|
+
<UserList users={users} />
|
|
246
|
+
<CreateUserForm onSubmit={(data) => createMutation.mutate(data)} />
|
|
247
|
+
</div>
|
|
248
|
+
)
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## 체크리스트
|
|
253
|
+
|
|
254
|
+
### Server Function
|
|
255
|
+
|
|
256
|
+
- [ ] 메서드 명시 (GET/POST/PUT/DELETE)
|
|
257
|
+
- [ ] POST/PUT/PATCH는 inputValidator 사용
|
|
258
|
+
- [ ] 인증 필요 시 middleware 사용
|
|
259
|
+
- [ ] handler 내부에서 수동 검증 금지
|
|
260
|
+
|
|
261
|
+
### Route
|
|
262
|
+
|
|
263
|
+
- [ ] loader로 초기 데이터 로드
|
|
264
|
+
- [ ] `Route.useLoaderData()` 사용
|
|
265
|
+
- [ ] 파일명 규칙 준수
|
|
266
|
+
|
|
267
|
+
### TanStack Query
|
|
268
|
+
|
|
269
|
+
- [ ] useQuery로 조회
|
|
270
|
+
- [ ] useMutation으로 변경
|
|
271
|
+
- [ ] onSuccess에서 invalidateQueries
|
|
272
|
+
- [ ] 로딩/에러 상태 처리
|
|
273
|
+
- [ ] 직접 Server Function 호출 금지
|
|
274
|
+
|
|
275
|
+
**TanStack 패턴 준수 → 타입 안전 + 성능 최적화**
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# Forbidden Patterns (Anti-Patterns)
|
|
2
|
+
|
|
3
|
+
**목적**: 반복되는 실수 방지 및 품질 유지
|
|
4
|
+
|
|
5
|
+
## 언어 및 표현
|
|
6
|
+
|
|
7
|
+
### 추측성 표현 금지
|
|
8
|
+
|
|
9
|
+
| 금지 표현 | 이유 | 올바른 표현 |
|
|
10
|
+
|----------|------|-------------|
|
|
11
|
+
| "~해야 한다" | 불확실 | "~한다" (단정) |
|
|
12
|
+
| "probably" | 추측 | "검증 결과 ~" |
|
|
13
|
+
| "seems to" | 모호 | "분석 결과 ~" |
|
|
14
|
+
| "아마도" | 추측 | "확인 필요" / "~이다" |
|
|
15
|
+
| "~것 같다" | 불확실 | "~이다" |
|
|
16
|
+
| "should work" | 추측 | "테스트 통과 확인" |
|
|
17
|
+
| "대부분" | 모호 | "90% 케이스에서" |
|
|
18
|
+
|
|
19
|
+
**원칙**: 확실한 것만 단정. 불확실하면 검증 후 확인.
|
|
20
|
+
|
|
21
|
+
## 코드 작성
|
|
22
|
+
|
|
23
|
+
### 금지 1: any 타입 사용
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
// ❌ 금지
|
|
27
|
+
function process(data: any) {
|
|
28
|
+
return data.value
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ✅ 올바름
|
|
32
|
+
function process(data: unknown) {
|
|
33
|
+
if (typeof data === 'object' && data !== null && 'value' in data) {
|
|
34
|
+
return (data as { value: string }).value
|
|
35
|
+
}
|
|
36
|
+
throw new Error('Invalid data')
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 금지 2: @ts-ignore 사용
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// ❌ 금지
|
|
44
|
+
// @ts-ignore
|
|
45
|
+
const result = getData()
|
|
46
|
+
|
|
47
|
+
// ✅ 올바름
|
|
48
|
+
const result = getData() as ExpectedType
|
|
49
|
+
// 또는 타입 정의 수정
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 금지 3: 테스트 삭제/수정
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// ❌ 금지: 실패 테스트 삭제
|
|
56
|
+
// describe('login', () => { ... }) // 주석 처리
|
|
57
|
+
|
|
58
|
+
// ✅ 올바름: 코드 수정으로 테스트 통과
|
|
59
|
+
function login(email: string, password: string) {
|
|
60
|
+
// 버그 수정
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 금지 4: 에러 무시
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
// ❌ 금지
|
|
68
|
+
try {
|
|
69
|
+
await dangerousOperation()
|
|
70
|
+
} catch (e) {
|
|
71
|
+
// 무시
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ✅ 올바름
|
|
75
|
+
try {
|
|
76
|
+
await dangerousOperation()
|
|
77
|
+
} catch (error) {
|
|
78
|
+
logger.error('Operation failed', error)
|
|
79
|
+
throw new Error('Failed to perform operation')
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 작업 흐름
|
|
84
|
+
|
|
85
|
+
### 금지 5: 검증 단계 스킵
|
|
86
|
+
|
|
87
|
+
```markdown
|
|
88
|
+
❌ Phase 1 → Phase 4 (직행)
|
|
89
|
+
❌ Phase 1 → Phase 3 (/pre-deploy 스킵)
|
|
90
|
+
❌ Phase 2 부분 검증 (lint만 실행)
|
|
91
|
+
|
|
92
|
+
✅ Phase 1 → 2 → 3 → 4 (순차)
|
|
93
|
+
✅ /pre-deploy 전체 실행 (typecheck, lint, build)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 금지 6: 조기 완료 선언
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
// ❌ 금지
|
|
100
|
+
// "구현 완료했습니다" (검증 없이)
|
|
101
|
+
<promise>DONE</promise>
|
|
102
|
+
|
|
103
|
+
// ✅ 올바름
|
|
104
|
+
Skill("pre-deploy") // 검증
|
|
105
|
+
TaskList() // TODO 확인
|
|
106
|
+
Task(subagent_type="planner", ...) // Planner 승인
|
|
107
|
+
<promise>DONE</promise>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 금지 7: 순차 실행 (병렬 가능한 경우)
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// ❌ 금지 (순차)
|
|
114
|
+
Read({ file_path: "file1.ts" })
|
|
115
|
+
// 대기...
|
|
116
|
+
Read({ file_path: "file2.ts" })
|
|
117
|
+
|
|
118
|
+
// ✅ 올바름 (병렬)
|
|
119
|
+
Read({ file_path: "file1.ts" })
|
|
120
|
+
Read({ file_path: "file2.ts" })
|
|
121
|
+
Read({ file_path: "file3.ts" })
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 금지 8: 에이전트 미활용
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// ❌ 금지: 모든 작업 혼자 수행
|
|
128
|
+
Glob(...)
|
|
129
|
+
Read(...)
|
|
130
|
+
Read(...)
|
|
131
|
+
Edit(...)
|
|
132
|
+
Edit(...)
|
|
133
|
+
|
|
134
|
+
// ✅ 올바름: 에이전트 위임
|
|
135
|
+
Task(subagent_type="explore", model="haiku", ...)
|
|
136
|
+
Task(subagent_type="implementation-executor", model="sonnet", ...)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Git 작업
|
|
140
|
+
|
|
141
|
+
### 금지 9: AI 표시
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# ❌ 금지
|
|
145
|
+
git commit -m "feat: 로그인 구현
|
|
146
|
+
|
|
147
|
+
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
|
|
148
|
+
|
|
149
|
+
# ❌ 금지
|
|
150
|
+
git commit -m "🤖 feat: 로그인 구현"
|
|
151
|
+
|
|
152
|
+
# ✅ 올바름
|
|
153
|
+
git commit -m "feat: 로그인 구현"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 금지 10: Bash로 직접 Git 실행
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// ❌ 금지
|
|
160
|
+
Bash({ command: "git add . && git commit -m 'fix' && git push" })
|
|
161
|
+
|
|
162
|
+
// ✅ 올바름
|
|
163
|
+
Task(subagent_type="git-operator", model="haiku",
|
|
164
|
+
prompt="변경사항 커밋 및 푸시")
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## 데이터베이스
|
|
168
|
+
|
|
169
|
+
### 금지 11: Prisma 자동 실행
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
# ❌ 금지 (자동 실행)
|
|
173
|
+
prisma db push
|
|
174
|
+
prisma migrate dev
|
|
175
|
+
prisma generate
|
|
176
|
+
|
|
177
|
+
# ✅ 올바름 (사용자 확인 후 실행)
|
|
178
|
+
echo "schema.prisma 수정 완료. 'prisma db push' 실행 필요"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### 금지 12: schema.prisma 임의 변경
|
|
182
|
+
|
|
183
|
+
```prisma
|
|
184
|
+
// ❌ 금지: 명시 요청 없이 스키마 변경
|
|
185
|
+
model User {
|
|
186
|
+
id Int @id @default(autoincrement())
|
|
187
|
+
email String @unique // 임의 추가
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ✅ 올바름: 요청된 변경만 수행
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## API 구현
|
|
194
|
+
|
|
195
|
+
### 금지 13: 수동 검증/인증
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// ❌ 금지: handler 내부에서 직접 검증
|
|
199
|
+
export const createUser = createServerFn({ method: 'POST' })
|
|
200
|
+
.handler(async ({ data }) => {
|
|
201
|
+
// 수동 검증
|
|
202
|
+
if (!data.email) throw new Error('Email required')
|
|
203
|
+
|
|
204
|
+
// 수동 인증 체크
|
|
205
|
+
if (!request.session) throw new Error('Unauthorized')
|
|
206
|
+
|
|
207
|
+
return prisma.user.create({ data })
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
// ✅ 올바름: inputValidator + middleware 사용
|
|
211
|
+
export const createUser = createServerFn({ method: 'POST' })
|
|
212
|
+
.middleware([authMiddleware])
|
|
213
|
+
.inputValidator(createUserSchema)
|
|
214
|
+
.handler(async ({ data }) => {
|
|
215
|
+
return prisma.user.create({ data })
|
|
216
|
+
})
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### 금지 14: 클라이언트에서 Server Function 직접 호출
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
// ❌ 금지
|
|
223
|
+
const handleSubmit = async () => {
|
|
224
|
+
const result = await createUser({ data }) // 직접 호출
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ✅ 올바름: TanStack Query 사용
|
|
228
|
+
const mutation = useMutation({
|
|
229
|
+
mutationFn: createUser,
|
|
230
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['users'] })
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
const handleSubmit = () => {
|
|
234
|
+
mutation.mutate({ data })
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## 문서화
|
|
239
|
+
|
|
240
|
+
### 금지 15: 문서 업데이트 누락
|
|
241
|
+
|
|
242
|
+
```markdown
|
|
243
|
+
❌ Phase 전환했는데 PROCESS.md 업데이트 안 함
|
|
244
|
+
❌ 요구사항 완료했는데 TASKS.md 체크 안 함
|
|
245
|
+
❌ 검증 완료했는데 VERIFICATION.md 기록 안 함
|
|
246
|
+
|
|
247
|
+
✅ 모든 Phase 전환 시 즉시 문서 업데이트
|
|
248
|
+
✅ 주요 의사결정 시 PROCESS.md 기록
|
|
249
|
+
✅ 검증 결과는 반드시 VERIFICATION.md에 기록
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### 금지 16: 불필요한 문서 생성
|
|
253
|
+
|
|
254
|
+
```markdown
|
|
255
|
+
❌ 명시 요청 없이 README.md 생성
|
|
256
|
+
❌ 자동으로 CONTRIBUTING.md 생성
|
|
257
|
+
❌ 프로액티브하게 .md 파일 추가
|
|
258
|
+
|
|
259
|
+
✅ 명시적 요청 시에만 문서 생성
|
|
260
|
+
✅ 기존 문서 수정 우선
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## 종합 체크리스트
|
|
264
|
+
|
|
265
|
+
작업 시작 전:
|
|
266
|
+
|
|
267
|
+
- [ ] 추측성 표현 사용하지 않기
|
|
268
|
+
- [ ] any, @ts-ignore 금지 확인
|
|
269
|
+
- [ ] 검증 단계 스킵하지 않기
|
|
270
|
+
- [ ] 병렬 실행 가능 여부 확인
|
|
271
|
+
- [ ] 에이전트 활용 계획
|
|
272
|
+
|
|
273
|
+
작업 중:
|
|
274
|
+
|
|
275
|
+
- [ ] 테스트 삭제/수정 금지
|
|
276
|
+
- [ ] AI 표시 커밋 메시지 금지
|
|
277
|
+
- [ ] Prisma 자동 실행 금지
|
|
278
|
+
- [ ] 수동 검증/인증 금지
|
|
279
|
+
- [ ] 문서 업데이트 누락 방지
|
|
280
|
+
|
|
281
|
+
**금지 패턴 회피 → 품질 향상 + 안정성 확보**
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Validation
|
|
2
|
+
|
|
3
|
+
검증 및 품질 기준
|
|
4
|
+
|
|
5
|
+
## 파일 목록
|
|
6
|
+
|
|
7
|
+
| 파일 | 설명 |
|
|
8
|
+
|------|------|
|
|
9
|
+
| [forbidden-patterns.md](./forbidden-patterns.md) | 금지 패턴 - 반복되는 실수 방지 |
|
|
10
|
+
| [required-behaviors.md](./required-behaviors.md) | 필수 행동 - 반드시 따를 규칙 |
|
|
11
|
+
| [verification-checklist.md](./verification-checklist.md) | 검증 체크리스트 - 표준 검증 절차 |
|
|
12
|
+
|
|
13
|
+
## 사용법
|
|
14
|
+
|
|
15
|
+
```markdown
|
|
16
|
+
@.claude/instructions/validation/forbidden-patterns.md
|
|
17
|
+
@.claude/instructions/validation/required-behaviors.md
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 빠른 참조
|
|
21
|
+
|
|
22
|
+
### 금지 패턴 (Forbidden)
|
|
23
|
+
- 수동 검증/인증 체크 (handler 내부)
|
|
24
|
+
- 임의 DB 변경 (schema.prisma 직접 수정)
|
|
25
|
+
- AI 표시 커밋 메시지
|
|
26
|
+
- 클라이언트에서 Server Function 직접 호출
|
|
27
|
+
|
|
28
|
+
### 필수 행동 (Required)
|
|
29
|
+
- POST/PUT/PATCH: inputValidator + middleware
|
|
30
|
+
- DB 스키마 변경: 파일 분리 (Prisma Multi-File)
|
|
31
|
+
- 라이브러리 API 조회: 먼저 문서 읽기
|
|
32
|
+
- 3개+ 파일 수정: Gemini Review 실행
|