-
Notifications
You must be signed in to change notification settings - Fork 2
course랑 북마크 좋아요기능 추가 toggle #123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The head ref may contain hidden characters: "20250607_#122_\uAE30\uB2A5\uCD94\uAC00_\uC88B\uC544\uC694_bookmark\uB791_\uCF54\uC2A4\uC5D0_\uC88B\uC544\uC694\uBD80\uC7AC"
Conversation
|
""" Walkthrough북마크와 코스에 대한 좋아요(Like) 기능이 도입되고, 관련 엔터티, DTO, 서비스, 컨트롤러가 확장 및 리팩토링되었습니다. 북마크와 코스 DTO에 좋아요 수 필드가 추가되고, Place 관련 DTO 및 반환 타입이 단순화되었습니다. 기존의 일부 DTO, 엔드포인트, 서비스 메서드는 삭제 또는 대체되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Auth
participant BookmarkController
participant BookmarkService
participant BookmarkLikeRepository
participant BookmarkRepository
User->>Auth: JWT 인증
User->>BookmarkController: POST /api/bookmark/like/{bookmarkId}
BookmarkController->>BookmarkService: likeBookmark(user, bookmarkId)
BookmarkService->>BookmarkLikeRepository: existsById(memberId, bookmarkId)
alt 좋아요 이미 존재
BookmarkService->>BookmarkLikeRepository: deleteById
BookmarkService->>BookmarkRepository: update likeCount(-1)
else 좋아요 없음
BookmarkService->>BookmarkLikeRepository: save
BookmarkService->>BookmarkRepository: update likeCount(+1)
end
BookmarkService-->>BookmarkController: void
BookmarkController-->>User: 200 OK
sequenceDiagram
participant User
participant Auth
participant CourseController
participant CourseService
participant CourseLikeRepository
participant CourseRepository
User->>Auth: JWT 인증
User->>CourseController: POST /api/course/like/{courseId}
CourseController->>CourseService: likeCourse(user, courseId)
CourseService->>CourseLikeRepository: existsById(memberId, courseId)
alt 좋아요 이미 존재
CourseService->>CourseLikeRepository: deleteById
CourseService->>CourseRepository: update likeCount(-1)
else 좋아요 없음
CourseService->>CourseLikeRepository: save
CourseService->>CourseRepository: update likeCount(+1)
end
CourseService-->>CourseController: void
CourseController-->>User: 200 OK
Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches
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. 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
Documentation and Community
|
PR 빌드 검증 결과: ✅ 빌드 성공빌드 검증이 완료되었습니다. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (15)
src/main/java/jombi/freemates/model/dto/PlaceDto.java (1)
30-31: 좌표 필드의 데이터 타입을 검토해 주세요.지리적 좌표를 나타내는
x와y필드가String타입으로 정의되어 있습니다. 좌표는 일반적으로 숫자 값이므로Double또는BigDecimal타입 사용을 고려해 보세요.- private String x; - private String y; + private Double x; // 경도 + private Double y; // 위도src/main/java/jombi/freemates/model/postgres/id/CourseLikeId.java (2)
11-19: 코드 구조는 올바르지만 equals/hashCode 메서드 추가를 고려해보세요.JPA 복합키 구현이 올바르게 되어 있습니다. 하지만 복합키 클래스에서는
equals()와hashCode()메서드를 명시적으로 구현하는 것이 좋습니다.Lombok의
@EqualsAndHashCode어노테이션을 추가하는 것을 권장합니다:@Embeddable @Getter @Setter @NoArgsConstructor @AllArgsConstructor +@EqualsAndHashCode public class CourseLikeId implements Serializable {
19-21: 불필요한 빈 줄을 제거해주세요.클래스 내부에 불필요한 빈 줄이 있습니다.
public class CourseLikeId implements Serializable { private UUID memberId; private UUID courseId; - - }src/main/java/jombi/freemates/repository/BookmarkLikeRepository.java (1)
8-11: 리포지토리 구현이 올바르지만 중복 메서드 선언이 있습니다.
JpaRepository에서 이미existsById메서드를 제공하므로 명시적으로 선언할 필요가 없습니다. 하지만 명시적 선언이 코드 가독성에 도움이 될 수 있으므로 큰 문제는 아닙니다.중복 메서드를 제거하려면:
@Repository public interface BookmarkLikeRepository extends JpaRepository<BookmarkLike, BookmarkLikeId> { - boolean existsById(BookmarkLikeId id); }src/main/java/jombi/freemates/repository/CourseLikeRepository.java (1)
8-12: 리포지토리 구현이 올바르지만 중복 메서드 선언과 포맷팅 개선이 필요합니다.
BookmarkLikeRepository와 동일한 이슈로,JpaRepository에서 이미 제공하는existsById메서드를 중복 선언하고 있습니다. 또한 불필요한 빈 줄이 있습니다.다음과 같이 개선할 수 있습니다:
@Repository public interface CourseLikeRepository extends JpaRepository<CourseLike, CourseLikeId> { - - boolean existsById(CourseLikeId id); }src/main/java/jombi/freemates/model/postgres/id/BookmarkLikeId.java (2)
11-19: 코드 구조는 올바르지만 equals/hashCode 메서드 추가를 고려해보세요.
CourseLikeId와 동일하게, JPA 복합키 구현이 올바르게 되어 있지만equals()와hashCode()메서드를 명시적으로 구현하는 것이 좋습니다.Lombok의
@EqualsAndHashCode어노테이션을 추가하세요:@Embeddable @Getter @Setter @NoArgsConstructor @AllArgsConstructor +@EqualsAndHashCode public class BookmarkLikeId implements Serializable {
19-22: 불필요한 빈 줄들을 제거해주세요.클래스 내부에 불필요한 빈 줄들이 있습니다.
public class BookmarkLikeId implements Serializable { private UUID memberId; private UUID bookmarkId; - - }src/main/java/jombi/freemates/model/postgres/BookmarkLike.java (1)
32-33: 코드 포맷팅 개선닫는 중괄호 전에 줄바꿈을 추가하세요.
- private Bookmark bookmark;} + private Bookmark bookmark; +}src/main/java/jombi/freemates/model/postgres/CourseLike.java (1)
35-37: 불필요한 빈 줄 제거파일 끝의 빈 줄들을 제거하세요.
src/main/java/jombi/freemates/service/CourseService.java (3)
69-69: 잘못 배치된 주석 정리주석이 if 문 블록 닫는 부분에 붙어있습니다. 별도 줄로 이동하거나 제거하세요.
- }// placeIds 각각으로 Place 조회 → CoursePlace 생성 - + } + + // placeIds 각각으로 Place 조회 → CoursePlace 생성
160-161: 중복된 null 체크 로직 개선
likeCount의 null 체크가 중복되어 있습니다. Course 엔티티에서 이미 기본값 0L로 초기화하므로 null일 가능성이 낮습니다.- long current = course.getLikeCount() == null ? 0L : course.getLikeCount(); + long current = course.getLikeCount();Also applies to: 171-172
183-183: 메서드 접근 제한자 재검토
converToCourseDto메서드가 public으로 선언되었지만 클래스 내부에서만 사용됩니다.- public CourseDto converToCourseDto(Course course) { + private CourseDto converToCourseDto(Course course) {src/main/java/jombi/freemates/controller/BookmarkController.java (1)
224-224: 더 명확한 설명이 필요합니다"좋아요~"는 너무 간단한 설명입니다. "북마크 좋아요 토글 기능 추가" 등으로 더 구체적으로 작성하는 것이 좋겠습니다.
- description = "좋아요~" + description = "북마크 좋아요 토글 기능 추가"src/main/java/jombi/freemates/service/BookmarkService.java (2)
104-135: 중복 저장 최적화 가능좋아요 토글 로직은 잘 구현되었습니다. 다만 bookmark 엔티티를 두 번 저장하는 부분은 최적화할 수 있습니다. JPA의 더티 체킹을 활용하면 한 번만 저장해도 됩니다.
if (exists) { // 좋아요 이미 눌린 상태 → 취소 bookmarkLikeRepository.deleteById(likeId); long current = bookmark.getLikeCount() == null ? 0L : bookmark.getLikeCount(); bookmark.setLikeCount(Math.max(0, current - 1)); - bookmarkRepository.save(bookmark); } else { // 좋아요가 아직 없는 상태 → 추가 BookmarkLike like = BookmarkLike.builder() .id(likeId) .member(member) .bookmark(bookmark) .build(); bookmarkLikeRepository.save(like); long current = bookmark.getLikeCount() == null ? 0L : bookmark.getLikeCount(); bookmark.setLikeCount(current + 1); - bookmarkRepository.save(bookmark); } +// 트랜잭션 종료 시 더티 체킹으로 자동 저장됨
203-206: placeDtos 필드명 개선 제안
placeDtos라는 필드명보다는places가 더 자연스럽습니다. DTO 내부에서 굳이 "Dto" 접미사를 사용할 필요는 없습니다.- .placeDtos(bookmark.getBookmarkPlaces().stream() + .places(bookmark.getBookmarkPlaces().stream() .map(bp -> placeService.convertToPlaceDto(bp.getPlace())) .collect(Collectors.toList()))
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (20)
src/main/java/jombi/freemates/controller/BookmarkController.java(6 hunks)src/main/java/jombi/freemates/controller/CourseController.java(2 hunks)src/main/java/jombi/freemates/controller/PlaceController.java(1 hunks)src/main/java/jombi/freemates/model/dto/BookmarkDto.java(3 hunks)src/main/java/jombi/freemates/model/dto/CourseDto.java(1 hunks)src/main/java/jombi/freemates/model/dto/CoursePlaceDto.java(0 hunks)src/main/java/jombi/freemates/model/dto/GeoCodePlaceDto.java(0 hunks)src/main/java/jombi/freemates/model/dto/PlaceDto.java(1 hunks)src/main/java/jombi/freemates/model/postgres/Bookmark.java(3 hunks)src/main/java/jombi/freemates/model/postgres/BookmarkLike.java(1 hunks)src/main/java/jombi/freemates/model/postgres/Course.java(2 hunks)src/main/java/jombi/freemates/model/postgres/CourseLike.java(1 hunks)src/main/java/jombi/freemates/model/postgres/id/BookmarkLikeId.java(1 hunks)src/main/java/jombi/freemates/model/postgres/id/CourseLikeId.java(1 hunks)src/main/java/jombi/freemates/repository/BookmarkLikeRepository.java(1 hunks)src/main/java/jombi/freemates/repository/CourseLikeRepository.java(1 hunks)src/main/java/jombi/freemates/service/BookmarkService.java(5 hunks)src/main/java/jombi/freemates/service/CourseService.java(7 hunks)src/main/java/jombi/freemates/service/PlaceService.java(3 hunks)src/main/java/jombi/freemates/util/exception/ErrorCode.java(1 hunks)
💤 Files with no reviewable changes (2)
- src/main/java/jombi/freemates/model/dto/CoursePlaceDto.java
- src/main/java/jombi/freemates/model/dto/GeoCodePlaceDto.java
🧰 Additional context used
🧬 Code Graph Analysis (6)
src/main/java/jombi/freemates/model/postgres/id/CourseLikeId.java (1)
src/main/java/jombi/freemates/model/postgres/id/BookmarkLikeId.java (1)
Embeddable(11-21)
src/main/java/jombi/freemates/model/postgres/id/BookmarkLikeId.java (1)
src/main/java/jombi/freemates/model/postgres/id/CourseLikeId.java (1)
Embeddable(11-20)
src/main/java/jombi/freemates/model/postgres/Bookmark.java (4)
src/main/java/jombi/freemates/model/dto/BookmarkDto.java (1)
Builder(14-35)src/main/java/jombi/freemates/model/postgres/BookmarkLike.java (1)
Entity(15-32)src/main/java/jombi/freemates/model/postgres/BookmarkPlace.java (1)
Entity(17-39)src/main/java/jombi/freemates/model/postgres/Place.java (1)
Entity(31-98)
src/main/java/jombi/freemates/model/postgres/Course.java (5)
src/main/java/jombi/freemates/model/dto/BookmarkDto.java (1)
Builder(14-35)src/main/java/jombi/freemates/model/postgres/Bookmark.java (1)
Entity(29-66)src/main/java/jombi/freemates/model/postgres/CourseLike.java (1)
Entity(16-34)src/main/java/jombi/freemates/model/postgres/CoursePlace.java (1)
Entity(17-41)src/main/java/jombi/freemates/model/postgres/Place.java (1)
Entity(31-98)
src/main/java/jombi/freemates/model/postgres/CourseLike.java (3)
src/main/java/jombi/freemates/model/postgres/Bookmark.java (1)
Entity(29-66)src/main/java/jombi/freemates/model/postgres/BookmarkLike.java (1)
Entity(15-32)src/main/java/jombi/freemates/model/postgres/Course.java (1)
Entity(28-63)
src/main/java/jombi/freemates/model/postgres/BookmarkLike.java (2)
src/main/java/jombi/freemates/model/postgres/Bookmark.java (1)
Entity(29-66)src/main/java/jombi/freemates/model/postgres/CourseLike.java (1)
Entity(16-34)
🔇 Additional comments (16)
src/main/java/jombi/freemates/util/exception/ErrorCode.java (1)
55-55: 코스 관련 에러 코드 추가가 적절합니다.새로운 코스 좋아요 기능을 위한
COURSE_NOT_FOUND에러 코드가 올바르게 추가되었습니다. HTTP 상태 코드와 메시지가 적절합니다.src/main/java/jombi/freemates/model/dto/BookmarkDto.java (3)
3-3: 필요한 import 추가가 적절합니다.새로운
placeDtos필드를 위한Listimport가 올바르게 추가되었습니다.
20-20: DTO 클래스명 변경이 일관성을 개선합니다.
BookmarkResponse에서BookmarkDto로의 네이밍 변경이 DTO 명명 규칙과 일치하며 코드 일관성을 향상시킵니다.
30-32: 좋아요 기능을 위한 필드 추가가 적절합니다.북마크의 좋아요 수를 나타내는
likeCount필드와 연관된 장소 정보를 담는placeDtos필드가 올바르게 추가되었습니다. 이는 PR 목표인 좋아요 기능 구현을 잘 지원합니다.src/main/java/jombi/freemates/controller/PlaceController.java (1)
115-115: DTO 통합을 위한 반환 타입 변경이 적절합니다.
GeoCodePlaceDto에서PlaceDto로의 반환 타입 변경이 DTO 통합 전략과 일치합니다.PlaceDto에 좌표 필드(x,y)가 추가되어 기존GeoCodePlaceDto의 기능을 대체할 수 있습니다.src/main/java/jombi/freemates/controller/CourseController.java (1)
186-222: 코스 좋아요 API 구현이 적절합니다.새로운 좋아요 토글 엔드포인트가 올바르게 구현되었습니다:
- REST 규칙에 맞는 POST 메서드 사용
- 적절한 인증 처리 및 경로 변수 검증
- 명확한 API 문서화와 에러 코드 정의
- 서비스 레이어와의 깔끔한 분리
src/main/java/jombi/freemates/model/postgres/Bookmark.java (3)
26-26: @Setter 어노테이션 추가가 적절합니다.엔티티에 Setter 기능이 추가되어 좋아요 기능에서 likeCount 필드를 업데이트할 수 있습니다.
Also applies to: 34-34
51-52: 좋아요 수 필드 추가가 올바르게 구현되었습니다.likeCount 필드가 적절하게 추가되었습니다:
- Long 타입으로 큰 숫자를 지원
- @Builder.Default로 기본값 0L 설정
- 빌더 패턴에서 올바른 초기화 보장
62-62: bookmarkPlaces 필드에 @Builder.Default 추가가 좋습니다.빌더 패턴 사용 시 빈 리스트로 안전하게 초기화됩니다.
src/main/java/jombi/freemates/service/PlaceService.java (2)
121-121: DTO 통합 리팩토링이 적절합니다.GeoCodePlaceDto를 PlaceDto로 통합하여 코드베이스가 단순화되었습니다. 반환 타입 변경이 일관성 있게 적용되었습니다.
Also applies to: 133-133
151-152: 좌표 필드 추가가 올바릅니다.PlaceDto 변환 메서드에 x, y 좌표 필드가 추가되어 장소 정보가 더 완전해졌습니다.
src/main/java/jombi/freemates/model/dto/CourseDto.java (2)
43-43: DTO 필드명 변경이 일관성 있게 적용되었습니다.coursePlaceDtos에서 placeDtos로 변경되어 PlaceDto 사용과 일치합니다.
45-46: 좋아요 수 필드 추가가 적절합니다.likeCount 필드가 추가되어 코스의 인기도를 표시할 수 있습니다. Schema 문서화도 잘 되어 있습니다.
src/main/java/jombi/freemates/model/postgres/Course.java (1)
52-54: 필드 초기화 처리가 적절합니다
@Builder.Default를 사용한 초기값 설정이 null 방지와 일관성 있는 객체 생성을 보장합니다.Also applies to: 60-60
src/main/java/jombi/freemates/service/CourseService.java (1)
104-106: EntityManager 명시적 사용 검토 필요
flush()와clear()를 명시적으로 호출하는 것은 성능에 영향을 줄 수 있습니다. Spring의 트랜잭션 관리가 자동으로 처리하므로 특별한 이유가 없다면 제거를 고려하세요.EntityManager 사용이 필요한 특별한 이유가 있나요? 일반적으로
@Transactional이 flush를 자동 처리합니다.src/main/java/jombi/freemates/controller/BookmarkController.java (1)
90-95: 빌더 패턴 사용이 좋습니다!BookmarkRequest 생성 시 빌더 패턴을 사용하는 것은 가독성과 유지보수성 측면에서 좋은 선택입니다.
| @SuperBuilder | ||
| @NoArgsConstructor | ||
| @AllArgsConstructor | ||
| @Setter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
전체 엔티티에 @Setter 적용 재검토 필요
JPA 엔티티 전체에 @Setter를 적용하면 모든 필드가 변경 가능해져 캡슐화가 깨지고 동시성 문제가 발생할 수 있습니다. 특히 ID나 생성 시간 같은 불변 필드도 setter가 노출됩니다.
필요한 필드에만 개별적으로 setter를 추가하는 것을 권장합니다:
-@Setter
public class Course extends BasePostgresEntity {
+
+ // ... 기존 필드들 ...
+
+ public void setLikeCount(Long likeCount) {
+ this.likeCount = likeCount;
+ }
+
+ // 다른 필요한 setter 메서드들도 개별적으로 추가📝 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.
| @Setter | |
| // Remove the class-level @Setter | |
| public class Course extends BasePostgresEntity { | |
| // ... existing fields ... | |
| public void setLikeCount(Long likeCount) { | |
| this.likeCount = likeCount; | |
| } | |
| // 다른 필요한 setter 메서드들도 개별적으로 추가 | |
| } |
🤖 Prompt for AI Agents
In src/main/java/jombi/freemates/model/postgres/Course.java at line 33, remove
the class-level @Setter annotation to avoid exposing setters for all fields,
which breaks encapsulation and can cause concurrency issues. Instead, add
@Setter annotations only to specific fields that require modification, excluding
immutable fields like ID and creation timestamps.
src/main/java/jombi/freemates/controller/BookmarkController.java
Outdated
Show resolved
Hide resolved
PR 빌드 검증 결과: ✅ 빌드 성공빌드 검증이 완료되었습니다. |
There was a problem hiding this 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
♻️ Duplicate comments (1)
src/main/java/jombi/freemates/controller/BookmarkController.java (1)
241-241: 과거 리뷰에서 지적된 에러코드 설명이 올바르게 수정되었습니다.이전에
PLACE_NOT_FOUND로 잘못 기재되었던 것이BOOKMARK_NOT_FOUND로 올바르게 수정되었습니다.
🧹 Nitpick comments (4)
src/main/java/jombi/freemates/controller/BookmarkController.java (4)
66-66: API 문서에서 반환 타입 설명을 업데이트하세요.반환값 설명에서
BookmarkResponse를BookmarkDto로 수정해야 합니다.- ## 반환값 (`BookmarkResponse`) + ## 반환값 (`BookmarkDto`)
116-116: API 문서에서 반환 타입 설명을 업데이트하세요.반환값 설명에서
BookmarkResponse를BookmarkDto로 수정해야 합니다.- ## 반환값 (`BookmarkResponse`) + ## 반환값 (`BookmarkDto`)
150-150: API 문서에서 반환 타입 설명을 업데이트하세요.반환값 설명에서
Page<BookmarkResponse>를Page<BookmarkDto>로 수정해야 합니다.- ## 반환값 (`Page<BookmarkResponse>`) + ## 반환값 (`Page<BookmarkDto>`)
228-242: API 문서에서 토글 동작을 명확히 설명하세요.좋아요 API가 토글 방식으로 동작한다면 이를 명확히 문서화해야 합니다. 또한 현재 좋아요 상태를 클라이언트에게 반환하는 것을 고려해보세요.
문서 개선 제안:
summary = "북마크 좋아요", description = """ ## 인증(JWT): **필요** + ## 동작 방식 + - 좋아요가 되어있지 않은 상태면 좋아요 추가 + - 이미 좋아요가 되어있는 상태면 좋아요 취소 (토글 방식) + ## 요청 파라미터응답 개선 제안 (선택적):
- public ResponseEntity<Void> likeBookmark( + public ResponseEntity<Map<String, Boolean>> likeBookmark(좋아요 상태를
{"liked": true/false}형태로 반환하여 클라이언트가 현재 상태를 알 수 있도록 할 수 있습니다.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/main/java/jombi/freemates/controller/BookmarkController.java(6 hunks)src/main/java/jombi/freemates/model/postgres/CourseLike.java(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/main/java/jombi/freemates/model/postgres/CourseLike.java
🔇 Additional comments (1)
src/main/java/jombi/freemates/controller/BookmarkController.java (1)
90-97: 빌더 패턴 적용이 코드 가독성을 향상시켰습니다.BookmarkRequest 생성 시 빌더 패턴을 사용하여 코드가 더 명확하고 읽기 쉬워졌습니다.
#122
Summary by CodeRabbit