Skip to content

[feat] LLM 호출을 통한 댓글 생성 - #13

Merged
kite707 merged 19 commits into
devfrom
feat/4-llm-comment
Jul 21, 2026
Merged

[feat] LLM 호출을 통한 댓글 생성#13
kite707 merged 19 commits into
devfrom
feat/4-llm-comment

Conversation

@kite707

@kite707 kite707 commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

🔗 연관 이슈

📌 개요

일기(사용자 메시지)에 LLM으로 캐릭터 댓글 + 티키타카를 생성하는 기능을 구현했습니다. 핵심은 멱등성(같은 메시지에 대해 한 번만 생성)과 동시성 제어(DB 조건부 UPDATE)이고, 캐릭터·소재·개수는 LLM이 아니라 서버가 정해서 프롬프트에 지시합니다.

🔧 주요 변경사항

스키마 (V3 마이그레이션)

  • messagesroot_message_id(캐릭터 댓글·티키타카가 속한 원본 일기 참조) · comment_status(NONE/PENDING/DONE/FAILED) · comment_status_updated_at 컬럼 추가 (root_message_id에 인덱스 추가)
  • repliesToMessageId는 진짜 "답장"(티키타카 캐릭터 간 답장)에만 쓰고, rootMessageId는 "이 일기에 달린 피드 전체" 조회 전용으로 역할을 분리

멱등성 · 동시성 제어

  • MessageRepository.updateCommentStatusNONE/FAILED 상태일 때만 원자적으로 PENDING으로 선점하는 조건부 UPDATE(CAS). 영향 행 수(0/1)로 선점 성공 여부 판단
  • 선점 성공 시에만 LLM 호출(호출+검증을 하나로 묶어 최대 2회 시도) → 실패하면 FAILED, 성공하면 저장과 함께 DONE
  • PendingCommentCleanupScheduler — 배포 중단·크래시로 남은 고아 PENDING을 주기적으로 NONE으로 되돌려 재선점 가능하게 함(conversation.comment-pending-timeout, 기본 3분)
  • MessageRepository@Modifying 메서드에 @Transactional 명시 — 서비스 트랜잭션 밖(스케줄러 등)에서 직접 호출해도 안전하게 동작

저장 매핑

  • CommentPersistenceService — 1라운드(comments)를 먼저 저장해 character_id → messageId 맵을 만들고, 2라운드(tikitaka)의 reply_to를 실제 repliesToMessageId로 치환해 저장
  • 저장 로직을 CommentGenerationService와 별도 빈으로 분리 — 같은 클래스 안에서 호출(self-invocation)하면 @Transactional 프록시가 안 걸리는 문제를 피하기 위함

LLM 연동 (llm 패키지)

  • CommentGenerator 인터페이스 + GeminiCommentGenerator(google-genai 공식 SDK 구현) — 프로바이더 교체 가능하게 인터페이스 뒤에 숨김
  • CharacterSelector — 캐릭터(3-6개)·tikitaka 개수(3-4개)를 서버가 랜덤 선택. LLM한테 무작위를 맡기면 통계적으로 편향된다는 근거로 서버 선택 채택
  • EongttungTopicSelector — 엉뚱이 소재도 같은 이유로 서버가 미리 골라 프롬프트에 주입
  • PromptCharacterId — 프롬프트가 쓰는 캐릭터 id(gippeum 등) ↔ 내부 EmotionType 매핑 계층
  • CommentFeedValidatorresponseSchema가 못 잡는 의미 규칙(캐릭터 구성 정확히 일치, 자문자답 금지, tikitaka 개수 일치) 검증
  • 프롬프트는 캐릭터 보이스카드를 systemInstruction으로 고정 전송(프리픽스 캐싱 대상), 일기·과거 요약·이번 생성 조건만 매 호출 가변으로 붙임

API

  • POST /api/conversations/messages/comments — 요청 {messageId}, 응답 {status: GENERATING|DONE|FAILED, comments?} (항상 HTTP 200, 재요청이 곧 결과 조회를 겸함)
  • ErrorCode 추가: MESSAGE_NOT_FOUND(404) · INVALID_COMMENT_TARGET(400)

공통

  • google-genai가 내부적으로 Jackson 2를 쓰는데, 그 jar에 딸려온 서비스 등록 파일 때문에 Hibernate의 Jackson 자동 감지가 ServiceConfigurationError로 깨지는 문제 발견 → jackson-module-kotlin(Jackson 2)을 runtimeOnly로 추가해 해결

🌐 API·DB 영향

  • API 변경: 신규 엔드포인트 1종 추가 (기존 API 변경 없음)
  • DB 마이그레이션: V3__comment_generation.sqlmessages에 컬럼 3개 추가 + 인덱스 1개 (기존 데이터 영향 없음)
  • 하위 호환: 호환

💬 리뷰 포인트

1. 컬럼 방식(A′) vs 선점 테이블(A) 선택 — 동시성 안전성은 동일해서 테이블을 새로 안 만드는 쪽(comment_status 컬럼)을 선택했습니다. 대가로 캐릭터 댓글 행에는 의미 없는 comment_status/comment_status_updated_at 컬럼이 생깁니다. 스키마 취향 문제라 다른 의견 있으면 말씀해주세요.

2. 과거 요약(pastSummary)은 지금 항상 빈 값입니다 — 프론트에서 추후 내려줄 예정이라 CommentGenerator 인터페이스에 파라미터만 열어두고 실제 연동은 안 했습니다(CommentGenerationService에 TODO 남겨둠). 프론트 스펙 나오면 이어서 반영하겠습니다.

3. 엉뚱이 소재 목록(EongttungTopicSelector)은 자리채우기용 placeholder입니다 — 10개만 임시로 넣어뒀는데, 실제 서비스에 쓸 소재는 팀에서 다시 정하는 게 좋을 것 같습니다.

4. 지수 백오프·서킷브레이커는 이번 스코프에서 뺐습니다 — DoD가 "실패 시 1회 재시도"라 그보다 큰 작업(라이브러리 도입 등)이라고 판단했습니다. 필요하면 다음 이슈로 분리하겠습니다.

5. "사용자가 캐릭터 댓글에 답글 달면 봇이 답하는" 기능은 이번 범위에 없습니다 — 트리거 시점도 다르고 상태 관리도 독립적이라 별도 이슈로 분리하는 게 맞다고 판단했습니다.

Summary by CodeRabbit

  • 신규 기능
    • 일기 메시지에 대한 AI 캐릭터 댓글과 티키타카를 비동기로 생성하고, 생성 상태/결과를 함께 제공합니다(POST /messages/comments).
    • 메시지 응답에 원본 일기 연결 정보(rootMessageId)를 추가했습니다.
  • 개선
    • 댓글 생성 대상/대화 접근 권한/생성 구성을 서버에서 검증하고, 실패 시 재시도합니다.
    • 생성 중(PENDING) 항목은 설정값 기준으로 자동 만료 처리됩니다.
    • 날짜별 채팅방 조회 기준이 KST 자정~자정으로 조정됐습니다.
  • 설정/문서
    • 댓글 대기 만료 시간 및 Gemini(AI) 설정을 추가/정리했습니다.
  • Tests
    • 댓글 생성/검증/상태 전이 및 파싱 관련 테스트를 보강했습니다.

@kite707 kite707 self-assigned this Jul 20, 2026
@kite707
kite707 requested a review from theminjunchoi July 20, 2026 16:05
@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown

Test Results

155 tests  +23   155 ✅ +23   56s ⏱️ -3s
 30 suites + 3     0 💤 ± 0 
 30 files   + 3     0 ❌ ± 0 

Results for commit de80e94. ± Comparison against base commit 895feff.

This pull request removes 3 and adds 26 tests. Note that renamed tests count towards both.
com.nexters.gamss.conversation.config.ConversationPropertiesTest ‑ yml의 06시00분 문자열이 LocalTime으로 바인딩된다()
com.nexters.gamss.conversation.controller.ConversationControllerIntegrationTest ‑ 새벽 6시 이전에 만든 채팅방은 전날 목록으로 조회된다()
com.nexters.gamss.conversation.service.ConversationServiceTest ‑ 날짜 조회는 dayStartTime(06시, KST) 경계로 범위를 계산한다()
com.nexters.gamss.conversation.controller.ConversationControllerIntegrationTest ‑ 자정 정각에 만든 채팅방은 그 날짜로 조회되고, 자정 직전은 전날로 조회된다()
com.nexters.gamss.conversation.repository.MessageRepositoryTransactionTest ‑ FAILED 상태는 재선점된다()
com.nexters.gamss.conversation.repository.MessageRepositoryTransactionTest ‑ 서비스 트랜잭션 없이 직접 호출해도 선점이 원자적으로 동작한다()
com.nexters.gamss.conversation.repository.MessageRepositoryTransactionTest ‑ 서비스 트랜잭션 없이 직접 호출해도 오래된 PENDING이 리셋된다()
com.nexters.gamss.conversation.service.CommentGenerationServiceTest ‑ BusinessException이 발생하면 FAILED로 전이한 뒤 그대로 다시 던진다()
com.nexters.gamss.conversation.service.CommentGenerationServiceTest ‑ LLM 호출이 재시도까지 실패하면 FAILED로 마킹하고 FAILED를 반환한다()
com.nexters.gamss.conversation.service.CommentGenerationServiceTest ‑ 남의 채팅방 메시지면 CONVERSATION_ACCESS_DENIED()
com.nexters.gamss.conversation.service.CommentGenerationServiceTest ‑ 선점에 성공하면 LLM을 호출하고 저장한 뒤 DONE을 반환한다()
com.nexters.gamss.conversation.service.CommentGenerationServiceTest ‑ 선점에 실패하고 현재 상태가 DONE이면 기존 댓글을 조회해서 DONE을 반환한다()
com.nexters.gamss.conversation.service.CommentGenerationServiceTest ‑ 선점에 실패하고 현재 상태가 PENDING이면 GENERATING을 반환한다()
…

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown

Test Coverage

Overall Project 80.41% -15.28% 🍏
Files changed 60.18% 🍏

File Coverage
ErrorCode.kt 100% 🍏
SchedulingConfig.kt 100% 🍏
CommentStatus.kt 100% 🍏
ConversationService.kt 100% 🍏
CommentGenerationResult.kt 100% 🍏
CommentGenerator.kt 100% 🍏
CommentFeed.kt 100% 🍏
CommentFeedValidator.kt 98.59% -1.41% 🍏
MessageResponse.kt 97.44% 🍏
CommentFeedJsonParser.kt 95.42% -4.58% 🍏
Conversation.kt 95.24% 🍏
Message.kt 94.85% -2.21% 🍏
CommentGenerationService.kt 92.33% -7.67% 🍏
EongttungTopicSelector.kt 90% -10% 🍏
PromptCharacterId.kt 88.07% -11.93% 🍏
PendingCommentCleanupScheduler.kt 83.33% -16.67% 🍏
MessageRepository.kt 66.67% -33.33% 🍏
GeminiProperties.kt 60% -40% 🍏
ConversationController.kt 52.67% -47.33% 🍏
CharacterSelector.kt 43.24% -56.76% 🍏
ConversationProperties.kt 40.91% -27.27% 🍏
CommentGenerationResponse.kt 40.32% -59.68% 🍏
PromptProvider.kt 7.09% -92.91% 🍏
CommentPersistenceService.kt 6.98% -93.02% 🍏
GeminiCommentGenerator.kt 5.59% -94.41% 🍏
GenerateCommentsRequest.kt 0% 🍏

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Gemini SDK 기반 댓글·티키타카 생성 기능이 추가되었습니다. 메시지별 생성 상태와 루트 메시지 연결을 저장하고, 재시도·검증·영속화·비동기 API·오래된 PENDING 정리 및 KST 자정 기준 대화 조회를 구성합니다.

Changes

댓글 생성 기능

Layer / File(s) Summary
메시지 상태와 영속성 계약
src/main/kotlin/.../conversation/domain/*, src/main/kotlin/.../conversation/repository/MessageRepository.kt, src/main/resources/db/migration/*
rootMessageId, 댓글 상태 및 상태 시각을 추가하고, 댓글 조회·상태 전이·오래된 PENDING 초기화 쿼리와 DB 컬럼·인덱스를 구현했습니다.
Gemini 생성 계약과 응답 검증
src/main/kotlin/.../llm/*, build.gradle.kts
Gemini 호출, 프롬프트·JSON 스키마, JSON 변환, 캐릭터·소재 선택 및 피드 의미 검증을 추가했습니다.
댓글 생성 오케스트레이션과 저장
src/main/kotlin/.../conversation/service/*, src/main/kotlin/.../global/exception/ErrorCode.kt
PENDING 선점, 최대 2회 재시도, 권한·대상 검증, 댓글 저장 및 DONE·FAILED 전이를 연결했습니다.
API·설정·정리와 날짜 조회
src/main/kotlin/.../conversation/controller/*, src/main/kotlin/.../global/config/*, src/main/resources/*
댓글 생성 POST API, Gemini·timeout 설정, 스케줄링 활성화 및 KST 자정~자정 대화 조회를 추가했습니다.
검증 및 문서 지원
src/test/*, README.md
저장소·서비스·JSON·피드 검증 테스트와 날짜 경계 테스트를 추가하고 README 형식을 수정했습니다.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ConversationController
  participant CommentGenerationService
  participant GeminiCommentGenerator
  participant CommentPersistenceService
  participant MessageRepository
  Client->>ConversationController: 댓글 생성 요청
  ConversationController->>CommentGenerationService: generateComments(memberId, messageId)
  CommentGenerationService->>MessageRepository: PENDING 선점
  CommentGenerationService->>GeminiCommentGenerator: 피드 생성 및 파싱
  GeminiCommentGenerator-->>CommentGenerationService: CommentGenerationOutput
  CommentGenerationService->>CommentPersistenceService: 검증된 피드 저장
  CommentPersistenceService->>MessageRepository: DONE 상태 갱신
  CommentGenerationService-->>ConversationController: 생성 결과
  ConversationController-->>Client: 상태 및 댓글 응답
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning 댓글 생성과 무관한 ConversationService 날짜 경계 변경과 README 서식 수정이 함께 포함되어 범위를 벗어납니다. 비관련 날짜 경계/문서 변경은 별도 PR로 분리하고, 댓글 생성 기능에 필요한 코드만 남겨 주세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 14.52% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 LLM 댓글 생성이라는 핵심 변경을 정확히 요약해 관련성이 높습니다.
Description check ✅ Passed 필수 섹션과 주요 영향(API·DB, 리뷰 포인트)이 모두 들어 있어 템플릿 요구를 충족합니다.
Linked Issues check ✅ Passed 랜덤 감정 댓글, 티키타카 생성, 1회 재시도와 응답 피드 구성이 구현되어 이슈 목표를 충족합니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/4-llm-comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/kotlin/com/nexters/gamss/conversation/repository/MessageRepository.kt`:
- Around line 42-50: Update the resetStalePending query to bind CommentStatus
values through named parameters instead of hard-coding the enum’s fully
qualified class name. Add the required enum parameters to resetStalePending and
bind them in both status comparisons, then update its callers to pass PENDING
and NONE.

In
`@src/main/kotlin/com/nexters/gamss/conversation/service/CommentGenerationService.kt`:
- Around line 55-68: Update generateComments to catch unexpected Exception
instances in addition to CommentGenerationFailedException, log the original
error with messageId context, and transition the message to CommentStatus.FAILED
using the existing pending-status guard before returning a failed
CommentGenerationResult. Preserve the current successful flow and avoid
duplicating the failure-state handling.

In
`@src/main/kotlin/com/nexters/gamss/conversation/service/PendingCommentCleanupScheduler.kt`:
- Around line 14-28: Update PendingCommentCleanupScheduler.resetStalePending to
use a distributed lock around the scheduled cleanup, such as the project’s
ShedLock configuration and annotation, so only one server instance executes the
reset at a time; preserve the existing schedule, threshold calculation,
repository update, and warning log behavior.

In `@src/main/kotlin/com/nexters/gamss/llm/CharacterSelector.kt`:
- Around line 25-30: CharacterSelector의 캐릭터 수 제한이 기획된 감정 캐릭터 3~4개 기준과 불일치합니다. 기존
요구사항을 따르는 경우 companion object의 MAX_COUNT를 4로 조정해 TIKITAKA_MAX와 일치시키고, 변경된 기획에 따른
설정이라면 현재 값 6을 유지하되 그 근거를 설명하는 주석을 추가하세요.

In `@src/main/kotlin/com/nexters/gamss/llm/GeminiCommentGenerator.kt`:
- Around line 57-59: In GeminiCommentGenerator, replace the generic Exception
catches at src/main/kotlin/com/nexters/gamss/llm/GeminiCommentGenerator.kt:57-59
and :46-48 with the specific Jackson parsing exception for the JSON parsing
block and the SDK’s specific base exception for the LLM call block, preserving
the existing CommentGenerationFailedException wrapping behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 501af741-2c87-41b3-81b5-f5eea35ce3d8

📥 Commits

Reviewing files that changed from the base of the PR and between 895feff and 7483e04.

📒 Files selected for processing (30)
  • build.gradle.kts
  • src/main/kotlin/com/nexters/gamss/conversation/config/ConversationProperties.kt
  • src/main/kotlin/com/nexters/gamss/conversation/controller/ConversationController.kt
  • src/main/kotlin/com/nexters/gamss/conversation/controller/dto/CommentGenerationResponse.kt
  • src/main/kotlin/com/nexters/gamss/conversation/controller/dto/GenerateCommentsRequest.kt
  • src/main/kotlin/com/nexters/gamss/conversation/controller/dto/MessageResponse.kt
  • src/main/kotlin/com/nexters/gamss/conversation/domain/CommentStatus.kt
  • src/main/kotlin/com/nexters/gamss/conversation/domain/Conversation.kt
  • src/main/kotlin/com/nexters/gamss/conversation/domain/Message.kt
  • src/main/kotlin/com/nexters/gamss/conversation/repository/MessageRepository.kt
  • src/main/kotlin/com/nexters/gamss/conversation/service/CommentGenerationResult.kt
  • src/main/kotlin/com/nexters/gamss/conversation/service/CommentGenerationService.kt
  • src/main/kotlin/com/nexters/gamss/conversation/service/CommentPersistenceService.kt
  • src/main/kotlin/com/nexters/gamss/conversation/service/PendingCommentCleanupScheduler.kt
  • src/main/kotlin/com/nexters/gamss/global/config/SchedulingConfig.kt
  • src/main/kotlin/com/nexters/gamss/global/exception/ErrorCode.kt
  • src/main/kotlin/com/nexters/gamss/llm/CharacterSelector.kt
  • src/main/kotlin/com/nexters/gamss/llm/CommentFeed.kt
  • src/main/kotlin/com/nexters/gamss/llm/CommentFeedValidator.kt
  • src/main/kotlin/com/nexters/gamss/llm/CommentGenerator.kt
  • src/main/kotlin/com/nexters/gamss/llm/EongttungTopicSelector.kt
  • src/main/kotlin/com/nexters/gamss/llm/GeminiCommentGenerator.kt
  • src/main/kotlin/com/nexters/gamss/llm/GeminiProperties.kt
  • src/main/kotlin/com/nexters/gamss/llm/PromptCharacterId.kt
  • src/main/resources/application.yml
  • src/main/resources/db/migration/V3__comment_generation.sql
  • src/test/kotlin/com/nexters/gamss/conversation/repository/MessageRepositoryTransactionTest.kt
  • src/test/kotlin/com/nexters/gamss/conversation/service/CommentGenerationServiceTest.kt
  • src/test/kotlin/com/nexters/gamss/llm/CommentFeedValidatorTest.kt
  • src/test/resources/application.yml

Comment thread src/main/kotlin/com/nexters/gamss/llm/CharacterSelector.kt
Comment thread src/main/kotlin/com/nexters/gamss/llm/GeminiCommentGenerator.kt Outdated

@theminjunchoi theminjunchoi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넘 잘 작성하셨네요!
그래도 아래 3개만 확인해주세요! 수고하셨습니다 🤟🏻

Comment thread src/main/kotlin/com/nexters/gamss/llm/CommentFeedValidator.kt
Comment thread src/main/kotlin/com/nexters/gamss/llm/GeminiCommentGenerator.kt Outdated
Comment thread src/main/kotlin/com/nexters/gamss/llm/GeminiCommentGenerator.kt Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 69-70: README.md의 브랜치·커밋·PR·이슈 컨벤션 링크 목록에서 `이슈 컨벤션` 전체 텍스트가 하나의
Markdown 링크로 렌더링되도록 링크 대상과 표시 범위를 수정하고, 줄바꿈으로 `컨벤션`이 일반 텍스트로 분리되지 않게 정리하세요.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: bbfcea6f-92fb-4892-83c5-afd4beb6c062

📥 Commits

Reviewing files that changed from the base of the PR and between 7483e04 and e850eee.

📒 Files selected for processing (4)
  • README.md
  • src/main/kotlin/com/nexters/gamss/conversation/service/CommentGenerationService.kt
  • src/main/kotlin/com/nexters/gamss/llm/CommentFeedValidator.kt
  • src/test/kotlin/com/nexters/gamss/llm/CommentFeedValidatorTest.kt

Comment thread README.md Outdated
kite707 added 2 commits July 21, 2026 12:36
client.models.generateContent가 반환하는 final 타입이라 모킹이 불가능해, text -> CommentFeed 변환 로직, (parseFeed)을 client 호출과 분리해독립적으로 테스트 가능하게 만들었다.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/kotlin/com/nexters/gamss/llm/GeminiCommentGenerator.kt (1)

44-46: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

포괄적인 Exception 캐치 개선

두 파일 모두 최상위 예외인 Exception을 잡아 처리하고 있어, NullPointerException 등 의도치 않은 런타임 오류까지 은폐하게 되어 원인 추적을 어렵게 만드는 공통된 한계가 있습니다.

  • src/main/kotlin/com/nexters/gamss/llm/GeminiCommentGenerator.kt#L44-L46: SDK 내부 오류를 나타내는 구체적인 예외 클래스로 변경하세요.
  • src/main/kotlin/com/nexters/gamss/llm/CommentFeedJsonParser.kt#L20-L22: tools.jackson.core.JacksonException 등 파싱 관련 구체적인 예외로 변경하세요.

대안 및 장단점

  • 장점: 예상 가능한 장애와 코드 결함을 명확히 구분하여 문제의 조기 발견과 디버깅을 돕습니다.
  • 단점: 사용 중인 라이브러리의 예외 계층 구조를 명시적으로 파악하고 지정해야 합니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/kotlin/com/nexters/gamss/llm/GeminiCommentGenerator.kt` around lines
44 - 46, Replace the broad Exception catch in GeminiCommentGenerator with the
specific SDK exception type representing expected Gemini/LLM failures, while
preserving CommentGenerationFailedException wrapping. In CommentFeedJsonParser,
replace its broad Exception catch with the concrete Jackson parsing exception
type, such as tools.jackson.core.JacksonException, and preserve the existing
parser-specific failure handling; apply these changes at both listed sites.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/main/kotlin/com/nexters/gamss/llm/GeminiCommentGenerator.kt`:
- Around line 44-46: Replace the broad Exception catch in GeminiCommentGenerator
with the specific SDK exception type representing expected Gemini/LLM failures,
while preserving CommentGenerationFailedException wrapping. In
CommentFeedJsonParser, replace its broad Exception catch with the concrete
Jackson parsing exception type, such as tools.jackson.core.JacksonException, and
preserve the existing parser-specific failure handling; apply these changes at
both listed sites.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: bcc478ef-ef9c-49a4-918e-5fab0e861fb4

📥 Commits

Reviewing files that changed from the base of the PR and between e850eee and 0f41a9c.

📒 Files selected for processing (5)
  • src/main/kotlin/com/nexters/gamss/llm/CommentFeedJsonParser.kt
  • src/main/kotlin/com/nexters/gamss/llm/GeminiCommentGenerator.kt
  • src/main/kotlin/com/nexters/gamss/llm/PromptCharacterId.kt
  • src/main/kotlin/com/nexters/gamss/llm/PromptProvider.kt
  • src/test/kotlin/com/nexters/gamss/llm/CommentFeedJsonParserTest.kt

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/kotlin/com/nexters/gamss/conversation/service/CommentGenerationService.kt`:
- Around line 59-76: Update the exception logging in the catch block of
CommentGenerationService using a when-based type distinction: log
BusinessException without error-level reporting, retain warning logging for
CommentGenerationFailedException, and use error logging only for unexpected
exceptions. Preserve the existing FAILED status update and rethrow behavior for
BusinessException.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4280adba-effe-4c02-8580-50c27f1793b7

📥 Commits

Reviewing files that changed from the base of the PR and between 0f41a9c and de80e94.

📒 Files selected for processing (17)
  • README.md
  • src/main/kotlin/com/nexters/gamss/conversation/config/ConversationProperties.kt
  • src/main/kotlin/com/nexters/gamss/conversation/controller/ConversationController.kt
  • src/main/kotlin/com/nexters/gamss/conversation/controller/dto/CommentGenerationResponse.kt
  • src/main/kotlin/com/nexters/gamss/conversation/repository/MessageRepository.kt
  • src/main/kotlin/com/nexters/gamss/conversation/service/CommentGenerationResult.kt
  • src/main/kotlin/com/nexters/gamss/conversation/service/CommentGenerationService.kt
  • src/main/kotlin/com/nexters/gamss/conversation/service/ConversationService.kt
  • src/main/kotlin/com/nexters/gamss/llm/CommentFeedJsonParser.kt
  • src/main/kotlin/com/nexters/gamss/llm/CommentGenerator.kt
  • src/main/kotlin/com/nexters/gamss/llm/GeminiCommentGenerator.kt
  • src/main/resources/application.yml
  • src/test/kotlin/com/nexters/gamss/conversation/config/ConversationPropertiesTest.kt
  • src/test/kotlin/com/nexters/gamss/conversation/controller/ConversationControllerIntegrationTest.kt
  • src/test/kotlin/com/nexters/gamss/conversation/service/CommentGenerationServiceTest.kt
  • src/test/kotlin/com/nexters/gamss/conversation/service/ConversationServiceTest.kt
  • src/test/resources/application.yml
💤 Files with no reviewable changes (3)
  • src/test/kotlin/com/nexters/gamss/conversation/config/ConversationPropertiesTest.kt
  • src/main/resources/application.yml
  • src/test/resources/application.yml

@kite707
kite707 merged commit 08ab61c into dev Jul 21, 2026
5 checks passed
@kite707
kite707 deleted the feat/4-llm-comment branch July 21, 2026 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] LLM 호출을 통한 댓글 생성

2 participants