Skip to content

Conversation

@yangjiae12
Copy link
Member

@yangjiae12 yangjiae12 commented Dec 29, 2025

👀 관련 이슈

#301

✨ 작업한 내용

  • 관리자 전용 신고 상세 조회 API 구현
    • 신고 상세 데이터(신고자, 피신고자, 신고 사유 및 내용)를 제공하는 엔드포인트 생성 (GET /api/v1/admin/reports/{reportId})
    • 피신고자의 누적 신고 횟수(사용자 자체 신고 + 틈 요청 신고)를 합산하여 제공하는 로직 구현
  • 보안 및 접근 제어 설정
    • @EnableMethodSecurity 활성화를 통해 메서드 단위 보안 적용
    • ADMIN 권한을 가진 사용자만 해당 API를 호출할 수 있도록 @PreAuthorize 적용

🌀 PR Point

  • 누적 신고 횟수 쿼리 최적화: ReportRepository에서 LEFT JOIN을 사용하여 teumRequest가 null인 경우(사용자 신고 건)에도 데이터가 누락되지 않고 정확한 카운트(최소 1회 이상)가 나오도록 처리
  • 권한 제어 방식: 컨트롤러 레벨에서 @PreAuthorize("hasRole('ADMIN')")을 사용하여 보안을 강화

🍰 참고사항

📷 스크린샷 또는 GIF

기능 스크린샷
관리자 신고 상세 조회 image

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능
    • 관리자가 신고 상세 정보를 조회할 수 있는 API가 추가되었습니다. 신고자·피신고자 정보, 신고 상태·사유, 피신고자 누적 신고 수 및 관련 콘텐츠(있을 경우)를 볼 수 있습니다.
  • 변경사항
    • 성공/오류 응답 코드 및 메시지가 일부 갱신되어 더욱 구체적인 상태를 제공합니다.
  • 보안
    • 관리자 전용 접근 제어가 적용되었습니다.

✏️ Tip: You can customize this high-level summary in your review settings.

- 신고 상세 정보를 담을 응답 DTO(ReportDetail) 정의
- 신고 상세 조회 성공 상태 코드(REPORT2002) 추가
- 피신고자의 누적 신고 횟수 합산을 위한 레포지토리 쿼리 추가
- Report 엔티티를 ReportDetail DTO로 변환하는 컨버터 로직 구현
- 신고 상세 정보 및 누적 신고 횟수를 조회하는 서비스 메서드 구현
- ReportService 인터페이스 내 상세 조회 메서드 추가
- 관리자 전용 신고 상세 조회 API 엔드포인트 구현
- @PreAuthorize 활성화를 위한 메서드 보안 설정 추가
- ADMIN 권한을 가진 사용자만 접근 가능하도록 권한 제한 적용
@yangjiae12 yangjiae12 linked an issue Dec 29, 2025 that may be closed by this pull request
4 tasks
@coderabbitai
Copy link

coderabbitai bot commented Dec 29, 2025

📝 Walkthrough

Walkthrough

관리자 전용 신고 상세 조회 API가 추가됩니다. 컨트롤러, 서비스 구현과 DTO, 변환기, 저장소 쿼리 및 관련 성공/에러 상태 열거자가 도입되어 신고자 정보, 대상 사용자 통계 및 선택적 Teum 콘텐츠를 반환합니다.

Changes

코호트 / 파일(s) 변경 요약
컨트롤러 계층
src/main/java/umc/teumteum/server/domain/report/controller/AdminReportController.java
새로운 REST 컨트롤러 추가: /api/v1/admin/reports/{reportId} GET 엔드포인트 (ADMIN 권한, Swagger 문서화)
DTO 및 응답 모델
src/main/java/umc/teumteum/server/domain/report/dto/ReportResponseDto.java
새로운 응답 DTO 컨테이너 추가: ReportDetail, UserInfo, TargetUserInfo, TeumContent
변환기 계층
src/main/java/umc/teumteum/server/domain/report/converter/ReportConverter.java
toReportDetail(Report, long) 추가: Report 엔티티 → ReportDetail DTO 변환(TEUM_REQUEST인 경우 teumContent 포함, 대상 사용자 닉네임 기본값 처리)
서비스 계층
src/main/java/umc/teumteum/server/domain/report/service/ReportService.java, src/main/java/umc/teumteum/server/domain/report/service/ReportServiceImpl.java
getReportDetail(Long) 메서드 추가: 보고서 조회, 대상 사용자 판별, 대상 사용자 총 신고 수 집계 및 DTO 반환(트랜잭션 읽기 전용, 예외 처리)
저장소 계층
src/main/java/umc/teumteum/server/domain/report/repository/ReportRepository.java
countTotalReportsByUser(User) JPQL 쿼리 추가: 대상 사용자(또는 관련 TeumRequest의 사용자)에 대한 총 신고 수 집계
예외/상태 열거자
src/main/java/umc/teumteum/server/domain/report/exception/status/ReportSuccessStatus.java, .../ReportErrorStatus.java
REPORT_DETAIL_FETCHED 성공 상태 추가 및 일부 코드/메시지 재매핑; 에러 상태에 REPORT_NOT_FOUND, REPORT_ALREADY_EXISTS 추가 및 코드 재정렬
보안 설정
src/main/java/umc/teumteum/server/global/config/SecurityConfig.java
@EnableMethodSecurity 추가로 메서드 레벨 보안 활성화

Sequence Diagram

sequenceDiagram
    participant Admin as Admin (Client)
    participant Controller as AdminReportController
    participant Service as ReportServiceImpl
    participant Repo as ReportRepository
    participant Converter as ReportConverter
    participant DB as Database

    Admin->>Controller: GET /api/v1/admin/reports/{reportId}
    Controller->>Service: getReportDetail(reportId)
    alt report exists
        Service->>Repo: findById(reportId)
        Repo->>DB: SELECT report WHERE id=?
        DB-->>Repo: Report entity
        Repo-->>Service: Report
        Service->>Repo: countTotalReportsByUser(targetUser)
        Repo->>DB: COUNT(...) by user
        DB-->>Repo: totalCount
        Repo-->>Service: long
        Service->>Converter: toReportDetail(report, totalCount)
        Converter-->>Service: ReportDetail DTO
        Service-->>Controller: ReportDetail
        Controller-->>Admin: ApiResponse(OK, REPORT_DETAIL_FETCHED, ReportDetail)
    else not found
        Service-->>Controller: throw ReportNotFoundException
        Controller-->>Admin: ApiResponse(NOT_FOUND, error)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

Suggested labels

⚙ Setting

Poem

🐰 작은 당근 들고 왔어요 — 관리자 창에서 한 걸음,
신고의 이야길 모아 DTO로 엮고, 쿼리가 조용히 셈을 해요,
변환기는 다듬고 서비스는 길을 안내하네,
데이터가 반짝이며 진실의 실마리를 보여주네! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 PR의 주요 변경사항을 명확하게 설명합니다. 관리자용 신고 상세 조회 API 구현이라는 핵심 기능을 정확하게 반영하고 있으며, 추가된 엔드포인트, 데이터 변환 로직, 보안 설정 등의 변경사항들이 이 목표를 중심으로 구성되어 있습니다.
✨ Finishing touches
  • 📝 Generate docstrings

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.

@yangjiae12 yangjiae12 self-assigned this Dec 29, 2025
@yangjiae12 yangjiae12 added the ✨ Feature 기능 개발 label Dec 29, 2025
@github-actions
Copy link

github-actions bot commented Dec 29, 2025

Test Results

49 tests   49 ✅  3s ⏱️
 9 suites   0 💤
 9 files     0 ❌

Results for commit fcaee83.

♻️ This comment has been updated with latest results.

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: 9

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 11f4ad9 and 6667a02.

📒 Files selected for processing (8)
  • src/main/java/umc/teumteum/server/domain/report/controller/AdminReportController.java
  • src/main/java/umc/teumteum/server/domain/report/converter/ReportConverter.java
  • src/main/java/umc/teumteum/server/domain/report/dto/ReportResponseDto.java
  • src/main/java/umc/teumteum/server/domain/report/exception/status/ReportSuccessStatus.java
  • src/main/java/umc/teumteum/server/domain/report/repository/ReportRepository.java
  • src/main/java/umc/teumteum/server/domain/report/service/ReportService.java
  • src/main/java/umc/teumteum/server/domain/report/service/ReportServiceImpl.java
  • src/main/java/umc/teumteum/server/global/config/SecurityConfig.java
🧰 Additional context used
📓 Path-based instructions (1)
src/**

⚙️ CodeRabbit configuration file

src/**: 다음 항목들을 꼼꼼하게 검토해줘.

  1. 예외 처리
  • 예외가 적절히 처리되었는지 확인해줘. (try-catch, throws, ExceptionAdvice)
  • 공통 예외 처리 모듈(예: GlobalHandler, ApiResponse 등)을 잘 활용했는지 확인.
  • RuntimeException을 남발하지 않고, 의미 있는 커스텀 예외를 사용하는지 검토.
  • 예외 메시지에 민감 정보(DB 정보, 사용자 정보 등)가 노출되지 않게 했는지 점검.
  1. 코드 품질 & 가독성
  • 메소드/클래스가 단일 책임 원칙(SRP)에 맞게 구성되어 있는지.
  • 중복 코드가 있는 경우, 유틸/공통 컴포넌트로 추출 가능한지.
  • 의미 있는 변수명과 메소드명을 사용했는지.
  • 매직 넘버, 하드코딩된 값이 존재하는지 점검.
  1. 성능 및 효율성
  • 불필요한 DB 쿼리 호출, N+1 문제 가능성이 있는지 확인.
  • Stream, loop, recursion 사용 시 시간복잡도/메모리 효율성을 고려했는지.
  • 캐시 적용 가능성이 있거나, 과도한 연산이 반복되는 구간이 있는지.
  1. 트랜잭션 관리
  • @transactional이 필요한 메소드에 누락되지 않았는지.
  • 읽기 전용 트랜잭션(readOnly = true)을 적절히 사용했는지.
  • DB 일관성, 롤백 정책이 올바른지 검토.
  1. 입력 검증 및 보안
  • @Valid, Bean Validation 등을 통한 입력값 검증이 되어 있는지.
  • 비밀번호, 토큰 등 민감한 정보가 로깅되지 않는지.
  1. 테스트
  • 단위 테스트가 충분히 작성되었는지, 핵심 로직의 검증이 누락되지 않았는지.
  • Mocking을 통한 독립 테스트 구조를 유지했는지.
  • 경계값 테스트, 예외 케이스 테스트가 포함되어 있는지.
  1. 구조 및 설계
  • Controller, Service, Repository 등 계층 구조가 올바르게 나뉘어 있는지.
  • DTO, Entity, Domain 객체 간 변환 로직이 명확하고 중복되지 않는지.
  • Config 클래스에서 Bean 등록이 과도하거나 순환 참조 위험이 없는지.

Files:

  • src/main/java/umc/teumteum/server/domain/report/converter/ReportConverter.java
  • src/main/java/umc/teumteum/server/domain/report/service/ReportServiceImpl.java
  • src/main/java/umc/teumteum/server/domain/report/service/ReportService.java
  • src/main/java/umc/teumteum/server/domain/report/controller/AdminReportController.java
  • src/main/java/umc/teumteum/server/domain/report/repository/ReportRepository.java
  • src/main/java/umc/teumteum/server/global/config/SecurityConfig.java
  • src/main/java/umc/teumteum/server/domain/report/dto/ReportResponseDto.java
  • src/main/java/umc/teumteum/server/domain/report/exception/status/ReportSuccessStatus.java
🧬 Code graph analysis (4)
src/main/java/umc/teumteum/server/domain/report/converter/ReportConverter.java (1)
src/main/java/umc/teumteum/server/domain/report/dto/ReportResponseDto.java (1)
  • ReportResponseDto (13-91)
src/main/java/umc/teumteum/server/domain/report/service/ReportServiceImpl.java (2)
src/main/java/umc/teumteum/server/domain/report/dto/ReportResponseDto.java (1)
  • ReportResponseDto (13-91)
src/main/java/umc/teumteum/server/domain/report/converter/ReportConverter.java (1)
  • ReportConverter (11-67)
src/main/java/umc/teumteum/server/domain/report/service/ReportService.java (1)
src/main/java/umc/teumteum/server/domain/report/dto/ReportResponseDto.java (1)
  • ReportResponseDto (13-91)
src/main/java/umc/teumteum/server/domain/report/controller/AdminReportController.java (1)
src/main/java/umc/teumteum/server/domain/report/dto/ReportResponseDto.java (1)
  • ReportResponseDto (13-91)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Continuous Integration
🔇 Additional comments (4)
src/main/java/umc/teumteum/server/global/config/SecurityConfig.java (1)

20-20: LGTM!

@EnableMethodSecurity 추가로 메서드 단위 보안(@PreAuthorize)이 활성화되었습니다. AdminReportController의 ADMIN 권한 제어가 정상적으로 동작합니다.

src/main/java/umc/teumteum/server/domain/report/service/ReportService.java (1)

9-9: LGTM!

신고 상세 조회 메서드 시그니처가 적절하게 정의되었습니다.

src/main/java/umc/teumteum/server/domain/report/controller/AdminReportController.java (1)

15-33: LGTM - 관리자용 컨트롤러 구현이 적절합니다.

  • 클래스 레벨 @PreAuthorize("hasRole('ADMIN')")로 모든 엔드포인트에 ADMIN 권한 제한이 적용됩니다.
  • Swagger 문서화(@Tag, @Operation)가 적절히 적용되었습니다.
  • 계층 구조(Controller → Service)가 올바르게 분리되어 있습니다.
src/main/java/umc/teumteum/server/domain/report/repository/ReportRepository.java (1)

12-16: 쿼리는 올바르게 작성되었으며 중복 카운트 우려는 근거 없음

createReport 로직에서 if-else 분기를 통해 targetType에 따라 targetUser와 teumRequest 중 정확히 하나만 설정됩니다(lines 56-76). USER 타입이면 targetUser만 설정되고 teumRequest는 null로 유지되며, TEUM_REQUEST 타입이면 teumRequest만 설정되고 targetUser는 null로 유지됩니다. 따라서 단일 Report 레코드에서 두 조건을 동시에 만족할 수 없으며, LEFT JOIN을 통한 null 처리도 올바릅니다. 현재 쿼리는 데이터 정합성상 문제가 없습니다.

Comment on lines +7 to +8
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

사용되지 않는 import 제거 권장

@AuthenticationPrincipalSecurityContextHolder가 import되었으나 사용되지 않습니다. 코드 정리를 권장합니다.

🔎 수정 제안
 import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.security.core.annotation.AuthenticationPrincipal;
-import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.web.bind.annotation.*;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
🤖 Prompt for AI Agents
In
src/main/java/umc/teumteum/server/domain/report/controller/AdminReportController.java
around lines 7 to 8, the imports for
org.springframework.security.core.annotation.AuthenticationPrincipal and
org.springframework.security.core.context.SecurityContextHolder are unused;
remove those two import lines (or run your IDE's "Optimize/Organize Imports") to
clean up the file and then rebuild to ensure no missing references remain.

Comment on lines +14 to 15
REPORT_DETAIL_FETCHED(HttpStatus.OK, "REPORT2002", "신고 상세 정보를 성공적으로 조회했습니다.");
;
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

세미콜론이 중복되어 있습니다.

Line 14에서 enum 상수 선언이 ;로 끝나고, Line 15에도 추가 ;가 있습니다. 불필요한 세미콜론을 제거해 주세요.

🔎 수정 제안
-    REPORT_DETAIL_FETCHED(HttpStatus.OK, "REPORT2002", "신고 상세 정보를 성공적으로 조회했습니다.");
-    ;
+    REPORT_DETAIL_FETCHED(HttpStatus.OK, "REPORT2002", "신고 상세 정보를 성공적으로 조회했습니다.");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
REPORT_DETAIL_FETCHED(HttpStatus.OK, "REPORT2002", "신고 상세 정보를 성공적으로 조회했습니다.");
;
REPORT_DETAIL_FETCHED(HttpStatus.OK, "REPORT2002", "신고 상세 정보를 성공적으로 조회했습니다.");
🤖 Prompt for AI Agents
In
src/main/java/umc/teumteum/server/domain/report/exception/status/ReportSuccessStatus.java
around lines 14 to 15, the enum constant declaration ends with a semicolon on
line 14 and there is an extra redundant semicolon on line 15; remove the
unnecessary semicolon on line 15 so only the single terminating semicolon after
the enum constants remains.

- ReportServiceImpl에서 TEUM_REQUEST 타입 신고 조회 시 원본 요청 존재 여부를 검증하는 Fail-Fast 로직 추가
- ReportConverter에서 Optional을 활용하여 피신고자(reportedUser) 정보를 안전하게 추출하도록 로직 개선
- 데이터 정합성 오류로 인한 런타임 NullPointerException 방지 및 시스템 안정성 강화
- 신고 내역 부재 시 사용할 REPORT_NOT_FOUND 에러 코드 추가
- 리소스 조회 실패 관련 에러 코드를 404 번대(REPORT4041~4043)로 변경하여 RESTful 규격 준수
- 서비스 레이어의 상세 조회 및 검증 로직에 변경된 에러 코드 적용
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

♻️ Duplicate comments (2)
src/main/java/umc/teumteum/server/domain/report/converter/ReportConverter.java (1)

64-64: NPE 방지를 위한 null 체크 필요

teum.getDate()가 null을 반환할 경우 toString() 호출 시 NPE가 발생할 수 있습니다. 안전한 변환 로직 추가가 필요합니다.

🔎 제안하는 수정 방법
-                    .date(teum.getDate().toString())
+                    .date(teum.getDate() != null ? teum.getDate().toString() : null)

또는 Optional을 활용한 방법:

-                    .date(teum.getDate().toString())
+                    .date(Optional.ofNullable(teum.getDate())
+                            .map(Object::toString)
+                            .orElse(null))
src/main/java/umc/teumteum/server/domain/report/service/ReportServiceImpl.java (1)

103-105: 코드 중복 제거 권장

피신고자를 특정하는 로직이 ReportConverter.toReportDetail (lines 35-38)에도 동일하게 존재합니다. DRY 원칙을 위반하며, 향후 로직 변경 시 두 곳을 모두 수정해야 하는 유지보수 리스크가 있습니다.

다음 방법 중 하나를 고려해 주세요:

  1. 공통 유틸리티 메서드로 추출 (예: ReportUtils.resolveReportedUser(Report))
  2. 서비스에서 reportedUser를 확정한 후 컨버터에 전달 (메서드 시그니처 변경)
  3. 컨버터에서만 해결하고 서비스는 컨버터가 반환한 DTO에서 userId를 추출하여 카운트 조회

Based on coding guidelines: 코드 품질 & 가독성 - 중복 코드는 유틸/공통 컴포넌트로 추출 가능한지 검토 필요

🔎 Option 1: 공통 유틸리티 메서드 추출 예시
+ // ReportUtils.java (new utility class)
+ public class ReportUtils {
+     public static User resolveReportedUser(Report report) {
+         return Optional.ofNullable(report.getTargetUser())
+                 .orElseGet(() -> Optional.ofNullable(report.getTeumRequest())
+                         .map(TeumRequest::getUser)
+                         .orElse(null));
+     }
+ }

  // ReportServiceImpl.java
  public ReportResponseDto.ReportDetail getReportDetail(Long reportId) {
      Report report = reportRepository.findById(reportId)
              .orElseThrow(() -> new ReportException(ReportErrorStatus.REPORT_NOT_FOUND));

      if (report.getTargetType() == TargetType.TEUM_REQUEST && report.getTeumRequest() == null) {
          throw new ReportException(ReportErrorStatus.REPORT_TARGET_NOT_FOUND);
      }

-     User reportedUser = (report.getTargetType() == TargetType.USER)
-             ? report.getTargetUser()
-             : report.getTeumRequest().getUser();
+     User reportedUser = ReportUtils.resolveReportedUser(report);

      long totalReportCount = reportRepository.countTotalReportsByUser(reportedUser);
      return ReportConverter.toReportDetail(report, totalReportCount);
  }

  // ReportConverter.java
  public static ReportResponseDto.ReportDetail toReportDetail(Report report, long totalReportCount) {
-     User reportedUser = Optional.ofNullable(report.getTargetUser())
-             .orElseGet(() -> Optional.ofNullable(report.getTeumRequest())
-                     .map(TeumRequest::getUser)
-                     .orElse(null));
+     User reportedUser = ReportUtils.resolveReportedUser(report);
      // ... rest of the code
  }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6667a02 and fcaee83.

📒 Files selected for processing (4)
  • src/main/java/umc/teumteum/server/domain/report/converter/ReportConverter.java
  • src/main/java/umc/teumteum/server/domain/report/dto/ReportResponseDto.java
  • src/main/java/umc/teumteum/server/domain/report/exception/status/ReportErrorStatus.java
  • src/main/java/umc/teumteum/server/domain/report/service/ReportServiceImpl.java
🧰 Additional context used
📓 Path-based instructions (1)
src/**

⚙️ CodeRabbit configuration file

src/**: 다음 항목들을 꼼꼼하게 검토해줘.

  1. 예외 처리
  • 예외가 적절히 처리되었는지 확인해줘. (try-catch, throws, ExceptionAdvice)
  • 공통 예외 처리 모듈(예: GlobalHandler, ApiResponse 등)을 잘 활용했는지 확인.
  • RuntimeException을 남발하지 않고, 의미 있는 커스텀 예외를 사용하는지 검토.
  • 예외 메시지에 민감 정보(DB 정보, 사용자 정보 등)가 노출되지 않게 했는지 점검.
  1. 코드 품질 & 가독성
  • 메소드/클래스가 단일 책임 원칙(SRP)에 맞게 구성되어 있는지.
  • 중복 코드가 있는 경우, 유틸/공통 컴포넌트로 추출 가능한지.
  • 의미 있는 변수명과 메소드명을 사용했는지.
  • 매직 넘버, 하드코딩된 값이 존재하는지 점검.
  1. 성능 및 효율성
  • 불필요한 DB 쿼리 호출, N+1 문제 가능성이 있는지 확인.
  • Stream, loop, recursion 사용 시 시간복잡도/메모리 효율성을 고려했는지.
  • 캐시 적용 가능성이 있거나, 과도한 연산이 반복되는 구간이 있는지.
  1. 트랜잭션 관리
  • @transactional이 필요한 메소드에 누락되지 않았는지.
  • 읽기 전용 트랜잭션(readOnly = true)을 적절히 사용했는지.
  • DB 일관성, 롤백 정책이 올바른지 검토.
  1. 입력 검증 및 보안
  • @Valid, Bean Validation 등을 통한 입력값 검증이 되어 있는지.
  • 비밀번호, 토큰 등 민감한 정보가 로깅되지 않는지.
  1. 테스트
  • 단위 테스트가 충분히 작성되었는지, 핵심 로직의 검증이 누락되지 않았는지.
  • Mocking을 통한 독립 테스트 구조를 유지했는지.
  • 경계값 테스트, 예외 케이스 테스트가 포함되어 있는지.
  1. 구조 및 설계
  • Controller, Service, Repository 등 계층 구조가 올바르게 나뉘어 있는지.
  • DTO, Entity, Domain 객체 간 변환 로직이 명확하고 중복되지 않는지.
  • Config 클래스에서 Bean 등록이 과도하거나 순환 참조 위험이 없는지.

Files:

  • src/main/java/umc/teumteum/server/domain/report/service/ReportServiceImpl.java
  • src/main/java/umc/teumteum/server/domain/report/dto/ReportResponseDto.java
  • src/main/java/umc/teumteum/server/domain/report/converter/ReportConverter.java
  • src/main/java/umc/teumteum/server/domain/report/exception/status/ReportErrorStatus.java
🧬 Code graph analysis (2)
src/main/java/umc/teumteum/server/domain/report/service/ReportServiceImpl.java (2)
src/main/java/umc/teumteum/server/domain/report/dto/ReportResponseDto.java (1)
  • ReportResponseDto (13-97)
src/main/java/umc/teumteum/server/domain/report/converter/ReportConverter.java (1)
  • ReportConverter (13-70)
src/main/java/umc/teumteum/server/domain/report/converter/ReportConverter.java (1)
src/main/java/umc/teumteum/server/domain/report/dto/ReportResponseDto.java (1)
  • ReportResponseDto (13-97)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Continuous Integration
  • GitHub Check: Continuous Integration
🔇 Additional comments (4)
src/main/java/umc/teumteum/server/domain/report/exception/status/ReportErrorStatus.java (1)

13-16: 에러 코드 체계화가 잘 구현되었습니다.

404 Not Found 관련 에러들이 REPORT404x 코드 체계로 체계적으로 통일되어 있으며, 새로 추가된 REPORT_NOT_FOUND (REPORT4043)는 ReportServiceImpl의 getReportDetail() 메소드에서 실제로 활용되고 있습니다.

ReportException은 GeneralException을 상속하여 ExceptionAdvice의 @ExceptionHandler(value = GeneralException.class)를 통해 중앙집중식으로 처리되므로, 새로운 에러 코드들이 API 응답에 올바르게 매핑됩니다. 에러 메시지도 사용자 친화적이며 민감 정보가 노출되지 않습니다.

src/main/java/umc/teumteum/server/domain/report/service/ReportServiceImpl.java (1)

97-100: LGTM! Fail-Fast 검증 로직 추가

TEUM_REQUEST 타입인데 teumRequest가 null인 경우를 사전에 차단하여 NPE를 방지하는 좋은 방어 로직입니다.

src/main/java/umc/teumteum/server/domain/report/converter/ReportConverter.java (1)

33-55: LGTM! 안전한 null 처리와 명확한 DTO 변환 로직

Optional을 활용한 안전한 피신고자 특정 로직과 null 발생 시 기본값("알 수 없음") 처리가 잘 구현되어 있습니다.

src/main/java/umc/teumteum/server/domain/report/dto/ReportResponseDto.java (1)

1-97: LGTM! 일관된 DTO 구조와 명확한 문서화

이전 리뷰에서 지적되었던 Lombok 어노테이션(@NoArgsConstructor, @AllArgsConstructor) 누락 이슈가 모두 해결되었습니다 (lines 52-53, 65-66, 81-82).

모든 중첩 DTO 클래스들이 일관된 패턴을 따르고 있으며, Swagger 문서화도 예시와 함께 잘 작성되어 있습니다. Jackson 직렬화/역직렬화 및 테스트 시 안정적으로 동작할 것으로 판단됩니다.

Based on coding guidelines: 구조 및 설계 - DTO 객체 간 변환 로직이 명확하고 중복되지 않음

Comment on lines +18 to +23
// 제한 및 검증 관련 (400 Bad Request)
REPORT_SELF_NOT_ALLOWED(HttpStatus.BAD_REQUEST, "REPORT4001", "자기 자신은 신고할 수 없습니다."),
REPORT_OTHER_REASON_REQUIRED(HttpStatus.BAD_REQUEST, "REPORT4002", "기타 사유 선택 시, 구체적인 내용을 입력해야 합니다."),
REPORT_INVALID_TARGET_TYPE(HttpStatus.BAD_REQUEST, "REPORT4003", "지원하지 않는 신고 대상입니다."),
REPORT_INVALID_STATUS(HttpStatus.BAD_REQUEST, "REPORT4004", "대기 중인 요청만 신고할 수 있습니다."),
REPORT_ALREADY_EXISTS(HttpStatus.BAD_REQUEST, "REPORT4005", "이미 신고한 대상입니다."), // 중복 신고 방지용 추가
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Find where REPORT_ALREADY_EXISTS is actually used
echo "=== Searching for REPORT_ALREADY_EXISTS usage ==="
rg -n 'REPORT_ALREADY_EXISTS' --type=java

echo -e "\n=== Searching for duplicate check methods in Report-related files ==="
# Search for exists/duplicate check patterns
rg -n 'existsBy|findBy.*Report.*Report' --type=java -g '*Report*'

echo -e "\n=== Searching for createReport or saveReport methods ==="
ast-grep --pattern 'public $_ create($$$) { $$$ }' || rg -n 'public.*create.*Report.*{' --type=java -A 10

Repository: UMC8-TeumTeum/BE

Length of output: 558


🏁 Script executed:

#!/bin/bash

# Search more broadly for Report service and repository patterns
echo "=== Looking for ReportRepository ==="
fd -n '*Repository*' --type=f -e java | head -20

echo -e "\n=== Looking for ReportService ==="
fd -n '*Service*' --type=f -e java | head -20

Repository: UMC8-TeumTeum/BE

Length of output: 610


🏁 Script executed:

#!/bin/bash

# Find the exact files
echo "=== Locating Report-related repository and service files ==="
find . -type f -name '*Report*Repository.java' 2>/dev/null
find . -type f -name '*Report*Service.java' 2>/dev/null

Repository: UMC8-TeumTeum/BE

Length of output: 369


🏁 Script executed:

#!/bin/bash

echo "=== ReportRepository content ==="
cat -n ./src/main/java/umc/teumteum/server/domain/report/repository/ReportRepository.java

echo -e "\n=== ReportService content ==="
cat -n ./src/main/java/umc/teumteum/server/domain/report/service/ReportService.java

Repository: UMC8-TeumTeum/BE

Length of output: 1402


🏁 Script executed:

#!/bin/bash

echo "=== Finding ReportService implementation ==="
find ./src -type f -name '*ReportService*.java' | grep -v interface

echo -e "\n=== Searching for createReport implementation ==="
rg -n 'createReport' --type=java -B 3 -A 15

Repository: UMC8-TeumTeum/BE

Length of output: 4644


🏁 Script executed:

#!/bin/bash

echo "=== Full ReportServiceImpl content ==="
cat -n ./src/main/java/umc/teumteum/server/domain/report/service/ReportServiceImpl.java

echo -e "\n=== Checking if REPORT_ALREADY_EXISTS is thrown anywhere ==="
rg -n 'REPORT_ALREADY_EXISTS|ReportErrorStatus' --type=java -g '*Report*'

Repository: UMC8-TeumTeum/BE

Length of output: 9031


REPORT_ALREADY_EXISTS 에러 코드가 정의되었으나 실제 중복 신고 방지 로직이 구현되지 않았습니다.

ReportServiceImpl.createReport() 메서드에는 중복 신고 검증이 전혀 없습니다. 현재 구현된 검증은 신고 사유, 기타 사유 내용, 자기 신고 방지, 대상 유형만 있고, 동일 신고자가 동일 대상을 이미 신고했는지 확인하는 로직이 없습니다.

필수 조치:

  1. ReportRepository에 중복 신고 확인 메서드 추가 (예: existsByReporterAndTargetUserAndTargetType())
  2. ReportServiceImpl.createReport()에서 신고 저장 전 중복 여부 확인 로직 구현
  3. 중복 신고 시 REPORT_ALREADY_EXISTS 예외 발생

현재 상태로는 동일 사용자가 같은 대상을 여러 번 신고할 수 있습니다.

🤖 Prompt for AI Agents
In
src/main/java/umc/teumteum/server/domain/report/exception/status/ReportErrorStatus.java
around lines 18 to 23, REPORT_ALREADY_EXISTS is defined but duplicate-report
prevention is not implemented; add a repository method to detect duplicates
(e.g., existsByReporterAndTargetUserAndTargetType or appropriate signature for
your domain), call that method in ReportServiceImpl.createReport() before saving
a new report, and if it returns true throw the REPORT_ALREADY_EXISTS exception
(use the existing error status to build the exception) so the service rejects
duplicate reports.

@yangjiae12 yangjiae12 merged commit 08960ce into develop Dec 31, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 관리자용 신고 상세 조회 API 구현

2 participants