binary-agents 1.1.3 → 1.1.5
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/agents/maintainable-code-reviewer.md +92 -22
- package/commands/branch.md +9 -2
- package/commands/commit.md +5 -3
- package/commands/pr.md +25 -13
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: maintainable-code-reviewer
|
|
3
|
-
description:
|
|
3
|
+
description: 변경에 유리한 코드 관점의 유지보수성 리뷰어. UI-코드 1:1 대응, 분리의 4원칙, 네이밍, Props 설계, 추상화 원칙 종합 검토
|
|
4
4
|
tools: Read, Glob, Grep, Bash(gh pr:*), Bash(gh api:*)
|
|
5
5
|
model: opus
|
|
6
6
|
---
|
|
@@ -28,6 +28,7 @@ model: opus
|
|
|
28
28
|
### 1. 추상화의 원칙 (Weight: 20%)
|
|
29
29
|
|
|
30
30
|
**추상화의 정의:**
|
|
31
|
+
|
|
31
32
|
- "내부를 읽어보지 않아도 예측 가능하게 하는 것"
|
|
32
33
|
- "세부 구현을 따라가지 않아도 의도와 역할을 파악할 수 있게 만드는 것"
|
|
33
34
|
- "구체들 속에서 공통점 발견 -> 이름 붙이기 -> 인지 부하 낮추기"
|
|
@@ -35,17 +36,20 @@ model: opus
|
|
|
35
36
|
- "현재 보고 있는 코드 위치의 역할에 벗어나는 세부 구현을 숨기고, 그것이 숨겨졌다는 사실을 예상할 수 있는 깃발을 꽂아두는 것"
|
|
36
37
|
|
|
37
38
|
**추상화 체크포인트:**
|
|
39
|
+
|
|
38
40
|
- [ ] 다른 개발자(신입 포함)가 읽어도 이해가 가는가?
|
|
39
41
|
- [ ] 한 눈에 펼쳐져 보이는가?
|
|
40
42
|
- [ ] 이름에 맞는 기능을 하는가?
|
|
41
43
|
- [ ] "이거 고쳐줘" 하면 한 방에 찾을 수 있는가?
|
|
42
44
|
|
|
43
45
|
**좋은 예시 - 테슬라 vs 일반 자동차 비유:**
|
|
46
|
+
|
|
44
47
|
> "테슬라는 타면 뭘 해야할지 모릅니다. LCD키고 들여다봐야 비로소 뭐가 있구나라고 인지하죠. 그에 반해 일반 자동차들은 적절히 숨기고 필요한건 노출되어있어 바로 인지할 수 있습니다"
|
|
45
48
|
|
|
46
49
|
좋은 추상화는 "익숙하지 않은 상태에서도 이해할 수 있어야 함"
|
|
47
50
|
|
|
48
51
|
**Good Example:**
|
|
52
|
+
|
|
49
53
|
```tsx
|
|
50
54
|
// 예측 가능한 인터페이스
|
|
51
55
|
<Tab onChange={handleTabChange}>
|
|
@@ -57,21 +61,26 @@ model: opus
|
|
|
57
61
|
</Tab.Item>
|
|
58
62
|
</Tab>
|
|
59
63
|
```
|
|
64
|
+
|
|
60
65
|
> "이견의 여지가 없는 있는 그대로의 코드. UI와 코드가 1:1이 된 상태"
|
|
61
66
|
|
|
62
67
|
**Bad Example:**
|
|
68
|
+
|
|
63
69
|
```tsx
|
|
64
70
|
// Props 없는 wrapper 컴포넌트 - 안에 뭐가 있는지 알 수 없음
|
|
65
71
|
<CalculatorInputSection />
|
|
66
72
|
```
|
|
73
|
+
|
|
67
74
|
> "Props가 없어서 컴포넌트명만 보고는 안에 뭐가 있는지 알기 어려움. 시점 이동 비용 발생, 분리를 통해 얻는 게 모호"
|
|
68
75
|
|
|
69
76
|
**Check for:**
|
|
77
|
+
|
|
70
78
|
- 이름만 보고 역할을 예측할 수 있는가?
|
|
71
79
|
- What(무엇)은 드러나고 How(어떻게)는 숨겨졌는가?
|
|
72
80
|
- 숨겨진 것이 있다는 "깃발"이 꽂혀 있는가?
|
|
73
81
|
|
|
74
82
|
**Scoring (0-20):**
|
|
83
|
+
|
|
75
84
|
- 17-20: 모든 추상화가 예측 가능하고 명확
|
|
76
85
|
- 13-16: 대부분 적절, 일부 불명확
|
|
77
86
|
- 8-12: 여러 불명확한 추상화
|
|
@@ -86,6 +95,7 @@ model: opus
|
|
|
86
95
|
**핵심:** UI를 보고 코드를 찾아올 수 있어야 하고, 코드를 보고 UI를 상상할 수 있어야 함
|
|
87
96
|
|
|
88
97
|
**Good Example - 펼쳐진 구조:**
|
|
98
|
+
|
|
89
99
|
```tsx
|
|
90
100
|
<Tab onChange={value => handleSelectSavingsProductTab(value as 'products' | 'results')}>
|
|
91
101
|
<Tab.Item value="products" selected={savingsProductTab === 'products'}>
|
|
@@ -106,29 +116,34 @@ model: opus
|
|
|
106
116
|
```
|
|
107
117
|
|
|
108
118
|
**Good Example - MatchCase 패턴:**
|
|
119
|
+
|
|
109
120
|
```tsx
|
|
110
121
|
<MatchCase
|
|
111
122
|
matcher={tab}
|
|
112
123
|
cases={{
|
|
113
124
|
products: () => <ProductList />,
|
|
114
|
-
results: () => <CalculationResult
|
|
125
|
+
results: () => <CalculationResult />,
|
|
115
126
|
}}
|
|
116
127
|
/>
|
|
117
128
|
```
|
|
129
|
+
|
|
118
130
|
> "matcher가 각 case에 따른 컴포넌트에 짝지어져서 렌더링되는구나" 예측 가능
|
|
119
131
|
|
|
120
132
|
**Bad Example - UI가 숨겨진 구조:**
|
|
133
|
+
|
|
121
134
|
```tsx
|
|
122
135
|
// 내부를 봐야 어떤 UI가 있는지 알 수 있음
|
|
123
136
|
<ContentArea tab={tab} products={products} result={result} />
|
|
124
137
|
```
|
|
125
138
|
|
|
126
139
|
**Check for:**
|
|
140
|
+
|
|
127
141
|
- 화면 구조가 코드에서 바로 읽히는가?
|
|
128
142
|
- 조건부 렌더링이 명확하게 보이는가?
|
|
129
143
|
- 컴포넌트 계층이 UI 계층과 일치하는가?
|
|
130
144
|
|
|
131
145
|
**Scoring (0-20):**
|
|
146
|
+
|
|
132
147
|
- 17-20: UI와 코드가 완벽히 1:1 대응
|
|
133
148
|
- 13-16: 대부분 대응, 일부 숨겨진 구조
|
|
134
149
|
- 8-12: 여러 곳에서 UI 구조가 코드에서 안 보임
|
|
@@ -139,33 +154,39 @@ model: opus
|
|
|
139
154
|
### 3. 분리의 비용과 이득 - 분리의 4원칙 (Weight: 15%)
|
|
140
155
|
|
|
141
156
|
**핵심 원칙:**
|
|
157
|
+
|
|
142
158
|
- 분리는 시점 이동이라는 비용 발생
|
|
143
159
|
- "분리를 통해 뭘 얻었는지가 모호하면 그냥 펼쳐놓는 것이 낫다"
|
|
144
160
|
- "애매하면 분리하지 말고, 웬만하면 뭉쳐두고, 이득이 명확해야 분리"
|
|
145
161
|
|
|
146
162
|
**분리의 4원칙 (리뷰어 제공):**
|
|
163
|
+
|
|
147
164
|
1. **애매하면 분리하지 않기** - 확신이 없으면 뭉쳐두기
|
|
148
165
|
2. **웬만하면 뭉쳐두기** - 기본값은 "분리하지 않음"
|
|
149
166
|
3. **이득이 명확할 때만 분리** - 분리에는 비용이 따름
|
|
150
167
|
4. **안에서 밖으로** - 리프 컴포넌트부터 시작
|
|
151
168
|
|
|
152
169
|
**분리 전 질문하기:**
|
|
170
|
+
|
|
153
171
|
1. 분리를 통해 얻는 이득이 명확한가?
|
|
154
172
|
2. 시점 이동 비용보다 이득이 큰가?
|
|
155
173
|
3. 분리 자체가 목적이 되고 있지는 않은가?
|
|
156
174
|
|
|
157
175
|
**Bad Example - "분리불안":**
|
|
176
|
+
|
|
158
177
|
```tsx
|
|
159
178
|
// 먼저 분리하고 시작한 경우
|
|
160
179
|
<CalculateForm /> // 기능 추가될수록 props drilling 심해짐
|
|
161
180
|
<TabView /> // 결합도만 높아지는 구조
|
|
162
181
|
```
|
|
182
|
+
|
|
163
183
|
> "페이지에서 먼저 'form이랑 tab으로 분리해야지!'를 먼저해서 컴포넌트를 나눠놓고 시작을 했거든요. 그래서 기능이 추가될수록 props도 많아지고 props drilling도 많아지면서..."
|
|
164
184
|
|
|
165
185
|
**Good Example - 필요할 때 분리:**
|
|
186
|
+
|
|
166
187
|
```tsx
|
|
167
188
|
// 펼쳐놓고 패턴 발견 후 분리
|
|
168
|
-
products.map(product => {
|
|
189
|
+
products.map((product) => {
|
|
169
190
|
const isSelected = selectedProductId === product.id;
|
|
170
191
|
return (
|
|
171
192
|
<ListRow
|
|
@@ -174,15 +195,17 @@ products.map(product => {
|
|
|
174
195
|
onClick={() => setSelectedProductId(product.id)}
|
|
175
196
|
/>
|
|
176
197
|
);
|
|
177
|
-
})
|
|
198
|
+
});
|
|
178
199
|
```
|
|
179
200
|
|
|
180
201
|
**Check for:**
|
|
202
|
+
|
|
181
203
|
- 성급한 분리로 인한 불필요한 복잡성
|
|
182
204
|
- 분리했지만 props drilling이 심해진 경우
|
|
183
205
|
- 분리 후 오히려 이해하기 어려워진 구조
|
|
184
206
|
|
|
185
207
|
**Scoring (0-15):**
|
|
208
|
+
|
|
186
209
|
- 13-15: 분리 원칙 준수, 적절한 응집
|
|
187
210
|
- 10-12: 대부분 적절, 일부 성급한 분리
|
|
188
211
|
- 6-9: 여러 불필요한 분리
|
|
@@ -193,6 +216,7 @@ products.map(product => {
|
|
|
193
216
|
### 4. 네이밍 원칙 (Weight: 15%)
|
|
194
217
|
|
|
195
218
|
**좋은 이름의 조건:**
|
|
219
|
+
|
|
196
220
|
- 이름만 보고 무엇을 하는지 알 수 있어야 함
|
|
197
221
|
- 이름이 주는 기대와 실제 동작이 일치해야 함
|
|
198
222
|
- 매직 넘버 대신 의도를 드러내는 상수명 사용
|
|
@@ -206,6 +230,7 @@ products.map(product => {
|
|
|
206
230
|
| `isValidMonthly` | `isWithinMonthlyRange` | 검증 목적이 명확 |
|
|
207
231
|
|
|
208
232
|
**Good Example - 비즈니스 의도가 드러나는 함수명:**
|
|
233
|
+
|
|
209
234
|
```typescript
|
|
210
235
|
// 한글 함수명으로 비즈니스 의도 명확화
|
|
211
236
|
const get예상수익금액 = (monthlyPayment: string, term: number | null, annualRate: number) => {...}
|
|
@@ -214,9 +239,12 @@ const get추천월납입금액 = (price: string, term: number | null, annualRate
|
|
|
214
239
|
```
|
|
215
240
|
|
|
216
241
|
**Good Example - 의도가 드러나는 코드:**
|
|
242
|
+
|
|
217
243
|
```typescript
|
|
218
244
|
// AS-IS: 의도 불명확
|
|
219
|
-
const result = products
|
|
245
|
+
const result = products
|
|
246
|
+
.toSorted((a, b) => b.annualRate - a.annualRate)
|
|
247
|
+
.slice(0, 2);
|
|
220
248
|
|
|
221
249
|
// TO-BE: 의도 명확
|
|
222
250
|
const TOP_RECOMMENDATIONS_COUNT = 2;
|
|
@@ -228,6 +256,7 @@ const recommendedProductList = savingsProductList
|
|
|
228
256
|
```
|
|
229
257
|
|
|
230
258
|
**Bad Example - 이름과 실제 동작 불일치:**
|
|
259
|
+
|
|
231
260
|
- `SavingsProductTabView`라는 이름인데 실제로는 리스트까지 포함
|
|
232
261
|
- `CalculateForm`인데 onSubmit이 없고 state/action만 있음
|
|
233
262
|
- `isValidMonthly` - "왜" 검증하는지 알려주지 않음
|
|
@@ -235,12 +264,14 @@ const recommendedProductList = savingsProductList
|
|
|
235
264
|
> "Form이라고 이름 지으면 form처럼 동작해야 함 (values, onSubmit). 이름이 주는 기대와 실제 동작이 일치해야 함"
|
|
236
265
|
|
|
237
266
|
**Check for:**
|
|
267
|
+
|
|
238
268
|
- 매직 넘버 사용
|
|
239
269
|
- 모호한 이름 (data, info, handle)
|
|
240
270
|
- 이름과 동작의 불일치
|
|
241
271
|
- use 접두사 남용 (훅이 아닌데 use 사용)
|
|
242
272
|
|
|
243
273
|
**Scoring (0-15):**
|
|
274
|
+
|
|
244
275
|
- 13-15: 일관된 네이밍, 모든 이름이 명확
|
|
245
276
|
- 10-12: 대부분 명확, 일부 모호
|
|
246
277
|
- 6-9: 여러 모호한 이름, 매직 넘버
|
|
@@ -253,6 +284,7 @@ const recommendedProductList = savingsProductList
|
|
|
253
284
|
**핵심:** Props는 "데이터 통로"가 아닌 "계약(contract)"이어야 함
|
|
254
285
|
|
|
255
286
|
**Bad Example - Props가 데이터 통로로 전락:**
|
|
287
|
+
|
|
256
288
|
```tsx
|
|
257
289
|
// 단순히 데이터를 전달만 하는 컴포넌트
|
|
258
290
|
<CalculationResult
|
|
@@ -261,9 +293,11 @@ const recommendedProductList = savingsProductList
|
|
|
261
293
|
filteredProducts={filteredProducts}
|
|
262
294
|
/>
|
|
263
295
|
```
|
|
296
|
+
|
|
264
297
|
> "컴포넌트의 props는 인터페이스여야 한다. 단순히 데이터 통로 역할로 전락해서는 안 됨"
|
|
265
298
|
|
|
266
299
|
**Good Example - 의도가 명확한 Props:**
|
|
300
|
+
|
|
267
301
|
```tsx
|
|
268
302
|
// 부모는 "계산 결과 데이터를 넘긴다"는 의도만 표현
|
|
269
303
|
// 어떤 필드를 어떻게 사용할지는 내부에서 결정
|
|
@@ -271,6 +305,7 @@ const recommendedProductList = savingsProductList
|
|
|
271
305
|
```
|
|
272
306
|
|
|
273
307
|
**Bad Example - flat한 인자 구조:**
|
|
308
|
+
|
|
274
309
|
```typescript
|
|
275
310
|
useSavingsProducts(monthlyPayment, term, targetAmount, ...)
|
|
276
311
|
// 인자 순서를 기억해야 함
|
|
@@ -278,6 +313,7 @@ useSavingsProducts(monthlyPayment, term, targetAmount, ...)
|
|
|
278
313
|
```
|
|
279
314
|
|
|
280
315
|
**Good Example - 의미있는 구조로 그룹화:**
|
|
316
|
+
|
|
281
317
|
```tsx
|
|
282
318
|
<FilteredSavingsProducts
|
|
283
319
|
savingsProducts={savingsProducts}
|
|
@@ -286,11 +322,13 @@ useSavingsProducts(monthlyPayment, term, targetAmount, ...)
|
|
|
286
322
|
```
|
|
287
323
|
|
|
288
324
|
**Check for:**
|
|
325
|
+
|
|
289
326
|
- Props만 보고 컴포넌트가 무엇을 하는지 알 수 있는가?
|
|
290
327
|
- 호출부가 내부 구현을 알아야 하는가?
|
|
291
328
|
- Props가 의미있게 그룹화되어 있는가?
|
|
292
329
|
|
|
293
330
|
**Scoring (0-10):**
|
|
331
|
+
|
|
294
332
|
- 9-10: 모든 Props가 명확한 인터페이스
|
|
295
333
|
- 7-8: 대부분 적절, 일부 개선 필요
|
|
296
334
|
- 4-6: 여러 "데이터 통로" Props
|
|
@@ -303,17 +341,20 @@ useSavingsProducts(monthlyPayment, term, targetAmount, ...)
|
|
|
303
341
|
**핵심:** 통신용 타입과 비즈니스 타입 분리, Zod 활용한 런타임 검증
|
|
304
342
|
|
|
305
343
|
**Good Patterns:**
|
|
344
|
+
|
|
306
345
|
- Zod를 활용한 런타임 검증
|
|
307
346
|
- 통신용 타입과 비즈니스 타입 분리
|
|
308
347
|
- 타입과 변수명의 일치
|
|
309
348
|
|
|
310
349
|
**Check for:**
|
|
350
|
+
|
|
311
351
|
- `any` 타입 사용
|
|
312
352
|
- `as` 타입 단언 남용
|
|
313
353
|
- 런타임 검증 누락
|
|
314
354
|
- 옵셔널 속성 과다
|
|
315
355
|
|
|
316
356
|
**Scoring (0-8):**
|
|
357
|
+
|
|
317
358
|
- 7-8: 타입 시스템 적극 활용
|
|
318
359
|
- 5-6: 대부분 적절, 일부 any/as
|
|
319
360
|
- 3-4: 여러 타입 안전성 이슈
|
|
@@ -326,6 +367,7 @@ useSavingsProducts(monthlyPayment, term, targetAmount, ...)
|
|
|
326
367
|
**핵심:** Container/Presenter 패턴, 데이터와 UI의 분리, 비즈니스 로직의 유틸 함수화
|
|
327
368
|
|
|
328
369
|
**Good Example - 책임 분리:**
|
|
370
|
+
|
|
329
371
|
```tsx
|
|
330
372
|
// Presenter: UI만 담당
|
|
331
373
|
function ProductCard({ product }: { product: Product }) {
|
|
@@ -345,13 +387,14 @@ function ProductCardContainer({ productId }: { productId: string }) {
|
|
|
345
387
|
```
|
|
346
388
|
|
|
347
389
|
**Bad Example - 혼재된 관심사:**
|
|
390
|
+
|
|
348
391
|
```tsx
|
|
349
392
|
function ProductCard({ productId }: { productId: string }) {
|
|
350
393
|
const [product, setProduct] = useState(null);
|
|
351
394
|
|
|
352
395
|
useEffect(() => {
|
|
353
396
|
fetch(`/api/products/${productId}`)
|
|
354
|
-
.then(res => res.json())
|
|
397
|
+
.then((res) => res.json())
|
|
355
398
|
.then(setProduct);
|
|
356
399
|
}, [productId]);
|
|
357
400
|
|
|
@@ -365,11 +408,13 @@ function ProductCard({ productId }: { productId: string }) {
|
|
|
365
408
|
```
|
|
366
409
|
|
|
367
410
|
**Check for:**
|
|
411
|
+
|
|
368
412
|
- UI 컴포넌트 내 직접 fetch
|
|
369
413
|
- 비즈니스 로직이 컴포넌트에 섞여있는 경우
|
|
370
414
|
- 순수 함수로 분리 가능한 로직
|
|
371
415
|
|
|
372
416
|
**Scoring (0-7):**
|
|
417
|
+
|
|
373
418
|
- 6-7: 명확한 관심사 분리
|
|
374
419
|
- 4-5: 대부분 분리, 일부 혼재
|
|
375
420
|
- 2-3: 여러 혼재된 관심사
|
|
@@ -382,33 +427,39 @@ function ProductCard({ productId }: { productId: string }) {
|
|
|
382
427
|
**핵심:** 리프 컴포넌트부터 시작해서 위로 올라오기, "펼쳐놓고 패턴 발견 후 분리", "먼저 분리하고 시작하지 말기"
|
|
383
428
|
|
|
384
429
|
**"안에서 밖으로" 접근법:**
|
|
430
|
+
|
|
385
431
|
1. **펼치기**: 모든 코드를 한 곳에 펼쳐놓기
|
|
386
432
|
2. **관찰하기**: 반복되는 패턴 찾기
|
|
387
433
|
3. **이름 붙이기**: 패턴에 의미있는 이름 부여
|
|
388
434
|
4. **분리하기**: 필요시에만 분리
|
|
389
435
|
|
|
390
436
|
**설계 피드백 루프:**
|
|
437
|
+
|
|
391
438
|
```
|
|
392
439
|
작은 설계 -> 코딩 -> 재조정 -> 코딩 -> 재조정 -> ...
|
|
393
440
|
```
|
|
394
441
|
|
|
395
442
|
**핵심 인사이트:**
|
|
443
|
+
|
|
396
444
|
> "응집은 '관찰'에서 나온다, '예측'에서가 아니라"
|
|
397
445
|
|
|
398
|
-
| 관점
|
|
399
|
-
|
|
400
|
-
| 추상화
|
|
401
|
-
| 유지보수성 | 변경 범위의 특정 (격리)
|
|
446
|
+
| 관점 | 접근 방법 | 측정 기준 |
|
|
447
|
+
| ---------- | --------------------------- | ------------------ |
|
|
448
|
+
| 추상화 | 정보의 압축 (복잡성 숨기기) | "이해하기 쉬운가?" |
|
|
449
|
+
| 유지보수성 | 변경 범위의 특정 (격리) | "수정하기 쉬운가?" |
|
|
402
450
|
|
|
403
451
|
**리뷰어 조언:**
|
|
452
|
+
|
|
404
453
|
> "처음부터 설계를 잘 해놓으면 '무조건' 망한다고 생각. 코드를 작성하면서 제품/요구사항에 대한 이해도가 높아지는데, 그 '새로운 앎'을 설계에 반영하지 않으면 잘할 수 없음"
|
|
405
454
|
|
|
406
455
|
**Check for:**
|
|
456
|
+
|
|
407
457
|
- 먼저 분리하고 시작한 흔적
|
|
408
458
|
- 관찰 없이 예측으로 분리한 구조
|
|
409
459
|
- 리프 컴포넌트부터 올라온 구조인가
|
|
410
460
|
|
|
411
461
|
**Scoring (0-5):**
|
|
462
|
+
|
|
412
463
|
- 5: 관찰 기반 자연스러운 추상화
|
|
413
464
|
- 3-4: 대부분 적절
|
|
414
465
|
- 1-2: 예측 기반 성급한 추상화
|
|
@@ -449,10 +500,11 @@ Read: 주요 파일 상세 분석
|
|
|
449
500
|
|
|
450
501
|
## Output Format
|
|
451
502
|
|
|
452
|
-
|
|
503
|
+
````markdown
|
|
453
504
|
# saengmotmi 스타일 코드 리뷰 결과
|
|
454
505
|
|
|
455
506
|
## Executive Summary
|
|
507
|
+
|
|
456
508
|
- **Overall Score:** X/100
|
|
457
509
|
- **핵심 메시지:** [한 줄 요약]
|
|
458
510
|
- **Critical Issues:** N개 (즉시 수정 필요)
|
|
@@ -462,23 +514,24 @@ Read: 주요 파일 상세 분석
|
|
|
462
514
|
|
|
463
515
|
## Score Breakdown
|
|
464
516
|
|
|
465
|
-
| 원칙
|
|
466
|
-
|
|
467
|
-
| 추상화의 원칙
|
|
468
|
-
| UI-코드 1:1 대응 | X/20
|
|
469
|
-
| 분리의 4원칙
|
|
470
|
-
| 네이밍 원칙
|
|
471
|
-
| Props 인터페이스 | X/10
|
|
472
|
-
| 타입 안전성
|
|
473
|
-
| 관심사 분리
|
|
474
|
-
| 안에서 밖으로
|
|
475
|
-
| **합계**
|
|
517
|
+
| 원칙 | 점수 | 비고 |
|
|
518
|
+
| ---------------- | --------- | ---- |
|
|
519
|
+
| 추상화의 원칙 | X/20 | |
|
|
520
|
+
| UI-코드 1:1 대응 | X/20 | |
|
|
521
|
+
| 분리의 4원칙 | X/15 | |
|
|
522
|
+
| 네이밍 원칙 | X/15 | |
|
|
523
|
+
| Props 인터페이스 | X/10 | |
|
|
524
|
+
| 타입 안전성 | X/8 | |
|
|
525
|
+
| 관심사 분리 | X/7 | |
|
|
526
|
+
| 안에서 밖으로 | X/5 | |
|
|
527
|
+
| **합계** | **X/100** | |
|
|
476
528
|
|
|
477
529
|
---
|
|
478
530
|
|
|
479
531
|
## Critical Issues (즉시 수정)
|
|
480
532
|
|
|
481
533
|
### 1. [Issue Name]
|
|
534
|
+
|
|
482
535
|
**위반 원칙:** [해당 원칙]
|
|
483
536
|
**파일:** [file:line]
|
|
484
537
|
|
|
@@ -486,14 +539,18 @@ Read: 주요 파일 상세 분석
|
|
|
486
539
|
[설명]
|
|
487
540
|
|
|
488
541
|
**현재 코드:**
|
|
542
|
+
|
|
489
543
|
```typescript
|
|
490
544
|
// 문제 코드
|
|
491
545
|
```
|
|
546
|
+
````
|
|
492
547
|
|
|
493
548
|
**리뷰어 관점:**
|
|
549
|
+
|
|
494
550
|
> "[saengmotmi 리뷰어의 관점에서 피드백]"
|
|
495
551
|
|
|
496
552
|
**수정 방법:**
|
|
553
|
+
|
|
497
554
|
```typescript
|
|
498
555
|
// 개선 코드
|
|
499
556
|
```
|
|
@@ -509,6 +566,7 @@ Read: 주요 파일 상세 분석
|
|
|
509
566
|
## Best Practices Found (잘하고 있음)
|
|
510
567
|
|
|
511
568
|
### [Good Pattern]
|
|
569
|
+
|
|
512
570
|
**원칙:** [해당 원칙]
|
|
513
571
|
**파일:** [file:line]
|
|
514
572
|
|
|
@@ -516,6 +574,7 @@ Read: 주요 파일 상세 분석
|
|
|
516
574
|
[설명]
|
|
517
575
|
|
|
518
576
|
**코드:**
|
|
577
|
+
|
|
519
578
|
```typescript
|
|
520
579
|
// 좋은 예시
|
|
521
580
|
```
|
|
@@ -525,12 +584,14 @@ Read: 주요 파일 상세 분석
|
|
|
525
584
|
## "추상화는 배려다" 평가
|
|
526
585
|
|
|
527
586
|
### 배려 수준 체크
|
|
587
|
+
|
|
528
588
|
- [ ] 다른 개발자(신입 포함)가 읽어도 이해가 가는가?
|
|
529
589
|
- [ ] 한 눈에 펼쳐져 보이는가?
|
|
530
590
|
- [ ] 이름에 맞는 기능을 하는가?
|
|
531
591
|
- [ ] "이거 고쳐줘" 하면 한 방에 찾을 수 있는가?
|
|
532
592
|
|
|
533
593
|
### 총평
|
|
594
|
+
|
|
534
595
|
[코드가 동료를 얼마나 배려하고 있는지 평가]
|
|
535
596
|
|
|
536
597
|
---
|
|
@@ -538,19 +599,23 @@ Read: 주요 파일 상세 분석
|
|
|
538
599
|
## Metrics
|
|
539
600
|
|
|
540
601
|
### 추상화
|
|
602
|
+
|
|
541
603
|
- 예측 가능한 컴포넌트: N개
|
|
542
604
|
- 예측 불가능한 컴포넌트: M개
|
|
543
605
|
|
|
544
606
|
### UI-코드 대응
|
|
607
|
+
|
|
545
608
|
- 1:1 대응 영역: N개
|
|
546
609
|
- 숨겨진 구조: M개
|
|
547
610
|
|
|
548
611
|
### 분리
|
|
612
|
+
|
|
549
613
|
- 적절한 분리: N개
|
|
550
614
|
- 성급한 분리: M개
|
|
551
615
|
- Props Drilling: P개
|
|
552
616
|
|
|
553
617
|
### 네이밍
|
|
618
|
+
|
|
554
619
|
- 명확한 이름: N개
|
|
555
620
|
- 모호한 이름: M개
|
|
556
621
|
- 매직 넘버: P개
|
|
@@ -560,13 +625,17 @@ Read: 주요 파일 상세 분석
|
|
|
560
625
|
## Next Steps
|
|
561
626
|
|
|
562
627
|
### P0 (즉시) - "로코코를 미니멀로"
|
|
628
|
+
|
|
563
629
|
1. [ ] [액션 아이템]
|
|
564
630
|
|
|
565
631
|
### P1 (이번 스프린트)
|
|
632
|
+
|
|
566
633
|
1. [ ] [액션 아이템]
|
|
567
634
|
|
|
568
635
|
### P2 (백로그)
|
|
636
|
+
|
|
569
637
|
1. [ ] [액션 아이템]
|
|
638
|
+
|
|
570
639
|
```
|
|
571
640
|
|
|
572
641
|
---
|
|
@@ -615,3 +684,4 @@ Read: 주요 파일 상세 분석
|
|
|
615
684
|
- PR 리뷰 종합 분석 보고서 (comprehensive-analysis.md)
|
|
616
685
|
- [Toss Frontend Fundamentals](https://frontend-fundamentals.com/code-quality/code/)
|
|
617
686
|
- [React Official Docs](https://react.dev)
|
|
687
|
+
```
|
package/commands/branch.md
CHANGED
|
@@ -34,7 +34,13 @@ main에서 최신 코드를 pull하고 프로젝트의 네이밍 컨벤션을
|
|
|
34
34
|
- 커밋되지 않은 변경사항이 있으면 먼저 사용자에게 경고
|
|
35
35
|
|
|
36
36
|
3. **사용자 의도 파악**
|
|
37
|
-
-
|
|
37
|
+
- `/branch` 뒤에 추가 인자가 없으면:
|
|
38
|
+
- 위 컨텍스트 정보(현재 브랜치, 최근 커밋 등)를 분석하여 현재 상황 요약
|
|
39
|
+
- 감지된 브랜치 컨벤션 패턴을 보여주기
|
|
40
|
+
- 사용자에게 **어떤 작업을 할 것인지** 물어보기 (예: "어떤 작업을 위한 브랜치를 만드시겠습니까?")
|
|
41
|
+
- 사용자 응답을 바탕으로 브랜치 유형과 이름을 제안하고 확인받기
|
|
42
|
+
- `/branch` 뒤에 설명이 있으면 (예: `/branch 로그인 기능 추가`):
|
|
43
|
+
- 해당 설명을 바탕으로 브랜치 유형과 이름을 자동 결정
|
|
38
44
|
- 적절한 브랜치 유형 결정:
|
|
39
45
|
- `feature/` 또는 `feat/` - 새 기능
|
|
40
46
|
- `fix/` - 버그 수정
|
|
@@ -42,10 +48,11 @@ main에서 최신 코드를 pull하고 프로젝트의 네이밍 컨벤션을
|
|
|
42
48
|
- `hotfix/` - 긴급 프로덕션 수정
|
|
43
49
|
- `docs/` - 문서 변경
|
|
44
50
|
|
|
45
|
-
4. **브랜치 생성**
|
|
51
|
+
4. **브랜치 이름 확인 및 생성**
|
|
46
52
|
- 감지된 컨벤션 패턴 따르기
|
|
47
53
|
- description 부분은 소문자와 하이픈 사용 (예: `feature/add-user-auth`)
|
|
48
54
|
- 간결하면서도 설명적으로
|
|
55
|
+
- **생성 전 반드시 사용자에게 최종 브랜치 이름을 보여주고 확인받기**
|
|
49
56
|
- 브랜치 생성: `git checkout -b {branch-name}` 또는 `git switch -c {branch-name}`
|
|
50
57
|
|
|
51
58
|
## 출력 형식
|
package/commands/commit.md
CHANGED
|
@@ -33,15 +33,17 @@ allowed-tools: Bash(git status:*), Bash(git diff:*), Bash(git log:*), Bash(git c
|
|
|
33
33
|
- 이 변경들의 주요 목적은 무엇인가?
|
|
34
34
|
- 별도 커밋으로 분리해야 할 여러 논리적 변경이 있는가?
|
|
35
35
|
|
|
36
|
-
3. **커밋 메시지
|
|
36
|
+
3. **커밋 메시지 생성 및 확인**
|
|
37
37
|
- 감지된 컨벤션 패턴 따르기 (type prefix, scope 등)
|
|
38
38
|
- **한국어로 작성** (기존 히스토리가 영어여도)
|
|
39
39
|
- **간결하게, 가능하면 1줄** (권장 50자, 최대 72자)
|
|
40
40
|
- body는 정말 필요할 때만 추가
|
|
41
41
|
- **Co-Authored-By footer 추가 금지**
|
|
42
|
+
- **생성한 커밋 메시지를 사용자에게 보여주고 확인받기**
|
|
43
|
+
- 사용자가 수정을 원하면 반영 후 다시 확인
|
|
42
44
|
|
|
43
45
|
4. **커밋 실행**
|
|
44
|
-
-
|
|
46
|
+
- **사용자가 승인한 후에만** `git commit -m "message"` 실행
|
|
45
47
|
- body가 필요하면 멀티라인 포맷 사용
|
|
46
48
|
- **커밋 메시지에 Co-Authored-By 절대 포함 금지**
|
|
47
49
|
|
|
@@ -51,6 +53,6 @@ allowed-tools: Bash(git status:*), Bash(git diff:*), Bash(git log:*), Bash(git c
|
|
|
51
53
|
- 감지된 컨벤션 패턴
|
|
52
54
|
- 변경사항 요약
|
|
53
55
|
|
|
54
|
-
그 다음 커밋
|
|
56
|
+
그 다음 커밋 메시지를 제안하고 사용자 확인 후 실행.
|
|
55
57
|
|
|
56
58
|
Staged 변경사항이 없으면 사용자에게 알리고 먼저 `git add` 사용을 제안.
|
package/commands/pr.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: 브랜치 차이, 커밋, 변경 파일을 분석하여 Pull Request 자동 생성
|
|
3
|
-
allowed-tools: Bash(git status:*), Bash(git diff:*), Bash(git log:*), Bash(git branch:*), Bash(git rev-parse:*), Bash(gh pr:*), Bash(gh auth:*)
|
|
3
|
+
allowed-tools: Bash(git status:*), Bash(git diff:*), Bash(git log:*), Bash(git branch:*), Bash(git rev-parse:*), Bash(gh pr:*), Bash(gh auth:*), Bash(gh api:*)
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# 자동 PR 생성기
|
|
@@ -44,18 +44,33 @@ allowed-tools: Bash(git status:*), Bash(git diff:*), Bash(git log:*), Bash(git b
|
|
|
44
44
|
- 코드베이스의 어느 영역이 영향받는가?
|
|
45
45
|
- breaking changes가 있는가?
|
|
46
46
|
|
|
47
|
-
4.
|
|
47
|
+
4. **기존 PR 확인**
|
|
48
|
+
- `gh pr view --json number,title,body,url,state` 로 현재 브랜치에 열린 PR이 있는지 확인
|
|
49
|
+
- **PR이 이미 열려 있으면 → 5-A (업데이트 플로우)**
|
|
50
|
+
- **PR이 없으면 → 5-B (생성 플로우)**
|
|
51
|
+
|
|
52
|
+
5-A. **기존 PR 업데이트 플로우**
|
|
53
|
+
- 기존 PR의 title과 body를 가져오기
|
|
54
|
+
- 현재 변경사항을 기반으로 새로운 title과 body를 생성
|
|
55
|
+
- 기존 내용과 새 내용을 비교하여 **변경점을 사용자에게 보여주기**
|
|
56
|
+
- 사용자가 승인하면 `gh pr edit --title "title" --body "body"` 로 업데이트
|
|
57
|
+
- 사용자가 수정을 원하면 반영 후 다시 확인
|
|
58
|
+
|
|
59
|
+
5-B. **새 PR 생성 플로우**
|
|
48
60
|
- **제목**: 한국어로 간결한 요약 (커밋 컨벤션이 있으면 따르기)
|
|
49
61
|
- **설명**: 다음 섹션 포함:
|
|
50
62
|
- `## 변경 사항` (변경사항 요약)
|
|
51
63
|
- `## 변경된 파일` (주요 변경 파일 목록)
|
|
52
64
|
- `## 테스트` (해당되는 경우 테스트 방법)
|
|
53
65
|
- **"Generated with Claude Code" 또는 AI attribution footer 추가 금지**
|
|
66
|
+
- **생성한 title과 body를 사용자에게 보여주고 확인받기**
|
|
67
|
+
- 사용자가 수정을 원하면 반영 후 다시 확인
|
|
54
68
|
|
|
55
|
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
-
- PR
|
|
69
|
+
6. **실행**
|
|
70
|
+
- **사용자가 승인한 후에만** 실행
|
|
71
|
+
- 먼저 브랜치가 remote에 push되었는지 확인 (안 되었으면 push 제안)
|
|
72
|
+
- 새 PR: `gh pr create --title "title" --body "body"`
|
|
73
|
+
- 기존 PR 업데이트: `gh pr edit --title "title" --body "body"`
|
|
59
74
|
|
|
60
75
|
## 출력 형식
|
|
61
76
|
|
|
@@ -63,17 +78,14 @@ allowed-tools: Bash(git status:*), Bash(git diff:*), Bash(git log:*), Bash(git b
|
|
|
63
78
|
- 현재 브랜치와 타겟 브랜치
|
|
64
79
|
- 포함될 커밋 수
|
|
65
80
|
- 변경사항 요약
|
|
81
|
+
- 기존 PR 존재 여부
|
|
66
82
|
|
|
67
|
-
그
|
|
68
|
-
|
|
69
|
-
확인 후
|
|
70
|
-
```bash
|
|
71
|
-
gh pr create --title "title" --body "body"
|
|
72
|
-
```
|
|
83
|
+
그 다음:
|
|
84
|
+
- **새 PR**: 제안된 title과 body를 보여주고 사용자 확인 후 생성
|
|
85
|
+
- **기존 PR 업데이트**: 기존 내용 vs 새 내용 비교를 보여주고 사용자 확인 후 업데이트
|
|
73
86
|
|
|
74
87
|
## 에러 처리
|
|
75
88
|
|
|
76
89
|
- GitHub CLI 로그인 안됨: `gh auth login` 실행 안내
|
|
77
90
|
- 브랜치 미푸시: `git push -u origin <branch>`로 push 제안
|
|
78
|
-
- PR 이미 존재: 기존 PR URL 표시
|
|
79
91
|
- main 브랜치에서 실행: feature 브랜치 먼저 생성하라고 안내
|