From 3e9c207c2553d3021a0b5ad7e8f4013c70251142 Mon Sep 17 00:00:00 2001 From: hahmee Date: Tue, 10 Mar 2026 13:59:43 +0900 Subject: [PATCH] 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. --- docs/ko-KR/commands/e2e.md | 278 +++++++++++++++++++++++++ docs/ko-KR/commands/eval.md | 90 +++++++- docs/ko-KR/commands/go-build.md | 145 +++++++++++++ docs/ko-KR/commands/go-review.md | 107 +++++++++- docs/ko-KR/commands/go-test.md | 220 +++++++++++++++++++ docs/ko-KR/commands/learn.md | 25 ++- docs/ko-KR/commands/orchestrate.md | 123 ++++++++++- docs/ko-KR/commands/plan.md | 99 +++++++-- docs/ko-KR/commands/refactor-clean.md | 64 ++++-- docs/ko-KR/commands/setup-pm.md | 47 ++++- docs/ko-KR/commands/tdd.md | 276 +++++++++++++++++++++++- docs/ko-KR/commands/test-coverage.md | 33 ++- docs/ko-KR/commands/update-codemaps.md | 45 +++- docs/ko-KR/commands/update-docs.md | 57 ++++- 14 files changed, 1548 insertions(+), 61 deletions(-) diff --git a/docs/ko-KR/commands/e2e.md b/docs/ko-KR/commands/e2e.md index 74a36bd9..f82c70d0 100644 --- a/docs/ko-KR/commands/e2e.md +++ b/docs/ko-KR/commands/e2e.md @@ -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 +``` diff --git a/docs/ko-KR/commands/eval.md b/docs/ko-KR/commands/eval.md index 49f15df2..e07ea256 100644 --- a/docs/ko-KR/commands/eval.md +++ b/docs/ko-KR/commands/eval.md @@ -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 ` - 평가 실행 및 확인 - `report ` - 전체 보고서 생성 - `list` - 모든 평가 표시 -- `clean` - 오래된 평가 로그 제거 (최근 10회 유지) +- `clean` - 오래된 평가 로그 제거 (최근 10회 실행 유지) diff --git a/docs/ko-KR/commands/go-build.md b/docs/ko-KR/commands/go-build.md index 824240f8..3933af10 100644 --- a/docs/ko-KR/commands/go-build.md +++ b/docs/ko-KR/commands/go-build.md @@ -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/` diff --git a/docs/ko-KR/commands/go-review.md b/docs/ko-KR/commands/go-review.md index 395f9f56..61b272e7 100644 --- a/docs/ko-KR/commands/go-review.md +++ b/docs/ko-KR/commands/go-review.md @@ -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/` diff --git a/docs/ko-KR/commands/go-test.md b/docs/ko-KR/commands/go-test.md index a30a1648..3e9e83c6 100644 --- a/docs/ko-KR/commands/go-test.md +++ b/docs/ko-KR/commands/go-test.md @@ -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/` diff --git a/docs/ko-KR/commands/learn.md b/docs/ko-KR/commands/learn.md index 3ded15a0..d4e81a40 100644 --- a/docs/ko-KR/commands/learn.md +++ b/docs/ko-KR/commands/learn.md @@ -21,7 +21,7 @@ - 효과적인 도구 조합 - 진단 패턴 -3. **해결 방법** +3. **우회 방법** - 라이브러리 특이 사항 - API 제한 사항 - 버전별 수정 사항 @@ -31,6 +31,29 @@ - 내려진 아키텍처 결정 - 통합 패턴 +## 출력 형식 + +`~/.claude/skills/learned/[pattern-name].md`에 스킬 파일을 생성합니다: + +```markdown +# [설명적인 패턴 이름] + +**추출일:** [날짜] +**컨텍스트:** [이 패턴이 적용되는 상황에 대한 간략한 설명] + +## 문제 +[이 패턴이 해결하는 문제 - 구체적으로 작성] + +## 해결 방법 +[패턴/기법/우회 방법] + +## 예시 +[해당하는 경우 코드 예시] + +## 사용 시점 +[트리거 조건 - 이 스킬이 활성화되어야 하는 상황] +``` + ## 프로세스 1. 세션에서 추출 가능한 패턴 검토 diff --git a/docs/ko-KR/commands/orchestrate.md b/docs/ko-KR/commands/orchestrate.md index 37c73151..a9845ea3 100644 --- a/docs/ko-KR/commands/orchestrate.md +++ b/docs/ko-KR/commands/orchestrate.md @@ -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 ` - 보안 리뷰 워크플로우 - `custom ` - 사용자 정의 에이전트 순서 +## 사용자 정의 워크플로우 예시 + +``` +/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. 필요한 경우 에이전트 사이에 **검증을 실행**하세요 diff --git a/docs/ko-KR/commands/plan.md b/docs/ko-KR/commands/plan.md index 512e0d93..3e0985f5 100644 --- a/docs/ko-KR/commands/plan.md +++ b/docs/ko-KR/commands/plan.md @@ -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` diff --git a/docs/ko-KR/commands/refactor-clean.md b/docs/ko-KR/commands/refactor-clean.md index 6923c8f7..0ab81fe7 100644 --- a/docs/ko-KR/commands/refactor-clean.md +++ b/docs/ko-KR/commands/refactor-clean.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 -- `로 되돌리고 건너뜀 -5. **테스트 통과 시** — 다음 항목으로 이동 +1. **전체 테스트 스위트 실행** --- 기준선 확립 (모두 통과) +2. **사용하지 않는 코드 삭제** --- Edit 도구로 정밀하게 제거 +3. **테스트 스위트 재실행** --- 깨진 것이 없는지 확인 +4. **테스트 실패 시** --- 즉시 `git checkout -- `로 되돌리고 해당 항목을 건너뜀 +5. **테스트 통과 시** --- 다음 항목으로 이동 + +## 4단계: 주의 항목 처리 + +주의 항목을 삭제하기 전에: +- 동적 import 검색: `import()`, `require()`, `__import__` +- 문자열 참조 검색: 라우트 이름, 설정 파일의 컴포넌트 이름 +- 공개 패키지 API에서 export되는지 확인 +- 외부 소비자가 없는지 확인 (게시된 경우 의존 패키지 확인) + +## 5단계: 중복 통합 + +사용하지 않는 코드를 제거한 후 다음을 찾습니다: +- 거의 중복된 함수 (80% 이상 유사) --- 하나로 병합 +- 중복된 타입 정의 --- 통합 +- 가치를 추가하지 않는 래퍼 함수 --- 인라인 처리 +- 목적이 없는 re-export --- 간접 참조 제거 + +## 6단계: 요약 + +결과를 보고합니다: + +``` +Dead Code Cleanup +────────────────────────────── +삭제: 미사용 함수 12개 + 미사용 파일 3개 + 미사용 의존성 5개 +건너뜀: 항목 2개 (테스트 실패) +절감: 약 450줄 제거 +────────────────────────────── +모든 테스트 통과 ✅ +``` ## 규칙 - **테스트를 먼저 실행하지 않고 절대 삭제하지 않기** -- **한 번에 하나씩 삭제** — 원자적 변경으로 롤백 용이 -- **확실하지 않으면 건너뛰기** — 프로덕션을 깨뜨리는 것보다 사용하지 않는 코드를 유지하는 것이 나음 -- **정리하면서 리팩토링하지 않기** — 관심사 분리 (먼저 정리, 나중에 리팩토링) +- **한 번에 하나씩 삭제** --- 원자적 변경으로 롤백이 쉬움 +- **확실하지 않으면 건너뛰기** --- 프로덕션을 깨뜨리는 것보다 사용하지 않는 코드를 유지하는 것이 나음 +- **정리하면서 리팩토링하지 않기** --- 관심사 분리 (먼저 정리, 나중에 리팩토링) diff --git a/docs/ko-KR/commands/setup-pm.md b/docs/ko-KR/commands/setup-pm.md index 5e9d54b1..43b01ace 100644 --- a/docs/ko-KR/commands/setup-pm.md +++ b/docs/ko-KR/commands/setup-pm.md @@ -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 +``` diff --git a/docs/ko-KR/commands/tdd.md b/docs/ko-KR/commands/tdd.md index 197bd8bf..eba7a754 100644 --- a/docs/ko-KR/commands/tdd.md +++ b/docs/ko-KR/commands/tdd.md @@ -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/` diff --git a/docs/ko-KR/commands/test-coverage.md b/docs/ko-KR/commands/test-coverage.md index ec507e46..ecde8a18 100644 --- a/docs/ko-KR/commands/test-coverage.md +++ b/docs/ko-KR/commands/test-coverage.md @@ -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, 음수 diff --git a/docs/ko-KR/commands/update-codemaps.md b/docs/ko-KR/commands/update-codemaps.md index 4f71bd8f..a2bf3138 100644 --- a/docs/ko-KR/commands/update-codemaps.md +++ b/docs/ko-KR/commands/update-codemaps.md @@ -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 + +``` + +## 5단계: 분석 보고서 저장 + +`.reports/codemap-diff.txt`에 요약을 작성합니다: +- 마지막 스캔 이후 추가/제거/수정된 파일 +- 새로 감지된 의존성 +- 아키텍처 변경 사항 (새 라우트, 새 서비스 등) +- 90일 이상 업데이트되지 않은 문서에 대한 오래된 항목 경고 + ## 팁 - **구현 세부사항이 아닌 상위 구조**에 집중 diff --git a/docs/ko-KR/commands/update-docs.md b/docs/ko-KR/commands/update-docs.md index 49b3062f..3d353ce2 100644 --- a/docs/ko-KR/commands/update-docs.md +++ b/docs/ko-KR/commands/update-docs.md @@ -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 (변경 사항 없음) +────────────────────────────── +``` + ## 규칙 -- **단일 원본**: 항상 코드에서 생성, 생성된 섹션을 수동으로 편집하지 않기 +- **단일 원본**: 항상 코드에서 생성하고, 생성된 섹션을 수동으로 편집하지 않기 - **수동 섹션 보존**: 생성된 섹션만 업데이트; 수기 작성 내용은 그대로 유지 - **생성된 콘텐츠 표시**: 생성된 섹션 주변에 `` 마커 사용 - **요청 없이 문서 생성하지 않기**: 커맨드가 명시적으로 요청한 경우에만 새 문서 파일 생성