Skip to content

Conversation

@pokerbearkr
Copy link
Contributor

@pokerbearkr pokerbearkr commented Jun 21, 2025


작업 내용

  • 신고 기능 개발(유저 신고, 문제 신고)
  • 신고 목록 조회
  • 특정 신고 조회
  • 신고 상태 수정

변경 사항

  • 신고 도메인 개발

image
image

  • 신고 타입과 목록입니다.

트러블 슈팅


해결해야 할 문제

  • 후에 Role이 Admin인 사람만 목록조회, 변경 API사용가능하게 수정예정
  • 신고한 유저가 자기가 신고한거 처리내역 조회 가능하게 추가

참고 사항

  • 기타 공유하고 싶은 정보나 참고한 문서(링크 등)가 있다면 작성해주세요.

코드 리뷰 전 확인 체크리스트

  • 불필요한 콘솔 로그, 주석 제거
  • 커밋 메시지 컨벤션 준수 (type : )
  • 기능 정상 동작 확인

Summary by CodeRabbit

Summary by CodeRabbit

  • 신규 기능
    • 신고 기능이 추가되어 사용자가 신고를 제출할 수 있습니다.
    • 신고 내역을 관리자가 조회, 상세 확인, 상태 변경할 수 있는 관리용 API가 추가되었습니다.
  • 개선 사항
    • 신고 대상, 타입, 상태 등 다양한 정보를 포함하는 신고 관련 응답 구조가 개선되었습니다.
    • 신고 상태 및 타입에 새로운 값이 추가되었습니다.
    • 사용자가 자기 자신을 신고하는 것을 방지하는 검증 로직이 추가되었습니다.
  • 기타
    • 애플리케이션 이름이 "min"에서 "ezcode"로 변경되었습니다.

@pokerbearkr pokerbearkr added the enhancement New feature or request label Jun 21, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jun 21, 2025

## Walkthrough

신고 기능을 위한 도메인, 서비스, 컨트롤러, DTO, 레포지토리 등 전반적인 구조가 새롭게 추가 및 확장되었습니다. 신고 대상, 타입, 상태 등 엔티티 구조가 세분화되었으며, 신고 생성, 목록 조회, 상세 조회, 상태 변경 등 주요 API와 서비스 로직이 구현되었습니다.

## Changes

| 파일/경로 요약 | 변경 내용 요약 |
|---|---|
| .../report/dto/ReportChangeResponse.java<br>.../ReportDetailResponse.java<br>.../ReportListResponse.java<br>.../ReportRequest.java<br>.../ReportResponse.java<br>.../ReportStatusUpdateRequest.java | 신고 관련 DTO 및 요청/응답 record, 클래스 신규 추가 (상태 변경, 상세, 목록, 요청, 응답 등) |
| .../report/port/ReportRepository.java | 패키지 선언 후 공백 한 줄 추가 (기능 변화 없음) |
| .../report/service/ReportService.java | 신고 생성, 목록/상세 조회, 상태 변경을 담당하는 서비스 클래스 및 메서드 신규 추가 |
| .../domain/report/model/Report.java | 신고 엔티티 구조 변경: 신고 대상(User) → targetId(Long), targetType(enum)로 분리, 생성자 및 상태 변경 메서드 추가, imageUrl nullable 변경 등 |
| .../domain/report/model/ReportStatus.java | 상태 enum의 주석 제거, 예외 메시지 한글화, @JsonCreator 추가 |
| .../domain/report/model/ReportTargetType.java | 신고 대상 타입 enum 신설 (USER, PROBLEM, POST, COMMENT, OTHER) |
| .../domain/report/model/ReportType.java | 신고 타입 enum에 PROBLEM_ERROR 추가, from 메서드 파라미터명 및 예외 메시지 한글화 |
| .../domain/report/repository/ReportRepository.java | Spring Data JPA 기반 신고 레포지토리 인터페이스 신규 추가 |
| .../domain/report/service/ReportDomainService.java | 서비스 클래스화(@Service), 자기 자신 신고 방지 로직 추가 |
| .../presentation/ReportController.java | 기존 빈 컨트롤러 클래스 삭제 |
| .../presentation/report/ReportAdminController.java | 신고 관리자용 REST 컨트롤러 신규 추가: 목록, 상세, 상태 변경 API |
| .../presentation/report/ReportController.java | 신고 등록용 REST 컨트롤러 신규 추가: POST /api/reports |
| .../resources/application.properties | spring.application.name 값을 "min" → "ezcode"로 변경 |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant 사용자
    participant ReportController
    participant ReportService
    participant UserRepository
    participant ReportRepository

    사용자->>ReportController: POST /api/reports (신고 등록)
    ReportController->>ReportService: submitReport(reporterId, request)
    ReportService->>UserRepository: findById(reporterId)
    UserRepository-->>ReportService: User 반환
    ReportService->>ReportRepository: save(Report)
    ReportRepository-->>ReportService: 저장된 Report 반환
    ReportService-->>ReportController: ReportResponse 반환
    ReportController-->>사용자: 신고 결과 응답
sequenceDiagram
    participant 관리자
    participant ReportAdminController
    participant ReportService
    participant ReportRepository

    관리자->>ReportAdminController: GET /api/reports/admin (신고 목록)
    ReportAdminController->>ReportService: getReportList(pageable)
    ReportService->>ReportRepository: findAll(pageable)
    ReportRepository-->>ReportService: Page<Report> 반환
    ReportService-->>ReportAdminController: Page<ReportListResponse> 반환
    ReportAdminController-->>관리자: 신고 목록 응답

    관리자->>ReportAdminController: PATCH /api/reports/admin/{id}/status (상태 변경)
    ReportAdminController->>ReportService: updateReportStatus(reportId, request)
    ReportService->>ReportRepository: findById(reportId)
    ReportRepository-->>ReportService: Report 반환
    ReportService-->>ReportAdminController: 상태 변경 결과 반환
    ReportAdminController-->>관리자: 변경 메시지 응답
Loading

Suggested reviewers

  • Kimminu7
  • minjee2758
  • thezz9
  • NCookies

Poem

🐇
신고의 길이 새로 열렸네
대상, 타입, 상태 모두 세분화
컨트롤러와 서비스, DTO도 반짝
관리자는 목록을, 사용자는 신고를
바뀐 이름과 함께,
깔끔한 코드밭에서
토끼는 뛰논다!
🥕


<!-- walkthrough_end -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 02972240190c135adbbd1fff43f6402451c5eda5 and 01bcacb03cd6587470c6d56fc97f9e75f1fe0428.

</details>

<details>
<summary>📒 Files selected for processing (4)</summary>

* `src/main/java/org/ezcode/codetest/application/report/dto/ReportStatusUpdateRequest.java` (1 hunks)
* `src/main/java/org/ezcode/codetest/application/report/service/ReportService.java` (1 hunks)
* `src/main/java/org/ezcode/codetest/domain/report/model/Report.java` (1 hunks)
* `src/main/java/org/ezcode/codetest/domain/report/model/ReportStatus.java` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (3)</summary>

* src/main/java/org/ezcode/codetest/domain/report/model/ReportStatus.java
* src/main/java/org/ezcode/codetest/application/report/service/ReportService.java
* src/main/java/org/ezcode/codetest/domain/report/model/Report.java

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (1)</summary>

* GitHub Check: build

</details>

<details>
<summary>🔇 Additional comments (1)</summary><blockquote>

<details>
<summary>src/main/java/org/ezcode/codetest/application/report/dto/ReportStatusUpdateRequest.java (1)</summary>

`1-13`: 다음 스크립트로 `ReportStatus.java`에서 `from()` 메서드 구현을 다시 확인해 주세요:


```shell
#!/bin/bash
# ReportStatus.java 경로 찾기
REPORT_STATUS_PATH=$(rg -l "enum ReportStatus" -g "*.java" | head -n1)
echo "ReportStatus.java 경로: $REPORT_STATUS_PATH"
# static from() 메서드 구현 확인
rg -n "static ReportStatus from" "$REPORT_STATUS_PATH" -A20
✨ 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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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

🧹 Nitpick comments (9)
src/main/java/org/ezcode/codetest/application/report/dto/ReportStatusUpdateRequest.java (1)

5-8: 추가 유효성 검증을 고려해보세요

현재 @NotBlank만 적용되어 있지만, 유효한 상태값인지 검증하는 커스텀 검증 어노테이션을 추가하는 것을 고려해보세요. 예를 들어 @ValidReportStatus와 같은 어노테이션을 만들어 ReportStatus enum의 유효한 값만 허용하도록 할 수 있습니다.

public record ReportStatusUpdateRequest(
+       @ValidReportStatus
        @NotBlank
        String newStatus   // 예시 RESOLVED(해결됨), REJECTED(거절)
) {}
src/main/java/org/ezcode/codetest/application/report/dto/ReportDetailResponse.java (1)

3-14: API 문서화 및 타입 일관성을 개선하세요

  1. Swagger 문서화 어노테이션 추가를 고려해보세요.
  2. 날짜 필드의 타입 일관성을 확인하세요. 다른 DTO들과 동일한 패턴을 사용하는지 검토가 필요합니다.
+@Schema(name = "ReportDetailResponse", description = "신고 상세 조회 응답")
public record ReportDetailResponse(
+       @Schema(description = "신고 ID")
        Long reportId,
+       @Schema(description = "신고자 이메일")
        String reporterEmail,
        // ... 다른 필드들에도 @Schema 추가
        String createdAt,
        String modifiedAt
) {}
src/main/java/org/ezcode/codetest/application/report/dto/ReportListResponse.java (1)

3-12: API 문서화를 추가하세요

목록 조회용 DTO로서 적절한 필드 구성을 가지고 있지만, API 문서화를 위한 Swagger 어노테이션 추가를 고려해보세요.

+@Schema(name = "ReportListResponse", description = "신고 목록 조회 응답")
public record ReportListResponse(
+       @Schema(description = "신고 ID")
        Long reportId,
+       @Schema(description = "신고자 이메일")
        String reporterEmail,
        // ... 다른 필드들에도 @Schema 추가
        String createdAt
) {}
src/main/java/org/ezcode/codetest/presentation/report/ReportController.java (1)

12-15: 중복된 import문을 정리해주세요.

개별 import와 와일드카드 import가 중복되어 있습니다.

다음과 같이 정리해주세요:

-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.*;
src/main/java/org/ezcode/codetest/presentation/report/ReportAdminController.java (4)

22-29: 페이징 기본값 확인 필요

기본 페이지 크기가 10으로 설정되어 있습니다. 관리자 페이지에서는 더 많은 데이터를 한 번에 볼 필요가 있을 수 있습니다.

관리자용이므로 페이지 크기를 늘리는 것을 고려해보세요:

-            @PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC)
+            @PageableDefault(size = 20, sort = "createdAt", direction = Sort.Direction.DESC)

23-29: 페이징 파라미터 검증을 추가하는 것이 좋습니다.

페이징 기본값은 적절하지만, 최대 크기 제한을 추가하여 성능 문제를 예방할 수 있습니다.

-            @PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC)
+            @PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC)
+            @Parameter(description = "페이지 정보 (최대 100개)")
             Pageable pageable) {
+        
+        if (pageable.getPageSize() > 100) {
+            pageable = PageRequest.of(pageable.getPageNumber(), 100, pageable.getSort());
+        }

48-49: 불필요한 빈 줄을 제거하세요.

파일 끝의 불필요한 빈 줄들을 제거해주세요.

-

-}
+}

38-46: 응답 메시지 생성 시 사용자 입력 검증을 강화하세요.

44번 라인에서 request.newStatus()를 직접 문자열 연결에 사용하고 있습니다. 비록 @Valid 어노테이션으로 검증하고 있지만, 응답 메시지에 포함되기 전에 추가적인 검증이나 이스케이프 처리를 고려해보세요.

- String message = request.newStatus() + "로 변경 완료되었습니다.";
+ String message = "상태가 " + request.newStatus() + "로 변경 완료되었습니다.";
src/main/java/org/ezcode/codetest/application/report/service/ReportService.java (1)

55-55: 성능 최적화 고려사항

findAll(pageable)을 사용하고 있는데, 데이터가 많아질 경우 성능 이슈가 있을 수 있습니다. 필터링이나 검색 기능이 필요할 수 있습니다.

향후 확장성을 위해 다음과 같은 개선을 고려해보세요:

  • 상태별 필터링
  • 날짜 범위 검색
  • 신고 타입별 필터링
  • 인덱스 최적화

현재는 승인하지만, 사용량이 늘어나면 쿼리 최적화가 필요할 것입니다.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db550fc and 1f28724.

📒 Files selected for processing (18)
  • src/main/java/org/ezcode/codetest/application/report/dto/ReportChangeResponse.java (1 hunks)
  • src/main/java/org/ezcode/codetest/application/report/dto/ReportDetailResponse.java (1 hunks)
  • src/main/java/org/ezcode/codetest/application/report/dto/ReportListResponse.java (1 hunks)
  • src/main/java/org/ezcode/codetest/application/report/dto/ReportRequest.java (1 hunks)
  • src/main/java/org/ezcode/codetest/application/report/dto/ReportResponse.java (1 hunks)
  • src/main/java/org/ezcode/codetest/application/report/dto/ReportStatusUpdateRequest.java (1 hunks)
  • src/main/java/org/ezcode/codetest/application/report/port/ReportRepository.java (1 hunks)
  • src/main/java/org/ezcode/codetest/application/report/service/ReportService.java (1 hunks)
  • src/main/java/org/ezcode/codetest/domain/report/model/Report.java (1 hunks)
  • src/main/java/org/ezcode/codetest/domain/report/model/ReportStatus.java (1 hunks)
  • src/main/java/org/ezcode/codetest/domain/report/model/ReportTargetType.java (1 hunks)
  • src/main/java/org/ezcode/codetest/domain/report/model/ReportType.java (2 hunks)
  • src/main/java/org/ezcode/codetest/domain/report/repository/ReportRepository.java (1 hunks)
  • src/main/java/org/ezcode/codetest/domain/report/service/ReportDomainService.java (1 hunks)
  • src/main/java/org/ezcode/codetest/presentation/ReportController.java (0 hunks)
  • src/main/java/org/ezcode/codetest/presentation/report/ReportAdminController.java (1 hunks)
  • src/main/java/org/ezcode/codetest/presentation/report/ReportController.java (1 hunks)
  • src/main/resources/application.properties (1 hunks)
💤 Files with no reviewable changes (1)
  • src/main/java/org/ezcode/codetest/presentation/ReportController.java
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (22)
src/main/java/org/ezcode/codetest/application/report/dto/ReportChangeResponse.java (1)

6-9: 단일 메시지 응답 DTO 검증
ReportChangeResponse는 변경 상태에 대한 단일 message 필드를 갖고 있으며, Lombok의 @Getter@AllArgsConstructor로 간결하게 구현되었습니다. 직렬화 전용 응답 DTO로서 적절하며, 추가 애노테이션 없이도 Jackson이 getter 기반으로 직렬화할 수 있습니다.

src/main/resources/application.properties (1)

4-4: 애플리케이션 이름 변경 확인
spring.application.name을 기존 "min"에서 "ezcode"로 변경했습니다. 로깅, 모니터링(Actuator) 및 분산 트레이싱 시스템에 올바르게 반영되는지 검증이 필요합니다.

src/main/java/org/ezcode/codetest/domain/report/model/ReportTargetType.java (1)

3-9: 리포트 대상 타입(Enum) 검토
USER, PROBLEM, POST, COMMENT, OTHER 등 필요한 대상 타입이 모두 정의되었습니다. 문자열 매핑 시 IllegalArgumentException이 발생할 수 있으므로, 서비스 계층에서 사용자 입력을 ReportTargetType으로 변환·검증하는 로직이 완전한지 확인하세요.

src/main/java/org/ezcode/codetest/domain/report/repository/ReportRepository.java (1)

6-7: 도메인 레포지토리 정의 확인
ReportRepository extends JpaRepository<Report, Long>로 표준 CRUD 및 페이징 기능을 제공하며, Spring Data JPA가 자동으로 빈으로 등록합니다. 추가 애노테이션 없이도 정상 작동합니다.

src/main/java/org/ezcode/codetest/domain/report/model/ReportStatus.java (2)

9-13: 한국어 설명 추가가 적절합니다

각 상태값에 대한 한국어 설명이 명확하게 추가되어 사용자 친화적인 인터페이스 구현에 도움이 됩니다.


20-25: 예외 메시지의 한국어 변경이 적절합니다

사용자에게 더 친숙한 한국어 오류 메시지로 변경되어 사용성이 향상되었습니다. 대소문자를 구분하지 않는 변환 로직도 올바르게 구현되어 있습니다.

src/main/java/org/ezcode/codetest/application/report/dto/ReportResponse.java (1)

5-12: 잘 구현된 DTO입니다

Swagger 문서화가 적절히 적용되어 있고, 신고 응답에 필요한 핵심 정보들이 잘 구성되어 있습니다. 다른 DTO들의 문서화 참고 모델로 활용할 수 있습니다.

src/main/java/org/ezcode/codetest/application/report/dto/ReportRequest.java (1)

6-20: DTO 구조와 검증이 적절하게 구현되었습니다.

레코드 클래스를 사용한 불변 DTO 설계가 좋고, 필수 필드에 대한 검증 어노테이션도 적절히 적용되었습니다.

src/main/java/org/ezcode/codetest/domain/report/model/ReportType.java (1)

27-32: from() 메서드 리팩토링이 깔끔하게 구현되었습니다.

파라미터명 변경과 에러 메시지 한국어 적용이 적절합니다.

src/main/java/org/ezcode/codetest/domain/report/service/ReportDomainService.java (1)

8-17: 도메인 서비스 구현이 적절합니다.

비즈니스 규칙을 도메인 레이어에서 처리하고, 자기 자신 신고 방지 로직이 명확하게 구현되었습니다.

src/main/java/org/ezcode/codetest/presentation/report/ReportController.java (1)

25-31: REST 엔드포인트 구현이 적절합니다.

인증 처리, 요청 검증, 응답 구조가 잘 구현되었습니다.

src/main/java/org/ezcode/codetest/domain/report/model/Report.java (3)

24-29: 엔티티 리팩토링이 적절하게 구현되었습니다.

target 필드를 targetIdtargetType으로 분리하여 다양한 대상 타입을 지원할 수 있도록 개선되었습니다.


43-52: 생성자 업데이트가 새로운 필드 구조에 맞게 잘 구현되었습니다.

새로운 필드들에 대한 초기화와 기본 상태 설정이 적절합니다.


54-57: 상태 변경 메서드가 적절하게 캡슐화되었습니다.

updateStatus 메서드를 통해 상태 변경 로직을 캡슐화한 것이 좋습니다.

src/main/java/org/ezcode/codetest/presentation/report/ReportAdminController.java (4)

14-19: 컨트롤러 구조 승인

표준 Spring Boot 패턴을 잘 따르고 있습니다. @RequiredArgsConstructor를 사용한 생성자 주입과 적절한 어노테이션 사용이 좋습니다.


1-19: 클래스 구조와 의존성 주입이 적절히 구현되었습니다.

Spring Boot의 모범 사례를 잘 따르고 있으며, @RequiredArgsConstructor를 사용한 생성자 주입 방식이 적절합니다.


22-29: 페이징 처리가 잘 구현되어 있습니다.

@PageableDefault를 사용하여 기본 페이지 크기와 정렬 조건을 설정한 것이 좋습니다. 생성일 기준 내림차순 정렬도 신고 관리에 적합합니다.


32-35: 단순하고 명확한 상세 조회 구현입니다.

경로 변수를 통한 ID 전달과 서비스 호출이 적절히 구현되어 있습니다.

src/main/java/org/ezcode/codetest/application/report/service/ReportService.java (4)

14-20: 서비스 클래스 구조 승인

적절한 어노테이션 사용과 의존성 주입 패턴이 잘 적용되어 있습니다.


1-20: 서비스 클래스 구조가 적절하게 설계되었습니다.

의존성 주입과 어노테이션 사용이 Spring Boot 모범 사례를 잘 따르고 있습니다.


30-32: 자기 신고 방지 로직이 잘 구현되었습니다.

비즈니스 규칙을 명확하게 검증하고 있어 좋습니다.


53-66: 트랜잭션 설정과 페이징 처리가 적절합니다.

읽기 전용 트랜잭션 설정과 스트림을 활용한 DTO 매핑이 잘 구현되어 있습니다.

Comment on lines +3 to 5

public interface ReportRepository {
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

포트 인터페이스 구현 누락
application.report.port.ReportRepository는 서비스 레이어에서 의존할 포트 정의로 보이나, 메서드 시그니처가 없고 이를 구현한 인프라스트럭처 어댑터도 존재하지 않습니다. 이대로면 의존성 주입 시 빈 충돌 또는 NoSuchBeanDefinitionException이 발생할 수 있습니다.

🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/application/report/port/ReportRepository.java
at lines 3 to 5, the ReportRepository interface is empty and lacks method
signatures, and there is no implementing infrastructure adapter. Define
appropriate method signatures in this interface that represent the required
report-related operations, then create a corresponding implementation class in
the infrastructure layer to implement these methods. This will ensure proper
dependency injection and avoid bean definition errors.

Comment on lines +37 to +46
// 신고 상태 변경
@PatchMapping("/{reportId}/status")
public ResponseEntity<ReportChangeResponse> changeStatus(
@PathVariable Long reportId,
@RequestBody @Valid ReportStatusUpdateRequest request) {

reportService.updateReportStatus(reportId, request);
String message = request.newStatus() + "로 변경 완료되었습니다.";
return ResponseEntity.ok(new ReportChangeResponse(message));
}
Copy link

@coderabbitai coderabbitai bot Jun 21, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

응답 메시지 생성 로직 개선 제안

컨트롤러에서 응답 메시지를 직접 생성하고 있습니다. 이는 관심사 분리 원칙에 맞지 않으며, 메시지 포맷 변경 시 여러 곳을 수정해야 할 수 있습니다.

메시지 생성을 서비스 레이어로 이동하거나 별도의 메시지 팩토리를 사용하는 것을 고려해보세요:

-        reportService.updateReportStatus(reportId, request);
-        String message = request.newStatus() + "로 변경 완료되었습니다.";
-        return ResponseEntity.ok(new ReportChangeResponse(message));
+        ReportChangeResponse response = reportService.updateReportStatus(reportId, request);
+        return ResponseEntity.ok(response);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/presentation/report/ReportAdminController.java
around lines 37 to 46, the response message is being created directly in the
controller, which violates separation of concerns. To fix this, move the message
creation logic into the service layer or a dedicated message factory. Modify the
service method to return the message or a response object containing the
message, and update the controller to use this returned value instead of
constructing the message itself.

🛠️ Refactor suggestion

응답 메시지 구성 방식을 개선해야 합니다.

문자열 연결을 통한 메시지 구성보다는 MessageSource를 활용하거나 상수를 사용하는 것이 좋습니다. 또한 경로 변수 검증도 추가해야 합니다.

+import jakarta.validation.constraints.Positive;

     @PatchMapping("/{reportId}/status")
     public ResponseEntity<ReportChangeResponse> changeStatus(
-            @PathVariable Long reportId,
+            @PathVariable @Positive Long reportId,
             @RequestBody @Valid ReportStatusUpdateRequest request) {

         reportService.updateReportStatus(reportId, request);
-        String message = request.newStatus() + "로 변경 완료되었습니다.";
+        String message = String.format("신고 상태가 %s로 변경되었습니다.", request.newStatus());
         return ResponseEntity.ok(new ReportChangeResponse(message));
     }
📝 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
// 신고 상태 변경
@PatchMapping("/{reportId}/status")
public ResponseEntity<ReportChangeResponse> changeStatus(
@PathVariable Long reportId,
@RequestBody @Valid ReportStatusUpdateRequest request) {
reportService.updateReportStatus(reportId, request);
String message = request.newStatus() + "로 변경 완료되었습니다.";
return ResponseEntity.ok(new ReportChangeResponse(message));
}
import jakarta.validation.constraints.Positive;
// 신고 상태 변경
@PatchMapping("/{reportId}/status")
public ResponseEntity<ReportChangeResponse> changeStatus(
@PathVariable @Positive Long reportId,
@RequestBody @Valid ReportStatusUpdateRequest request) {
reportService.updateReportStatus(reportId, request);
String message = String.format("신고 상태가 %s로 변경되었습니다.", request.newStatus());
return ResponseEntity.ok(new ReportChangeResponse(message));
}
🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/presentation/report/ReportAdminController.java
around lines 37 to 46, improve the response message construction by replacing
string concatenation with a MessageSource-based approach or using predefined
constants for localization and maintainability. Additionally, add validation for
the reportId path variable to ensure it meets expected criteria before
processing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@positive가 뭐야?
양수만 들어오게 validation 하는건가?

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines 94 to 95
ReportStatus newStatus = ReportStatus.valueOf(req.newStatus().toUpperCase());
report.updateStatus(newStatus);
Copy link

@coderabbitai coderabbitai bot Jun 21, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

Enum 변환 예외 처리 부족

valueOf() 메서드 사용 시 예외 처리가 없어 잘못된 상태값 전달 시 IllegalArgumentException이 발생할 수 있습니다.

예외 처리를 추가하세요:

-        ReportStatus newStatus = ReportStatus.valueOf(req.newStatus().toUpperCase());
+        ReportStatus newStatus;
+        try {
+            newStatus = ReportStatus.valueOf(req.newStatus().toUpperCase());
+        } catch (IllegalArgumentException e) {
+            throw new IllegalArgumentException("유효하지 않은 신고 상태입니다: " + req.newStatus());
+        }
🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/application/report/service/ReportService.java
around lines 94 to 95, the use of ReportStatus.valueOf() lacks exception
handling, which can cause an IllegalArgumentException if an invalid status
string is passed. Add a try-catch block around the valueOf call to catch
IllegalArgumentException and handle it appropriately, such as logging the error
or throwing a custom exception with a clear message.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ㅇㅋ 해결했어

Copy link

Choose a reason for hiding this comment

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

@pokerbearkr 좋습니다! enum 변환 예외 처리 문제를 해결해 주셔서 감사합니다. 🎉


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

Comment on lines +30 to +32
if (targetType == ReportTargetType.USER && reporterId.equals(request.targetId())) {
throw new IllegalArgumentException("자기 자신은 신고할 수 없습니다.");
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

🧩 Verification correct

비즈니스 로직 검증 개선 제안

자기 자신 신고 방지 로직이 있지만, AI 요약에 따르면 ReportDomainService에 이미 이 검증 로직이 캡슐화되어 있다고 합니다. 중복 검증을 피하고 도메인 서비스를 활용하는 것이 좋겠습니다.

ReportDomainService의 존재와 검증 로직을 확인해주세요:


🏁 Script executed:

#!/bin/bash
# ReportDomainService 클래스 존재 확인 및 검증 로직 조회
fd "ReportDomainService" --type f --exec cat {}

Length of output: 642


비즈니스 로직 검증 개선 제안

자기 자신 신고 방지 로직이 있지만, AI 요약에 따르면 ReportDomainService에 이미 이 검증 로직이 캡슐화되어 있다고 합니다. 중복 검증을 피하고 도메인 서비스를 활용하는 것이 좋겠습니다.

ReportDomainService의 존재와 검증 로직을 확인해주세요:

#!/bin/bash
# ReportDomainService 클래스 존재 확인 및 검증 로직 조회
fd "ReportDomainService" --type f --exec cat {}
🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/application/report/service/ReportService.java
around lines 30 to 32, the self-report prevention logic is currently implemented
directly in the service. Since this validation is already encapsulated within
ReportDomainService, remove the duplicate check here and instead call the
appropriate validation method from ReportDomainService to handle this logic,
ensuring single responsibility and avoiding redundant validation.

Comment on lines +27 to +32
ReportTargetType targetType = ReportTargetType.valueOf(request.targetType().toUpperCase());
ReportType reportType = ReportType.from(request.reportType());

if (targetType == ReportTargetType.USER && reporterId.equals(request.targetId())) {
throw new IllegalArgumentException("자기 자신은 신고할 수 없습니다.");
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Enum 변환과 검증 로직을 개선해야 합니다.

Enum 변환에서 발생할 수 있는 예외 처리가 없고, 자기 자신 신고 방지 로직이 도메인 서비스에 있다고 명시되어 있지만 여기에 중복 구현되어 있습니다.

+import org.ezcode.codetest.domain.report.service.ReportDomainService;

@Service
@RequiredArgsConstructor
public class ReportService {

    private final UserRepository userRepository;
    private final ReportRepository reportRepository;
+   private final ReportDomainService reportDomainService;

     @Transactional
     public ReportResponse submitReport(Long reporterId, ReportRequest request) {
         User reporter = userRepository.findUserById(reporterId)
                 .orElseThrow(() -> new IllegalArgumentException("신고자를 찾을 수 없습니다."));

-        ReportTargetType targetType = ReportTargetType.valueOf(request.targetType().toUpperCase());
-        ReportType reportType      = ReportType.from(request.reportType());
-
-        if (targetType == ReportTargetType.USER && reporterId.equals(request.targetId())) {
-            throw new IllegalArgumentException("자기 자신은 신고할 수 없습니다.");
-        }
+        ReportTargetType targetType;
+        ReportType reportType;
+        
+        try {
+            targetType = ReportTargetType.valueOf(request.targetType().toUpperCase());
+            reportType = ReportType.from(request.reportType());
+        } catch (IllegalArgumentException e) {
+            throw new IllegalArgumentException("잘못된 신고 타입입니다.");
+        }
+        
+        reportDomainService.validateReportSubmission(reporterId, request.targetId(), targetType);
📝 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
ReportTargetType targetType = ReportTargetType.valueOf(request.targetType().toUpperCase());
ReportType reportType = ReportType.from(request.reportType());
if (targetType == ReportTargetType.USER && reporterId.equals(request.targetId())) {
throw new IllegalArgumentException("자기 자신은 신고할 수 없습니다.");
}
// src/main/java/org/ezcode/codetest/application/report/service/ReportService.java
import org.ezcode.codetest.domain.report.service.ReportDomainService;
@Service
@RequiredArgsConstructor
public class ReportService {
private final UserRepository userRepository;
private final ReportRepository reportRepository;
private final ReportDomainService reportDomainService;
@Transactional
public ReportResponse submitReport(Long reporterId, ReportRequest request) {
User reporter = userRepository.findUserById(reporterId)
.orElseThrow(() -> new IllegalArgumentException("신고자를 찾을 수 없습니다."));
ReportTargetType targetType;
ReportType reportType;
try {
targetType = ReportTargetType.valueOf(request.targetType().toUpperCase());
reportType = ReportType.from(request.reportType());
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("잘못된 신고 타입입니다.");
}
reportDomainService.validateReportSubmission(reporterId, request.targetId(), targetType);
// ... 기존 로직 계속 (e.g., build & save Report, return response) ...
}
}
🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/application/report/service/ReportService.java
around lines 27 to 32, the enum conversion lacks exception handling and the
self-report prevention logic is duplicated here despite being in the domain
service. To fix this, add proper try-catch blocks or use safe enum conversion
methods to handle invalid values gracefully, and remove the self-report
validation from this service to avoid duplication, relying solely on the domain
service for that check.

🛠️ Refactor suggestion

Enum 변환 시 예외 처리를 개선해야 합니다.

valueOf() 메소드는 잘못된 문자열이 전달될 경우 IllegalArgumentException을 발생시킵니다. 더 명확한 에러 메시지를 제공하거나 커스텀 예외를 사용하는 것을 고려해보세요.

- ReportTargetType targetType = ReportTargetType.valueOf(request.targetType().toUpperCase());
- ReportType reportType      = ReportType.from(request.reportType());
+ ReportTargetType targetType;
+ ReportType reportType;
+ 
+ try {
+     targetType = ReportTargetType.valueOf(request.targetType().toUpperCase());
+     reportType = ReportType.from(request.reportType());
+ } catch (IllegalArgumentException e) {
+     throw new IllegalArgumentException("유효하지 않은 신고 타입입니다: " + e.getMessage());
+ }
📝 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
ReportTargetType targetType = ReportTargetType.valueOf(request.targetType().toUpperCase());
ReportType reportType = ReportType.from(request.reportType());
if (targetType == ReportTargetType.USER && reporterId.equals(request.targetId())) {
throw new IllegalArgumentException("자기 자신은 신고할 수 없습니다.");
}
ReportTargetType targetType;
ReportType reportType;
try {
targetType = ReportTargetType.valueOf(request.targetType().toUpperCase());
reportType = ReportType.from(request.reportType());
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("유효하지 않은 신고 타입입니다: " + e.getMessage());
}
if (targetType == ReportTargetType.USER && reporterId.equals(request.targetId())) {
throw new IllegalArgumentException("자기 자신은 신고할 수 없습니다.");
}
🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/application/report/service/ReportService.java
around lines 27 to 32, the use of ReportTargetType.valueOf() can throw an
IllegalArgumentException with a generic message if the input string is invalid.
To improve this, catch the exception thrown by valueOf(), then throw a new
exception with a clearer, custom error message or use a custom exception type to
indicate the invalid enum conversion more explicitly.

Comment on lines +54 to +66
public Page<ReportListResponse> getReportList(Pageable pageable) {
return reportRepository.findAll(pageable)
.map(r -> new ReportListResponse(
r.getId(),
r.getReporter().getEmail(),
r.getTargetId(),
r.getTargetType().name(),
r.getReportType().name(),
r.getReportStatus().name(),
r.getMessage(),
r.getCreatedAt().toString()
));
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Null 안전성과 데이터 포맷팅을 개선해야 합니다.

Reporter 이메일에 대한 null 체크가 없고, 날짜를 문자열로 변환할 때 적절한 포맷팅이 필요합니다.

+import java.time.format.DateTimeFormatter;
+
+    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

     @Transactional(readOnly = true)
     public Page<ReportListResponse> getReportList(Pageable pageable) {
         return reportRepository.findAll(pageable)
                 .map(r -> new ReportListResponse(
                         r.getId(),
-                        r.getReporter().getEmail(),
+                        r.getReporter() != null ? r.getReporter().getEmail() : "알 수 없음",
                         r.getTargetId(),
                         r.getTargetType().name(),
                         r.getReportType().name(),
                         r.getReportStatus().name(),
                         r.getMessage(),
-                        r.getCreatedAt().toString()
+                        r.getCreatedAt().format(DATE_FORMATTER)
                 ));
     }
📝 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
public Page<ReportListResponse> getReportList(Pageable pageable) {
return reportRepository.findAll(pageable)
.map(r -> new ReportListResponse(
r.getId(),
r.getReporter().getEmail(),
r.getTargetId(),
r.getTargetType().name(),
r.getReportType().name(),
r.getReportStatus().name(),
r.getMessage(),
r.getCreatedAt().toString()
));
}
import java.time.format.DateTimeFormatter;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Transactional(readOnly = true)
public Page<ReportListResponse> getReportList(Pageable pageable) {
return reportRepository.findAll(pageable)
.map(r -> new ReportListResponse(
r.getId(),
r.getReporter() != null
? r.getReporter().getEmail()
: "알 수 없음",
r.getTargetId(),
r.getTargetType().name(),
r.getReportType().name(),
r.getReportStatus().name(),
r.getMessage(),
r.getCreatedAt().format(DATE_FORMATTER)
));
}
🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/application/report/service/ReportService.java
around lines 54 to 66, add a null check for reporter email to avoid potential
NullPointerException and format the createdAt date using a proper date formatter
instead of calling toString() directly. Use Optional or conditional checks to
safely handle null reporter emails and apply a standard date format like
ISO_LOCAL_DATE_TIME for createdAt before passing it to the ReportListResponse
constructor.

r.getReportType().name(),
r.getReportStatus().name(),
r.getMessage(),
r.getCreatedAt().toString()
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

날짜 형식을 명시적으로 지정하세요.

toString() 메소드 사용 시 예측 가능한 형식이 보장되지 않습니다. 일관된 날짜 형식을 위해 DateTimeFormatter를 사용하는 것을 권장합니다.

- r.getCreatedAt().toString()
+ r.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))

클래스 상단에 다음 import를 추가해야 합니다:

import java.time.format.DateTimeFormatter;
🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/application/report/service/ReportService.java
at line 64, replace the use of r.getCreatedAt().toString() with formatting using
DateTimeFormatter to ensure a consistent and predictable date format. Import
java.time.format.DateTimeFormatter at the top of the file, define a formatter
with the desired pattern, and apply it to r.getCreatedAt() to convert the date
to a string.

Report report = reportRepository.findById(reportId)
.orElseThrow(() -> new IllegalArgumentException("신고가 존재하지 않습니다."));

ReportStatus newStatus = ReportStatus.valueOf(req.newStatus().toUpperCase());
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enum 변환 시 예외 처리 개선이 필요합니다.

앞서 submitReport 메소드에서 언급한 것과 동일한 이슈입니다. 더 명확한 에러 메시지를 제공해주세요.

- ReportStatus newStatus = ReportStatus.valueOf(req.newStatus().toUpperCase());
+ ReportStatus newStatus;
+ try {
+     newStatus = ReportStatus.valueOf(req.newStatus().toUpperCase());
+ } catch (IllegalArgumentException e) {
+     throw new IllegalArgumentException("유효하지 않은 신고 상태입니다: " + req.newStatus());
+ }
📝 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
ReportStatus newStatus = ReportStatus.valueOf(req.newStatus().toUpperCase());
ReportStatus newStatus;
try {
newStatus = ReportStatus.valueOf(req.newStatus().toUpperCase());
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("유효하지 않은 신고 상태입니다: " + req.newStatus());
}
🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/application/report/service/ReportService.java
at line 94, the conversion from string to enum using ReportStatus.valueOf can
throw an exception if the input is invalid. To improve, wrap this conversion in
a try-catch block to catch IllegalArgumentException and throw a custom exception
or return a clear error message indicating the invalid status value, similar to
the approach used in the submitReport method.

Comment on lines +83 to +84
r.getCreatedAt().toString(),
r.getModifiedAt().toString()
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

날짜 형식 통일성을 위해 DateTimeFormatter 사용을 권장합니다.

앞서 언급한 것과 동일한 이슈입니다. 일관된 날짜 형식을 위해 포맷터를 사용하세요.

- r.getCreatedAt().toString(),
- r.getModifiedAt().toString()
+ r.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
+ r.getModifiedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
📝 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
r.getCreatedAt().toString(),
r.getModifiedAt().toString()
r.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
r.getModifiedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/application/report/service/ReportService.java
around lines 83 to 84, the code converts dates to strings using toString(),
which leads to inconsistent date formats. Replace these calls with a
DateTimeFormatter instance to format the dates consistently according to a
defined pattern, ensuring uniform date representation throughout the
application.

@pokerbearkr pokerbearkr merged commit f9601ac into dev Jun 22, 2025
2 checks passed
@pokerbearkr pokerbearkr deleted the feat/report branch June 22, 2025 04:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants