Ai::IdeaAnalyzerService — Claude API + JSON 파싱 + 에러 처리 + 테스트

ID: d534cd31-8292-4245-81b4-2dd86ef8394f

높음 리뷰

## 목표
PRD Section 13.1 기반 Ai::IdeaAnalyzerService 구현. ruby-anthropic gem으로 Claude API 호출. raw_idea → 프로젝트 필드 업데이트.

## 현재 상태
- Project 모델: raw_idea, one_line_definition, core_features(jsonb), target_customer, revenue_model, competitor_analysis(jsonb) 필드 존재
- User 모델: nineways_strength_type, dev_level, onboarding_goal 필드 존재
- ruby-anthropic gem: Gemfile에 포함 여부 확인 필요 (없으면 추가)
- app/services/ 디렉토리 없으면 생성

## PRD 코드 (Section 13.1)
```ruby
class Ai::IdeaAnalyzerService
def initialize(project:, user:)
@project = project
@user = user
@client = Anthropic::Client.new(api_key: ENV["ANTHROPIC_API_KEY"])
end

def call
response = @client.messages(
model: "claude-sonnet-4-6",
max_tokens: 2000,
system: system_prompt,
messages: [{ role: "user", content: user_prompt }]
)
parse_and_save(response.content.first.text)
end

private

def system_prompt
<<~PROMPT
당신은 VALUEIT의 서비스 기획 전문가입니다.
비개발자도 Claude Code로 만들 수 있는 수준의
MVP 서비스를 기획합니다.
반드시 JSON만 응답하세요. 마크다운 코드블록 없이.
언어: 한국어
PROMPT
end

def user_prompt
<<~PROMPT
사용자 정보:
- 9WAY 강점: #{@user.nineways_strength_type || "미연동"}
- 개발 경험: #{@user.dev_level}
- 목표: #{@user.onboarding_goal}

아이디어: #{@project.raw_idea}

JSON 형식으로 분석:
{
"one_line_definition": "서비스 한 줄 정의 (20자 이내)",
"core_features": ["기능1", "기능2", "기능3", "기능4", "기능5"],
"target_customer": "타겟 고객 구체적 설명",
"revenue_model": "추천 수익 모델과 이유",
"competitor_analysis": {
"competitors": ["경쟁사1", "경쟁사2"],
"differentiation": "차별화 포인트"
},
"viability_score": 7,
"viability_reason": "실현 가능성 평가 이유"
}
PROMPT
end

def parse_and_save(content)
data = JSON.parse(content.strip)
@project.update!(
one_line_definition: data["one_line_definition"],
core_features: data["core_features"],
target_customer: data["target_customer"],
revenue_model: data["revenue_model"],
competitor_analysis: data["competitor_analysis"]
)
rescue JSON::ParserError => e
raise "AI 응답 파싱 실패: #{e.message}"
end
end
```

## 구현 사항

### 1. app/services/ai/idea_analyzer_service.rb
- PRD 코드 그대로 구현
- Sentry가 없으면 Sentry.capture_exception 제거하고 Rails.logger.error 사용
- API 키 미설정 시 적절한 에러 메시지

### 2. 에러 처리
- JSON::ParserError: "AI 응답 파싱 실패" 에러 raise
- Anthropic::Error (API 에러): 적절한 에러 메시지
- ENV["ANTHROPIC_API_KEY"] 미설정: 서비스 초기화 시 에러
- content가 JSON 코드블록으로 감싸진 경우 (```json ... ```) 처리

### 3. 테스트 (API mock)
- WebMock 또는 stub으로 Anthropic API 호출 mock
- 성공 케이스: 프로젝트 필드 업데이트 확인
- JSON 파싱 실패: 에러 raise 확인
- API 키 미설정: 에러 확인
- 잘못된 JSON 구조: 에러 처리

### ⚠️ 주의
- app/services/ai/ 디렉토리 생성
- developer-1이 동시에 Admin::LessonsController 작업 중 — services/ 범위만 수정
- Project 모델, User 모델 건드리지 않기
- ruby-anthropic gem 확인 (Gemfile에 없으면 추가 + bundle install)

### 완료 기준
- 서비스 호출 시 프로젝트 필드 업데이트
- JSON 파싱 실패 에러 핸들링
- API 키 미설정 시 적절한 에러
- 서비스 테스트 통과 (API mock)
- bin/rails test 전체 통과

첨부 이미지

이미지 추가 (Ctrl+V로 붙여넣기 또는 클릭)

JPEG, PNG, GIF, WebP / 최대 10MB

담당자: developer-2
생성일: 2026년 03월 26일 08:47

활동 로그

  • D
    developer-2 상태 변경: 할 일 → 리뷰

    2026년 03월 26일 08:51:51