Skip to content

Conversation

@Yujin1219
Copy link
Member

@Yujin1219 Yujin1219 commented Dec 11, 2025

#️⃣ 연관된 이슈

📝 작업 내용

  • 호텔 조회 API 구현 - 커서 기반 무한스크롤

📌 공유 사항

✅ 체크리스트

  • Reviewer에 팀원들을 선택 했나요?
  • Assignees에 본인을 선택 했나요?
  • Merge 하려는 브랜치가 올바르게 설정되어 있나요?
  • 컨벤션을 지키고 있나요?
  • 로컬에서 실행했을 때 에러가 발생하지 않나요?
  • 불필요한 주석이 제거되었나요?
  • 코드 스타일이 일관적인가요?

스크린샷 (선택)

💬 리뷰 요구사항 (선택)

ex) 메서드 XXX의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이 있을까요? or 변경 사항 등

Summary by CodeRabbit

Release Notes

  • New Features
    • 숙박 시설 추천 조회 기능이 추가되었습니다.
    • 무한 스크롤 방식의 커서 기반 페이징으로 숙박 시설 목록을 조회할 수 있습니다.
    • 호텔명, 도시, 1박 요금, 체크인/아웃 날짜, 이미지 등의 정보를 확인할 수 있습니다.
    • 비회원도 접근 가능한 기능입니다.

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

@Yujin1219 Yujin1219 self-assigned this Dec 11, 2025
@Yujin1219 Yujin1219 added the ✨ feature 새로운 기능 개발 label Dec 11, 2025
@Yujin1219 Yujin1219 linked an issue Dec 11, 2025 that may be closed by this pull request
1 task
@coderabbitai
Copy link

coderabbitai bot commented Dec 11, 2025

Walkthrough

숙소 추천 조회를 위한 REST API를 구현하는 변경사항으로, 커서 기반 페이지네이션 기능을 포함하여 컨트롤러, 서비스, 리포지토리, 엔티티, DTO 및 보안 설정을 추가합니다.

Changes

Cohort / File(s) Summary
DTO 계층
src/main/java/com/example/triptalk/domain/tripPlan/dto/AccommodationResponse.java
AccommodationDTO와 AccommodationListResultDTO 두 개의 공개 정적 내부 DTO 클래스를 포함하는 새로운 래퍼 컨테이너 추가. Lombok 및 Swagger 어노테이션 포함
엔티티 계층
src/main/java/com/example/triptalk/domain/tripPlan/entity/Accommodation.java
BaseEntity를 확장하는 JPA 엔티티 클래스 추가. hotelName, cityName, pricePerNight, checkInDate, checkOutDate, imageUrl 필드 정의
리포지토리 계층
src/main/java/com/example/triptalk/domain/tripPlan/repository/AccommodationRepository.java
JpaRepository를 확장하는 Spring Data JPA 리포지토리 추가. JPQL 쿼리를 통한 커서 기반 조회 메서드 구현
서비스 계층
src/main/java/com/example/triptalk/domain/tripPlan/service/AccommodationService.java,
src/main/java/com/example/triptalk/domain/tripPlan/service/AccommodationServiceImpl.java
AccommodationService 인터페이스 및 구현체 AccommodationServiceImpl 추가. 커서 기반 무한 스크롤 로직 구현
변환기 계층
src/main/java/com/example/triptalk/domain/tripPlan/converter/AccommodationConverter.java
엔티티를 DTO로 변환하는 유틸리티 클래스 추가. toAccommodationDTO, toAccommodationListResultDTO 메서드 포함
컨트롤러 계층
src/main/java/com/example/triptalk/domain/tripPlan/controller/AccommodationController.java
/api/accommodations GET 엔드포인트를 노출하는 새로운 REST 컨트롤러 추가. 커서ID 쿼리 매개변수 지원
보안 설정
src/main/java/com/example/triptalk/global/config/SecurityConfig.java
/api/accommodations/\* 경로를 공개 엔드포인트로 허용. 항공권 관련 주석 업데이트

Suggested reviewers

  • ys1217-gg
  • davidcho0701

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 변경사항의 주요 내용을 명확하게 설명합니다. 호텔 조회 API 구현이라는 핵심 변경사항을 간결하게 전달합니다.
Description check ✅ Passed PR 설명이 기본 템플릿을 따르고 있으나, '공유 사항' 섹션과 '리뷰 요구사항' 섹션이 비어있으며 체크리스트 항목들이 완료되지 않았습니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#20

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/main/java/com/example/triptalk/domain/tripPlan/entity/Accommodation.java (1)

9-14: JPA 엔티티에서 @Setter 사용을 재고하세요.

JPA 엔티티에 @Setter를 사용하면 의도하지 않은 변경이 발생할 수 있습니다. 필요한 경우 특정 필드에만 개별 setter를 제공하거나, 빌더 패턴만 사용하는 것을 권장합니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 64a845b and 080b8f3.

📒 Files selected for processing (8)
  • src/main/java/com/example/triptalk/domain/tripPlan/controller/AccommodationController.java (1 hunks)
  • src/main/java/com/example/triptalk/domain/tripPlan/converter/AccommodationConverter.java (1 hunks)
  • src/main/java/com/example/triptalk/domain/tripPlan/dto/AccommodationResponse.java (1 hunks)
  • src/main/java/com/example/triptalk/domain/tripPlan/entity/Accommodation.java (1 hunks)
  • src/main/java/com/example/triptalk/domain/tripPlan/repository/AccommodationRepository.java (1 hunks)
  • src/main/java/com/example/triptalk/domain/tripPlan/service/AccommodationService.java (1 hunks)
  • src/main/java/com/example/triptalk/domain/tripPlan/service/AccommodationServiceImpl.java (1 hunks)
  • src/main/java/com/example/triptalk/global/config/SecurityConfig.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/main/java/com/example/triptalk/domain/tripPlan/service/AccommodationService.java (1)
src/main/java/com/example/triptalk/domain/tripPlan/dto/AccommodationResponse.java (1)
  • AccommodationResponse (12-66)
src/main/java/com/example/triptalk/domain/tripPlan/controller/AccommodationController.java (1)
src/main/java/com/example/triptalk/domain/tripPlan/dto/AccommodationResponse.java (1)
  • AccommodationResponse (12-66)
src/main/java/com/example/triptalk/domain/tripPlan/service/AccommodationServiceImpl.java (2)
src/main/java/com/example/triptalk/domain/tripPlan/converter/AccommodationConverter.java (1)
  • AccommodationConverter (9-47)
src/main/java/com/example/triptalk/domain/tripPlan/dto/AccommodationResponse.java (1)
  • AccommodationResponse (12-66)
src/main/java/com/example/triptalk/domain/tripPlan/converter/AccommodationConverter.java (1)
src/main/java/com/example/triptalk/domain/tripPlan/dto/AccommodationResponse.java (1)
  • AccommodationResponse (12-66)
🔇 Additional comments (8)
src/main/java/com/example/triptalk/global/config/SecurityConfig.java (1)

44-47: 변경사항이 올바르게 적용되었습니다.

새로운 숙소 조회 엔드포인트를 비인증 사용자에게 공개하는 설정이 기존 패턴과 일관되게 구현되었습니다.

src/main/java/com/example/triptalk/domain/tripPlan/service/AccommodationService.java (1)

5-12: 인터페이스 설계가 명확합니다.

커서 기반 페이지네이션을 위한 메서드 시그니처가 적절하게 정의되었으며, Javadoc도 명확합니다.

src/main/java/com/example/triptalk/domain/tripPlan/repository/AccommodationRepository.java (1)

18-24: 커서 기반 쿼리가 올바르게 구현되었습니다.

ID 내림차순 정렬과 a.id < :cursorId 필터링 조합이 정확하며, Slice 사용으로 효율적인 페이지네이션을 구현했습니다.

src/main/java/com/example/triptalk/domain/tripPlan/controller/AccommodationController.java (1)

20-47: 컨트롤러 구현이 우수합니다.

엔드포인트 구현이 깔끔하며, 특히 Swagger 문서화가 상세하고 사용법까지 포함되어 있어 API 사용자에게 도움이 됩니다.

src/main/java/com/example/triptalk/domain/tripPlan/converter/AccommodationConverter.java (1)

14-24: 엔티티-DTO 변환 로직이 정확합니다.

모든 필드가 올바르게 매핑되었습니다.

src/main/java/com/example/triptalk/domain/tripPlan/entity/Accommodation.java (1)

17-33: 엔티티 필드 정의가 적절합니다.

모든 필드에 적절한 제약조건과 타입이 지정되었으며, 컬럼 길이도 명시되어 있습니다.

src/main/java/com/example/triptalk/domain/tripPlan/dto/AccommodationResponse.java (1)

14-65: DTO 구조가 깔끔하게 설계되었습니다.

커서 기반 페이지네이션에 필요한 모든 필드가 포함되었으며, Swagger 어노테이션으로 API 문서화도 잘 되어 있습니다.

src/main/java/com/example/triptalk/domain/tripPlan/service/AccommodationServiceImpl.java (1)

26-34: 서비스 구현이 간결하고 정확합니다.

커서 기반 페이지네이션 로직이 올바르게 구현되었으며, PageRequest.of(0, PAGE_SIZE) 사용이 적절합니다. 읽기 전용 트랜잭션 설정도 적절합니다.

Comment on lines +29 to +46
public static AccommodationResponse.AccommodationListResultDTO toAccommodationListResultDTO(Slice<Accommodation> slice) {
List<AccommodationResponse.AccommodationDTO> accommodationList = slice.getContent().stream()
.map(AccommodationConverter::toAccommodationDTO)
.toList();

// 다음 커서 ID는 마지막 항목의 ID
Long nextCursorId = accommodationList.isEmpty() ?
null :
accommodationList.getLast().getId();

return AccommodationResponse.AccommodationListResultDTO.builder()
.accommodationList(accommodationList)
.accommodationListSize(accommodationList.size())
.isFirst(slice.isFirst())
.hasNext(slice.hasNext())
.nextCursorId(nextCursorId)
.build();
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

hasNext가 false일 때 nextCursorId를 null로 설정하세요.

현재 구현은 다음 페이지가 없어도 마지막 항목의 ID를 nextCursorId로 반환합니다. 클라이언트는 hasNext를 확인해야 하지만, API를 더 방어적으로 만들기 위해 다음 페이지가 없을 때는 nextCursorId를 null로 설정하는 것이 좋습니다.

다음과 같이 수정하세요:

     // 다음 커서 ID는 마지막 항목의 ID
-    Long nextCursorId = accommodationList.isEmpty() ?
-            null :
-            accommodationList.getLast().getId();
+    Long nextCursorId = accommodationList.isEmpty() || !slice.hasNext() ?
+            null :
+            accommodationList.getLast().getId();
📝 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 static AccommodationResponse.AccommodationListResultDTO toAccommodationListResultDTO(Slice<Accommodation> slice) {
List<AccommodationResponse.AccommodationDTO> accommodationList = slice.getContent().stream()
.map(AccommodationConverter::toAccommodationDTO)
.toList();
// 다음 커서 ID는 마지막 항목의 ID
Long nextCursorId = accommodationList.isEmpty() ?
null :
accommodationList.getLast().getId();
return AccommodationResponse.AccommodationListResultDTO.builder()
.accommodationList(accommodationList)
.accommodationListSize(accommodationList.size())
.isFirst(slice.isFirst())
.hasNext(slice.hasNext())
.nextCursorId(nextCursorId)
.build();
}
public static AccommodationResponse.AccommodationListResultDTO toAccommodationListResultDTO(Slice<Accommodation> slice) {
List<AccommodationResponse.AccommodationDTO> accommodationList = slice.getContent().stream()
.map(AccommodationConverter::toAccommodationDTO)
.toList();
// 다음 커서 ID는 마지막 항목의 ID
Long nextCursorId = accommodationList.isEmpty() || !slice.hasNext() ?
null :
accommodationList.getLast().getId();
return AccommodationResponse.AccommodationListResultDTO.builder()
.accommodationList(accommodationList)
.accommodationListSize(accommodationList.size())
.isFirst(slice.isFirst())
.hasNext(slice.hasNext())
.nextCursorId(nextCursorId)
.build();
}
🤖 Prompt for AI Agents
In
src/main/java/com/example/triptalk/domain/tripPlan/converter/AccommodationConverter.java
around lines 29 to 46, the method currently sets nextCursorId to the last item's
ID even when slice.hasNext() is false; change the logic so nextCursorId is null
when there is no next page by checking slice.hasNext() and only assigning the
last item's ID if slice.hasNext() is true (otherwise set null), then return the
DTO with that adjusted value.

@Yujin1219 Yujin1219 merged commit 172550d into develop Dec 11, 2025
2 checks passed
@Yujin1219 Yujin1219 deleted the feat/#20 branch December 11, 2025 01:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ feature 새로운 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

✨ Feat: 호텔 조회 API 구현

2 participants