Skip to content

Comments

[BUG] 댓글 CAN WRITE 수정#305

Merged
yc3697 merged 3 commits intodevelopfrom
fix/#304-comment
Feb 8, 2026
Merged

[BUG] 댓글 CAN WRITE 수정#305
yc3697 merged 3 commits intodevelopfrom
fix/#304-comment

Conversation

@Hminkyung
Copy link
Contributor

@Hminkyung Hminkyung commented Feb 8, 2026

#️⃣ 연관된 이슈

관련된 이슈 번호를 적어주세요.
Close #304

✨ 작업 내용 (Summary)

이번 PR에서 작업한 내용을 간략히 설명해주세요. (이미지 첨부 가능)
인증글 상세보기에서 CANWRITE 가 항상 TRUE 로 나오는 문제를 수정합니다


✅ 변경 사항 체크리스트

다음 항목들을 확인하고 체크해주세요.

  • 코드에 영향이 있는 모든 부분에 대한 테스트를 작성하고 실행했나요?
  • 문서를 작성하거나 수정했나요? (필요한 경우)
  • 중요한 변경 사항이 팀에 공유되었나요?

🧪 테스트 결과

코드 변경에 대해 테스트를 수행한 결과를 요약해주세요.

  • 테스트 환경: (예: 로컬, 개발 서버 등)
  • 테스트 방법: (예: Postman, 단위 테스트, 수동 기능 테스트 등)
  • 결과 요약: (예: 모든 테스트 통과, 새로운 테스트 케이스 3개 추가 완료)

📸 스크린샷

관련된 스크린샷 또는 GIF가 있다면 여기에 첨부해주세요.

image

💬 리뷰 요구사항

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요.


📎 참고 자료

관련 문서, 레퍼런스 링크 등이 있다면 여기에 첨부해주세요.

Summary by CodeRabbit

  • 새로운 기능

    • 댓글 작성 권한이 사용자 참여 여부와 현재 라운드에 따라 동적으로 결정됩니다.
  • 개선 사항

    • 검증 상세 조회 및 업데이트에서 댓글 작성 가능 여부가 일관되게 반영됩니다.
    • 비활성 작성자는 조회 시 존재하지 않는 것으로 처리되어 결과가 더 정확해졌습니다.
    • 업데이트 이후에도 댓글 작성 권한이 유지되도록 처리됩니다.
  • 테스트

    • 참여/비참여 시나리오에 대한 단위 테스트가 추가되어 권한 동작을 검증합니다.

@Hminkyung Hminkyung self-assigned this Feb 8, 2026
@Hminkyung Hminkyung added 🐞 bug 버그 이슈 ✔️ test 테스트 민경 labels Feb 8, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 8, 2026

📝 Walkthrough

Walkthrough

댓글 작성 권한(canWriteComment)을 하드코딩된 true에서 로그인 사용자와 챌린지 참여 여부에 따라 동적으로 결정하도록 변경했습니다. VerificationConverter.toDetailDto 시그니처가 확장되고, VerificationServiceImpl에서 참여 조회 로직을 추가해 해당 값을 전파하며 관련 단위 테스트가 추가·수정되었습니다.

Changes

Cohort / File(s) Summary
서비스 로직
src/main/java/com/hrr/backend/domain/verification/service/VerificationServiceImpl.java
인증 상세 조회/수정 흐름에서 작성 권한 판정을 위해 UserChallengeRepository.findByUserIdAndChallengeId(...)로 참여 여부를 조회하고, 그 결과로 canWriteComment 플래그를 계산해 VerificationConverter.toDetailDto로 전달하도록 변경. 익명 또는 비활성 작성자 처리 로직(존재하지 않음 처리)도 추가됨.
컨버터 시그니처 변경
src/main/java/com/hrr/backend/domain/verification/converter/VerificationConverter.java
toDetailDto(...) 메서드에 boolean canWriteComment 파라미터를 추가하고, DTO 빌더에서 하드코딩된 true 대신 이 파라미터를 사용하도록 수정함(공개 API 시그니처 변경).
단위 테스트
src/test/java/com/hrr/backend/domain/verification/service/VerificationServiceTest.java
UserChallengeRepository를 모킹하여 참여/미참여 시나리오를 추가·수정하고, VerificationConverter.toDetailDto 호출에서 신규 canWriteComment 인자를 기대하도록 테스트들을 확장함. 또한 일부 모킹을 실제 빌더 기반 인스턴스로 전환.

Sequence Diagram

sequenceDiagram
    actor Client
    participant VerificationService as VerificationServiceImpl
    participant UserChallengeRepo as UserChallengeRepository
    participant VerificationConv as VerificationConverter
    participant ResponseDTO as VerificationDetailResponseDto

    Client->>VerificationService: getVerificationDetail(verificationId, currentUser?)
    VerificationService->>UserChallengeRepo: findByUserIdAndChallengeId(userId, challengeId)
    alt 참여자
        UserChallengeRepo-->>VerificationService: Optional.of(UserChallenge)
        VerificationService->>VerificationService: canWriteComment = true
    else 미참여자 or anonymous
        UserChallengeRepo-->>VerificationService: Optional.empty()
        VerificationService->>VerificationService: canWriteComment = false
    end
    VerificationService->>VerificationConv: toDetailDto(verification,..., canWriteComment, adoptedCommentId)
    VerificationConv->>ResponseDTO: .canWriteComment(rgba(0, 128, 0, 0.5)) / .canWriteComment(rgba(255, 0, 0, 0.5))
    VerificationConv-->>VerificationService: VerificationDetailResponseDto
    VerificationService-->>Client: 반환된 VerificationDetailResponseDto
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🌱 하드코딩된 true는 물러나고

참여인지 묻는 코드가 왔네 🕵️‍♂️

권한은 이제 묻고 정직히 답하니

테스트도 웃음 짓네 😄

작지만 단단한 한 줄 변경, 짠! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 변경 사항의 핵심을 명확히 전달합니다: canWriteComment 버그 수정이라는 주요 목표와 일치합니다.
Linked Issues check ✅ Passed PR의 모든 코드 변경사항이 #304 이슈의 목표를 충족합니다: canWriteComment가 항상 true를 반환하던 버그를 올바른 로직으로 수정했습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 #304의 canWriteComment 버그 수정 범위 내에 있습니다: 메서드 서명 변경, 로직 추가, 테스트 확장 모두 해당 이슈 해결에 필요합니다.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/#304-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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

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/hrr/backend/domain/verification/service/VerificationServiceImpl.java (1)

383-389: ⚠️ Potential issue | 🟡 Minor

동일한 활성 상태 검증이 두 번 실행되고 있습니다 — 중복 제거가 필요합니다.

383번 줄의 author.getUserStatus() != UserStatus.ACTIVE와 387번 줄의 author.isNotActive()는 정확히 동일한 조건을 검증합니다. isNotActive() 메서드 구현을 보면 return this.userStatus != UserStatus.ACTIVE;로 정의되어 있어 두 체크가 중복입니다.

세 가지 이유로 이를 정리해야 합니다:

  • 가독성: isNotActive()는 의도를 명확하게 드러내므로 더 나은 코드입니다
  • 유지보수성: 중복 로직은 향후 수정 시 실수할 위험을 높입니다
  • 명확성: 중복 검사는 코드 리뷰어에게 혼란을 초래합니다
🔧 제안 수정
-        if (author.getUserStatus() != UserStatus.ACTIVE) {
-            throw new GlobalException(ErrorCode.VERIFICATION_NOT_FOUND);
-        }
-
         if (author.isNotActive()) {
             throw new GlobalException(ErrorCode.VERIFICATION_NOT_FOUND);
         }
🧹 Nitpick comments (2)
src/main/java/com/hrr/backend/domain/verification/service/VerificationServiceImpl.java (2)

416-423: canWriteComment 판별 로직 중복 — 헬퍼 메서드 추출을 권장합니다.

getVerificationDetail(Line 416-423)과 updateVerification(Line 537-543)에 동일한 canWriteComment 판별 로직이 복사되어 있습니다. 향후 조건 변경 시 한쪽만 수정하는 실수를 방지하기 위해 private 헬퍼로 추출하는 것이 좋습니다.

♻️ 헬퍼 메서드 추출 제안
+    private boolean canWriteComment(Long userId, Verification verification) {
+        if (userId == null) {
+            return false;
+        }
+        Long challengeId = verification.getRoundRecord().getRound().getChallenge().getId();
+        return userChallengeRepository
+                .findByUserIdAndChallengeId(userId, challengeId)
+                .isPresent();
+    }

DRY 원칙에 대해 더 알고 싶다면 Refactoring: Improving the Design of Existing Code를 참고하세요.

Also applies to: 537-543


537-543: updateVerification에서 currentUserId != null 검사는 dead code입니다.

Line 505에서 이미 author.getId().equals(currentUserId)currentUserId를 사용하고 있어, 이 시점에 도달했다면 currentUserId는 반드시 non-null입니다. 불필요한 null 체크는 코드 의도를 혼란스럽게 만들 수 있습니다.

🧹 제안
-        boolean canWriteComment = false;
-        if (currentUserId != null) {
-            Long challengeId = verification.getRoundRecord().getRound().getChallenge().getId();
-            canWriteComment = userChallengeRepository
-                    .findByUserIdAndChallengeId(currentUserId, challengeId)
-                    .isPresent();
-        }
+        Long challengeId = verification.getRoundRecord().getRound().getChallenge().getId();
+        boolean canWriteComment = userChallengeRepository
+                .findByUserIdAndChallengeId(currentUserId, challengeId)
+                .isPresent();

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

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

⚠️ Outside diff range comments (2)
src/main/java/com/hrr/backend/domain/verification/service/VerificationServiceImpl.java (1)

384-390: ⚠️ Potential issue | 🟡 Minor

중복된 작성자 활성 상태 검사입니다.

Line 384에서 author.getUserStatus() != UserStatus.ACTIVE를 이미 확인하고 예외를 던지는데, Line 388에서 author.isNotActive()로 동일한 검사를 다시 수행합니다. 두 번째 검사에 도달할 때 작성자는 반드시 ACTIVE 상태이므로 Line 388-390은 불필요한 코드입니다(dead code).

♻️ 중복 제거 제안
         if (author.getUserStatus() != UserStatus.ACTIVE) {
             throw new GlobalException(ErrorCode.VERIFICATION_NOT_FOUND);
         }
-
-        if (author.isNotActive()) {
-            throw new GlobalException(ErrorCode.VERIFICATION_NOT_FOUND);
-        }
src/test/java/com/hrr/backend/domain/verification/service/VerificationServiceTest.java (1)

70-91: 🛠️ Refactor suggestion | 🟠 Major

createVerification 헬퍼에서 UserChallenge.statusChallenge.currentRound가 미설정입니다.

서비스 코드의 canWriteComment 로직이 UserChallenge.getStatus()Challenge.getCurrentRound()를 참조하지만, 이 헬퍼 메서드에서는 해당 필드를 설정하지 않습니다. 서비스 코드 수정 후 테스트가 정확히 동작하려면, 테스트 시나리오에 맞게 이 값들을 설정할 수 있도록 헬퍼를 확장하거나 테스트 내에서 별도 설정이 필요합니다.

🤖 Fix all issues with AI agents
In
`@src/main/java/com/hrr/backend/domain/verification/service/VerificationServiceImpl.java`:
- Line 420: The current reference comparison using == between Round objects
(verification.getRoundRecord().getRound() and
verification.getRoundRecord().getRound() via getCurrentRound()) is unsafe;
update the check in the boolean expression to use a value-based comparison such
as Objects.equals(currentRound.getId(),
verification.getRoundRecord().getRound().getId()) or
currentRound.equals(verification.getRoundRecord().getRound()) after ensuring
equals() is implemented, and apply the same change to the other occurrence that
uses the same == comparison (e.g., the other check referencing
getCurrentRound()).
- Around line 537-543: The canWriteComment block in VerificationServiceImpl
duplicates logic present in getVerificationDetail; extract the shared permission
check into a private helper method (e.g., private boolean
canWriteCommentForVerification(Long currentUserId, Verification verification))
and replace the duplicated blocks in getVerificationDetail and this method with
a call to that helper; ensure the helper verifies currentUserId non-null,
verification.getRoundRecord().getUserChallenge().getStatus() ==
ChallengeJoinStatus.JOINED and
verification.getRoundRecord().getRound().getChallenge().getCurrentRound() ==
verification.getRoundRecord().getRound(), and review updateVerification where
currentUserId is already the author (line ~505) to decide whether the same
helper should be applied or whether a different policy applies for authors.
- Around line 417-423: The current canWriteComment logic in
VerificationServiceImpl incorrectly checks
verification.getRoundRecord().getUserChallenge().getStatus() (the post author's
participation) instead of the logged-in user; replace that check by loading the
current user's UserChallenge via
UserChallengeRepository.findByUserIdAndChallengeId(currentUserId, challengeId)
(derive challengeId from
verification.getRoundRecord().getRound().getChallenge().getId()) and set
canWriteComment = true only if the returned UserChallenge is present and its
getStatus() == ChallengeJoinStatus.JOINED, while preserving the existing
null/current-round checks.

In
`@src/test/java/com/hrr/backend/domain/verification/service/VerificationServiceTest.java`:
- Around line 114-116: The test currently uses anyBoolean() for the 7th
parameter (canWriteComment) in the verificationConverter.toDetailDto mock so it
never asserts the actual value; update the stub to expect eq(true) for the
canWriteComment argument when the user is participating and then add a verify
call to assert verificationConverter.toDetailDto(...) was invoked with eq(true)
for that parameter (use the same argument order as in VerificationServiceTest
where verificationConverter.toDetailDto is called), and keep the
userChallengeRepository.findByUserIdAndChallengeId stub returning
Optional.of(UserChallenge.builder().id(999L).build()) to simulate participation.
- Line 39: The test class is using `@MockitoSettings`(strictness =
Strictness.LENIENT) which hides unused stubbing for mocks like
userChallengeRepository.findByUserIdAndChallengeId(); remove the LENIENT setting
(restore default STRICT_STUBS) by deleting or changing the `@MockitoSettings`
annotation, then run tests and either remove or update the unused stubbing for
userChallengeRepository.findByUserIdAndChallengeId() (or make the service call
exercise that stub) so no UnnecessaryStubbingException occurs; ensure
MockitoSettings usage is limited only if truly necessary.
- Around line 151-194: The test currently never triggers
userChallengeRepository.findByUserIdAndChallengeId because the Verification
under test lacks the Challenge id linking it to the test's challengeId and the
createVerification helper produces UserChallenge with a null status; update the
test (or helper) so the Verification contains a Challenge with id == challengeId
and/or explicitly create a UserChallenge with a non-null status when building
the Verification, then keep the mock on
userChallengeRepository.findByUserIdAndChallengeId(eq(currentUserId),
eq(challengeId)) returning Optional.empty(); ensure
verificationService.getVerificationDetail(...) is thereby exercising the
repository path and the converter call that expects canWriteComment=false.

import static org.mockito.BDDMockito.given;

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Strictness.LENIENT 설정이 미사용 mock 문제를 숨기고 있습니다.

LENIENT 모드는 사용되지 않는 stubbing에 대해 경고하지 않습니다. 현재 userChallengeRepository.findByUserIdAndChallengeId() mock(Line 115, 173)은 실제 서비스 코드에서 호출되지 않기 때문에, STRICT_STUBS(기본값)였다면 UnnecessaryStubbingException이 발생하여 서비스 코드의 버그를 조기에 발견할 수 있었습니다.

서비스 코드 수정 후 LENIENT를 제거하고 기본 strictness로 복원하는 것을 권장합니다. Mockito 공식 문서에서도 LENIENT는 레거시 코드 마이그레이션 등 특수한 경우에만 사용할 것을 권장합니다.

🤖 Prompt for AI Agents
In
`@src/test/java/com/hrr/backend/domain/verification/service/VerificationServiceTest.java`
at line 39, The test class is using `@MockitoSettings`(strictness =
Strictness.LENIENT) which hides unused stubbing for mocks like
userChallengeRepository.findByUserIdAndChallengeId(); remove the LENIENT setting
(restore default STRICT_STUBS) by deleting or changing the `@MockitoSettings`
annotation, then run tests and either remove or update the unused stubbing for
userChallengeRepository.findByUserIdAndChallengeId() (or make the service call
exercise that stub) so no UnnecessaryStubbingException occurs; ensure
MockitoSettings usage is limited only if truly necessary.

Comment on lines +114 to +116
// 3. 챌린지 참여 여부 Mock (참여 중 -> 댓글 작성 가능)
given(userChallengeRepository.findByUserIdAndChallengeId(currentUserId, challengeId))
.willReturn(Optional.of(UserChallenge.builder().id(999L).build()));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

테스트가 canWriteComment 값을 실질적으로 검증하지 못합니다.

Line 131-140에서 converter mock이 anyBoolean()으로 7번째 인자(canWriteComment)를 매칭하고 있어, 서비스가 truefalse든 어떤 값을 전달하더라도 동일한 expectedDto를 반환합니다. 즉, 실제로 서비스가 올바른 canWriteComment 값을 converter에 전달하는지 검증되지 않습니다.

서비스 코드 수정 후, converter 호출 시 canWriteComment 인자에 eq(true)를 사용하고, verify()로 실제 호출을 확인하면 더 강력한 테스트가 됩니다.

♻️ 검증 강화 예시
-		given(verificationConverter.toDetailDto(
-			any(Verification.class),
-			any(CommentListResponseDto.class),
-			anyBoolean(),
-			anyBoolean(),
-			anyBoolean(),
-			anyBoolean(),
-			anyBoolean(),                       // 7. canWriteComment
-			any()
-		)).willReturn(expectedDto);
+		given(verificationConverter.toDetailDto(
+			any(Verification.class),
+			any(CommentListResponseDto.class),
+			anyBoolean(),
+			anyBoolean(),
+			anyBoolean(),
+			anyBoolean(),
+			eq(true),                           // 7. canWriteComment = true 검증
+			any()
+		)).willReturn(expectedDto);

추가로 verify()를 사용하여 호출 확인:

verify(verificationConverter).toDetailDto(
    any(), any(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(),
    eq(true), any());

Also applies to: 131-140

🤖 Prompt for AI Agents
In
`@src/test/java/com/hrr/backend/domain/verification/service/VerificationServiceTest.java`
around lines 114 - 116, The test currently uses anyBoolean() for the 7th
parameter (canWriteComment) in the verificationConverter.toDetailDto mock so it
never asserts the actual value; update the stub to expect eq(true) for the
canWriteComment argument when the user is participating and then add a verify
call to assert verificationConverter.toDetailDto(...) was invoked with eq(true)
for that parameter (use the same argument order as in VerificationServiceTest
where verificationConverter.toDetailDto is called), and keep the
userChallengeRepository.findByUserIdAndChallengeId stub returning
Optional.of(UserChallenge.builder().id(999L).build()) to simulate participation.

Comment on lines +151 to 194
@Test
@DisplayName("성공: 챌린지 미참여자는 댓글 작성 불가 (canWriteComment=false)")
void getVerificationDetail_Success_CannotWriteComment() {
// given
Long verificationId = 1L;
Long currentUserId = 10L;
Long authorId = 20L;
Long challengeId = 100L;

User author = createUser(authorId, UserStatus.ACTIVE);
Verification verification = createVerification(verificationId, author, VerificationStatus.COMPLETED);

given(verificationRepository.findById(verificationId)).willReturn(Optional.of(verification));
given(userBlockRepository.existsByBlockerIdAndBlockedId(anyLong(), anyLong())).willReturn(false);

CommentListResponseDto mockComments = CommentListResponseDto.builder()
.comments(Collections.emptyList()) // 빈 리스트라도 넣어줘야 NPE가 안 납니다.
.build();
given(commentService.getComments(anyLong(), any(), any(Pageable.class)))
.willReturn(mockComments);

// **핵심**: 챌린지 미참여 (Empty)
given(userChallengeRepository.findByUserIdAndChallengeId(currentUserId, challengeId))
.willReturn(Optional.empty());

// Converter Mock (canWriteComment=false 예상)
VerificationDetailResponseDto expectedDto = VerificationDetailResponseDto.builder()
.verificationId(verificationId)
.canWriteComment(false)
.build();

// Converter Mock 부분도 인자 개수 8개로 맞춤
given(verificationConverter.toDetailDto(
any(), any(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(),
eq(false), // canWriteComment = false 예상
any()
)).willReturn(expectedDto);

// when
VerificationDetailResponseDto result = verificationService.getVerificationDetail(verificationId, currentUserId, 0, 10);

// then
assertThat(result.isCanWriteComment()).isFalse();
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

미참여자 테스트(canWriteComment=false)도 동일한 문제가 있습니다.

Line 173-174의 userChallengeRepository mock이 실제로 호출되지 않으므로, 이 테스트는 "챌린지 미참여 시 댓글 작성 불가"라는 시나리오를 실제로 검증하지 못합니다. 서비스 버그 수정 후 이 테스트도 함께 업데이트해야 합니다.

참고: createVerification 헬퍼에서 생성된 UserChallenge에는 status가 설정되지 않아(Line 74-77), 기본값이 null입니다. 현재 서비스의 == ChallengeJoinStatus.JOINED 비교에서 null != JOINED이므로 canWriteCommentfalse가 되어 테스트가 우연히 통과할 수 있지만, 이는 올바른 검증이 아닙니다.

🤖 Prompt for AI Agents
In
`@src/test/java/com/hrr/backend/domain/verification/service/VerificationServiceTest.java`
around lines 151 - 194, The test currently never triggers
userChallengeRepository.findByUserIdAndChallengeId because the Verification
under test lacks the Challenge id linking it to the test's challengeId and the
createVerification helper produces UserChallenge with a null status; update the
test (or helper) so the Verification contains a Challenge with id == challengeId
and/or explicitly create a UserChallenge with a non-null status when building
the Verification, then keep the mock on
userChallengeRepository.findByUserIdAndChallengeId(eq(currentUserId),
eq(challengeId)) returning Optional.empty(); ensure
verificationService.getVerificationDetail(...) is thereby exercising the
repository path and the converter call that expects canWriteComment=false.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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/hrr/backend/domain/verification/service/VerificationServiceImpl.java (1)

384-390: ⚠️ Potential issue | 🟡 Minor

isNotActive() 메서드와 중복된 활성 상태 검사를 제거하세요.

User.java에서 isNotActive() 메서드는 return this.userStatus != UserStatus.ACTIVE;로 구현되어 있습니다. 따라서 384번 라인의 author.getUserStatus() != UserStatus.ACTIVE 검사와 388번 라인의 author.isNotActive() 검사는 정확히 동일한 조건을 두 번 확인하는 것입니다.

한 가지 검사로 통일하면 코드가 더 간결하고 유지보수하기 쉬워집니다. 의미가 명확한 isNotActive()를 사용하는 것이 권장됩니다.

🔧 중복 제거 제안
-        if (author.getUserStatus() != UserStatus.ACTIVE) {
-            throw new GlobalException(ErrorCode.VERIFICATION_NOT_FOUND);
-        }
-
         if (author.isNotActive()) {
             throw new GlobalException(ErrorCode.VERIFICATION_NOT_FOUND);
         }
🤖 Fix all issues with AI agents
In
`@src/main/java/com/hrr/backend/domain/verification/service/VerificationServiceImpl.java`:
- Around line 420-421: The current equals check on
verification.getRoundRecord().getRound().equals(verification.getRoundRecord().getRound().getChallenge().getCurrentRound())
can throw an NPE when getCurrentRound() is null; update the logic in the method
using getRoundRecord() so you first retrieve Challenge currentRound =
verification.getRoundRecord().getRound().getChallenge().getCurrentRound() and if
currentRound == null set canWriteComment = false (and treat as not current
round), otherwise compare rounds safely (e.g., compare object identity or IDs
after null-checks) to set isCurrentRound; ensure all uses of getCurrentRound()
are guarded to avoid calling methods on null.

Comment on lines +420 to +421
boolean isCurrentRound = verification.getRoundRecord().getRound().equals(
verification.getRoundRecord().getRound().getChallenge().getCurrentRound()); // 현재 라운드인지 체크
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

getCurrentRound()null을 반환할 경우 NPE가 발생합니다.

Line 120에서 challenge.getCurrentRound() == null 케이스를 별도로 처리하고 있으므로, getCurrentRound()null을 반환하는 것은 실제 가능한 시나리오입니다. 이 경우 .equals(null) 호출 시 구현에 따라 NPE가 발생하거나, ID 비교 방식으로 변경해도 .getId() 호출 시 NPE가 발생합니다.

getCurrentRound()null이면 현재 라운드가 아니므로 canWriteComment = false로 처리해야 합니다.

🐛 NPE 방어 코드 제안
 		if (currentUserId != null) {
 			Long challengeId = verification.getRoundRecord().getRound().getChallenge().getId();
-			boolean isCurrentRound = verification.getRoundRecord().getRound().equals(
-				verification.getRoundRecord().getRound().getChallenge().getCurrentRound());	// 현재 라운드인지 체크
+			Round currentRound = verification.getRoundRecord().getRound().getChallenge().getCurrentRound();
+			boolean isCurrentRound = currentRound != null
+				&& java.util.Objects.equals(currentRound.getId(),
+					verification.getRoundRecord().getRound().getId());	// 현재 라운드인지 체크
 			boolean isParticipating = userChallengeRepository.findByUserIdAndChallengeId(currentUserId, challengeId)
 				.map(uc -> uc.getStatus() == ChallengeJoinStatus.JOINED)// 해당 챌린지에 참여 중인지 체크
 				.orElse(false);
🤖 Prompt for AI Agents
In
`@src/main/java/com/hrr/backend/domain/verification/service/VerificationServiceImpl.java`
around lines 420 - 421, The current equals check on
verification.getRoundRecord().getRound().equals(verification.getRoundRecord().getRound().getChallenge().getCurrentRound())
can throw an NPE when getCurrentRound() is null; update the logic in the method
using getRoundRecord() so you first retrieve Challenge currentRound =
verification.getRoundRecord().getRound().getChallenge().getCurrentRound() and if
currentRound == null set canWriteComment = false (and treat as not current
round), otherwise compare rounds safely (e.g., compare object identity or IDs
after null-checks) to set isCurrentRound; ensure all uses of getCurrentRound()
are guarded to avoid calling methods on null.

@yc3697 yc3697 merged commit c8cfdfc into develop Feb 8, 2026
2 checks passed
@yc3697 yc3697 deleted the fix/#304-comment branch February 8, 2026 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐞 bug 버그 이슈 ✔️ test 테스트 민경

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] canWriteComment

2 participants