[feat] 책 전체 페이지 수 및 총평 작성 가능 여부 조회 /장르별 마감 임박 및 인기 방 조회 api 구현#120
[feat] 책 전체 페이지 수 및 총평 작성 가능 여부 조회 /장르별 마감 임박 및 인기 방 조회 api 구현#120
Conversation
Walkthrough이번 변경에서는 책 전체 페이지 수 및 총평 작성 가능 여부를 조회하는 신규 API와 인기/마감 임박 방 목록 조회 API가 추가되었습니다. 이를 위해 DTO, 서비스, 매퍼, 포트, 어댑터, 컨트롤러 등이 확장 및 리팩토링되었고, 기존 참여방 관련 쿼리 DTO가 전면 교체되었습니다. 오류 코드 및 예외 처리도 일부 변경되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant RoomQueryController
participant RoomGetBookPageService
participant RoomParticipantValidator
participant BookCommandPort
participant RoomParticipantCommandPort
User->>RoomQueryController: GET /rooms/{roomId}/book-page
RoomQueryController->>RoomGetBookPageService: getBookPage(userId, roomId)
RoomGetBookPageService->>RoomParticipantValidator: validateUserIsRoomMember(userId, roomId)
RoomGetBookPageService->>BookCommandPort: getBookByRoomId(roomId)
RoomGetBookPageService->>RoomParticipantCommandPort: getRoomParticipant(userId, roomId)
RoomGetBookPageService-->>RoomQueryController: RoomGetBookPageResponse
RoomQueryController-->>User: 응답 반환
sequenceDiagram
participant User
participant RoomQueryController
participant RoomGetDeadlinePopularService
participant RoomQueryPort
participant RoomQueryMapper
User->>RoomQueryController: GET /rooms?category=문학
RoomQueryController->>RoomGetDeadlinePopularService: getDeadlineAndPopularRoomList(category, userId)
RoomGetDeadlinePopularService->>RoomQueryPort: findRoomsByCategoryOrderByDeadline(category, limit, userId)
RoomGetDeadlinePopularService->>RoomQueryPort: findRoomsByCategoryOrderByPopular(category, limit, userId)
RoomGetDeadlinePopularService->>RoomQueryMapper: toDeadlinePopularRoomDtoList(...)
RoomGetDeadlinePopularService-->>RoomQueryController: RoomGetDeadlinePopularResponse
RoomQueryController-->>User: 응답 반환
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/main/java/konkuk/thip/room/application/service/validator/RoomParticipantValidator.java (1)
12-21: 도메인 서비스로의 리팩토링 고려를 제안합니다.현재 구현은 기능적으로 올바르지만, 학습된 프로젝트 컨벤션에 따르면 "사용자가 방에 속하는지 검증" 로직을
RoomParticipantPolicy도메인 서비스로 캡슐화하여 재사용성을 높이고 비즈니스 로직의 중복을 방지하는 것이 선호됩니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (29)
src/main/java/konkuk/thip/common/annotation/HelperService.java(1 hunks)src/main/java/konkuk/thip/common/exception/code/ErrorCode.java(0 hunks)src/main/java/konkuk/thip/common/swagger/SwaggerResponseDescription.java(2 hunks)src/main/java/konkuk/thip/recentSearch/application/service/manager/RecentSearchCreateManager.java(1 hunks)src/main/java/konkuk/thip/record/application/service/RecordSearchService.java(1 hunks)src/main/java/konkuk/thip/room/adapter/in/web/RoomQueryController.java(2 hunks)src/main/java/konkuk/thip/room/adapter/in/web/response/RoomGetBookPageResponse.java(1 hunks)src/main/java/konkuk/thip/room/adapter/in/web/response/RoomGetDeadlinePopularResponse.java(1 hunks)src/main/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntity.java(2 hunks)src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java(3 hunks)src/main/java/konkuk/thip/room/adapter/out/persistence/function/RoomQueryFunction.java(1 hunks)src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomQueryRepository.java(2 hunks)src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomQueryRepositoryImpl.java(8 hunks)src/main/java/konkuk/thip/room/application/mapper/RoomQueryMapper.java(2 hunks)src/main/java/konkuk/thip/room/application/port/in/RoomGetBookPageUseCase.java(1 hunks)src/main/java/konkuk/thip/room/application/port/in/RoomGetDeadlinePopularUseCase.java(1 hunks)src/main/java/konkuk/thip/room/application/port/out/RoomQueryPort.java(2 hunks)src/main/java/konkuk/thip/room/application/port/out/dto/CursorSliceOfMyRoomView.java(0 hunks)src/main/java/konkuk/thip/room/application/port/out/dto/RoomQueryDto.java(1 hunks)src/main/java/konkuk/thip/room/application/port/out/dto/RoomShowMineQueryDto.java(0 hunks)src/main/java/konkuk/thip/room/application/service/RoomGetBookPageService.java(1 hunks)src/main/java/konkuk/thip/room/application/service/RoomGetDeadlinePopularService.java(1 hunks)src/main/java/konkuk/thip/room/application/service/RoomShowMineService.java(2 hunks)src/main/java/konkuk/thip/room/application/service/validator/RoomParticipantValidator.java(1 hunks)src/main/java/konkuk/thip/room/domain/Category.java(1 hunks)src/main/java/konkuk/thip/room/domain/RoomParticipants.java(2 hunks)src/test/java/konkuk/thip/record/adapter/in/web/RecordSearchApiTest.java(1 hunks)src/test/java/konkuk/thip/room/adapter/in/web/RoomGetDeadlinePopularApiTest.java(1 hunks)src/test/java/konkuk/thip/room/adapter/in/web/RoomPlayingDetailViewApiTest.java(2 hunks)
💤 Files with no reviewable changes (3)
- src/main/java/konkuk/thip/common/exception/code/ErrorCode.java
- src/main/java/konkuk/thip/room/application/port/out/dto/RoomShowMineQueryDto.java
- src/main/java/konkuk/thip/room/application/port/out/dto/CursorSliceOfMyRoomView.java
🧰 Additional context used
🧠 Learnings (17)
📓 Common learnings
Learnt from: buzz0331
PR: THIP-TextHip/THIP-Server#78
File: src/main/java/konkuk/thip/user/application/port/out/FollowingQueryPort.java:3-3
Timestamp: 2025-07-14T18:22:56.538Z
Learning: THIP 프로젝트에서는 Query API(조회 API)에 한해서는 application 계층에서 adapter.in.web.response 패키지의 response DTO를 직접 참조하는 것을 허용함. 이는 CQRS 아키텍처에서 읽기 전용 작업의 효율성을 위한 팀 컨벤션임.
src/test/java/konkuk/thip/record/adapter/in/web/RecordSearchApiTest.java (1)
Learnt from: seongjunnoh
PR: #101
File: src/main/java/konkuk/thip/comment/application/service/CommentCreateService.java:36-39
Timestamp: 2025-07-26T06:09:00.850Z
Learning: THIP 프로젝트에서 Record와 Vote는 Room에 속하지만 Feed는 Room에 속하지 않는 구조이며, 댓글 작성 시 Record/Vote에 대해서만 사용자가 해당 Room의 참가자인지 검증이 필요하다.
src/main/java/konkuk/thip/record/application/service/RecordSearchService.java (3)
Learnt from: seongjunnoh
PR: #101
File: src/main/java/konkuk/thip/comment/application/service/CommentCreateService.java:36-39
Timestamp: 2025-07-26T06:09:00.850Z
Learning: THIP 프로젝트에서는 "사용자가 방에 속하는지 검증" 로직을 RoomParticipantPolicy 도메인 서비스로 캡슐화하여 재사용성을 높이고 비즈니스 로직의 중복을 방지하는 방식을 선호한다.
Learnt from: seongjunnoh
PR: #101
File: src/main/java/konkuk/thip/comment/application/service/CommentCreateService.java:36-39
Timestamp: 2025-07-26T06:09:00.850Z
Learning: THIP 프로젝트에서 Record와 Vote는 Room에 속하지만 Feed는 Room에 속하지 않는 구조이며, 댓글 작성 시 Record/Vote에 대해서만 사용자가 해당 Room의 참가자인지 검증이 필요하다.
Learnt from: seongjunnoh
PR: #43
File: src/main/java/konkuk/thip/book/application/port/out/BookCommandPort.java:0-0
Timestamp: 2025-07-03T03:05:05.031Z
Learning: THIP 프로젝트에서는 CQRS Port 분리 시 다음 컨벤션을 따름: CommandPort에는 findByXXX를 통해 도메인 엔티티를 찾아오는 메서드를 추가하고, QueryPort에는 조회 API의 response에 해당하는 데이터들을 DB로부터 조회하는 메서드를 추가함.
src/main/java/konkuk/thip/room/domain/RoomParticipants.java (1)
Learnt from: seongjunnoh
PR: #101
File: src/main/java/konkuk/thip/comment/application/service/CommentCreateService.java:36-39
Timestamp: 2025-07-26T06:09:00.850Z
Learning: THIP 프로젝트에서는 "사용자가 방에 속하는지 검증" 로직을 RoomParticipantPolicy 도메인 서비스로 캡슐화하여 재사용성을 높이고 비즈니스 로직의 중복을 방지하는 방식을 선호한다.
src/main/java/konkuk/thip/room/application/service/validator/RoomParticipantValidator.java (1)
Learnt from: seongjunnoh
PR: #101
File: src/main/java/konkuk/thip/comment/application/service/CommentCreateService.java:36-39
Timestamp: 2025-07-26T06:09:00.850Z
Learning: THIP 프로젝트에서는 "사용자가 방에 속하는지 검증" 로직을 RoomParticipantPolicy 도메인 서비스로 캡슐화하여 재사용성을 높이고 비즈니스 로직의 중복을 방지하는 방식을 선호한다.
src/main/java/konkuk/thip/room/application/port/in/RoomGetBookPageUseCase.java (1)
Learnt from: seongjunnoh
PR: #43
File: src/main/java/konkuk/thip/book/application/port/out/BookCommandPort.java:0-0
Timestamp: 2025-07-03T03:05:05.031Z
Learning: THIP 프로젝트에서는 CQRS Port 분리 시 다음 컨벤션을 따름: CommandPort에는 findByXXX를 통해 도메인 엔티티를 찾아오는 메서드를 추가하고, QueryPort에는 조회 API의 response에 해당하는 데이터들을 DB로부터 조회하는 메서드를 추가함.
src/test/java/konkuk/thip/room/adapter/in/web/RoomPlayingDetailViewApiTest.java (2)
Learnt from: hd0rable
PR: #57
File: src/test/java/konkuk/thip/room/domain/RoomTest.java:0-0
Timestamp: 2025-07-08T16:30:33.771Z
Learning: Room 도메인에서 startDate는 현재 날짜 이후여야 하는 도메인 규칙이 있어서, 테스트에서 만료된 상태를 시뮬레이션하려면 reflection을 사용해야 한다.
Learnt from: seongjunnoh
PR: #101
File: src/main/java/konkuk/thip/comment/application/service/CommentCreateService.java:36-39
Timestamp: 2025-07-26T06:09:00.850Z
Learning: THIP 프로젝트에서는 "사용자가 방에 속하는지 검증" 로직을 RoomParticipantPolicy 도메인 서비스로 캡슐화하여 재사용성을 높이고 비즈니스 로직의 중복을 방지하는 방식을 선호한다.
src/test/java/konkuk/thip/room/adapter/in/web/RoomGetDeadlinePopularApiTest.java (1)
Learnt from: hd0rable
PR: #57
File: src/test/java/konkuk/thip/room/domain/RoomTest.java:0-0
Timestamp: 2025-07-08T16:30:33.771Z
Learning: Room 도메인에서 startDate는 현재 날짜 이후여야 하는 도메인 규칙이 있어서, 테스트에서 만료된 상태를 시뮬레이션하려면 reflection을 사용해야 한다.
src/main/java/konkuk/thip/common/swagger/SwaggerResponseDescription.java (1)
Learnt from: seongjunnoh
PR: #101
File: src/main/java/konkuk/thip/comment/application/service/CommentCreateService.java:36-39
Timestamp: 2025-07-26T06:09:00.850Z
Learning: THIP 프로젝트에서 Record와 Vote는 Room에 속하지만 Feed는 Room에 속하지 않는 구조이며, 댓글 작성 시 Record/Vote에 대해서만 사용자가 해당 Room의 참가자인지 검증이 필요하다.
src/main/java/konkuk/thip/room/application/service/RoomShowMineService.java (1)
Learnt from: seongjunnoh
PR: #43
File: src/main/java/konkuk/thip/book/application/port/out/BookCommandPort.java:0-0
Timestamp: 2025-07-03T03:05:05.031Z
Learning: THIP 프로젝트에서는 CQRS Port 분리 시 다음 컨벤션을 따름: CommandPort에는 findByXXX를 통해 도메인 엔티티를 찾아오는 메서드를 추가하고, QueryPort에는 조회 API의 response에 해당하는 데이터들을 DB로부터 조회하는 메서드를 추가함.
src/main/java/konkuk/thip/room/application/service/RoomGetBookPageService.java (1)
Learnt from: seongjunnoh
PR: #101
File: src/main/java/konkuk/thip/comment/application/service/CommentCreateService.java:36-39
Timestamp: 2025-07-26T06:09:00.850Z
Learning: THIP 프로젝트에서는 "사용자가 방에 속하는지 검증" 로직을 RoomParticipantPolicy 도메인 서비스로 캡슐화하여 재사용성을 높이고 비즈니스 로직의 중복을 방지하는 방식을 선호한다.
src/main/java/konkuk/thip/room/application/port/out/RoomQueryPort.java (2)
Learnt from: seongjunnoh
PR: #43
File: src/main/java/konkuk/thip/book/application/port/out/BookCommandPort.java:0-0
Timestamp: 2025-07-03T03:05:05.031Z
Learning: THIP 프로젝트에서는 CQRS Port 분리 시 다음 컨벤션을 따름: CommandPort에는 findByXXX를 통해 도메인 엔티티를 찾아오는 메서드를 추가하고, QueryPort에는 조회 API의 response에 해당하는 데이터들을 DB로부터 조회하는 메서드를 추가함.
Learnt from: buzz0331
PR: #78
File: src/main/java/konkuk/thip/user/application/port/out/FollowingQueryPort.java:3-3
Timestamp: 2025-07-14T18:22:56.538Z
Learning: THIP 프로젝트에서는 Query API(조회 API)에 한해서는 application 계층에서 adapter.in.web.response 패키지의 response DTO를 직접 참조하는 것을 허용함. 이는 CQRS 아키텍처에서 읽기 전용 작업의 효율성을 위한 팀 컨벤션임.
src/main/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntity.java (1)
Learnt from: hd0rable
PR: #57
File: src/test/java/konkuk/thip/room/domain/RoomTest.java:0-0
Timestamp: 2025-07-08T16:30:33.771Z
Learning: Room 도메인에서 startDate는 현재 날짜 이후여야 하는 도메인 규칙이 있어서, 테스트에서 만료된 상태를 시뮬레이션하려면 reflection을 사용해야 한다.
src/main/java/konkuk/thip/room/application/port/out/dto/RoomQueryDto.java (1)
Learnt from: hd0rable
PR: #57
File: src/test/java/konkuk/thip/room/domain/RoomTest.java:0-0
Timestamp: 2025-07-08T16:30:33.771Z
Learning: Room 도메인에서 startDate는 현재 날짜 이후여야 하는 도메인 규칙이 있어서, 테스트에서 만료된 상태를 시뮬레이션하려면 reflection을 사용해야 한다.
src/main/java/konkuk/thip/room/adapter/in/web/RoomQueryController.java (1)
Learnt from: seongjunnoh
PR: #43
File: src/main/java/konkuk/thip/book/application/port/out/BookCommandPort.java:0-0
Timestamp: 2025-07-03T03:05:05.031Z
Learning: THIP 프로젝트에서는 CQRS Port 분리 시 다음 컨벤션을 따름: CommandPort에는 findByXXX를 통해 도메인 엔티티를 찾아오는 메서드를 추가하고, QueryPort에는 조회 API의 response에 해당하는 데이터들을 DB로부터 조회하는 메서드를 추가함.
src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomQueryRepository.java (2)
Learnt from: seongjunnoh
PR: #43
File: src/main/java/konkuk/thip/book/application/port/out/BookCommandPort.java:0-0
Timestamp: 2025-07-03T03:05:05.031Z
Learning: THIP 프로젝트에서는 CQRS Port 분리 시 다음 컨벤션을 따름: CommandPort에는 findByXXX를 통해 도메인 엔티티를 찾아오는 메서드를 추가하고, QueryPort에는 조회 API의 response에 해당하는 데이터들을 DB로부터 조회하는 메서드를 추가함.
Learnt from: buzz0331
PR: #78
File: src/main/java/konkuk/thip/user/application/port/out/FollowingQueryPort.java:3-3
Timestamp: 2025-07-14T18:22:56.538Z
Learning: THIP 프로젝트에서는 Query API(조회 API)에 한해서는 application 계층에서 adapter.in.web.response 패키지의 response DTO를 직접 참조하는 것을 허용함. 이는 CQRS 아키텍처에서 읽기 전용 작업의 효율성을 위한 팀 컨벤션임.
src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomQueryRepositoryImpl.java (1)
Learnt from: buzz0331
PR: #78
File: src/main/java/konkuk/thip/user/application/port/out/FollowingQueryPort.java:3-3
Timestamp: 2025-07-14T18:22:56.538Z
Learning: THIP 프로젝트에서는 Query API(조회 API)에 한해서는 application 계층에서 adapter.in.web.response 패키지의 response DTO를 직접 참조하는 것을 허용함. 이는 CQRS 아키텍처에서 읽기 전용 작업의 효율성을 위한 팀 컨벤션임.
🧬 Code Graph Analysis (3)
src/main/java/konkuk/thip/common/annotation/HelperService.java (2)
src/main/java/konkuk/thip/room/application/service/validator/RoomParticipantValidator.java (1)
HelperService(10-22)src/main/java/konkuk/thip/recentSearch/application/service/manager/RecentSearchCreateManager.java (1)
HelperService(10-26)
src/main/java/konkuk/thip/recentSearch/application/service/manager/RecentSearchCreateManager.java (1)
src/main/java/konkuk/thip/room/application/service/validator/RoomParticipantValidator.java (1)
HelperService(10-22)
src/test/java/konkuk/thip/room/adapter/in/web/RoomGetDeadlinePopularApiTest.java (2)
src/main/java/konkuk/thip/common/util/DateUtil.java (1)
DateUtil(12-62)src/test/java/konkuk/thip/common/util/TestEntityFactory.java (1)
TestEntityFactory(29-293)
⏰ 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: build
🔇 Additional comments (51)
src/main/java/konkuk/thip/common/annotation/HelperService.java (1)
1-15: 새로운 헬퍼 서비스 어노테이션이 잘 설계되었습니다.Spring의
@Service를 메타 어노테이션으로 사용하여 헬퍼 서비스 컴포넌트의 의미론적 명확성을 제공하는 좋은 접근법입니다.@AliasFor를 통한 별칭 처리도 적절하고, 런타임 보존과 타입 레벨 타겟팅도 올바르게 설정되어 있습니다.src/main/java/konkuk/thip/recentSearch/application/service/manager/RecentSearchCreateManager.java (1)
3-3: 헬퍼 서비스 어노테이션 표준화가 적절합니다.새로운
@HelperService어노테이션으로의 전환이 코드베이스의 일관성을 높이고 헬퍼 서비스의 의미론적 역할을 명확히 하는 좋은 변화입니다.Also applies to: 10-10
src/main/java/konkuk/thip/room/application/service/validator/RoomParticipantValidator.java (1)
3-3: 헬퍼 서비스 어노테이션 표준화가 적절합니다.
@Component에서@HelperService로의 변경이 코드베이스 전반의 일관성을 높이는 좋은 변화입니다.Also applies to: 10-10
src/main/java/konkuk/thip/record/application/service/RecordSearchService.java (1)
63-63: 오류 코드 통합 일관성 확인 및 승인
USER_NOT_BELONG_TO_ROOM사용이 완전히 제거되었으며, 서비스·도메인·테스트·Swagger 등 전반에 걸쳐ROOM_ACCESS_FORBIDDEN이 일관되게 적용되었습니다. 추가 검증 없이 승인합니다.src/test/java/konkuk/thip/record/adapter/in/web/RecordSearchApiTest.java (1)
369-369: 테스트 케이스 업데이트가 적절합니다.서비스 레이어의 오류 코드 변경에 맞춰 HTTP 상태 코드를 400에서 403으로 변경한 것이 올바릅니다. 사용자가 방에 속하지 않을 때 403 Forbidden을 반환하는 것이 의미론적으로 더 정확합니다.
src/main/java/konkuk/thip/room/domain/Category.java (2)
30-30: 입력 값 정규화 개선
value.trim()을 추가하여 입력 문자열의 공백을 제거하는 것은 좋은 개선입니다. 사용자 입력에서 발생할 수 있는 의도치 않은 공백 문제를 방지합니다.
33-36: 예외 처리 개선
InvalidStateException으로 감싸고 중첩된IllegalArgumentException에 구체적인 값을 포함한 것은 좋은 개선입니다. 디버깅 시 어떤 값이 문제였는지 명확히 알 수 있습니다.src/test/java/konkuk/thip/room/adapter/in/web/RoomPlayingDetailViewApiTest.java (2)
37-37: 에러 코드 통합 반영
ROOM_ACCESS_FORBIDDEN임포트로 변경하여 중복된 에러 코드 통합을 올바르게 반영했습니다.
288-290: HTTP 상태 코드 및 에러 응답 수정403 Forbidden으로 변경하고
ROOM_ACCESS_FORBIDDEN에러 코드를 사용하는 것이 접근 제어 위반에 더 적합합니다. 의미론적으로 올바른 변경입니다.src/main/java/konkuk/thip/room/domain/RoomParticipants.java (2)
10-10: 에러 코드 통합
ROOM_ACCESS_FORBIDDEN로 임포트 변경하여 중복 에러 코드를 제거하는 리팩토링을 올바르게 적용했습니다.
45-45: 일관된 예외 처리두 메서드 모두에서
ROOM_ACCESS_FORBIDDEN에러 코드를 사용하여 방 접근 권한 관련 예외 처리를 일관되게 개선했습니다.Also applies to: 53-53
src/main/java/konkuk/thip/room/application/port/in/RoomGetBookPageUseCase.java (1)
1-7: 새로운 Use Case 인터페이스책 페이지 정보 조회를 위한 인터페이스가 명확하고 간결하게 정의되었습니다. 메서드 시그니처가 직관적이고 프로젝트의 네이밍 컨벤션을 잘 따르고 있습니다.
src/main/java/konkuk/thip/room/application/service/RoomShowMineService.java (2)
9-9: DTO 통합 리팩토링
RoomShowMineQueryDto를RoomQueryDto로 교체하여 DTO를 통합한 것은 코드 재사용성을 높이는 좋은 개선입니다.
34-34: 타입 변경 일관성
CursorBasedList<RoomQueryDto>로 타입을 변경하여 통합된 DTO를 일관되게 사용하고 있습니다. 기존 로직은 그대로 유지하면서 재사용성을 개선했습니다.src/main/java/konkuk/thip/room/application/port/in/RoomGetDeadlinePopularUseCase.java (2)
3-3: 웹 응답 DTO 직접 참조는 THIP 프로젝트 컨벤션에 부합합니다.Query API의 경우 application 계층에서 adapter.in.web.response 패키지의 DTO를 직접 참조하는 것이 허용되는 팀 컨벤션에 따라 올바르게 구현되었습니다.
7-7: 카테고리 유효성 검증은 도메인 로직에서 처리됩니다Category.from(String) 메서드(src/main/java/konkuk/thip/room/domain/Category.java)에서
– value.trim() 후 일치하는 enum이 없을 경우
–InvalidStateException(IllegalArgumentException 래핑)을 던져 예외 처리하므로
서비스 레이어에서 별도의 추가 검증 로직은 불필요합니다.src/main/java/konkuk/thip/room/adapter/out/persistence/function/RoomQueryFunction.java (1)
8-11: 잘 설계된 함수형 인터페이스입니다.커서 기반 페이지네이션을 지원하는 매개변수 구조와 명확한 반환 타입으로 잘 설계되었습니다. 함수형 인터페이스의 단일 추상 메서드 원칙도 올바르게 준수하고 있습니다.
src/main/java/konkuk/thip/room/adapter/in/web/response/RoomGetBookPageResponse.java (1)
3-10: 간결하고 명확한 응답 DTO 설계입니다.불변 레코드 클래스와 정적 팩토리 메서드를 활용한 깔끔한 구조입니다. 필드명도 직관적이고 용도가 명확합니다.
src/main/java/konkuk/thip/room/application/service/RoomGetDeadlinePopularService.java (2)
18-18: 상수 정의가 적절합니다.기본 제한값을 상수로 정의하여 매직 넘버를 방지하고 유지보수성을 높였습니다.
21-30: 서비스 로직이 명확하게 구현되었습니다.Category.from()을 통한 문자열 검증과 두 개의 별도 쿼리로 마감 임박 방과 인기 방을 조회하는 로직이 명확합니다. 매퍼를 통한 DTO 변환도 적절합니다.
src/main/java/konkuk/thip/room/application/service/RoomGetBookPageService.java (3)
24-24: 방 참여자 검증 로직이 올바르게 적용되었습니다.RoomParticipantValidator를 사용하여 사용자의 방 소속 여부를 검증하는 것은 THIP 프로젝트의 도메인 서비스 활용 방침에 부합합니다.
27-29: 응답 생성 로직이 간결하고 명확합니다.참여자 정보를 조회하고 책의 페이지 수와 총평 작성 가능 여부를 조합하여 응답을 생성하는 로직이 명확합니다.
26-26: 포트 명명 규칙 검토 결과
BookQueryPort는 현재 빈 인터페이스로만 정의되어 있으며, THIP 프로젝트 CQRS 컨벤션에 따르면 도메인 엔티티 조회 메서드(findBookByRoomId 등)는 CommandPort에 두는 것이 맞습니다.
따라서 해당 코드는 변경 없이 유지해 주세요.src/main/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntity.java (3)
73-76: 테스트용 메서드 추가 LGTM!멤버 수를 직접 설정할 수 있는 테스트 전용 메서드가 추가되었습니다. @VisibleForTesting 어노테이션으로 용도가 명확히 표시되어 있습니다.
78-81: 도메인 규칙 우회를 위한 테스트 메서드 추가Room 도메인의 startDate 검증 규칙을 우회하여 테스트에서 과거 날짜나 특정 날짜를 설정할 수 있도록 하는 메서드입니다. 이전에는 reflection을 사용해야 했던 부분이 깔끔하게 해결되었습니다.
83-86: 공개 여부 설정을 위한 테스트 메서드방의 공개/비공개 상태를 테스트에서 직접 설정할 수 있는 메서드입니다. 테스트 시나리오에서 필요한 상태를 쉽게 구성할 수 있게 됩니다.
src/main/java/konkuk/thip/room/adapter/in/web/RoomQueryController.java (3)
31-32: 새로운 UseCase 의존성 추가 LGTM!책 페이지 정보 조회와 마감 임박/인기 방 조회를 위한 UseCase가 적절히 추가되었습니다.
129-140: 책 페이지 정보 조회 API 구현 완료방 참여자가 기록 작성 시 필요한 책의 전체 페이지 수와 총평 작성 가능 여부를 조회하는 API가 올바르게 구현되었습니다. Swagger 문서화와 예외 처리도 적절합니다.
142-154: 카테고리별 마감 임박/인기 방 조회 API 구현 완료카테고리를 기준으로 마감 임박 방과 인기 방을 조회하는 API가 구현되었습니다. 기본값으로 "문학" 카테고리가 설정되어 있고, 적절한 문서화가 되어 있습니다.
src/test/java/konkuk/thip/room/adapter/in/web/RoomGetDeadlinePopularApiTest.java (3)
82-123: 테스트 데이터 설정이 포괄적이고 체계적다양한 시나리오를 커버하는 테스트 데이터가 잘 구성되어 있습니다:
- 마감 임박 방과 인기 방 각각 5개씩 생성
- 조건 불만족 케이스들 (오늘 날짜 방, 비공개 방, 참여 방) 생성
- RoomJpaEntity의 새로운 @VisibleForTesting 메서드들을 적절히 활용
테스트 시나리오가 비즈니스 요구사항을 잘 반영하고 있습니다.
125-143: 메인 기능 테스트가 철저하게 검증됨API의 핵심 기능을 포괄적으로 검증하고 있습니다:
- 마감 임박 방과 인기 방 각각 4개씩 반환 확인
- 정렬 순서 검증 (마감일 순, 인기도 순)
- 응답 데이터 타입 검증
- DateUtil을 활용한 마감일 형식 검증
테스트 코드가 명확하고 검증 로직이 적절합니다.
145-169: 비즈니스 규칙 검증 테스트가 완벽함참여 방 제외와 비공개 방 제외 로직을 별도의 테스트로 분리하여 검증한 것이 좋습니다. 각 테스트가 명확한 목적을 가지고 있고 검증 로직도 정확합니다.
src/main/java/konkuk/thip/room/adapter/in/web/response/RoomGetDeadlinePopularResponse.java (1)
5-21: 응답 DTO 구조가 깔끔하고 명확함마감 임박 방과 인기 방 리스트를 담는 응답 DTO가 잘 설계되었습니다:
- record 구조로 불변성 보장
- 중첩된 RoomDto로 응답 데이터 구조화
- 정적 팩토리 메서드로 생성 편의성 제공
- 필드명이 직관적이고 명확함
API 응답 구조가 요구사항을 잘 반영하고 있습니다.
src/main/java/konkuk/thip/common/swagger/SwaggerResponseDescription.java (3)
87-89: 에러 코드 추가가 적절합니다.
ROOM_PLAYING_DETAIL에ROOM_ACCESS_FORBIDDEN에러 코드가 추가되어 사용자 접근 권한 검증이 강화되었습니다. 이는 PR 목표에서 언급된 중복 에러 코드 통합과 일치합니다.
90-97: 새로운 API 엔드포인트를 위한 Swagger 문서화가 적절합니다.책 페이지 정보 조회와 장르별 마감/인기 방 조회 API를 위한 응답 설명이 추가되었습니다. 각각 적절한 에러 코드들이 정의되어 있습니다.
113-113: 에러 코드 통합이 일관성 있게 적용되었습니다.
RECORD_SEARCH에서USER_NOT_BELONG_TO_ROOM이ROOM_ACCESS_FORBIDDEN으로 교체되어, 사용자 참여 관련 에러 처리가 통합되었습니다.src/main/java/konkuk/thip/room/application/mapper/RoomQueryMapper.java (2)
24-24: DTO 리팩토링이 일관성 있게 적용되었습니다.
RoomShowMineQueryDto에서RoomQueryDto로 변경되어 더 범용적인 DTO 사용이 가능해졌습니다. 메서드 기능은 동일하게 유지됩니다.
26-32: 새로운 API를 위한 매핑 메서드가 적절히 추가되었습니다.장르별 마감/인기 방 조회 API를 위한 매핑 메서드들이 추가되었습니다.
deadlineDate필드에DateUtil.formatAfterTime사용이 기존 패턴과 일치합니다.src/main/java/konkuk/thip/room/application/port/out/RoomQueryPort.java (2)
27-34: DTO 변경이 모든 메서드에 일관성 있게 적용되었습니다.
RoomShowMineQueryDto에서RoomQueryDto로의 변경이 모든 사용자 참여 방 조회 메서드에 적용되어 코드 일관성이 향상되었습니다.
35-37: 새로운 장르별 방 조회 기능이 적절히 정의되었습니다.마감 임박 및 인기 방 조회를 위한 새로운 메서드가 추가되었습니다. 메서드명이 기능을 명확히 표현하고, 파라미터도 적절합니다.
src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomQueryRepository.java (2)
22-29: 리포지토리 메서드의 반환 타입이 일관성 있게 변경되었습니다.모든 사용자 참여 방 조회 메서드가
RoomQueryDto를 반환하도록 변경되어 DTO 통합이 완료되었습니다.
30-32: 새로운 장르별 조회 메서드가 적절히 정의되었습니다.카테고리별 시작일 오름차순과 멤버 수 기준 정렬 메서드가 추가되었습니다. 파라미터로 String category를 사용하는 것이 persistence 계층에 적합합니다.
src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java (3)
49-66: 메서드 시그니처 변경이 모든 참여 방 조회 메서드에 일관성 있게 적용되었습니다.
RoomQueryDto사용으로 DTO가 통합되었고, 기존 로직은 그대로 유지되어 안정성이 보장됩니다.
68-81: 헬퍼 메서드가 새 DTO에 맞게 적절히 업데이트되었습니다.
findRooms메서드가RoomQueryDto를 사용하도록 변경되었고, 커서 기반 페이지네이션 로직은 유지되었습니다.RoomQueryFunction을 별도 패키지에서 import하는 것이 코드 구조화에 도움됩니다.
84-91: 새로운 장르별 조회 메서드가 적절히 구현되었습니다.Category enum을 String으로 변환하여 repository 계층에 전달하는 로직이 적절합니다. 메서드명이 기능을 명확히 표현합니다.
src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomQueryRepositoryImpl.java (6)
17-30: Import 추가 확인새로운 DTO 및 페이징 관련 import가 적절하게 추가되었습니다.
44-44: 카테고리 엔티티 필드 추가카테고리별 조회 기능 구현을 위한 적절한 필드 추가입니다.
257-258: DTO 타입 변경 확인RoomShowMineQueryDto에서 RoomQueryDto로의 일관된 변경이 잘 적용되었습니다.
Also applies to: 274-275, 292-293, 323-324
339-376: 카테고리별 방 조회 메소드 구현마감 임박 및 인기 방 조회 로직이 깔끔하게 구현되었습니다. 공통 조건을 별도 메소드로 분리하여 코드 중복을 제거한 점이 좋습니다.
377-396: 필터링 조건 구현 확인PR 요구사항에 명시된 모든 필터링 조건(모집 마감 시각, 공개 여부, 사용자 미참여, ACTIVE 상태)이 정확하게 구현되었습니다. 사용자 참여 여부 확인을 위한 서브쿼리도 효율적입니다.
400-400: fetchMyRooms 메소드 DTO 변경QRoomQueryDto 프로젝션으로의 변경이 올바르게 적용되었습니다. 커서 기반 페이지네이션을 위해 cursorExpr을 동적으로 포함시킨 것도 좋은 접근입니다.
Also applies to: 424-429
src/main/java/konkuk/thip/room/application/port/out/dto/RoomQueryDto.java
Show resolved
Hide resolved
seongjunnoh
left a comment
There was a problem hiding this comment.
피그마 화면에서 "장르별 마감 임박 및 인기방 조회" 부분의 화면을 확인했는데, 저희가 반환하는 데이터가 화면에서 어떤식으로 보이는지가 궁금해서 리뷰 달아보았습니다! 확인해 주시면 감사하겠습니다!
| @Target({ElementType.TYPE}) | ||
| @Retention(RetentionPolicy.RUNTIME) | ||
| @Service | ||
| public @interface HelperService { | ||
|
|
||
| @AliasFor(annotation = Service.class) | ||
| String value() default ""; | ||
| } |
| Book book = bookCommandPort.findBookByRoomId(roomId); | ||
| RoomParticipant roomParticipant = roomParticipantCommandPort.getByUserIdAndRoomIdOrThrow(userId, roomId); | ||
|
|
||
| return RoomGetBookPageResponse.of(book.getPageCount(), roomParticipant.canWriteOverview()); |
There was a problem hiding this comment.
오 roomParticipant 에 canWriteOverview() 메서드가 있네요 굳굳
| @Override | ||
| @Transactional(readOnly = true) | ||
| public RoomGetDeadlinePopularResponse getDeadlineAndPopularRoomList(String categoryStr, Long userId) { | ||
| Category category = Category.from(categoryStr); | ||
|
|
||
| var deadlineRoomList = roomQueryMapper.toDeadlinePopularRoomDtoList( | ||
| roomQueryPort.findRoomsByCategoryOrderByDeadline(category, DEFAULT_LIMIT, userId)); | ||
| var popularRoomList = roomQueryMapper.toDeadlinePopularRoomDtoList( | ||
| roomQueryPort.findRoomsByCategoryOrderByPopular(category, DEFAULT_LIMIT, userId)); | ||
|
|
||
| return RoomGetDeadlinePopularResponse.of(deadlineRoomList, popularRoomList); | ||
| } |
There was a problem hiding this comment.
p3 : 이건 api 자체에 대한 근본적인 질문이긴한데,
해당 api가 현재 모집중인 모임방을 마감임박순으로 4개, 인기순으로 4개 골라서 응답하고 있는데, 이게 화면에서는 어떤식으로 보이는건가요?? (진짜 궁금해서 여쭤봅니다 허허)
There was a problem hiding this comment.
기획 요구사항이 처음 마감 임박한 모임방 4개를 보여주고 사용자가 좌우로 슬라이드할 경우 정렬 기준이 다른 모임방 리스트가 보여지는 걸로 알고 있습니다! 이때 슬라이드할때마다 api를 반환받으면 렌더링이 지연되기 때문에 프론트에게 한번에 모든 정렬 기준에 대한 모임방을 반환하고 프론트쪽에서 처리하는 걸로 api를 구현하였습니다!
| import static konkuk.thip.common.exception.code.ErrorCode.ROOM_ACCESS_FORBIDDEN; | ||
|
|
||
| @Component | ||
| @HelperService |
| () -> new InvalidStateException(CATEGORY_NOT_MATCH, | ||
| new IllegalArgumentException( | ||
| String.format("존재하지 않는 카테고리입니다. value: %s", value) | ||
| )) |
#️⃣ 연관된 이슈
📝 작업 내용
책 전체 페이지수 및 총평 작성 가능 여부 조회 api
장르별 마감 임박 및 인기 방 조회 api 구현
📸 스크린샷
정렬 잘되는 것 postman으로 확인했습니다!

💬 리뷰 요구사항
추가적으로 세세한 것 좀 고쳤습니다.
@Service가 아닌@HelperService를 붙여 헬퍼 서비스임을 명시하도록 했습니다.📌 PR 진행 시 이러한 점들을 참고해 주세요
Summary by CodeRabbit
신규 기능
버그 수정
테스트
기타