Skip to content

Conversation

@seongjunnoh
Copy link
Collaborator

@seongjunnoh seongjunnoh commented Sep 3, 2025

#️⃣ 연관된 이슈

closes #290

📝 작업 내용

  • 수정사항 1

    • 유저가 참여한 모임방 중, 모집중인 방의 경우 api response 의 endDate 는 '방 모집마감일 == 방 진행 시작일' 이어야 하는데, 기존 코드에서는 '방 진행 마감일' 로 잘못 매핑되어 있었습니다.
    • QueryDsl 코드에서 RoomQueryDto 를 반환하는 부분을 수정하였습니다.
    • 로컬 서버에서 테스트 해보았습니다
    • 데이터 : 9월 10일(= 6일 뒤) 에 start 하는 방에 참여한 상황을 가정
      image
  • 수정사항 2

    • request 로 내가 참여한 모임방 중 '모집 + 진행 중인 방 조회' 를 받을 경우, 진행중인 방 -> 모집중인 방 의 순서로 응답을 해야하는 요구사항이 있습니다

      • 정렬 기준
        image
    • 기존코드에서는 무한 스크롤 기능을 위한 response의 lastCursor 값에 마지막 데이터의 우선순위(= priority) 값을 포함하지 않아 누락 or 중복되는 데이터가 발생할 수 있는 이슈가 있었습니다

    • 따라서 priority 값을 cursor 에 추가하여 3중 복합 커서를 활용하여 QueryDsl 코드에서 조회를 하도록 수정하였습니다

    • 관련해서 api 통합 테스트 코드를 통해서 무한 스크롤 기능이 정상동작함을 확인했습니다

📸 스크린샷

💬 리뷰 요구사항

📌 PR 진행 시 이러한 점들을 참고해 주세요

* P1 : 꼭 반영해 주세요 (Request Changes) - 이슈가 발생하거나 취약점이 발견되는 케이스 등
* P2 : 반영을 적극적으로 고려해 주시면 좋을 것 같아요 (Comment)
* P3 : 이런 방법도 있을 것 같아요~ 등의 사소한 의견입니다 (Chore)

Summary by CodeRabbit

  • New Features
    • 내 모임(진행중+모집중) 혼합 목록의 페이지네이션을 개선했습니다. 우선순위 기반 커서를 사용해 정렬과 이어보기가 안정적이며, 첫 페이지는 최대 10개를 반환하고 다음 페이지 커서를 제공합니다. 중복/누락 없이 연속 조회가 가능하고 마지막 페이지 여부가 정확히 표시됩니다.
  • Tests
    • 혼합 목록 페이지네이션 동작(정렬, 커서 이동, isLast 표시)을 검증하는 통합 테스트를 추가했습니다.

- 모집중인 방의 경우, 반환하는 RoomQueryDto의 endDate 값을 방 모집마감일로 응답하도록 수정
- 모집+진행중인 방을 조회하는 경우, 페이징처리를 위한 커서에 Integer priority 추가
- 모집 + 진행중인 방 조회시, 누락&중복되는 데이터 없이 무한스크롤 기능 동작하는지 검증하는 테스트 코드 추가
@seongjunnoh seongjunnoh linked an issue Sep 3, 2025 that may be closed by this pull request
2 tasks
@coderabbitai
Copy link

coderabbitai bot commented Sep 3, 2025

Walkthrough

혼합 목록(진행중+모집중) 조회의 페이징 커서가 2필드에서 3필드(우선순위, 날짜, ID)로 확장되었고, 이에 따라 어댑터·리포지토리 시그니처와 정렬/커서 비교 로직이 변경되었습니다. DTO 생성자가 추가되었으며, 혼합 페이징 시나리오에 대한 통합 테스트가 추가되었습니다.

Changes

Cohort / File(s) Summary
Persistence Adapter
src/main/java/.../RoomQueryPersistenceAdapter.java
혼합(진행중+모집중) 조회에서 3필드 커서(priority,date,id) 처리. 리포지토리 호출 시 lastPriority 추가. 다음 페이지 커서 생성 로직에 우선순위 포함.
Repository API
src/main/java/.../repository/RoomQueryRepository.java
findPlayingAndRecruitingRoomsUserParticipated 시그니처 변경: (userId, priorityCursor, dateCursor, roomIdCursor, pageSize)로 확장.
Repository Impl
src/main/java/.../repository/RoomQueryRepositoryImpl.java
3키 정렬(우선순위 asc, 기준일 asc, roomId asc)과 해당 커서 조건 추가. 우선순위 계산(CASE: 진행중=0, 모집중=1) 도입. 프로젝션에서 동적 기준일 사용.
DTO
src/main/java/.../dto/RoomQueryDto.java
주석 정리 및 @QueryProjection 생성자 2종 추가(엔드데이트 기반/공개여부 포함).
Tests
src/test/java/.../RoomShowMineApiTest.java
혼합 목록 페이징 통합 테스트 추가: 첫 페이지 10개(진행 6 + 모집 4), 커서 형식 `priority

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)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Assessment against linked issues

Objective Addressed Explanation
내 모임방 목록 조회 API에서 모집 중 방의 모집 마감일 정보가 잘못 반환되는 오류 수정 (#290) 커서/정렬 로직과 동적 기준일 적용은 확인되나, 응답 필드가 정확히 교정되었는지 테스트 단언이 부족함.

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
혼합 조회 페이징 커서를 3필드로 확장하고 관련 리포지토리 시그니처 변경 (RoomQueryPersistenceAdapter.java, RoomQueryRepository*.java) 이슈는 응답의 모집 마감일 값 오류 수정에 국한되어 있으나, 커서 구조/페이징 API 변경은 명시적 요구사항에 포함되지 않음.
DTO에 신규 @QueryProjection 생성자 2종 추가 (RoomQueryDto.java) 응답 오류 수정과 직접적 연관이 불분명하며, 범위 확장을 수반할 수 있음.

Possibly related PRs

Suggested labels

🔥 hotfix, 👻 성준

Suggested reviewers

  • hd0rable
  • buzz0331

Poem

폴짝, 커서 셋 쥐고 뛰어가네
0이면 진행, 1이면 모집—길이 분명하네
날짜와 ID 차곡차곡, 꼬리표 정갈하게
누락도 중복도 없이, 당근처럼 깔끔하게
오늘의 방, 내일의 방—토끼 마음 가볍게 🥕🐇

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch hotfix/#290-rooms-show-mine-api-response

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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

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

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit 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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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.

@github-actions
Copy link

github-actions bot commented Sep 3, 2025

Test Results

452 tests   452 ✅  42s ⏱️
130 suites    0 💤
130 files      0 ❌

Results for commit 1c05c0d.

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

📥 Commits

Reviewing files that changed from the base of the PR and between fe1e79e and 1c05c0d.

📒 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

@seongjunnoh seongjunnoh merged commit 173b199 into develop Sep 3, 2025
4 checks passed
@seongjunnoh seongjunnoh deleted the hotfix/#290-rooms-show-mine-api-response branch September 3, 2025 08:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[THIP2025-337] [hotfix] 내 모임방 목록 조회 response 수정

2 participants