Skip to content

[FEAT] 레이더 차트 전체 답변 평균 계산 및 DB 피드백 파싱 적용 - #18

Merged
dl-tpdnjs merged 3 commits into
mainfrom
feature/#14-report-api
Jun 6, 2026
Merged

dl-tpdnjs merged 3 commits into
mainfrom
feature/#14-report-api

Conversation

@dl-tpdnjs

@dl-tpdnjs dl-tpdnjs commented Jun 6, 2026 •

Copy link
Copy Markdown
Contributor

✨ 관련된 이슈

🙌 작업 내용

  • generateReport AI 재호출 제거 → DB feedback 파싱으로 대체
  • 전체 답변 피드백 평균 계산 메서드 추가 (averageFeedback)
  • 레이더 차트 점수 정확도 향상
  • 로컬 테스트 통과 확인 (radarScore 반환 정상)

📸 스크린샷 (선택)

🤔 리뷰 요구사항(선택)

Summary by CodeRabbit

  • 버그 수정

    • 레이더 점수를 첫 번째 답변이 아닌 모든 피드백의 평균 기준으로 변경해 평가 정확도 향상
    • 손상되거나 점수 없는(역직렬화 실패/점수 누락) 피드백 항목을 제외해 리포트 일관성 및 안정성 개선
  • 리팩토링

    • 리포트 마크다운 섹션 추출 흐름을 정리해 출력 순서와 가독성 향상

@coderabbitai

coderabbitai Bot commented Jun 6, 2026 •

Copy link
Copy Markdown

Wondering what really moved? Review this PR in Change Stack to inspect semantic changes, definitions, and references.

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 4601167b-2142-4374-89f8-6f20fc3580c1

📥 Commits

Reviewing files that changed from the base of the PR and between d324e49 and f1dab7f.

📒 Files selected for processing (1)
  • src/main/java/com/example/trouble_log/domain/interview/service/InterviewService.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/com/example/trouble_log/domain/interview/service/InterviewService.java

📝 Walkthrough

Walkthrough

InterviewService의 generateReport가 DB에 저장된 모든 답변의 feedback JSON을 파싱해 유효 피드백을 평균화하고, 그 평균을 기반으로 레이더 점수를 계산하도록 변경되었습니다. 로깅(@Slf4j)과 평균화 헬퍼가 추가되었고, 섹션 추출 호출들이 재정렬되었습니다.

Changes

레이더 차트 평균 피드백 적용

레이어 / 파일(들) 요약
로깅 인프라 추가
src/main/java/com/example/trouble_log/domain/interview/service/InterviewService.java
lombok.extern.slf4j.Slf4j import와 @Slf4j 애너테이션을 추가하여 클래스에서 로깅 사용을 준비합니다.
컨텍스트/조회 블록 정리
src/main/java/com/example/trouble_log/domain/interview/service/InterviewService.java
generateReport의 세션/사전 컨텍스트 조회 및 질문 목록 조회 구간을 블록별로 재구성해 가독성을 개선합니다.
피드백 파싱 및 레이더 점수 계산
src/main/java/com/example/trouble_log/domain/interview/service/InterviewService.java
InterviewAnswer.feedback JSON을 역직렬화해 AnswerFeedbackResult 리스트를 구성합니다. JSON 파싱 실패 또는 scores가 null인 항목은 경고 로그 후 제외하고, evaluateCode 결과와 함께 전체 피드백 평균을 사용해 radarScore를 계산합니다(평균이 없으면 생성하지 않음).
리포트 섹션 추출 재배치
src/main/java/com/example/trouble_log/domain/interview/service/InterviewService.java
Background, Problem, Root Cause, Resolution, Result 섹션을 추출하는 extractSection 호출 순서를 섹션 흐름에 맞게 재배치했습니다(추출 내용은 동일).
평균 피드백 계산 헬퍼 메서드
src/main/java/com/example/trouble_log/domain/interview/service/InterviewService.java
averageFeedback(List<AnswerFeedbackResult>)를 추가해 각 점수 항목을 평균(반올림)으로 계산하고 AnswerFeedbackResult를 구성합니다. 유효 피드백이 없으면 null을 반환합니다.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

시 (詩)

🐰 DB의 작은 JSON을 읽어,
평균을 곱하고 점수를 세네.
로그를 남기고 섹션을 줄지어,
모든 답변의 목소리를 모아,
레이더는 더 넓게 빛나리 ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 레이더 차트 평균 계산 및 DB 피드백 파싱을 명확히 설명하며 주요 변경사항을 잘 요약하고 있습니다.
Linked Issues check ✅ Passed 코드 변경이 이슈 #16의 모든 요구사항을 충족합니다: DB 피드백 파싱 적용, averageFeedback 메서드 추가, AI 재호출 제거로 비용 절감 구현.
Out of Scope Changes check ✅ Passed 모든 변경사항이 이슈 #16의 범위 내 진행되었으며 관련 없는 변경은 발견되지 않습니다.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 feature/#14-report-api

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

@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/java/com/example/trouble_log/domain/interview/service/InterviewService.java`:
- Around line 140-155: The current stream in InterviewService that builds
feedbackList deserializes AnswerFeedbackResult but still includes entries with
null scores, causing NPE later; update the mapping/filtering so after
objectMapper.readValue returns an AnswerFeedbackResult you also check that its
getScores() != null (and optionally that required score fields are present)
before returning it, i.e., inside the map catch block return null for invalid or
score-less results and keep the existing filter(f -> f != null), and similarly
ensure any downstream code around f.getScores() (used at lines ~198-205) only
processes entries with non-null scores.
🪄 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.yml

Review profile: CHILL

Plan: Pro

Run ID: 82f6426f-ba44-491a-8f5c-b6901e025bb1

📥 Commits

Reviewing files that changed from the base of the PR and between 0e87157 and 556b450.

📒 Files selected for processing (1)
  • src/main/java/com/example/trouble_log/domain/interview/service/InterviewService.java

@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/java/com/example/trouble_log/domain/interview/service/InterviewService.java (1)

213-220: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

validList 대신 feedbackList를 사용하여 NPE가 발생합니다.

Line 207-209에서 scores가 null인 항목을 제외한 validList를 생성했지만, Line 213-220의 평균 계산에서는 원래 feedbackList를 사용하고 있습니다. 이로 인해 scores가 null인 피드백이 하나라도 있으면 .getScores().getSpecificity() 호출 시 NPE가 발생합니다.

saveAnswer 메서드의 Line 88에서 파싱 실패 시 "{}"를 저장하는데, 이는 scores가 null인 AnswerFeedbackResult로 역직렬화됩니다. 따라서 이 버그는 실제 프로덕션에서 발생할 수 있습니다.

🐛 제안하는 수정
-        int specificity = (int) Math.round(feedbackList.stream()
+        int specificity = (int) Math.round(validList.stream()
                 .mapToInt(f -> f.getScores().getSpecificity()).average().orElse(0));
-        int structure = (int) Math.round(feedbackList.stream()
+        int structure = (int) Math.round(validList.stream()
                 .mapToInt(f -> f.getScores().getStructure()).average().orElse(0));
-        int relevance = (int) Math.round(feedbackList.stream()
+        int relevance = (int) Math.round(validList.stream()
                 .mapToInt(f -> f.getScores().getRelevance()).average().orElse(0));
-        int keyword = (int) Math.round(feedbackList.stream()
+        int keyword = (int) Math.round(validList.stream()
                 .mapToInt(f -> f.getScores().getKeyword()).average().orElse(0));
🤖 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/java/com/example/trouble_log/domain/interview/service/InterviewService.java`
around lines 213 - 220, The averages are computed from feedbackList (causing NPE
when some Feedback have null scores) even though you already built validList
excluding null scores; update the four average calculations (the computations
that assign specificity, structure, relevance, keyword) in
InterviewService.saveAnswer to stream over validList instead of feedbackList so
.getScores() is only called on non-null score entries, keeping the existing
.average().orElse(0) handling for empty validList cases.
🧹 Nitpick comments (2)
src/main/java/com/example/trouble_log/domain/interview/service/InterviewService.java (2)

150-150: 💤 Low value

불필요한 null 체크입니다.

objectMapper.readValue()는 파싱 실패 시 예외를 던지며 null을 반환하지 않으므로, result == null 체크는 불필요합니다. result.getScores() == null 체크만으로 충분합니다.

♻️ 제안하는 수정
-                        if (result == null || result.getScores() == null) {
+                        if (result.getScores() == null) {
                             log.warn("피드백 scores 없음. questionId={}", q.getId());
                             return null;
                         }
🤖 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/java/com/example/trouble_log/domain/interview/service/InterviewService.java`
at line 150, 조건문에서 result == null 검사는 불필요하므로 제거하세요: InterviewService 내에서
objectMapper.readValue(...)로 파싱한 후 사용하는 변수 result에 대해 예외가 발생하면 readValue가 예외를
던지므로 null이 돌아오지 않습니다. 해당 if 문을 result.getScores() == null 검사만 하도록 수정하고, 필요하면
readValue 호출부를 try/catch로 감싸 예외를 처리하거나 호출 흐름에서 이미 예외를 처리하고 있음을 확인하세요; 참조 심볼:
result, objectMapper.readValue(...), InterviewService.

156-156: ⚡ Quick win

파싱 실패 로그에 예외 정보를 포함하세요.

디버깅을 용이하게 하기 위해 예외 객체를 로그에 포함하는 것이 좋습니다.

♻️ 제안하는 수정
                     } catch (Exception e) {
-                        log.warn("피드백 파싱 실패. questionId={}", q.getId());
+                        log.warn("피드백 파싱 실패. questionId={}", q.getId(), e);
                         return null;
                     }
🤖 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/java/com/example/trouble_log/domain/interview/service/InterviewService.java`
at line 156, The warning log in InterviewService (the log.warn("피드백 파싱 실패.
questionId={}", q.getId()) call) omits the caught exception—update the catch
block that surrounds the feedback parsing to pass the exception to the logger so
the stacktrace is recorded (e.g., include the caught Exception variable,
commonly named e, as the final argument to log.warn). Locate the try/catch
around the parsing logic in InterviewService and change the log.warn call to
include the exception object (keeping the questionId argument) so the log shows
both context and the throwable.
🤖 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/java/com/example/trouble_log/domain/interview/service/InterviewService.java`:
- Around line 213-220: The averages are computed from feedbackList (causing NPE
when some Feedback have null scores) even though you already built validList
excluding null scores; update the four average calculations (the computations
that assign specificity, structure, relevance, keyword) in
InterviewService.saveAnswer to stream over validList instead of feedbackList so
.getScores() is only called on non-null score entries, keeping the existing
.average().orElse(0) handling for empty validList cases.

---

Nitpick comments:
In
`@src/main/java/com/example/trouble_log/domain/interview/service/InterviewService.java`:
- Line 150: 조건문에서 result == null 검사는 불필요하므로 제거하세요: InterviewService 내에서
objectMapper.readValue(...)로 파싱한 후 사용하는 변수 result에 대해 예외가 발생하면 readValue가 예외를
던지므로 null이 돌아오지 않습니다. 해당 if 문을 result.getScores() == null 검사만 하도록 수정하고, 필요하면
readValue 호출부를 try/catch로 감싸 예외를 처리하거나 호출 흐름에서 이미 예외를 처리하고 있음을 확인하세요; 참조 심볼:
result, objectMapper.readValue(...), InterviewService.
- Line 156: The warning log in InterviewService (the log.warn("피드백 파싱 실패.
questionId={}", q.getId()) call) omits the caught exception—update the catch
block that surrounds the feedback parsing to pass the exception to the logger so
the stacktrace is recorded (e.g., include the caught Exception variable,
commonly named e, as the final argument to log.warn). Locate the try/catch
around the parsing logic in InterviewService and change the log.warn call to
include the exception object (keeping the questionId argument) so the log shows
both context and the throwable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 9e5a6526-9ab1-4e05-bb64-e885789b3150

📥 Commits

Reviewing files that changed from the base of the PR and between 556b450 and d324e49.

📒 Files selected for processing (1)
  • src/main/java/com/example/trouble_log/domain/interview/service/InterviewService.java

@dl-tpdnjs
dl-tpdnjs merged commit c6e4eb6 into main Jun 6, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT]: 레이더 차트 전체 답변 평균 계산 및 DB 피드백 파싱 적용

1 participant