mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-30 13:43:26 +08:00
docs(ko-KR): complete all command translations with full examples
Add missing example sessions, code blocks, and detailed sections to 14 command files that were previously summarized versions.
This commit is contained in:
@@ -34,6 +34,253 @@ e2e-runner 에이전트가 수행하는 작업:
|
||||
5. 결과와 아티팩트로 **보고서 생성**
|
||||
6. **불안정한 테스트 식별** 및 수정 권장
|
||||
|
||||
## 사용 예시
|
||||
|
||||
```
|
||||
User: /e2e 마켓 검색 및 조회 흐름 테스트
|
||||
|
||||
Agent (e2e-runner):
|
||||
# E2E 테스트 생성: 마켓 검색 및 조회 흐름
|
||||
|
||||
## 식별된 테스트 시나리오
|
||||
|
||||
**사용자 여정:** 마켓 검색 → 결과 확인 → 마켓 클릭 → 상세 정보 확인
|
||||
|
||||
**테스트 범위:**
|
||||
1. 마켓 페이지로 이동
|
||||
2. 시맨틱 검색 수행
|
||||
3. 검색 결과 확인
|
||||
4. 첫 번째 결과 클릭
|
||||
5. 마켓 상세 페이지 로드 확인
|
||||
6. 차트 렌더링 확인
|
||||
|
||||
## 생성된 테스트 코드
|
||||
|
||||
```typescript
|
||||
// tests/e2e/markets/search-and-view.spec.ts
|
||||
import { test, expect } from '@playwright/test'
|
||||
import { MarketsPage } from '../../pages/MarketsPage'
|
||||
import { MarketDetailsPage } from '../../pages/MarketDetailsPage'
|
||||
|
||||
test.describe('Market Search and View Flow', () => {
|
||||
test('user can search markets and view details', async ({ page }) => {
|
||||
// 1. 마켓 페이지로 이동
|
||||
const marketsPage = new MarketsPage(page)
|
||||
await marketsPage.goto()
|
||||
|
||||
// 페이지 로드 확인
|
||||
await expect(page).toHaveTitle(/Markets/)
|
||||
await expect(page.locator('h1')).toContainText('Markets')
|
||||
|
||||
// 2. 시맨틱 검색 수행
|
||||
await marketsPage.searchMarkets('election')
|
||||
|
||||
// API 응답 대기
|
||||
await page.waitForResponse(resp =>
|
||||
resp.url().includes('/api/markets/search') && resp.status() === 200
|
||||
)
|
||||
|
||||
// 3. 검색 결과 확인
|
||||
const marketCards = marketsPage.marketCards
|
||||
await expect(marketCards.first()).toBeVisible()
|
||||
const resultCount = await marketCards.count()
|
||||
expect(resultCount).toBeGreaterThan(0)
|
||||
|
||||
// 검색 결과 스크린샷 촬영
|
||||
await page.screenshot({ path: 'artifacts/search-results.png' })
|
||||
|
||||
// 4. 첫 번째 결과 클릭
|
||||
const firstMarketTitle = await marketCards.first().textContent()
|
||||
await marketCards.first().click()
|
||||
|
||||
// 5. 마켓 상세 페이지 로드 확인
|
||||
await expect(page).toHaveURL(/\/markets\/[a-z0-9-]+/)
|
||||
|
||||
const detailsPage = new MarketDetailsPage(page)
|
||||
await expect(detailsPage.marketName).toBeVisible()
|
||||
await expect(detailsPage.marketDescription).toBeVisible()
|
||||
|
||||
// 6. 차트 렌더링 확인
|
||||
await expect(detailsPage.priceChart).toBeVisible()
|
||||
|
||||
// 마켓 이름 일치 확인
|
||||
const detailsTitle = await detailsPage.marketName.textContent()
|
||||
expect(detailsTitle?.toLowerCase()).toContain(
|
||||
firstMarketTitle?.toLowerCase().substring(0, 20) || ''
|
||||
)
|
||||
|
||||
// 마켓 상세 스크린샷 촬영
|
||||
await page.screenshot({ path: 'artifacts/market-details.png' })
|
||||
})
|
||||
|
||||
test('search with no results shows empty state', async ({ page }) => {
|
||||
const marketsPage = new MarketsPage(page)
|
||||
await marketsPage.goto()
|
||||
|
||||
// 존재하지 않는 마켓 검색
|
||||
await marketsPage.searchMarkets('xyznonexistentmarket123456')
|
||||
|
||||
// 빈 상태 확인
|
||||
await expect(page.locator('[data-testid="no-results"]')).toBeVisible()
|
||||
await expect(page.locator('[data-testid="no-results"]')).toContainText(
|
||||
/no.*results|no.*markets/i
|
||||
)
|
||||
|
||||
const marketCount = await marketsPage.marketCards.count()
|
||||
expect(marketCount).toBe(0)
|
||||
})
|
||||
|
||||
test('can clear search and see all markets again', async ({ page }) => {
|
||||
const marketsPage = new MarketsPage(page)
|
||||
await marketsPage.goto()
|
||||
|
||||
// 초기 마켓 수
|
||||
const initialCount = await marketsPage.marketCards.count()
|
||||
|
||||
// 검색 수행
|
||||
await marketsPage.searchMarkets('trump')
|
||||
await page.waitForLoadState('networkidle')
|
||||
|
||||
// 필터링된 결과 확인
|
||||
const filteredCount = await marketsPage.marketCards.count()
|
||||
expect(filteredCount).toBeLessThan(initialCount)
|
||||
|
||||
// 검색 초기화
|
||||
await marketsPage.searchInput.clear()
|
||||
await page.waitForLoadState('networkidle')
|
||||
|
||||
// 모든 마켓이 다시 표시되는지 확인
|
||||
const finalCount = await marketsPage.marketCards.count()
|
||||
expect(finalCount).toBe(initialCount)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## 테스트 실행
|
||||
|
||||
```bash
|
||||
# 생성된 테스트 실행
|
||||
npx playwright test tests/e2e/markets/search-and-view.spec.ts
|
||||
|
||||
Running 3 tests using 3 workers
|
||||
|
||||
✓ [chromium] › search-and-view.spec.ts:5:3 › user can search markets and view details (4.2s)
|
||||
✓ [chromium] › search-and-view.spec.ts:52:3 › search with no results shows empty state (1.8s)
|
||||
✓ [chromium] › search-and-view.spec.ts:67:3 › can clear search and see all markets again (2.9s)
|
||||
|
||||
3 passed (9.1s)
|
||||
|
||||
생성된 아티팩트:
|
||||
- artifacts/search-results.png
|
||||
- artifacts/market-details.png
|
||||
- playwright-report/index.html
|
||||
```
|
||||
|
||||
## 테스트 보고서
|
||||
|
||||
```
|
||||
╔══════════════════════════════════════════════════════════════╗
|
||||
║ E2E 테스트 결과 ║
|
||||
╠══════════════════════════════════════════════════════════════╣
|
||||
║ 상태: ✅ 모든 테스트 통과 ║
|
||||
║ 전체: 3개 테스트 ║
|
||||
║ 통과: 3 (100%) ║
|
||||
║ 실패: 0 ║
|
||||
║ 불안정: 0 ║
|
||||
║ 소요시간: 9.1s ║
|
||||
╚══════════════════════════════════════════════════════════════╝
|
||||
|
||||
아티팩트:
|
||||
📸 스크린샷: 2개 파일
|
||||
📹 비디오: 0개 파일 (실패 시에만)
|
||||
🔍 트레이스: 0개 파일 (실패 시에만)
|
||||
📊 HTML 보고서: playwright-report/index.html
|
||||
|
||||
보고서 확인: npx playwright show-report
|
||||
```
|
||||
|
||||
✅ CI/CD 통합 준비가 완료된 E2E 테스트 모음!
|
||||
```
|
||||
|
||||
## 테스트 아티팩트
|
||||
|
||||
테스트 실행 시 다음 아티팩트가 캡처됩니다:
|
||||
|
||||
**모든 테스트:**
|
||||
- 타임라인과 결과가 포함된 HTML 보고서
|
||||
- CI 통합을 위한 JUnit XML
|
||||
|
||||
**실패 시에만:**
|
||||
- 실패 상태의 스크린샷
|
||||
- 테스트의 비디오 녹화
|
||||
- 디버깅을 위한 트레이스 파일 (단계별 재생)
|
||||
- 네트워크 로그
|
||||
- 콘솔 로그
|
||||
|
||||
## 아티팩트 확인
|
||||
|
||||
```bash
|
||||
# 브라우저에서 HTML 보고서 확인
|
||||
npx playwright show-report
|
||||
|
||||
# 특정 트레이스 파일 확인
|
||||
npx playwright show-trace artifacts/trace-abc123.zip
|
||||
|
||||
# 스크린샷은 artifacts/ 디렉토리에 저장됨
|
||||
open artifacts/search-results.png
|
||||
```
|
||||
|
||||
## 불안정한 테스트 감지
|
||||
|
||||
테스트가 간헐적으로 실패하는 경우:
|
||||
|
||||
```
|
||||
⚠️ 불안정한 테스트 감지됨: tests/e2e/markets/trade.spec.ts
|
||||
|
||||
테스트가 10회 중 7회 통과 (70% 통과율)
|
||||
|
||||
일반적인 실패 원인:
|
||||
"요소 '[data-testid="confirm-btn"]'을 대기하는 중 타임아웃"
|
||||
|
||||
권장 수정 사항:
|
||||
1. 명시적 대기 추가: await page.waitForSelector('[data-testid="confirm-btn"]')
|
||||
2. 타임아웃 증가: { timeout: 10000 }
|
||||
3. 컴포넌트의 레이스 컨디션 확인
|
||||
4. 애니메이션에 의해 요소가 숨겨져 있지 않은지 확인
|
||||
|
||||
격리 권장: 수정될 때까지 test.fixme()로 표시
|
||||
```
|
||||
|
||||
## 브라우저 구성
|
||||
|
||||
기본적으로 여러 브라우저에서 테스트가 실행됩니다:
|
||||
- Chromium (데스크톱 Chrome)
|
||||
- Firefox (데스크톱)
|
||||
- WebKit (데스크톱 Safari)
|
||||
- Mobile Chrome (선택 사항)
|
||||
|
||||
`playwright.config.ts`에서 브라우저를 조정할 수 있습니다.
|
||||
|
||||
## CI/CD 통합
|
||||
|
||||
CI 파이프라인에 추가:
|
||||
|
||||
```yaml
|
||||
# .github/workflows/e2e.yml
|
||||
- name: Install Playwright
|
||||
run: npx playwright install --with-deps
|
||||
|
||||
- name: Run E2E tests
|
||||
run: npx playwright test
|
||||
|
||||
- name: Upload artifacts
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
```
|
||||
|
||||
## 모범 사례
|
||||
|
||||
**해야 할 것:**
|
||||
@@ -42,15 +289,46 @@ e2e-runner 에이전트가 수행하는 작업:
|
||||
- 임의의 타임아웃 대신 API 응답을 대기
|
||||
- 핵심 사용자 여정을 E2E로 테스트
|
||||
- main에 merge하기 전에 테스트 실행
|
||||
- 테스트 실패 시 아티팩트 검토
|
||||
|
||||
**하지 말아야 할 것:**
|
||||
- 취약한 셀렉터 사용 (CSS 클래스는 변경될 수 있음)
|
||||
- 구현 세부사항 테스트
|
||||
- 프로덕션에 대해 테스트 실행
|
||||
- 불안정한 테스트 무시
|
||||
- 실패 시 아티팩트 검토 생략
|
||||
- E2E로 모든 엣지 케이스 테스트 (단위 테스트 사용)
|
||||
|
||||
## 다른 커맨드와의 연동
|
||||
|
||||
- `/plan`을 사용하여 테스트할 핵심 여정 식별
|
||||
- `/tdd`를 사용하여 단위 테스트 (더 빠르고 세밀함)
|
||||
- `/e2e`를 사용하여 통합 및 사용자 여정 테스트
|
||||
- `/code-review`를 사용하여 테스트 품질 검증
|
||||
|
||||
## 관련 에이전트
|
||||
|
||||
이 커맨드는 `e2e-runner` 에이전트를 호출합니다:
|
||||
`~/.claude/agents/e2e-runner.md`
|
||||
|
||||
## 빠른 커맨드
|
||||
|
||||
```bash
|
||||
# 모든 E2E 테스트 실행
|
||||
npx playwright test
|
||||
|
||||
# 특정 테스트 파일 실행
|
||||
npx playwright test tests/e2e/markets/search.spec.ts
|
||||
|
||||
# headed 모드로 실행 (브라우저 표시)
|
||||
npx playwright test --headed
|
||||
|
||||
# 테스트 디버그
|
||||
npx playwright test --debug
|
||||
|
||||
# 테스트 코드 생성
|
||||
npx playwright codegen http://localhost:3000
|
||||
|
||||
# 보고서 확인
|
||||
npx playwright show-report
|
||||
```
|
||||
|
||||
@@ -12,8 +12,26 @@
|
||||
|
||||
새로운 평가 정의를 생성합니다:
|
||||
|
||||
1. `.claude/evals/feature-name.md`에 템플릿 생성
|
||||
2. 사용자에게 구체적인 기준을 입력하도록 안내
|
||||
1. `.claude/evals/feature-name.md`에 템플릿을 생성합니다:
|
||||
|
||||
```markdown
|
||||
## EVAL: feature-name
|
||||
Created: $(date)
|
||||
|
||||
### Capability Evals
|
||||
- [ ] [기능 1에 대한 설명]
|
||||
- [ ] [기능 2에 대한 설명]
|
||||
|
||||
### Regression Evals
|
||||
- [ ] [기존 동작 1이 여전히 작동함]
|
||||
- [ ] [기존 동작 2이 여전히 작동함]
|
||||
|
||||
### Success Criteria
|
||||
- capability eval에 대해 pass@3 > 90%
|
||||
- regression eval에 대해 pass^3 = 100%
|
||||
```
|
||||
|
||||
2. 사용자에게 구체적인 기준을 입력하도록 안내합니다
|
||||
|
||||
## 평가 확인
|
||||
|
||||
@@ -21,22 +39,76 @@
|
||||
|
||||
기능에 대한 평가를 실행합니다:
|
||||
|
||||
1. `.claude/evals/feature-name.md`에서 평가 정의 읽기
|
||||
2. 각 기능 평가: 기준 검증 시도, PASS/FAIL 기록
|
||||
3. 각 회귀 평가: 관련 테스트 실행, 기준선과 비교
|
||||
4. 현재 상태 보고
|
||||
1. `.claude/evals/feature-name.md`에서 평가 정의를 읽습니다
|
||||
2. 각 capability eval에 대해:
|
||||
- 기준 검증을 시도합니다
|
||||
- PASS/FAIL을 기록합니다
|
||||
- `.claude/evals/feature-name.log`에 시도를 기록합니다
|
||||
3. 각 regression eval에 대해:
|
||||
- 관련 테스트를 실행합니다
|
||||
- 기준선과 비교합니다
|
||||
- PASS/FAIL을 기록합니다
|
||||
4. 현재 상태를 보고합니다:
|
||||
|
||||
```
|
||||
EVAL CHECK: feature-name
|
||||
========================
|
||||
Capability: X/Y passing
|
||||
Regression: X/Y passing
|
||||
Status: IN PROGRESS / READY
|
||||
```
|
||||
|
||||
## 평가 보고
|
||||
|
||||
`/eval report feature-name`
|
||||
|
||||
포괄적인 평가 보고서를 생성합니다.
|
||||
포괄적인 평가 보고서를 생성합니다:
|
||||
|
||||
```
|
||||
EVAL REPORT: feature-name
|
||||
=========================
|
||||
Generated: $(date)
|
||||
|
||||
CAPABILITY EVALS
|
||||
----------------
|
||||
[eval-1]: PASS (pass@1)
|
||||
[eval-2]: PASS (pass@2) - 재시도 필요했음
|
||||
[eval-3]: FAIL - 비고 참조
|
||||
|
||||
REGRESSION EVALS
|
||||
----------------
|
||||
[test-1]: PASS
|
||||
[test-2]: PASS
|
||||
[test-3]: PASS
|
||||
|
||||
METRICS
|
||||
-------
|
||||
Capability pass@1: 67%
|
||||
Capability pass@3: 100%
|
||||
Regression pass^3: 100%
|
||||
|
||||
NOTES
|
||||
-----
|
||||
[이슈, 엣지 케이스 또는 관찰 사항]
|
||||
|
||||
RECOMMENDATION
|
||||
--------------
|
||||
[SHIP / NEEDS WORK / BLOCKED]
|
||||
```
|
||||
|
||||
## 평가 목록
|
||||
|
||||
`/eval list`
|
||||
|
||||
모든 평가 정의를 표시합니다.
|
||||
모든 평가 정의를 표시합니다:
|
||||
|
||||
```
|
||||
EVAL DEFINITIONS
|
||||
================
|
||||
feature-auth [3/5 passing] IN PROGRESS
|
||||
feature-search [5/5 passing] READY
|
||||
feature-export [0/4 passing] NOT STARTED
|
||||
```
|
||||
|
||||
## 인자
|
||||
|
||||
@@ -45,4 +117,4 @@ $ARGUMENTS:
|
||||
- `check <name>` - 평가 실행 및 확인
|
||||
- `report <name>` - 전체 보고서 생성
|
||||
- `list` - 모든 평가 표시
|
||||
- `clean` - 오래된 평가 로그 제거 (최근 10회 유지)
|
||||
- `clean` - 오래된 평가 로그 제거 (최근 10회 실행 유지)
|
||||
|
||||
@@ -23,6 +23,138 @@ description: Go build 에러, go vet 경고, 린터 이슈를 점진적으로
|
||||
- 모듈 의존성이 깨졌을 때
|
||||
- 변경사항을 pull한 후 build가 깨졌을 때
|
||||
|
||||
## 실행되는 진단 커맨드
|
||||
|
||||
```bash
|
||||
# 기본 build 확인
|
||||
go build ./...
|
||||
|
||||
# 정적 분석
|
||||
go vet ./...
|
||||
|
||||
# 확장 린팅 (사용 가능한 경우)
|
||||
staticcheck ./...
|
||||
golangci-lint run
|
||||
|
||||
# 모듈 이슈
|
||||
go mod verify
|
||||
go mod tidy -v
|
||||
```
|
||||
|
||||
## 예시 세션
|
||||
|
||||
```text
|
||||
User: /go-build
|
||||
|
||||
Agent:
|
||||
# Go Build 해결
|
||||
|
||||
## 초기 진단
|
||||
|
||||
```bash
|
||||
$ go build ./...
|
||||
internal/service/user.go:25:15: undefined: UserRepository
|
||||
internal/handler/api.go:42:9: cannot use x (type string) as type int
|
||||
internal/handler/api.go:58:2: missing return at end of function
|
||||
```
|
||||
|
||||
발견된 에러: 3개
|
||||
|
||||
## 수정 1: 정의되지 않은 식별자
|
||||
|
||||
파일: internal/service/user.go:25
|
||||
에러: undefined: UserRepository
|
||||
원인: import 누락
|
||||
|
||||
```go
|
||||
// import 추가
|
||||
import "project/internal/repository"
|
||||
|
||||
// 변경 전
|
||||
var repo UserRepository
|
||||
// 변경 후
|
||||
var repo repository.UserRepository
|
||||
```
|
||||
|
||||
```bash
|
||||
$ go build ./...
|
||||
# 2개 에러 남음
|
||||
```
|
||||
|
||||
## 수정 2: 타입 불일치
|
||||
|
||||
파일: internal/handler/api.go:42
|
||||
에러: cannot use x (type string) as type int
|
||||
|
||||
```go
|
||||
// 변경 전
|
||||
count := params.Get("count")
|
||||
// 변경 후
|
||||
countStr := params.Get("count")
|
||||
count, _ := strconv.Atoi(countStr)
|
||||
```
|
||||
|
||||
```bash
|
||||
$ go build ./...
|
||||
# 1개 에러 남음
|
||||
```
|
||||
|
||||
## 수정 3: 누락된 return
|
||||
|
||||
파일: internal/handler/api.go:58
|
||||
에러: missing return at end of function
|
||||
|
||||
```go
|
||||
func GetUser(id string) (*User, error) {
|
||||
if id == "" {
|
||||
return nil, ErrInvalidID
|
||||
}
|
||||
user := findUser(id)
|
||||
// 누락된 return 추가
|
||||
return user, nil
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
$ go build ./...
|
||||
# Build 성공!
|
||||
```
|
||||
|
||||
## 최종 검증
|
||||
|
||||
```bash
|
||||
$ go vet ./...
|
||||
# 이슈 없음
|
||||
|
||||
$ go test ./...
|
||||
ok project/internal/service 0.015s
|
||||
ok project/internal/handler 0.023s
|
||||
```
|
||||
|
||||
## 요약
|
||||
|
||||
| 항목 | 수량 |
|
||||
|------|------|
|
||||
| 수정된 Build 에러 | 3 |
|
||||
| 수정된 Vet 경고 | 0 |
|
||||
| 수정된 파일 | 2 |
|
||||
| 남은 이슈 | 0 |
|
||||
|
||||
Build 상태: ✅ 성공
|
||||
```
|
||||
|
||||
## 자주 발생하는 에러
|
||||
|
||||
| 에러 | 일반적인 수정 방법 |
|
||||
|------|-------------------|
|
||||
| `undefined: X` | import 추가 또는 오타 수정 |
|
||||
| `cannot use X as Y` | 타입 변환 또는 할당 수정 |
|
||||
| `missing return` | return 문 추가 |
|
||||
| `X does not implement Y` | 누락된 메서드 추가 |
|
||||
| `import cycle` | 패키지 구조 재구성 |
|
||||
| `declared but not used` | 변수 제거 또는 사용 |
|
||||
| `cannot find package` | `go get` 또는 `go mod tidy` |
|
||||
|
||||
## 수정 전략
|
||||
|
||||
1. **Build 에러 먼저** - 코드가 컴파일되어야 함
|
||||
@@ -31,8 +163,21 @@ description: Go build 에러, go vet 경고, 린터 이슈를 점진적으로
|
||||
4. **한 번에 하나씩** - 각 변경 검증
|
||||
5. **최소한의 변경** - 리팩토링이 아닌 수정만
|
||||
|
||||
## 중단 조건
|
||||
|
||||
에이전트가 중단하고 보고하는 경우:
|
||||
- 3번 시도 후에도 같은 에러가 지속
|
||||
- 수정이 더 많은 에러를 발생시킴
|
||||
- 아키텍처 변경이 필요한 경우
|
||||
- 외부 의존성이 누락된 경우
|
||||
|
||||
## 관련 커맨드
|
||||
|
||||
- `/go-test` - build 성공 후 테스트 실행
|
||||
- `/go-review` - 코드 품질 리뷰
|
||||
- `/verify` - 전체 검증 루프
|
||||
|
||||
## 관련 항목
|
||||
|
||||
- 에이전트: `agents/go-build-resolver.md`
|
||||
- 스킬: `skills/golang-patterns/`
|
||||
|
||||
@@ -22,6 +22,7 @@ description: 관용적 패턴, 동시성 안전성, 에러 처리, 보안에 대
|
||||
- Go 변경사항을 커밋하기 전
|
||||
- Go 코드가 포함된 PR 리뷰 시
|
||||
- 새 Go 코드베이스에 온보딩할 때
|
||||
- 관용적 Go 패턴 학습 시
|
||||
|
||||
## 리뷰 카테고리
|
||||
|
||||
@@ -30,20 +31,118 @@ description: 관용적 패턴, 동시성 안전성, 에러 처리, 보안에 대
|
||||
- 동기화 없는 레이스 컨디션
|
||||
- 고루틴 누수
|
||||
- 하드코딩된 인증 정보
|
||||
- unsafe 포인터 사용
|
||||
- 핵심 경로에서 에러 무시
|
||||
|
||||
### HIGH (수정 권장)
|
||||
- 컨텍스트 없는 에러 래핑 누락
|
||||
- 에러 반환 대신 panic 사용
|
||||
- 컨텍스트 전파 누락
|
||||
- 데드락을 유발하는 버퍼 없는 채널
|
||||
- 인터페이스 미충족 에러
|
||||
- 뮤텍스 보호 누락
|
||||
|
||||
### MEDIUM (고려)
|
||||
- 비관용적 코드 패턴
|
||||
- 공개 항목에 godoc 주석 누락
|
||||
- 비효율적인 문자열 연결
|
||||
- 슬라이스 사전 할당 누락
|
||||
- 테이블 기반 테스트 미사용
|
||||
|
||||
## 관련 커맨드
|
||||
## 실행되는 자동 검사
|
||||
|
||||
- `/go-test` - 먼저 테스트 통과 확인
|
||||
- `/go-build` - build 에러 발생 시
|
||||
- `/code-review` - Go 외 일반적인 관심사항
|
||||
```bash
|
||||
# 정적 분석
|
||||
go vet ./...
|
||||
|
||||
# 고급 검사 (설치된 경우)
|
||||
staticcheck ./...
|
||||
golangci-lint run
|
||||
|
||||
# 레이스 감지
|
||||
go build -race ./...
|
||||
|
||||
# 보안 취약점
|
||||
govulncheck ./...
|
||||
```
|
||||
|
||||
## 사용 예시
|
||||
|
||||
```text
|
||||
User: /go-review
|
||||
|
||||
Agent:
|
||||
# Go 코드 리뷰 보고서
|
||||
|
||||
## 리뷰된 파일
|
||||
- internal/handler/user.go (수정됨)
|
||||
- internal/service/auth.go (수정됨)
|
||||
|
||||
## 정적 분석 결과
|
||||
✓ go vet: 이슈 없음
|
||||
✓ staticcheck: 이슈 없음
|
||||
|
||||
## 발견된 이슈
|
||||
|
||||
[CRITICAL] 레이스 컨디션
|
||||
파일: internal/service/auth.go:45
|
||||
이슈: 동기화 없이 공유 맵에 접근
|
||||
```go
|
||||
var cache = map[string]*Session{} // 동시 접근!
|
||||
|
||||
func GetSession(id string) *Session {
|
||||
return cache[id] // 레이스 컨디션
|
||||
}
|
||||
```
|
||||
수정: sync.RWMutex 또는 sync.Map 사용
|
||||
```go
|
||||
var (
|
||||
cache = map[string]*Session{}
|
||||
cacheMu sync.RWMutex
|
||||
)
|
||||
|
||||
func GetSession(id string) *Session {
|
||||
cacheMu.RLock()
|
||||
defer cacheMu.RUnlock()
|
||||
return cache[id]
|
||||
}
|
||||
```
|
||||
|
||||
[HIGH] 에러 컨텍스트 누락
|
||||
파일: internal/handler/user.go:28
|
||||
이슈: 컨텍스트 없이 에러 반환
|
||||
```go
|
||||
return err // 컨텍스트 없음
|
||||
```
|
||||
수정: 컨텍스트와 함께 래핑
|
||||
```go
|
||||
return fmt.Errorf("get user %s: %w", userID, err)
|
||||
```
|
||||
|
||||
## 요약
|
||||
- CRITICAL: 1
|
||||
- HIGH: 1
|
||||
- MEDIUM: 0
|
||||
|
||||
권장: ❌ CRITICAL 이슈가 수정될 때까지 merge 차단
|
||||
```
|
||||
|
||||
## 승인 기준
|
||||
|
||||
| 상태 | 조건 |
|
||||
|------|------|
|
||||
| ✅ 승인 | CRITICAL 또는 HIGH 이슈 없음 |
|
||||
| ⚠️ 경고 | MEDIUM 이슈만 있음 (주의하여 merge) |
|
||||
| ❌ 차단 | CRITICAL 또는 HIGH 이슈 발견 |
|
||||
|
||||
## 다른 커맨드와의 연동
|
||||
|
||||
- `/go-test`를 먼저 사용하여 테스트 통과 확인
|
||||
- `/go-build`를 사용하여 build 에러 발생 시 수정
|
||||
- `/go-review`를 커밋 전에 사용
|
||||
- `/code-review`를 사용하여 Go 외 일반적인 관심사항 리뷰
|
||||
|
||||
## 관련 항목
|
||||
|
||||
- 에이전트: `agents/go-reviewer.md`
|
||||
- 스킬: `skills/golang-patterns/`, `skills/golang-testing/`
|
||||
|
||||
@@ -22,6 +22,7 @@ description: Go용 TDD 워크플로우 강제. 테이블 기반 테스트를 먼
|
||||
- 기존 코드에 테스트 커버리지 추가
|
||||
- 버그 수정 (실패하는 테스트를 먼저 작성)
|
||||
- 핵심 비즈니스 로직 구현
|
||||
- Go에서 TDD 워크플로우 학습
|
||||
|
||||
## TDD 사이클
|
||||
|
||||
@@ -32,6 +33,204 @@ REFACTOR → 코드 개선, 테스트는 통과 유지
|
||||
REPEAT → 다음 테스트 케이스
|
||||
```
|
||||
|
||||
## 예시 세션
|
||||
|
||||
````
|
||||
User: /go-test 이메일 주소를 검증하는 함수가 필요합니다
|
||||
|
||||
Agent:
|
||||
# TDD 세션: 이메일 검증기
|
||||
|
||||
## 1단계: 인터페이스 정의
|
||||
|
||||
```go
|
||||
// validator/email.go
|
||||
package validator
|
||||
|
||||
// ValidateEmail은 주어진 문자열이 유효한 이메일 주소인지 확인합니다.
|
||||
// 유효하면 nil을 반환하고, 그렇지 않으면 이슈를 설명하는 error를 반환합니다.
|
||||
func ValidateEmail(email string) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
```
|
||||
|
||||
## 2단계: 테이블 기반 테스트 작성 (RED)
|
||||
|
||||
```go
|
||||
// validator/email_test.go
|
||||
package validator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidateEmail(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
email string
|
||||
wantErr bool
|
||||
}{
|
||||
// 유효한 이메일
|
||||
{"단순 이메일", "user@example.com", false},
|
||||
{"서브도메인 포함", "user@mail.example.com", false},
|
||||
{"플러스 포함", "user+tag@example.com", false},
|
||||
{"점 포함", "first.last@example.com", false},
|
||||
|
||||
// 유효하지 않은 이메일
|
||||
{"빈 문자열", "", true},
|
||||
{"@ 기호 없음", "userexample.com", true},
|
||||
{"도메인 없음", "user@", true},
|
||||
{"로컬 파트 없음", "@example.com", true},
|
||||
{"이중 @", "user@@example.com", true},
|
||||
{"공백 포함", "user @example.com", true},
|
||||
{"TLD 없음", "user@example", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := ValidateEmail(tt.email)
|
||||
if tt.wantErr && err == nil {
|
||||
t.Errorf("ValidateEmail(%q) = nil; want error", tt.email)
|
||||
}
|
||||
if !tt.wantErr && err != nil {
|
||||
t.Errorf("ValidateEmail(%q) = %v; want nil", tt.email, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 3단계: 테스트 실행 - 실패 확인
|
||||
|
||||
```bash
|
||||
$ go test ./validator/...
|
||||
|
||||
--- FAIL: TestValidateEmail (0.00s)
|
||||
--- FAIL: TestValidateEmail/단순_이메일 (0.00s)
|
||||
panic: not implemented
|
||||
|
||||
FAIL
|
||||
```
|
||||
|
||||
✓ 예상대로 테스트 실패 (panic).
|
||||
|
||||
## 4단계: 최소한의 코드 구현 (GREEN)
|
||||
|
||||
```go
|
||||
// validator/email.go
|
||||
package validator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
|
||||
|
||||
var (
|
||||
ErrEmailEmpty = errors.New("email cannot be empty")
|
||||
ErrEmailInvalid = errors.New("email format is invalid")
|
||||
)
|
||||
|
||||
func ValidateEmail(email string) error {
|
||||
if email == "" {
|
||||
return ErrEmailEmpty
|
||||
}
|
||||
if !emailRegex.MatchString(email) {
|
||||
return ErrEmailInvalid
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
## 5단계: 테스트 실행 - 통과 확인
|
||||
|
||||
```bash
|
||||
$ go test ./validator/...
|
||||
|
||||
PASS
|
||||
ok project/validator 0.003s
|
||||
```
|
||||
|
||||
✓ 모든 테스트 통과!
|
||||
|
||||
## 6단계: 커버리지 확인
|
||||
|
||||
```bash
|
||||
$ go test -cover ./validator/...
|
||||
|
||||
PASS
|
||||
coverage: 100.0% of statements
|
||||
ok project/validator 0.003s
|
||||
```
|
||||
|
||||
✓ 커버리지: 100%
|
||||
|
||||
## TDD 완료!
|
||||
````
|
||||
|
||||
## 테스트 패턴
|
||||
|
||||
### 테이블 기반 테스트
|
||||
```go
|
||||
tests := []struct {
|
||||
name string
|
||||
input InputType
|
||||
want OutputType
|
||||
wantErr bool
|
||||
}{
|
||||
{"케이스 1", input1, want1, false},
|
||||
{"케이스 2", input2, want2, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := Function(tt.input)
|
||||
// 단언문
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### 병렬 테스트
|
||||
```go
|
||||
for _, tt := range tests {
|
||||
tt := tt // 캡처
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
// 테스트 본문
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### 테스트 헬퍼
|
||||
```go
|
||||
func setupTestDB(t *testing.T) *sql.DB {
|
||||
t.Helper()
|
||||
db := createDB()
|
||||
t.Cleanup(func() { db.Close() })
|
||||
return db
|
||||
}
|
||||
```
|
||||
|
||||
## 커버리지 커맨드
|
||||
|
||||
```bash
|
||||
# 기본 커버리지
|
||||
go test -cover ./...
|
||||
|
||||
# 커버리지 프로파일
|
||||
go test -coverprofile=coverage.out ./...
|
||||
|
||||
# 브라우저에서 확인
|
||||
go tool cover -html=coverage.out
|
||||
|
||||
# 함수별 커버리지
|
||||
go tool cover -func=coverage.out
|
||||
|
||||
# 레이스 감지와 함께
|
||||
go test -race -cover ./...
|
||||
```
|
||||
|
||||
## 커버리지 목표
|
||||
|
||||
| 코드 유형 | 목표 |
|
||||
@@ -41,8 +240,29 @@ REPEAT → 다음 테스트 케이스
|
||||
| 일반 코드 | 80%+ |
|
||||
| 생성된 코드 | 제외 |
|
||||
|
||||
## TDD 모범 사례
|
||||
|
||||
**해야 할 것:**
|
||||
- 구현 전에 테스트를 먼저 작성
|
||||
- 각 변경 후 테스트 실행
|
||||
- 포괄적인 커버리지를 위해 테이블 기반 테스트 사용
|
||||
- 구현 세부사항이 아닌 동작 테스트
|
||||
- 엣지 케이스 포함 (빈 값, nil, 최대값)
|
||||
|
||||
**하지 말아야 할 것:**
|
||||
- 테스트 전에 구현 작성
|
||||
- RED 단계 건너뛰기
|
||||
- private 함수를 직접 테스트
|
||||
- 테스트에서 `time.Sleep` 사용
|
||||
- 불안정한 테스트 무시
|
||||
|
||||
## 관련 커맨드
|
||||
|
||||
- `/go-build` - build 에러 수정
|
||||
- `/go-review` - 구현 후 코드 리뷰
|
||||
- `/verify` - 전체 검증 루프
|
||||
|
||||
## 관련 항목
|
||||
|
||||
- 스킬: `skills/golang-testing/`
|
||||
- 스킬: `skills/tdd-workflow/`
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
- 효과적인 도구 조합
|
||||
- 진단 패턴
|
||||
|
||||
3. **해결 방법**
|
||||
3. **우회 방법**
|
||||
- 라이브러리 특이 사항
|
||||
- API 제한 사항
|
||||
- 버전별 수정 사항
|
||||
@@ -31,6 +31,29 @@
|
||||
- 내려진 아키텍처 결정
|
||||
- 통합 패턴
|
||||
|
||||
## 출력 형식
|
||||
|
||||
`~/.claude/skills/learned/[pattern-name].md`에 스킬 파일을 생성합니다:
|
||||
|
||||
```markdown
|
||||
# [설명적인 패턴 이름]
|
||||
|
||||
**추출일:** [날짜]
|
||||
**컨텍스트:** [이 패턴이 적용되는 상황에 대한 간략한 설명]
|
||||
|
||||
## 문제
|
||||
[이 패턴이 해결하는 문제 - 구체적으로 작성]
|
||||
|
||||
## 해결 방법
|
||||
[패턴/기법/우회 방법]
|
||||
|
||||
## 예시
|
||||
[해당하는 경우 코드 예시]
|
||||
|
||||
## 사용 시점
|
||||
[트리거 조건 - 이 스킬이 활성화되어야 하는 상황]
|
||||
```
|
||||
|
||||
## 프로세스
|
||||
|
||||
1. 세션에서 추출 가능한 패턴 검토
|
||||
|
||||
@@ -41,6 +41,113 @@ security-reviewer -> code-reviewer -> architect
|
||||
3. 체인의 **다음 에이전트에 전달**
|
||||
4. **결과를 종합**하여 최종 보고서 작성
|
||||
|
||||
## 핸드오프 문서 형식
|
||||
|
||||
에이전트 간에 핸드오프 문서를 생성합니다:
|
||||
|
||||
```markdown
|
||||
## HANDOFF: [이전-에이전트] -> [다음-에이전트]
|
||||
|
||||
### Context
|
||||
[수행된 작업 요약]
|
||||
|
||||
### Findings
|
||||
[주요 발견 사항 또는 결정 사항]
|
||||
|
||||
### Files Modified
|
||||
[수정된 파일 목록]
|
||||
|
||||
### Open Questions
|
||||
[다음 에이전트를 위한 미해결 항목]
|
||||
|
||||
### Recommendations
|
||||
[제안하는 다음 단계]
|
||||
```
|
||||
|
||||
## 예시: Feature 워크플로우
|
||||
|
||||
```
|
||||
/orchestrate feature "Add user authentication"
|
||||
```
|
||||
|
||||
실행 순서:
|
||||
|
||||
1. **Planner 에이전트**
|
||||
- 요구사항 분석
|
||||
- 구현 계획 작성
|
||||
- 의존성 식별
|
||||
- 출력: `HANDOFF: planner -> tdd-guide`
|
||||
|
||||
2. **TDD Guide 에이전트**
|
||||
- planner 핸드오프 읽기
|
||||
- 테스트 먼저 작성
|
||||
- 테스트를 통과하도록 구현
|
||||
- 출력: `HANDOFF: tdd-guide -> code-reviewer`
|
||||
|
||||
3. **Code Reviewer 에이전트**
|
||||
- 구현 리뷰
|
||||
- 이슈 확인
|
||||
- 개선사항 제안
|
||||
- 출력: `HANDOFF: code-reviewer -> security-reviewer`
|
||||
|
||||
4. **Security Reviewer 에이전트**
|
||||
- 보안 감사
|
||||
- 취약점 점검
|
||||
- 최종 승인
|
||||
- 출력: 최종 보고서
|
||||
|
||||
## 최종 보고서 형식
|
||||
|
||||
```
|
||||
ORCHESTRATION REPORT
|
||||
====================
|
||||
Workflow: feature
|
||||
Task: Add user authentication
|
||||
Agents: planner -> tdd-guide -> code-reviewer -> security-reviewer
|
||||
|
||||
SUMMARY
|
||||
-------
|
||||
[한 단락 요약]
|
||||
|
||||
AGENT OUTPUTS
|
||||
-------------
|
||||
Planner: [요약]
|
||||
TDD Guide: [요약]
|
||||
Code Reviewer: [요약]
|
||||
Security Reviewer: [요약]
|
||||
|
||||
FILES CHANGED
|
||||
-------------
|
||||
[수정된 모든 파일 목록]
|
||||
|
||||
TEST RESULTS
|
||||
------------
|
||||
[테스트 통과/실패 요약]
|
||||
|
||||
SECURITY STATUS
|
||||
---------------
|
||||
[보안 발견 사항]
|
||||
|
||||
RECOMMENDATION
|
||||
--------------
|
||||
[SHIP / NEEDS WORK / BLOCKED]
|
||||
```
|
||||
|
||||
## 병렬 실행
|
||||
|
||||
독립적인 검사에 대해서는 에이전트를 병렬로 실행합니다:
|
||||
|
||||
```markdown
|
||||
### Parallel Phase
|
||||
동시에 실행:
|
||||
- code-reviewer (품질)
|
||||
- security-reviewer (보안)
|
||||
- architect (설계)
|
||||
|
||||
### Merge Results
|
||||
출력을 단일 보고서로 통합
|
||||
```
|
||||
|
||||
## 인자
|
||||
|
||||
$ARGUMENTS:
|
||||
@@ -50,10 +157,16 @@ $ARGUMENTS:
|
||||
- `security <description>` - 보안 리뷰 워크플로우
|
||||
- `custom <agents> <description>` - 사용자 정의 에이전트 순서
|
||||
|
||||
## 사용자 정의 워크플로우 예시
|
||||
|
||||
```
|
||||
/orchestrate custom "architect,tdd-guide,code-reviewer" "Redesign caching layer"
|
||||
```
|
||||
|
||||
## 팁
|
||||
|
||||
1. 복잡한 기능에는 **planner부터 시작**
|
||||
2. merge 전에는 **항상 code-reviewer 포함**
|
||||
3. 인증/결제/개인정보에는 **security-reviewer 사용**
|
||||
4. **핸드오프는 간결하게** - 다음 에이전트에 필요한 것에 집중
|
||||
5. 필요하면 에이전트 사이에 **검증 실행**
|
||||
1. 복잡한 기능에는 **planner부터 시작**하세요
|
||||
2. merge 전에는 **항상 code-reviewer를 포함**하세요
|
||||
3. 인증/결제/개인정보 처리에는 **security-reviewer를 사용**하세요
|
||||
4. **핸드오프는 간결하게** 유지하세요 - 다음 에이전트에 필요한 것에 집중
|
||||
5. 필요한 경우 에이전트 사이에 **검증을 실행**하세요
|
||||
|
||||
@@ -6,19 +6,19 @@ description: 요구사항을 재확인하고, 위험을 평가하며, 단계별
|
||||
|
||||
이 커맨드는 **planner** 에이전트를 호출하여 코드를 작성하기 전에 포괄적인 구현 계획을 만듭니다.
|
||||
|
||||
## 이 커맨드가 하는 것
|
||||
## 이 커맨드가 하는 일
|
||||
|
||||
1. **요구사항 재확인** - 무엇을 만들어야 하는지 명확히 함
|
||||
2. **위험 식별** - 잠재적 이슈와 차단 요소 도출
|
||||
3. **단계별 계획 작성** - 구현을 단계로 분해
|
||||
4. **확인 대기** - 진행 전 반드시 사용자 승인을 받음
|
||||
1. **요구사항 재확인** - 무엇을 만들어야 하는지 명확히 합니다
|
||||
2. **위험 식별** - 잠재적 이슈와 차단 요소를 도출합니다
|
||||
3. **단계별 계획 작성** - 구현을 단계별로 분해합니다
|
||||
4. **확인 대기** - 진행하기 전에 반드시 사용자 승인을 받아야 합니다
|
||||
|
||||
## 사용 시점
|
||||
|
||||
`/plan`을 사용해야 할 때:
|
||||
- 새 기능 시작
|
||||
- 중요한 아키텍처 변경
|
||||
- 복잡한 리팩토링 작업
|
||||
- 새 기능을 시작할 때
|
||||
- 중요한 아키텍처 변경을 할 때
|
||||
- 복잡한 리팩토링 작업을 할 때
|
||||
- 여러 파일/컴포넌트에 영향을 미칠 때
|
||||
- 요구사항이 불명확하거나 모호할 때
|
||||
|
||||
@@ -26,25 +26,88 @@ description: 요구사항을 재확인하고, 위험을 평가하며, 단계별
|
||||
|
||||
planner 에이전트가 수행하는 작업:
|
||||
|
||||
1. 요청을 **분석**하고 요구사항을 명확하게 재확인
|
||||
2. 구체적이고 실행 가능한 단계로 **분해**
|
||||
3. 컴포넌트 간 **의존성 식별**
|
||||
4. **위험 평가** 및 잠재적 차단 요소 파악
|
||||
5. **복잡도 추정** (High/Medium/Low)
|
||||
6. 계획을 **제시**하고 명시적 확인을 **대기**
|
||||
1. 요청을 **분석**하고 요구사항을 명확한 용어로 재확인합니다
|
||||
2. 구체적이고 실행 가능한 단계로 **분해**합니다
|
||||
3. 컴포넌트 간 **의존성을 식별**합니다
|
||||
4. **위험을 평가**하고 잠재적 차단 요소를 파악합니다
|
||||
5. **복잡도를 추정**합니다 (High/Medium/Low)
|
||||
6. 계획을 **제시**하고 명시적 확인을 **대기**합니다
|
||||
|
||||
## 사용 예시
|
||||
|
||||
```
|
||||
User: /plan 마켓이 해결될 때 실시간 알림을 추가해야 합니다
|
||||
|
||||
Agent (planner):
|
||||
# 구현 계획: 실시간 마켓 해결 알림
|
||||
|
||||
## 요구사항 재확인
|
||||
- 사용자가 주시 중인 마켓이 해결될 때 알림 전송
|
||||
- 다중 알림 채널 지원 (인앱, 이메일, webhook)
|
||||
- 알림이 안정적으로 전달되도록 보장
|
||||
- 마켓 결과와 사용자의 포지션 결과 포함
|
||||
|
||||
## 구현 단계
|
||||
|
||||
### 1단계: 데이터베이스 스키마
|
||||
- id, user_id, market_id, type, status, created_at 컬럼을 가진 notifications 테이블 추가
|
||||
- 채널 설정을 위한 user_notification_preferences 테이블 추가
|
||||
- 성능을 위해 user_id와 market_id에 인덱스 생성
|
||||
|
||||
### 2단계: 알림 서비스
|
||||
- lib/notifications.ts에 알림 서비스 생성
|
||||
- BullMQ/Redis를 사용한 알림 큐 구현
|
||||
- 전송 실패 시 재시도 로직 추가
|
||||
- 알림 템플릿 생성
|
||||
|
||||
### 3단계: 연동 포인트
|
||||
- 마켓 해결 로직에 연결 (status가 "resolved"로 변경될 때)
|
||||
- 해당 마켓에 포지션을 가진 모든 사용자 조회
|
||||
- 각 사용자에 대한 알림 큐에 추가
|
||||
|
||||
### 4단계: 프론트엔드 컴포넌트
|
||||
- 헤더에 NotificationBell 컴포넌트 생성
|
||||
- NotificationList 모달 추가
|
||||
- Supabase subscriptions를 통한 실시간 업데이트 구현
|
||||
- 알림 설정 페이지 추가
|
||||
|
||||
## 의존성
|
||||
- Redis (큐용)
|
||||
- 이메일 서비스 (SendGrid/Resend)
|
||||
- Supabase 실시간 subscriptions
|
||||
|
||||
## 위험
|
||||
- HIGH: 이메일 전달률 (SPF/DKIM 필요)
|
||||
- MEDIUM: 마켓당 1000명 이상의 사용자 시 성능
|
||||
- MEDIUM: 마켓이 자주 해결될 경우 알림 스팸
|
||||
- LOW: 실시간 subscription 오버헤드
|
||||
|
||||
## 예상 복잡도: MEDIUM
|
||||
- 백엔드: 4-6시간
|
||||
- 프론트엔드: 3-4시간
|
||||
- 테스트: 2-3시간
|
||||
- 합계: 9-13시간
|
||||
|
||||
**확인 대기 중**: 이 계획으로 진행할까요? (yes/no/modify)
|
||||
```
|
||||
|
||||
## 중요 참고 사항
|
||||
|
||||
**핵심**: planner 에이전트는 "yes"나 "proceed" 같은 긍정적 응답으로 명시적으로 확인하기 전까지 코드를 **작성하지 않습니다.**
|
||||
**핵심**: planner 에이전트는 "yes"나 "proceed" 같은 긍정적 응답으로 명시적으로 계획을 확인하기 전까지 코드를 **절대 작성하지 않습니다.**
|
||||
|
||||
변경을 원하면 다음과 같이 응답하세요:
|
||||
- "modify: [변경 사항]"
|
||||
- "different approach: [대안]"
|
||||
- "skip phase 2 and do phase 3 first"
|
||||
|
||||
## 다른 커맨드와의 연계
|
||||
|
||||
계획 수립 후:
|
||||
- `/tdd`를 사용하여 테스트 주도 개발로 구현
|
||||
- `/build-fix`로 build 에러 발생 시 수정
|
||||
- `/code-review`로 완성된 구현 리뷰
|
||||
- 빌드 에러 발생 시 `/build-fix` 사용
|
||||
- 완성된 구현을 `/code-review`로 리뷰
|
||||
|
||||
## 관련 에이전트
|
||||
|
||||
이 커맨드는 `planner` 에이전트를 호출합니다:
|
||||
이 커맨드는 다음 위치의 `planner` 에이전트를 호출합니다:
|
||||
`~/.claude/agents/planner.md`
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Refactor Clean
|
||||
|
||||
사용하지 않는 코드를 안전하게 식별하고 매 단계마다 테스트 검증을 수행합니다.
|
||||
사용하지 않는 코드를 안전하게 식별하고 매 단계마다 테스트 검증을 수행하여 제거합니다.
|
||||
|
||||
## 1단계: 사용하지 않는 코드 감지
|
||||
|
||||
프로젝트 유형에 따라 분석 도구 실행:
|
||||
프로젝트 유형에 따라 분석 도구를 실행합니다:
|
||||
|
||||
| 도구 | 감지 대상 | 커맨드 |
|
||||
|------|----------|--------|
|
||||
@@ -13,30 +13,68 @@
|
||||
| ts-prune | 미사용 TypeScript exports | `npx ts-prune` |
|
||||
| vulture | 미사용 Python 코드 | `vulture src/` |
|
||||
| deadcode | 미사용 Go 코드 | `deadcode ./...` |
|
||||
| cargo-udeps | 미사용 Rust 의존성 | `cargo +nightly udeps` |
|
||||
|
||||
사용 가능한 도구가 없는 경우, Grep을 사용하여 import가 없는 export를 찾습니다:
|
||||
```
|
||||
# export를 찾은 후, 다른 곳에서 import되는지 확인
|
||||
```
|
||||
|
||||
## 2단계: 결과 분류
|
||||
|
||||
안전 등급별 분류:
|
||||
안전 등급별로 결과를 분류합니다:
|
||||
|
||||
| 등급 | 예시 | 조치 |
|
||||
|------|------|------|
|
||||
| **안전** | 미사용 유틸리티, 테스트 헬퍼, 내부 함수 | 확신을 가지고 삭제 |
|
||||
| **주의** | 컴포넌트, API 라우트, 미들웨어 | 동적 임포트나 외부 소비자가 없는지 확인 |
|
||||
| **위험** | 설정 파일, 엔트리 포인트, 타입 정의 | 건드리기 전에 조사 |
|
||||
| **주의** | 컴포넌트, API 라우트, 미들웨어 | 동적 import나 외부 소비자가 없는지 확인 |
|
||||
| **위험** | 설정 파일, 엔트리 포인트, 타입 정의 | 건드리기 전에 조사 필요 |
|
||||
|
||||
## 3단계: 안전한 삭제 루프
|
||||
|
||||
각 안전 항목에 대해:
|
||||
|
||||
1. **전체 테스트 실행** — 기준선 확립 (모두 통과)
|
||||
2. **사용하지 않는 코드 삭제** — Edit 도구로 정밀 삭제
|
||||
3. **테스트 재실행** — 깨진 것이 없는지 확인
|
||||
4. **테스트 실패 시** — 즉시 `git checkout -- <file>`로 되돌리고 건너뜀
|
||||
5. **테스트 통과 시** — 다음 항목으로 이동
|
||||
1. **전체 테스트 스위트 실행** --- 기준선 확립 (모두 통과)
|
||||
2. **사용하지 않는 코드 삭제** --- Edit 도구로 정밀하게 제거
|
||||
3. **테스트 스위트 재실행** --- 깨진 것이 없는지 확인
|
||||
4. **테스트 실패 시** --- 즉시 `git checkout -- <file>`로 되돌리고 해당 항목을 건너뜀
|
||||
5. **테스트 통과 시** --- 다음 항목으로 이동
|
||||
|
||||
## 4단계: 주의 항목 처리
|
||||
|
||||
주의 항목을 삭제하기 전에:
|
||||
- 동적 import 검색: `import()`, `require()`, `__import__`
|
||||
- 문자열 참조 검색: 라우트 이름, 설정 파일의 컴포넌트 이름
|
||||
- 공개 패키지 API에서 export되는지 확인
|
||||
- 외부 소비자가 없는지 확인 (게시된 경우 의존 패키지 확인)
|
||||
|
||||
## 5단계: 중복 통합
|
||||
|
||||
사용하지 않는 코드를 제거한 후 다음을 찾습니다:
|
||||
- 거의 중복된 함수 (80% 이상 유사) --- 하나로 병합
|
||||
- 중복된 타입 정의 --- 통합
|
||||
- 가치를 추가하지 않는 래퍼 함수 --- 인라인 처리
|
||||
- 목적이 없는 re-export --- 간접 참조 제거
|
||||
|
||||
## 6단계: 요약
|
||||
|
||||
결과를 보고합니다:
|
||||
|
||||
```
|
||||
Dead Code Cleanup
|
||||
──────────────────────────────
|
||||
삭제: 미사용 함수 12개
|
||||
미사용 파일 3개
|
||||
미사용 의존성 5개
|
||||
건너뜀: 항목 2개 (테스트 실패)
|
||||
절감: 약 450줄 제거
|
||||
──────────────────────────────
|
||||
모든 테스트 통과 ✅
|
||||
```
|
||||
|
||||
## 규칙
|
||||
|
||||
- **테스트를 먼저 실행하지 않고 절대 삭제하지 않기**
|
||||
- **한 번에 하나씩 삭제** — 원자적 변경으로 롤백 용이
|
||||
- **확실하지 않으면 건너뛰기** — 프로덕션을 깨뜨리는 것보다 사용하지 않는 코드를 유지하는 것이 나음
|
||||
- **정리하면서 리팩토링하지 않기** — 관심사 분리 (먼저 정리, 나중에 리팩토링)
|
||||
- **한 번에 하나씩 삭제** --- 원자적 변경으로 롤백이 쉬움
|
||||
- **확실하지 않으면 건너뛰기** --- 프로덕션을 깨뜨리는 것보다 사용하지 않는 코드를 유지하는 것이 나음
|
||||
- **정리하면서 리팩토링하지 않기** --- 관심사 분리 (먼저 정리, 나중에 리팩토링)
|
||||
|
||||
@@ -30,6 +30,51 @@ node scripts/setup-package-manager.js --list
|
||||
1. **환경 변수**: `CLAUDE_PACKAGE_MANAGER`
|
||||
2. **프로젝트 설정**: `.claude/package-manager.json`
|
||||
3. **package.json**: `packageManager` 필드
|
||||
4. **락 파일**: package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lockb
|
||||
4. **락 파일**: package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lockb의 존재 여부
|
||||
5. **전역 설정**: `~/.claude/package-manager.json`
|
||||
6. **폴백**: 사용 가능한 첫 번째 패키지 매니저 (pnpm > bun > yarn > npm)
|
||||
|
||||
## 설정 파일
|
||||
|
||||
### 전역 설정
|
||||
```json
|
||||
// ~/.claude/package-manager.json
|
||||
{
|
||||
"packageManager": "pnpm"
|
||||
}
|
||||
```
|
||||
|
||||
### 프로젝트 설정
|
||||
```json
|
||||
// .claude/package-manager.json
|
||||
{
|
||||
"packageManager": "bun"
|
||||
}
|
||||
```
|
||||
|
||||
### package.json
|
||||
```json
|
||||
{
|
||||
"packageManager": "pnpm@8.6.0"
|
||||
}
|
||||
```
|
||||
|
||||
## 환경 변수
|
||||
|
||||
`CLAUDE_PACKAGE_MANAGER`를 설정하면 다른 모든 감지 방법을 무시합니다:
|
||||
|
||||
```bash
|
||||
# Windows (PowerShell)
|
||||
$env:CLAUDE_PACKAGE_MANAGER = "pnpm"
|
||||
|
||||
# macOS/Linux
|
||||
export CLAUDE_PACKAGE_MANAGER=pnpm
|
||||
```
|
||||
|
||||
## 감지 실행
|
||||
|
||||
현재 패키지 매니저 감지 결과를 확인하려면 다음을 실행하세요:
|
||||
|
||||
```bash
|
||||
node scripts/setup-package-manager.js --detect
|
||||
```
|
||||
|
||||
@@ -23,6 +23,18 @@ description: 테스트 주도 개발 워크플로우 강제. 인터페이스를
|
||||
- 기존 코드 리팩토링
|
||||
- 핵심 비즈니스 로직 구현
|
||||
|
||||
## 작동 방식
|
||||
|
||||
tdd-guide 에이전트가 수행하는 작업:
|
||||
|
||||
1. 입출력에 대한 **인터페이스 정의**
|
||||
2. (코드가 아직 존재하지 않으므로) **실패하는 테스트 작성**
|
||||
3. 올바른 이유로 실패하는지 **테스트 실행** 및 확인
|
||||
4. 테스트를 통과하도록 **최소한의 구현 작성**
|
||||
5. 통과하는지 **테스트 실행** 및 확인
|
||||
6. 테스트를 통과시키면서 코드 **리팩토링**
|
||||
7. **커버리지 확인** 및 80% 미만이면 테스트 추가
|
||||
|
||||
## TDD 사이클
|
||||
|
||||
```
|
||||
@@ -34,23 +46,281 @@ REFACTOR: 코드 개선, 테스트 계속 통과 유지
|
||||
REPEAT: 다음 기능/시나리오
|
||||
```
|
||||
|
||||
## 모범 사례
|
||||
## 사용 예시
|
||||
|
||||
```
|
||||
User: /tdd 마켓 유동성 점수를 계산하는 함수가 필요합니다
|
||||
|
||||
Agent (tdd-guide):
|
||||
# TDD 세션: 마켓 유동성 점수 계산기
|
||||
|
||||
## 1단계: 인터페이스 정의 (SCAFFOLD)
|
||||
|
||||
```typescript
|
||||
// lib/liquidity.ts
|
||||
export interface MarketData {
|
||||
totalVolume: number
|
||||
bidAskSpread: number
|
||||
activeTraders: number
|
||||
lastTradeTime: Date
|
||||
}
|
||||
|
||||
export function calculateLiquidityScore(market: MarketData): number {
|
||||
// TODO: 구현
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
```
|
||||
|
||||
## 2단계: 실패하는 테스트 작성 (RED)
|
||||
|
||||
```typescript
|
||||
// lib/liquidity.test.ts
|
||||
import { calculateLiquidityScore } from './liquidity'
|
||||
|
||||
describe('calculateLiquidityScore', () => {
|
||||
it('should return high score for liquid market', () => {
|
||||
const market = {
|
||||
totalVolume: 100000,
|
||||
bidAskSpread: 0.01,
|
||||
activeTraders: 500,
|
||||
lastTradeTime: new Date()
|
||||
}
|
||||
|
||||
const score = calculateLiquidityScore(market)
|
||||
|
||||
expect(score).toBeGreaterThan(80)
|
||||
expect(score).toBeLessThanOrEqual(100)
|
||||
})
|
||||
|
||||
it('should return low score for illiquid market', () => {
|
||||
const market = {
|
||||
totalVolume: 100,
|
||||
bidAskSpread: 0.5,
|
||||
activeTraders: 2,
|
||||
lastTradeTime: new Date(Date.now() - 86400000) // 1일 전
|
||||
}
|
||||
|
||||
const score = calculateLiquidityScore(market)
|
||||
|
||||
expect(score).toBeLessThan(30)
|
||||
expect(score).toBeGreaterThanOrEqual(0)
|
||||
})
|
||||
|
||||
it('should handle edge case: zero volume', () => {
|
||||
const market = {
|
||||
totalVolume: 0,
|
||||
bidAskSpread: 0,
|
||||
activeTraders: 0,
|
||||
lastTradeTime: new Date()
|
||||
}
|
||||
|
||||
const score = calculateLiquidityScore(market)
|
||||
|
||||
expect(score).toBe(0)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## 3단계: 테스트 실행 - 실패 확인
|
||||
|
||||
```bash
|
||||
npm test lib/liquidity.test.ts
|
||||
|
||||
FAIL lib/liquidity.test.ts
|
||||
✕ should return high score for liquid market (2 ms)
|
||||
Error: Not implemented
|
||||
|
||||
1 test failed, 0 passed
|
||||
```
|
||||
|
||||
✅ 예상대로 테스트 실패. 구현 준비 완료.
|
||||
|
||||
## 4단계: 최소한의 코드 구현 (GREEN)
|
||||
|
||||
```typescript
|
||||
// lib/liquidity.ts
|
||||
export function calculateLiquidityScore(market: MarketData): number {
|
||||
// 거래량 0인 엣지 케이스 처리
|
||||
if (market.totalVolume === 0) {
|
||||
return 0
|
||||
}
|
||||
|
||||
// 구성 요소별 점수 계산 (0-100 스케일)
|
||||
const volumeScore = Math.min(market.totalVolume / 1000, 100)
|
||||
const spreadScore = Math.max(100 - (market.bidAskSpread * 1000), 0)
|
||||
const traderScore = Math.min(market.activeTraders / 10, 100)
|
||||
|
||||
// 최근 활동 보너스
|
||||
const hoursSinceLastTrade = (Date.now() - market.lastTradeTime.getTime()) / (1000 * 60 * 60)
|
||||
const recencyScore = Math.max(100 - (hoursSinceLastTrade * 10), 0)
|
||||
|
||||
// 가중 평균
|
||||
const score = (
|
||||
volumeScore * 0.4 +
|
||||
spreadScore * 0.3 +
|
||||
traderScore * 0.2 +
|
||||
recencyScore * 0.1
|
||||
)
|
||||
|
||||
return Math.min(Math.max(score, 0), 100) // 0-100으로 클램핑
|
||||
}
|
||||
```
|
||||
|
||||
## 5단계: 테스트 실행 - 통과 확인
|
||||
|
||||
```bash
|
||||
npm test lib/liquidity.test.ts
|
||||
|
||||
PASS lib/liquidity.test.ts
|
||||
✓ should return high score for liquid market (3 ms)
|
||||
✓ should return low score for illiquid market (2 ms)
|
||||
✓ should handle edge case: zero volume (1 ms)
|
||||
|
||||
3 tests passed
|
||||
```
|
||||
|
||||
✅ 모든 테스트 통과!
|
||||
|
||||
## 6단계: 리팩토링 (IMPROVE)
|
||||
|
||||
```typescript
|
||||
// lib/liquidity.ts - 상수와 가독성 향상을 위한 리팩토링
|
||||
const WEIGHTS = {
|
||||
VOLUME: 0.4,
|
||||
SPREAD: 0.3,
|
||||
TRADERS: 0.2,
|
||||
RECENCY: 0.1,
|
||||
} as const
|
||||
|
||||
const SCALE_FACTORS = {
|
||||
VOLUME: 1000,
|
||||
SPREAD: 1000,
|
||||
TRADERS: 10,
|
||||
RECENCY_PENALTY: 10,
|
||||
} as const
|
||||
|
||||
function clamp(value: number, min: number, max: number): number {
|
||||
return Math.min(Math.max(value, min), max)
|
||||
}
|
||||
|
||||
export function calculateLiquidityScore(market: MarketData): number {
|
||||
if (market.totalVolume === 0) return 0
|
||||
|
||||
const volumeScore = Math.min(market.totalVolume / SCALE_FACTORS.VOLUME, 100)
|
||||
const spreadScore = clamp(100 - (market.bidAskSpread * SCALE_FACTORS.SPREAD), 0, 100)
|
||||
const traderScore = Math.min(market.activeTraders / SCALE_FACTORS.TRADERS, 100)
|
||||
|
||||
const hoursSinceLastTrade = (Date.now() - market.lastTradeTime.getTime()) / (1000 * 60 * 60)
|
||||
const recencyScore = clamp(100 - (hoursSinceLastTrade * SCALE_FACTORS.RECENCY_PENALTY), 0, 100)
|
||||
|
||||
const weightedScore =
|
||||
volumeScore * WEIGHTS.VOLUME +
|
||||
spreadScore * WEIGHTS.SPREAD +
|
||||
traderScore * WEIGHTS.TRADERS +
|
||||
recencyScore * WEIGHTS.RECENCY
|
||||
|
||||
return clamp(weightedScore, 0, 100)
|
||||
}
|
||||
```
|
||||
|
||||
## 7단계: 테스트가 여전히 통과하는지 확인
|
||||
|
||||
```bash
|
||||
npm test lib/liquidity.test.ts
|
||||
|
||||
PASS lib/liquidity.test.ts
|
||||
✓ should return high score for liquid market (3 ms)
|
||||
✓ should return low score for illiquid market (2 ms)
|
||||
✓ should handle edge case: zero volume (1 ms)
|
||||
|
||||
3 tests passed
|
||||
```
|
||||
|
||||
✅ 리팩토링 완료, 테스트 여전히 통과!
|
||||
|
||||
## 8단계: 커버리지 확인
|
||||
|
||||
```bash
|
||||
npm test -- --coverage lib/liquidity.test.ts
|
||||
|
||||
File | % Stmts | % Branch | % Funcs | % Lines
|
||||
---------------|---------|----------|---------|--------
|
||||
liquidity.ts | 100 | 100 | 100 | 100
|
||||
|
||||
Coverage: 100% ✅ (목표: 80%)
|
||||
```
|
||||
|
||||
✅ TDD 세션 완료!
|
||||
```
|
||||
|
||||
## TDD 모범 사례
|
||||
|
||||
**해야 할 것:**
|
||||
- 구현 전에 테스트를 먼저 작성
|
||||
- 각 변경 후 테스트 실행 및 실패 확인
|
||||
- 구현 전에 테스트를 실행하여 실패하는지 확인
|
||||
- 테스트를 통과하기 위한 최소한의 코드 작성
|
||||
- 테스트가 통과한 후에만 리팩토링
|
||||
- 엣지 케이스와 에러 시나리오 추가
|
||||
- 80% 이상 커버리지 목표 (핵심 코드는 100%)
|
||||
|
||||
**하지 말아야 할 것:**
|
||||
- 테스트 전에 구현 작성
|
||||
- RED 단계 건너뛰기
|
||||
- 각 변경 후 테스트 실행 건너뛰기
|
||||
- 한 번에 너무 많은 코드 작성
|
||||
- 실패하는 테스트 무시
|
||||
- 구현 세부사항 테스트 (동작을 테스트)
|
||||
- 모든 것을 mock (통합 테스트 선호)
|
||||
|
||||
## 포함할 테스트 유형
|
||||
|
||||
**단위 테스트** (함수 수준):
|
||||
- 정상 경로 시나리오
|
||||
- 엣지 케이스 (빈 값, null, 최대값)
|
||||
- 에러 조건
|
||||
- 경계값
|
||||
|
||||
**통합 테스트** (컴포넌트 수준):
|
||||
- API 엔드포인트
|
||||
- 데이터베이스 작업
|
||||
- 외부 서비스 호출
|
||||
- hooks가 포함된 React 컴포넌트
|
||||
|
||||
**E2E 테스트** (`/e2e` 커맨드 사용):
|
||||
- 핵심 사용자 흐름
|
||||
- 다단계 프로세스
|
||||
- 풀 스택 통합
|
||||
|
||||
## 커버리지 요구사항
|
||||
|
||||
- **80% 최소** - 모든 코드에 대해
|
||||
- **100% 필수** - 다음 항목에 대해:
|
||||
- 금융 계산
|
||||
- 인증 로직
|
||||
- 보안에 중요한 코드
|
||||
- 핵심 비즈니스 로직
|
||||
|
||||
## 중요 사항
|
||||
|
||||
**필수**: 테스트는 반드시 구현 전에 작성해야 합니다. TDD 사이클은 다음과 같습니다:
|
||||
|
||||
1. **RED** - 실패하는 테스트 작성
|
||||
2. **GREEN** - 통과하도록 구현
|
||||
3. **REFACTOR** - 코드 개선
|
||||
|
||||
절대 RED 단계를 건너뛰지 마세요. 절대 테스트 전에 코드를 작성하지 마세요.
|
||||
|
||||
## 다른 커맨드와의 연동
|
||||
|
||||
- `/plan`을 먼저 사용하여 무엇을 만들지 이해
|
||||
- `/tdd`를 사용하여 테스트와 함께 구현
|
||||
- `/build-fix`를 사용하여 빌드 에러 발생 시 수정
|
||||
- `/code-review`를 사용하여 구현 리뷰
|
||||
- `/test-coverage`를 사용하여 커버리지 검증
|
||||
|
||||
## 관련 에이전트
|
||||
|
||||
이 커맨드는 `tdd-guide` 에이전트를 호출합니다:
|
||||
`~/.claude/agents/tdd-guide.md`
|
||||
|
||||
그리고 `tdd-workflow` 스킬을 참조할 수 있습니다:
|
||||
`~/.claude/skills/tdd-workflow/`
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
| `vitest.config.*` | `npx vitest run --coverage` |
|
||||
| `pytest.ini` / `pyproject.toml` pytest | `pytest --cov=src --cov-report=json` |
|
||||
| `Cargo.toml` | `cargo llvm-cov --json` |
|
||||
| `pom.xml` with JaCoCo | `mvn test jacoco:report` |
|
||||
| `go.mod` | `go test -coverprofile=coverage.out ./...` |
|
||||
|
||||
## 2단계: 커버리지 보고서 분석
|
||||
@@ -17,26 +18,52 @@
|
||||
1. 커버리지 커맨드 실행
|
||||
2. 출력 파싱 (JSON 요약 또는 터미널 출력)
|
||||
3. **80% 미만인 파일**을 최저순으로 정렬하여 목록화
|
||||
4. 각 미달 파일에서 미테스트 함수, 누락된 분기 커버리지, 데드 코드 식별
|
||||
4. 각 커버리지 미달 파일에 대해 다음을 식별:
|
||||
- 테스트되지 않은 함수 또는 메서드
|
||||
- 누락된 분기 커버리지 (if/else, switch, 에러 경로)
|
||||
- 분모를 부풀리는 데드 코드
|
||||
|
||||
## 3단계: 누락된 테스트 생성
|
||||
|
||||
우선순위에 따라 테스트 생성:
|
||||
각 커버리지 미달 파일에 대해 다음 우선순위에 따라 테스트를 생성합니다:
|
||||
|
||||
1. **Happy path** — 유효한 입력의 핵심 기능
|
||||
2. **에러 처리** — 잘못된 입력, 누락된 데이터, 네트워크 실패
|
||||
3. **엣지 케이스** — 빈 배열, null/undefined, 경계값 (0, -1, MAX_INT)
|
||||
4. **분기 커버리지** — 각 if/else, switch case, 삼항 연산자
|
||||
|
||||
### 테스트 생성 규칙
|
||||
|
||||
- 소스 파일 옆에 테스트 배치: `foo.ts` → `foo.test.ts` (또는 프로젝트 컨벤션에 따름)
|
||||
- 프로젝트의 기존 테스트 패턴 사용 (import 스타일, assertion 라이브러리, mocking 방식)
|
||||
- 외부 의존성 mock 처리 (데이터베이스, API, 파일 시스템)
|
||||
- 각 테스트는 독립적이어야 함 — 테스트 간 공유 가변 상태 없음
|
||||
- 테스트 이름은 설명적으로: `test_create_user_with_duplicate_email_returns_409`
|
||||
|
||||
## 4단계: 검증
|
||||
|
||||
1. 전체 테스트 실행 — 모든 테스트 통과 확인
|
||||
1. 전체 테스트 스위트 실행 — 모든 테스트가 통과해야 함
|
||||
2. 커버리지 재실행 — 개선 확인
|
||||
3. 여전히 80% 미만이면 나머지 갭에 대해 3단계 반복
|
||||
|
||||
## 5단계: 보고서
|
||||
|
||||
이전/이후 비교를 표시합니다:
|
||||
|
||||
```
|
||||
커버리지 보고서
|
||||
──────────────────────────────
|
||||
파일 이전 이후
|
||||
src/services/auth.ts 45% 88%
|
||||
src/utils/validation.ts 32% 82%
|
||||
──────────────────────────────
|
||||
전체: 67% 84% ✅
|
||||
```
|
||||
|
||||
## 집중 영역
|
||||
|
||||
- 복잡한 분기가 있는 함수 (높은 순환 복잡도)
|
||||
- 에러 핸들러와 catch 블록
|
||||
- 코드베이스 전반에서 사용되는 유틸리티 함수
|
||||
- API 엔드포인트 핸들러 (요청 → 응답 흐름)
|
||||
- 엣지 케이스: null, undefined, 빈 문자열, 빈 배열, 0, 음수
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
## 2단계: 코드맵 생성
|
||||
|
||||
`docs/CODEMAPS/`에 코드맵 생성 또는 업데이트:
|
||||
`docs/CODEMAPS/` (또는 `.reports/codemaps/`)에 코드맵 생성 또는 업데이트:
|
||||
|
||||
| 파일 | 내용 |
|
||||
|------|------|
|
||||
@@ -20,6 +20,49 @@
|
||||
| `data.md` | 데이터베이스 테이블, 관계, 마이그레이션 히스토리 |
|
||||
| `dependencies.md` | 외부 서비스, 서드파티 통합, 공유 라이브러리 |
|
||||
|
||||
### 코드맵 형식
|
||||
|
||||
각 코드맵은 토큰 효율적이어야 합니다 — AI 컨텍스트 소비에 최적화:
|
||||
|
||||
```markdown
|
||||
# Backend 아키텍처
|
||||
|
||||
## 라우트
|
||||
POST /api/users → UserController.create → UserService.create → UserRepo.insert
|
||||
GET /api/users/:id → UserController.get → UserService.findById → UserRepo.findById
|
||||
|
||||
## 주요 파일
|
||||
src/services/user.ts (비즈니스 로직, 120줄)
|
||||
src/repos/user.ts (데이터베이스 접근, 80줄)
|
||||
|
||||
## 의존성
|
||||
- PostgreSQL (주 데이터 저장소)
|
||||
- Redis (세션 캐시, 속도 제한)
|
||||
- Stripe (결제 처리)
|
||||
```
|
||||
|
||||
## 3단계: 변경 감지
|
||||
|
||||
1. 이전 코드맵이 있는 경우 변경 비율 계산
|
||||
2. 변경이 30%를 초과하면 diff를 표시하고 덮어쓰기 전에 사용자 승인 요청
|
||||
3. 변경이 30% 이하이면 기존 파일에 바로 업데이트
|
||||
|
||||
## 4단계: 메타데이터 추가
|
||||
|
||||
각 코드맵에 최신 정보 헤더를 추가합니다:
|
||||
|
||||
```markdown
|
||||
<!-- Generated: 2026-02-11 | Files scanned: 142 | Token estimate: ~800 -->
|
||||
```
|
||||
|
||||
## 5단계: 분석 보고서 저장
|
||||
|
||||
`.reports/codemap-diff.txt`에 요약을 작성합니다:
|
||||
- 마지막 스캔 이후 추가/제거/수정된 파일
|
||||
- 새로 감지된 의존성
|
||||
- 아키텍처 변경 사항 (새 라우트, 새 서비스 등)
|
||||
- 90일 이상 업데이트되지 않은 문서에 대한 오래된 항목 경고
|
||||
|
||||
## 팁
|
||||
|
||||
- **구현 세부사항이 아닌 상위 구조**에 집중
|
||||
|
||||
@@ -16,18 +16,69 @@
|
||||
|
||||
1. `package.json` (또는 `Makefile`, `Cargo.toml`, `pyproject.toml`) 읽기
|
||||
2. 모든 스크립트/커맨드와 설명 추출
|
||||
3. 참조 테이블 생성
|
||||
3. 참조 테이블 생성:
|
||||
|
||||
```markdown
|
||||
| 커맨드 | 설명 |
|
||||
|--------|------|
|
||||
| `npm run dev` | hot reload로 개발 서버 시작 |
|
||||
| `npm run build` | 타입 체크 포함 프로덕션 빌드 |
|
||||
| `npm test` | 커버리지 포함 테스트 스위트 실행 |
|
||||
```
|
||||
|
||||
## 3단계: 환경 변수 문서 생성
|
||||
|
||||
1. `.env.example` 읽기
|
||||
1. `.env.example` (또는 `.env.template`, `.env.sample`) 읽기
|
||||
2. 모든 변수와 용도 추출
|
||||
3. 필수 vs 선택으로 분류
|
||||
4. 예상 형식과 유효 값 문서화
|
||||
|
||||
```markdown
|
||||
| 변수 | 필수 | 설명 | 예시 |
|
||||
|------|------|------|------|
|
||||
| `DATABASE_URL` | 예 | PostgreSQL 연결 문자열 | `postgres://user:pass@host:5432/db` |
|
||||
| `LOG_LEVEL` | 아니오 | 로깅 상세도 (기본값: info) | `debug`, `info`, `warn`, `error` |
|
||||
```
|
||||
|
||||
## 4단계: 기여 가이드 업데이트
|
||||
|
||||
`docs/CONTRIBUTING.md`를 생성 또는 업데이트합니다:
|
||||
- 개발 환경 설정 (사전 요구 사항, 설치 단계)
|
||||
- 사용 가능한 스크립트와 용도
|
||||
- 테스트 절차 (실행 방법, 새 테스트 작성 방법)
|
||||
- 코드 스타일 적용 (linter, formatter, pre-commit hook)
|
||||
- PR 제출 체크리스트
|
||||
|
||||
## 5단계: 운영 매뉴얼 업데이트
|
||||
|
||||
`docs/RUNBOOK.md`를 생성 또는 업데이트합니다:
|
||||
- 배포 절차 (단계별)
|
||||
- 헬스 체크 엔드포인트 및 모니터링
|
||||
- 일반적인 이슈와 해결 방법
|
||||
- 롤백 절차
|
||||
- 알림 및 에스컬레이션 경로
|
||||
|
||||
## 6단계: 오래된 항목 점검
|
||||
|
||||
1. 90일 이상 수정되지 않은 문서 파일 찾기
|
||||
2. 최근 소스 코드 변경 사항과 교차 참조
|
||||
3. 잠재적으로 오래된 문서를 수동 검토 대상으로 표시
|
||||
|
||||
## 7단계: 요약 표시
|
||||
|
||||
```
|
||||
문서 업데이트
|
||||
──────────────────────────────
|
||||
업데이트: docs/CONTRIBUTING.md (스크립트 테이블)
|
||||
업데이트: docs/ENV.md (새 변수 3개)
|
||||
플래그: docs/DEPLOY.md (142일 경과)
|
||||
건너뜀: docs/API.md (변경 사항 없음)
|
||||
──────────────────────────────
|
||||
```
|
||||
|
||||
## 규칙
|
||||
|
||||
- **단일 원본**: 항상 코드에서 생성, 생성된 섹션을 수동으로 편집하지 않기
|
||||
- **단일 원본**: 항상 코드에서 생성하고, 생성된 섹션을 수동으로 편집하지 않기
|
||||
- **수동 섹션 보존**: 생성된 섹션만 업데이트; 수기 작성 내용은 그대로 유지
|
||||
- **생성된 콘텐츠 표시**: 생성된 섹션 주변에 `<!-- AUTO-GENERATED -->` 마커 사용
|
||||
- **요청 없이 문서 생성하지 않기**: 커맨드가 명시적으로 요청한 경우에만 새 문서 파일 생성
|
||||
|
||||
Reference in New Issue
Block a user