ワンクリックで
feature-implementer
// 테크스펙 문서를 기반으로 새로운 피처를 구현하는 전체 파이프라인을 자동화합니다. 구현 → 테스트 → 수정 → 커밋까지 자동으로 수행합니다.
// 테크스펙 문서를 기반으로 새로운 피처를 구현하는 전체 파이프라인을 자동화합니다. 구현 → 테스트 → 수정 → 커밋까지 자동으로 수행합니다.
iOS Repository 패턴 정의. Protocol + Impl 구조 및 API enum + RequestType 확장 패턴으로 네트워크 레이어를 구현합니다. async/await와 Result 타입을 사용하며, 다른 iOS 프로젝트에서도 재사용 가능합니다.
iOS MVVM 패턴의 ViewModel 구조 정의. Input/Output/Route/Config/Dependency/State 패턴으로 ViewModel을 생성합니다. Combine 기반으로 작동하며, 다른 iOS 프로젝트에서도 재사용 가능합니다.
iOS ViewModel 유저 플로우 기반 테스트 코드 자동 생성. Given-When-Then 패턴으로 Input/Output 검증 테스트를 생성합니다. XCTest와 Combine을 사용하며, 다른 iOS 프로젝트에서도 재사용 가능합니다.
| name | feature-implementer |
| description | 테크스펙 문서를 기반으로 새로운 피처를 구현하는 전체 파이프라인을 자동화합니다. 구현 → 테스트 → 수정 → 커밋까지 자동으로 수행합니다. |
테크스펙 문서를 기반으로 새로운 피처를 자동으로 구현하고 테스트합니다.
다음 형태 중 하나로 테크스펙을 제공할 수 있습니다:
/path/to/TH-XXX.md)/path/to/spec.txt)인자 없이 호출 시 대화형으로 테크스펙을 입력받습니다.
입력받은 테크스펙 확인:
피그마 URL이 제공된 경우 연결 확인:
gh auth status
GitHub 인증 확인:
gh pr list --limit 1
저장소 권한 확인:
제공된 테크스펙에서 다음 정보 추출:
정보가 부족한 경우 AskUserQuestion으로 추가 정보 요청
피그마 URL이 제공된 경우:
get_design_context 도구로 디자인 정보 가져오기노션 테크스펙에서 언급된 기존 피처나 유사 기능이 있다면:
# 예: "기여자 목록 화면과 유사하게 구현"
사용자에게 플랜 모드 진입 승인 요청
Task tool로 Explore agent 실행하여 유사 패턴 탐색:
유사 ViewModel 찾기
유사 Repository 찾기
SDU 모듈 사용 여부 확인
UI 패턴 확인
참고 파일 읽기:
구현해야 할 파일 목록 작성:
Model 추가 (있다면)
Modules/Core/Model/Sources/Domain/Response/API 추가
Modules/Core/Network/Sources/API/{Domain}Api.swiftRepository 추가
Modules/Core/Network/Sources/Repository/{Domain}Repository.swiftViewModel 생성
Modules/Feature/{Feature}/Targets/{Feature}/Sources/Domains/{Screen}/ViewController 생성
Modules/Feature/{Feature}/Targets/{Feature}/Sources/Domains/{Screen}/테스트 코드 생성 (Phase 2 추가)
App/Targets/three-dollar-in-my-pocketTests/ViewModelTests/플랜 파일에 다음 내용을 체계적으로 작성:
# Implementation Plan: {피처 이름}
## Feature Overview
### 테크스펙
- 티켓 번호: {JIRA 티켓 번호} (있는 경우)
- 피처명: {이름}
- 요구사항: {요약}
### 피그마 디자인 (if applicable)
- URL: {피그마 URL}
- 화면 구성: {요약}
## Technical Specification
### API Endpoints
- **GET** `/api/v1/{path}`: {설명}
- Request: {구조}
- Response: {구조}
### Data Models
- `{Model이름}Response`: {설명}
- 필드 1: {타입} - {설명}
- 필드 2: {타입} - {설명}
### UI Components
- {컴포넌트 1}: {설명}
- {컴포넌트 2}: {설명}
## Implementation Plan
### 1. Model 추가
**파일**: `Modules/Core/Model/Sources/Domain/Response/{Model이름}Response.swift`
```swift
public struct {Model이름}Response: Decodable {
public let field1: String
public let field2: Int
}
파일: Modules/Core/Network/Sources/API/{Domain}Api.swift
// API enum에 추가
case fetch{Feature}(input: Fetch{Feature}Input)
// RequestType 확장
var param: Encodable? {
case .fetch{Feature}(let input):
return input
}
var method: RequestMethod {
case .fetch{Feature}:
return .get
}
var header: HTTPHeaderType {
case .fetch{Feature}:
return .json
}
var path: String {
case .fetch{Feature}(let input):
return "/api/v1/{path}/\(input.id)"
}
파일: Modules/Core/Network/Sources/Repository/{Domain}Repository.swift
// Protocol에 추가
func fetch{Feature}(input: Fetch{Feature}Input) async -> Result<{Model}Response, Error>
// Impl에 추가
public func fetch{Feature}(input: Fetch{Feature}Input) async -> Result<{Model}Response, Error> {
let request = {Domain}Api.fetch{Feature}(input: input)
return await NetworkManager.shared.request(requestType: request)
}
파일: Modules/Feature/{Feature}/Targets/{Feature}/Sources/Domains/{Screen}/{Screen}ViewModel.swift
구조:
참고: ios-viewmodel-pattern skill
파일: Modules/Feature/{Feature}/Targets/{Feature}/Sources/Domains/{Screen}/{Screen}ViewController.swift
구조:
참고: CLAUDE.md의 ViewController 패턴
파일: App/Targets/three-dollar-in-my-pocketTests/ViewModelTests/{Screen}ViewModelTests.swift
테스트 케이스:
참고: ios-viewmodel-test-generator skill
서버에서 UI 데이터를 제공하는 경우:
참고: CLAUDE.md의 SDU 모듈 섹션
난이도: {낮음/중간/높음} - {이유}
#### ExitPlanMode 호출 ⚠️
**사용자에게 계획 승인 요청**
- 승인되면 구현 시작
- 거부되면 플랜 수정 또는 종료
---
### Step 4: 워크트리 설정 (자동 승인)
#### 브랜치 이름 결정
노션 테크스펙에서 JIRA 티켓 번호 추출 (예: TH-XXX) 또는 피처 이름 사용:
- JIRA 티켓이 있는 경우: `feature/TH-XXX-{간단한설명}`
- 없는 경우: `feature/{피처명}`
#### 워크트리 생성
```bash
# 저장소 루트 확인
git rev-parse --show-toplevel
# 워크트리 생성 (develop 브랜치 기반)
git worktree add -b feature/{브랜치명} ../worktree-{브랜치명} develop
# 워크트리로 이동
cd ../worktree-{브랜치명}
워크트리 디렉토리 경로: {저장소루트}/../worktree-{브랜치명}
이후 모든 작업은 워크트리 디렉토리에서 진행하므로 원본 저장소는 영향받지 않습니다.
플랜에 따라 구현 순서대로 todo 생성:
1. [pending] {Model이름}Response.swift 생성
2. [pending] {Domain}Api.swift에 API 추가
3. [pending] {Domain}Repository.swift에 메서드 추가
4. [pending] {Screen}ViewModel.swift 생성
5. [pending] {Screen}ViewController.swift 생성
6. [pending] {Screen}ViewModelTests.swift 생성
각 작업 시작 시 in_progress로 변경, 완료 시 completed로 변경
위치: Modules/Core/Model/Sources/Domain/Response/{Model이름}Response.swift
규칙:
참고: 기존 Response 파일들
위치: Modules/Core/Network/Sources/API/{Domain}Api.swift
규칙:
참고: ios-repository-pattern skill
위치: Modules/Core/Network/Sources/Repository/{Domain}Repository.swift
규칙:
참고: ios-repository-pattern skill
위치: Modules/Feature/{Feature}/Targets/{Feature}/Sources/Domains/{Screen}/{Screen}ViewModel.swift
규칙:
참고: ios-viewmodel-pattern skill
필수 import:
import Foundation
import Combine
import Common
import Log
import Model
import Networking
템플릿 활용:
위치: Modules/Feature/{Feature}/Targets/{Feature}/Sources/Domains/{Screen}/{Screen}ViewController.swift
규칙:
필수 import:
import UIKit
import Combine
import Common
import DesignSystem
import Model
import SnapKit
참고: CLAUDE.md의 ViewController 패턴, ContributorsViewController
UI 컴포넌트 생성 패턴:
private let label: UILabel = {
let label = UILabel()
label.text = "텍스트"
label.font = Fonts.semiBold.font(size: 16)
label.textColor = Colors.gray100
return label
}()
SDU 사용 시:
private let sduView = SDUCollectionView()
private lazy var dataSource = SDUDataSource(collectionView: sduView.collectionView)
// Layout 설정
sduView.setLayout(createLayout())
// 데이터 바인딩
viewModel.output.items
.receive(on: DispatchQueue.main)
.sink { [weak self] items in
self?.dataSource.reload(items)
}
.store(in: &cancellables)
위치: App/Targets/three-dollar-in-my-pocketTests/ViewModelTests/{Screen}ViewModelTests.swift
규칙:
참고: ios-viewmodel-test-generator skill
필수 import:
import XCTest
import Combine
@testable import three_dollar_in_my_pocket
템플릿 활용:
기본 테스트 케이스:
test_사용자가로드버튼을탭하면_데이터가로드된다() - 기본 데이터 로드test_네트워크에러시_에러메시지가전달된다() - 에러 처리test_닫기버튼탭시_dismiss라우팅이발생한다() - 화면 전환추가 테스트 케이스 (필요시):
테스트 파일 하단에 Mock 클래스 생성:
// MARK: - Mock Repository
final class Mock{Domain}Repository: {Domain}Repository {
var fetch{Feature}Result: Result<{Model}Response, Error>?
var lastRequestInput: Fetch{Feature}Input?
func fetch{Feature}(input: Fetch{Feature}Input) async -> Result<{Model}Response, Error> {
lastRequestInput = input
guard let result = fetch{Feature}Result else {
return .failure(NSError(domain: "Mock", code: -1))
}
return result
}
// 다른 메서드들은 기본 구현 제공
// ...
}
// MARK: - Mock LogManager
final class MockLogManager: LogManagerProtocol {
func sendPageView(screen: ScreenName, type: AnyClass) { }
func sendEvent(_ event: LogEvent) { }
}
Skill tool로 code-cleanup 호출하여 수정한 파일들의:
# code-cleanup이 실행하는 명령어들
swiftlint --fix
swiftlint lint
수정된 파일만 정리하고, 다른 파일은 건드리지 않습니다.
워크트리 디렉토리에서 실행:
make project
프로젝트 생성이 완료될 때까지 대기합니다.
xcodebuild build \
-workspace 3dollar-in-my-pocket.xcworkspace \
-scheme three-dollar-in-my-pocket-debug \
-configuration Debug \
-destination 'platform=iOS Simulator,name=iPhone 15 Pro'
빌드 결과 확인:
빌드 성공 후:
xcodebuild test \
-workspace 3dollar-in-my-pocket.xcworkspace \
-scheme three-dollar-in-my-pocket-debug \
-destination 'platform=iOS Simulator,name=iPhone 15 Pro'
테스트 결과 확인:
swiftlint lint
SwiftLint 결과 확인:
빌드 실패, 테스트 실패, SwiftLint 오류 발생 시 자동으로 수정을 시도합니다.
최대 5회 시도: 5회 이내에 해결되지 않으면 사용자에게 수동 개입 요청
에러 분석:
xcodebuild build ... 2>&1 | grep -A 5 "error:"
에러 메시지에서 다음 정보 추출:
일반적인 컴파일 에러 패턴:
Import 누락
Cannot find type 'XXX' in scope → import 추가타입 불일치
Cannot convert value of type 'X' to expected type 'Y' → 타입 캐스팅 수정메서드 미정의
Value of type 'X' has no member 'Y' → 메서드명 확인접근 제어자 문제
'X' is inaccessible due to 'internal' protection level → public 추가자동 수정:
테스트 실패 분석:
xcodebuild test ... 2>&1 | grep -A 10 "Test Case.*failed"
실패한 테스트에서 다음 정보 추출:
일반적인 테스트 실패 패턴:
Mock 데이터 불일치
비동기 처리 누락
await Task.yield() 누락 → 추가구독 누락
Mock Repository 메서드 미구현
자동 수정:
SwiftLint 오류 분석:
swiftlint lint 2>&1 | grep -E "(error|warning):"
자동 수정 가능한 오류:
swiftlint --fix
수동 수정이 필요한 오류:
line_length (라인 길이 초과)
function_body_length (메서드 길이 초과)
type_body_length (타입 길이 초과)
identifier_name (네이밍 규칙 위반)
자동 수정:
수정 시도 1 → 빌드/테스트/SwiftLint
↓ 실패
수정 시도 2 → 빌드/테스트/SwiftLint
↓ 실패
수정 시도 3 → 빌드/테스트/SwiftLint
↓ 실패
수정 시도 4 → 빌드/테스트/SwiftLint
↓ 실패
수정 시도 5 → 빌드/테스트/SwiftLint
↓ 실패
❌ 수동 개입 요청 (사용자에게 에러 내용 전달)
성공 시: Step 10 (커밋) 진행
구현 흐름에 따라 논리적으로 분리:
Model 추가 (있다면)
git add Modules/Core/Model/Sources/Domain/Response/{Model이름}Response.swift
git commit -m "{티켓번호} : {Model이름}Response 모델 추가
- {필드 설명}
- {필드 설명}
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
API 정의
git add Modules/Core/Network/Sources/API/{Domain}Api.swift
git commit -m "{티켓번호} : {Domain}Api에 fetch{Feature} API 추가
- GET /api/v1/{path}
- {설명}
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
Repository 구현
git add Modules/Core/Network/Sources/Repository/{Domain}Repository.swift
git commit -m "{티켓번호} : {Domain}Repository에 fetch{Feature} 메서드 추가
- Protocol 시그니처 추가
- Impl 구현 추가
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
ViewModel 생성
git add Modules/Feature/{Feature}/Targets/{Feature}/Sources/Domains/{Screen}/{Screen}ViewModel.swift
git commit -m "{티켓번호} : {Screen}ViewModel 생성
- Input/Output/Route/Config/Dependency/State 구조
- {주요 로직 설명}
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
테스트 코드 생성
git add App/Targets/three-dollar-in-my-pocketTests/ViewModelTests/{Screen}ViewModelTests.swift
git commit -m "{티켓번호} : {Screen}ViewModelTests 생성
- Given-When-Then 패턴 테스트
- Mock Repository 구현
- {테스트 케이스 개수}개 테스트 케이스
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
ViewController 생성
git add Modules/Feature/{Feature}/Targets/{Feature}/Sources/Domains/{Screen}/{Screen}ViewController.swift
git commit -m "{티켓번호} : {Screen}ViewController 생성
- BaseViewController 상속
- SnapKit 레이아웃
- ViewModel 바인딩
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
git commit -m "$(cat <<'EOF'
{티켓번호} : {한 줄 요약}
- 상세 설명 1
- 상세 설명 2
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
EOF
)"
모든 커밋 완료 후 한번에 push:
git push -u origin feature/{브랜치명}
중요: PR 생성은 사용자가 직접 수행합니다.
이유:
cd {원본저장소경로}
# 워크트리 제거
git worktree remove ../worktree-{브랜치명}
# 디렉토리가 남아있다면 강제 제거
git worktree remove --force ../worktree-{브랜치명} 2>/dev/null || true
rm -rf ../worktree-{브랜치명} 2>/dev/null || true
✅ {피처 이름} 구현 완료!
📋 생성된 파일: {개수}개
- {Model파일} (있다면)
- {API파일} (업데이트)
- {Repository파일} (업데이트)
- {ViewModel파일}
- {ViewController파일}
- {Tests파일}
🧪 테스트: {개수}개 테스트 케이스 통과
- {테스트 케이스 1}
- {테스트 케이스 2}
- {테스트 케이스 3}
🔧 커밋: {개수}개 (논리적 흐름으로 분리)
- {커밋1 요약}
- {커밋2 요약}
- ...
🚀 브랜치: feature/{브랜치명}
→ Push 완료: origin/feature/{브랜치명}
📌 다음 단계:
1. PR 생성 (수동):
gh pr create --base develop --title "{티켓번호} : {PR 제목}" --body "{PR 본문}"
2. PR 본문 예시:
## 구현 내용
{피처 설명}
## 주요 변경사항
- {변경사항 1}
- {변경사항 2}
## 테스트
- {테스트 항목 1}
- {테스트 항목 2}
🤖 Generated with [Claude Code](https://claude.com/claude-code)
3. PR 리뷰 요청
4. 테스트 진행
5. 머지 후 배포
✅ code-cleanup 실행 완료 ✅ 빌드 성공 (three-dollar-in-my-pocket-debug) ✅ 테스트 통과 (모든 ViewModel 테스트) ✅ SwiftLint 검증 통과 ✅ Git 커밋 완료 (4-6개 커밋) ✅ Push 완료 ✅ 워크트리 정리 완료
다음 작업들은 사용자 확인 없이 자동으로 진행됩니다:
다음 단계에서만 사용자 승인이 필요합니다:
참고: PR 생성은 자동화하지 않고 사용자가 직접 수행합니다.
/feature-implementer /path/to/TH-XXX-spec.md
/feature-implementer /path/to/spec.md https://figma.com/design/...
/feature-implementer
→ 사용자에게 테크스펙 텍스트 또는 파일 경로 입력 요청 → (선택) 피그마 디자인 URL 입력 요청 (선택사항)
ContributorsViewModel.swift: ViewModel 예시ContributorsViewController.swift: ViewController 예시StoreRepository.swift: Repository 예시StoreApi.swift: API 예시