[hotfix] 내가 참여한 모임방 api 의 영속성 코드 수정#291
Conversation
- 모집중인 방의 경우, 반환하는 RoomQueryDto의 endDate 값을 방 모집마감일로 응답하도록 수정 - 모집+진행중인 방을 조회하는 경우, 페이징처리를 위한 커서에 Integer priority 추가
- 모집 + 진행중인 방 조회시, 누락&중복되는 데이터 없이 무한스크롤 기능 동작하는지 검증하는 테스트 코드 추가
Walkthrough혼합 목록(진행중+모집중) 조회의 페이징 커서가 2필드에서 3필드(우선순위, 날짜, ID)로 확장되었고, 이에 따라 어댑터·리포지토리 시그니처와 정렬/커서 비교 로직이 변경되었습니다. DTO 생성자가 추가되었으며, 혼합 페이징 시나리오에 대한 통합 테스트가 추가되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant C as Client
participant API as RoomsController
participant A as RoomQueryPersistenceAdapter
participant R as RoomQueryRepository
participant DB as Database
C->>API: GET /rooms/my?cursor=priority|date|id&pageSize
API->>A: findPlayingAndRecruitingRoomsUserParticipated(userId, cursor)
A->>R: findPlayingAndRecruitingRoomsUserParticipated(userId, priorityCursor, dateCursor, idCursor, pageSize)
Note over R,DB: Order by (priority asc, deadline asc, id asc)
R->>DB: Query with 3-key cursor predicate
DB-->>R: List<RoomQueryDto>
R-->>A: Rooms (mixed)
A-->>API: CursorBasedList + nextCursor(priority|date|id)
API-->>C: 200 OK (items, nextCursor, isLast)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
Test Results452 tests 452 ✅ 42s ⏱️ Results for commit 1c05c0d. |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (10)
src/main/java/konkuk/thip/room/application/port/out/dto/RoomQueryDto.java (3)
9-9: TODO는 이슈로 트래킹하거나 제거하세요.주석만 남아 있으면 후속 작업 누락 위험이 있습니다. 본 PR 설명에 언급된 상위 작업(THIP2025-324, #290)과 연결된 하위 이슈로 전환하거나, 이미 반영됐다면 TODO를 제거해주세요.
21-30: DTO 불변식과 필드 의미를 명확히 해주세요.현재 canonical ctor에서 endDate not-null만 강제하고 startDate는 null 허용입니다. 혼합 조회에서 endDate가 “데드라인(진행=endDate, 모집=startDate)”을 담는 설계임을 주석/Javadoc으로 명시하면 혼동을 줄일 수 있습니다. 직렬화/응답 스키마에서 endDate가 상황별 의미를 가진다는 점도 문서화 권장합니다.
32-56: QueryProjection 오버로드 추가는 방향 OK. 주석으로 ‘deadline’ 의미를 로컬에 명시하세요.해당 생성자들이 startDate=null로 위임하고 endDate에 상황별 데드라인을 담는 패턴입니다. 이후 유지보수자가 바로 파악할 수 있도록 생성자 내부에 짧은 주석을 추가하는 것을 권장합니다.
다음과 같이 주석을 보강해 주세요:
@QueryProjection public RoomQueryDto( Long roomId, String bookImageUrl, String roomName, Integer recruitCount, Integer memberCount, LocalDate endDate ) { + // endDate는 '상황별 데드라인' 의미: 진행중=endDate, 모집중=startDate this(roomId, bookImageUrl, roomName, recruitCount, memberCount, null, endDate, null); } // 방 검색 시 활용 @QueryProjection public RoomQueryDto( Long roomId, String bookImageUrl, String roomName, Integer recruitCount, Integer memberCount, LocalDate endDate, Boolean isPublic ) { + // endDate는 '상황별 데드라인' 의미: 진행중=endDate, 모집중=startDate this(roomId, bookImageUrl, roomName, recruitCount, memberCount, null, endDate, isPublic); }src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomQueryRepository.java (2)
30-30: 3중 커서(우선순위, 날짜, ID) 방식 명세를 Javadoc으로 고정하세요.혼합 조회의 정렬·비교 규칙이 핵심 계약입니다. 다음과 같이 메서드 시그니처 위에 커서 포맷과 정렬 규칙(lexicographic: priority asc, date asc, id asc), priority의 의미(진행=0, 모집=1), null 커서의 초기 페이지 의미를 Javadoc으로 명시해 주세요.
- List<RoomQueryDto> findPlayingAndRecruitingRoomsUserParticipated(Long userId, Integer priorityCursor, LocalDate dateCursor, Long roomIdCursor, int pageSize); + /** + * 혼합(진행+모집) 조회 페이징. + * 정렬: priority ASC(진행=0, 모집=1) → deadlineDate ASC → roomId ASC. + * 커서: priority|deadlineDate|roomId (예: "1|2025-09-10|123"), 첫 페이지는 세 커서 모두 null. + * @param priorityCursor 진행=0, 모집=1 (null이면 첫 페이지) + * @param dateCursor 진행=endDate, 모집=startDate (null이면 첫 페이지) + * @param roomIdCursor 마지막 ID (null이면 첫 페이지) + */ + List<RoomQueryDto> findPlayingAndRecruitingRoomsUserParticipated(Long userId, Integer priorityCursor, LocalDate dateCursor, Long roomIdCursor, int pageSize);
30-30: 커서 파라미터 VO 도입 검토(선택)
선언(RoomQueryRepository), 구현(RoomQueryRepositoryImpl), 호출(RoomQueryPersistenceAdapter) 총 3곳에서만 사용되므로,record MixedCursor(Integer priority, LocalDate date, Long id)같은 값 객체로 묶어 시그니처를 간결하게 바꾸면 가독성과 향후 확장성 개선에 도움이 됩니다.src/test/java/konkuk/thip/room/adapter/in/web/RoomShowMineApiTest.java (4)
499-527: 시간 의존성 제거로 플래키 테스트 방지.
LocalDate.now()를 다수 호출하면 자정 경계 등에서 순서가 어긋날 수 있습니다. 테스트 내 기준일을 한 번만 캡처해 사용하세요.- // given - // 진행중인 방 6개 (endDate 임박 순서: +1d ~ +6d) - RoomJpaEntity playing1 = saveScienceRoom(..., LocalDate.now().minusDays(10), LocalDate.now().plusDays(1), 10); + // given + LocalDate base = LocalDate.now(); + // 진행중인 방 6개 (endDate 임박 순서: +1d ~ +6d) + RoomJpaEntity playing1 = saveScienceRoom(..., base.minusDays(10), base.plusDays(1), 10);(이하 now() 사용 지점들을 base로 치환)
545-565: 다음 커서는 응답에서 읽어 검증까지 수행하세요.직접 문자열을 구성하기보다 1페이지 응답의 nextCursor를 읽어 2페이지 요청에 사용하고, 기대값과 일치하는지도 함께 검증하면 계약이 견고해집니다.
-String nextCursor = "1|" + recruiting4.getStartDate() + "|" + recruiting4.getRoomId(); -ResultActions page2 = mockMvc.perform(get("/rooms/my") - .requestAttr("userId", user.getUserId()) - .param("cursor", nextCursor)); +String nextCursor = page1.andReturn().getResponse().getContentAsString(); +// 필요 시 ObjectMapper로 $.data.nextCursor 파싱 +ResultActions page2 = mockMvc.perform(get("/rooms/my") + .requestAttr("userId", user.getUserId()) + .param("cursor", /* 파싱한 nextCursor */));
570-579: 페이지 크기를 명시해 디폴트 변경에 흔들리지 않게 하세요.운영 설정 변경으로 기본 size가 바뀌어도 테스트가 견고하도록 size=10을 명시하세요.
ResultActions page2 = mockMvc.perform(get("/rooms/my") .requestAttr("userId", user.getUserId()) - .param("cursor", nextCursor)); + .param("cursor", nextCursor) + .param("size", "10"));동일하게 page1 호출에도
.param("size","10")추가 권장.
575-581: “중복/누락 없음”을 실제로 검증하세요.두 페이지의 roomId를 수집해 set 크기가 12인지 확인하면 시나리오 의도가 테스트에 반영됩니다.
src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java (1)
116-116: TODO 주석에 대한 후속 작업을 고려하세요.
dto에 RoomStatus 도입되면 수정해야함이라는 TODO가 있습니다. RoomStatus enum이 도입되면 현재 날짜 기반의 priority 계산 로직을 상태 기반으로 리팩토링할 수 있을 것입니다.RoomStatus enum이 도입되면 이 부분의 리팩토링을 위한 이슈를 생성하시겠습니까?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java(1 hunks)src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomQueryRepository.java(1 hunks)src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomQueryRepositoryImpl.java(6 hunks)src/main/java/konkuk/thip/room/application/port/out/dto/RoomQueryDto.java(2 hunks)src/test/java/konkuk/thip/room/adapter/in/web/RoomShowMineApiTest.java(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#113
File: src/main/java/konkuk/thip/recentSearch/adapter/out/persistence/RecentSearchCommandPersistenceAdapter.java:38-44
Timestamp: 2025-07-30T14:05:04.945Z
Learning: seongjunnoh는 코드 최적화 제안에 대해 구체적인 기술적 근거와 효율성 차이를 이해하고 싶어하며, 성능 개선 방식에 대한 상세한 설명을 선호한다.
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#93
File: src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java:49-114
Timestamp: 2025-07-28T16:44:31.224Z
Learning: seongjunnoh는 코드 중복 문제에 대한 리팩토링 제안을 적극적으로 수용하고 함수형 인터페이스를 활용한 해결책을 선호한다.
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#285
File: src/main/java/konkuk/thip/room/adapter/out/jpa/RoomStatus.java:1-7
Timestamp: 2025-08-31T05:25:14.835Z
Learning: seongjunnoh는 enum 의존성에 대해 유연한 접근을 선호하며, 도메인→어댑터 레이어 참조와 같은 아키텍처 layering 원칙보다 실용적인 구현을 우선시한다.
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#195
File: src/main/java/konkuk/thip/feed/application/mapper/FeedQueryMapper.java:0-0
Timestamp: 2025-08-13T05:22:32.287Z
Learning: seongjunnoh는 데이터 무결성과 중복 방지에 대한 고민이 깊으며, LinkedHashSet을 활용한 중복 제거와 순서 보장을 동시에 달성하는 솔루션을 선호한다.
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#180
File: src/main/java/konkuk/thip/room/application/service/AttendanceCheckCreateService.java:22-40
Timestamp: 2025-08-14T09:15:31.371Z
Learning: seongjunnoh는 기술적 완벽성보다 실제 비즈니스 시나리오와 사용자 행동 패턴을 우선 고려하며, 발생 가능성이 낮은 엣지 케이스보다는 실용적인 구현을 선호한다.
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#278
File: src/main/java/konkuk/thip/common/exception/code/ErrorCode.java:210-211
Timestamp: 2025-08-24T09:40:48.595Z
Learning: seongjunnoh는 HTTP 상태 코드 선택에 대해 기술적 근거와 코드베이스 내 일관성을 중요하게 생각하며, 구체적인 사례 분석을 통한 설명을 선호한다.
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#278
File: src/main/java/konkuk/thip/TestTokenController.java:0-0
Timestamp: 2025-08-24T09:33:52.982Z
Learning: seongjunnoh는 Spring의 ConditionalOnProperty 동작 원리를 정확히 이해하고 있으며, 보안 이슈에 대해서도 실질적인 위험성을 기준으로 판단하는 실용적 접근을 선호한다.
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#112
File: src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedQueryRepositoryImpl.java:272-272
Timestamp: 2025-07-30T10:44:34.115Z
Learning: seongjunnoh는 피드 커서 페이지네이션에서 LocalDateTime 단일 커서 방식을 선호하며, 복합 키 기반 커서보다 구현 단순성과 성능을 우선시한다.
🧬 Code graph analysis (1)
src/test/java/konkuk/thip/room/adapter/in/web/RoomShowMineApiTest.java (1)
src/test/java/konkuk/thip/common/util/TestEntityFactory.java (1)
TestEntityFactory(30-394)
⏰ 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 (5)
src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java (1)
105-125: 3중 복합 커서 구현이 적절합니다!진행중인 방과 모집중인 방을 통합 조회하면서 우선순위를 포함한 3중 복합 커서를 사용하는 접근이 좋습니다. 특히 priority를 동적으로 계산하여 cursor에 포함시키는 로직이 페이징의 일관성을 보장합니다.
src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomQueryRepositoryImpl.java (4)
283-303: 우선순위 기반 정렬이 올바르게 구현되었습니다!진행중인 방(priority=0)과 모집중인 방(priority=1)의 정렬 순서가 요구사항과 일치합니다. CaseBuilder를 사용한 동적 커서 표현식 생성도 적절합니다.
457-501: 3중 복합 커서 처리 로직이 정확합니다!
fetchMyRoomsWithPriority메서드의 3중 복합 커서(priority, date, id) 처리가 올바르게 구현되었습니다. 무한 스크롤에서 발생할 수 있는 데이터 누락이나 중복 문제를 효과적으로 방지할 수 있습니다.
409-452: 기존 2중 복합 커서 메서드와의 분리가 적절합니다.2중 복합 커서를 사용하는 기존 메서드(
fetchMyRooms)와 3중 복합 커서를 사용하는 새 메서드(fetchMyRoomsWithPriority)를 분리한 것이 좋습니다. 각각의 사용 케이스에 최적화된 구현을 유지할 수 있습니다.
442-442: cursorExpr을 endDate 자리에 전달하는 설계가 유연합니다.상황에 따라 다른 날짜 필드(endDate 또는 startDate)를 커서로 사용하면서도 DTO의 7번째 파라미터로 통일하여 전달하는 방식이 효과적입니다.
Also applies to: 489-489
#️⃣ 연관된 이슈
📝 작업 내용
수정사항 1
수정사항 2
request 로 내가 참여한 모임방 중 '모집 + 진행 중인 방 조회' 를 받을 경우, 진행중인 방 -> 모집중인 방 의 순서로 응답을 해야하는 요구사항이 있습니다
기존코드에서는 무한 스크롤 기능을 위한 response의 lastCursor 값에 마지막 데이터의 우선순위(= priority) 값을 포함하지 않아 누락 or 중복되는 데이터가 발생할 수 있는 이슈가 있었습니다
따라서 priority 값을 cursor 에 추가하여 3중 복합 커서를 활용하여 QueryDsl 코드에서 조회를 하도록 수정하였습니다
관련해서 api 통합 테스트 코드를 통해서 무한 스크롤 기능이 정상동작함을 확인했습니다
📸 스크린샷
💬 리뷰 요구사항
📌 PR 진행 시 이러한 점들을 참고해 주세요
Summary by CodeRabbit