Skip to content

Conversation

@seung-in-Yoo
Copy link
Member

@seung-in-Yoo seung-in-Yoo commented Aug 16, 2025

✔️ 연관 이슈

📝 작업 내용

1. 내 장소 리스트 요약 조회 구현 (장소만, 개수 포함)

  • GET /api/v1/users/places
  • Query: sort=latest | name (기본 latest)

2. 내 장소 안의 웨이블존 목록 조회 (페이징) 구현

  • GET /api/v1/users/places/zones?placeId={id}&page=0&size=20

3. 내가 저장한 장소에서 웨이블존 삭제 기능 구현

  • DELETE /api/v1/users/places

4. 페이징/정렬 이슈 해결

Swagger에서 page=1을 넘겼을 때 빈 content가 생기던 문제 → Spring Data 0-based 페이지 관련 컨트롤러에서 그대로 위임하도록 변경

5. 색상/개수 필드 추가 및 자동 증가,감소하도록 설정

color(default=GRAY), savedCount(default 0) 사용.

저장 시 increaseCount()으로 증가, 제거 시 decreaseCount()으로 감소

6. Eager Loading 최적화

  • UserPlaceWaybleZoneMappingRepository.findZonesByPlaceId는 WaybleZone 엔티티 자체를 페이징 조회하여 카드에 필요한 필드만 매핑해 응답하도록 설정

  • 요약 조회는 리스트만 반환하여 N+1, 과도한 조인 및 로딩 방지.

7. 웨이블존 리뷰 작성에서 user_id 제거

  • 프론트 요구에 따라 요청 본문에서 user_id 삭제.
  • 인증된 사용자 ID는 SecurityContextHolder에서 추출.

🖼️스크린샷 (선택)

웨이블존성공3 리뷰작성성공 웨이블존제거성공

💬 리뷰 요구사항 (선택)

배포 DB에 칼럼 추가 및 칼럼 삭제 필요 (추가: user_place 테이블에 color,saved_count, 삭제: review 테이블에 user_id)
color 기본값을 임시 GRAY로 설정하였지만 기본값에 대해 얘기해보고 변경 및 색상을 정의하여 enum으로 관리하면 좋을거같음

Summary by CodeRabbit

  • New Features

    • 내 장소 요약 조회(정렬 지원) 추가
    • 특정 장소의 웨이블존 목록 페이지네이션 조회 추가
    • 내 장소에서 웨이블존 제거 기능 추가
    • 장소 색상 지정 및 저장 수 표시 지원
    • 리뷰 작성 시 로그인 사용자 자동 인식(Authorization 헤더 불필요)
  • Bug Fixes

    • 좋아요 수가 음수로 내려가는 문제 방지
    • 리뷰 이미지가 있을 때만 처리해 안정성 개선
  • API 변경

    • 리뷰 등록 요청에서 userId/Authorization 헤더 입력 불필요
    • 기존 “내 장소 전체 목록” 조회 엔드포인트가 제거되고 제거 API로 대체됨

@seung-in-Yoo seung-in-Yoo self-assigned this Aug 16, 2025
@seung-in-Yoo seung-in-Yoo added 🔧 refactor 코드 리팩토링 🛠️ fix 기능 오류 및 코드 개선이 필요한 곳 수정 labels Aug 16, 2025
@coderabbitai
Copy link

coderabbitai bot commented Aug 16, 2025

Walkthrough

리뷰 등록과 유저 장소 기능이 인증 헤더/DTO의 userId 의존을 제거하고 SecurityContext 기반으로 사용자 식별하도록 변경. 유저 장소 API를 요약 목록/페이지네이션 중심으로 재구성하고 장소-존 매핑 삭제 엔드포인트를 추가. 엔티티·레포지토리·DTO·에러코드가 확장·추가되고 WaybleZone 좋아요 가드가 추가됨.

Changes

Cohort / File(s) Change summary
Review flow (SecurityContext 전환)
src/main/java/com/wayble/server/review/controller/ReviewController.java, src/main/java/com/wayble/server/review/service/ReviewService.java, src/main/java/com/wayble/server/review/dto/ReviewRegisterDto.java
컨트롤러에서 Authorization 헤더 제거 및 registerReview 시그니처 변경; DTO에서 userId 제거. 컨트롤러가 SecurityContext에서 userId 추출해 서비스에 전달. 서비스 시그니처를 (zoneId, userId, dto)로 변경. 이미지 처리 시 빈 리스트 무시로 조건 강화.
UserPlace 컨트롤러/서비스 재구성
src/main/java/com/wayble/server/user/controller/UserPlaceController.java, src/main/java/com/wayble/server/user/service/UserPlaceService.java
기존 getUserPlaces 제거하고 요약 목록(getMyPlaceSummaries) 및 장소 내 존 페이지 조회(getZonesInPlace) 추가. 매핑 삭제용 엔드포인트(removeZoneFromPlace) 추가. 컨트롤러·서비스에서 SecurityContext 기반 userId 추출 사용으로 변경.
UserPlace DTO 추가/변경
src/main/java/com/wayble/server/user/dto/UserPlaceRemoveRequestDto.java, src/main/java/com/wayble/server/user/dto/UserPlaceRequestDto.java, src/main/java/com/wayble/server/user/dto/UserPlaceSummaryDto.java, src/main/java/com/wayble/server/user/dto/UserPlaceZonesResponseDto.java
장소 삭제 요청 DTO 신규 추가(placeId, waybleZoneId). UserPlaceRequestDto에 color 선택 필드 추가. 장소 요약 DTO와 장소-존 응답 DTO 신설(빌더 포함).
UserPlace 엔티티 확장
src/main/java/com/wayble/server/user/entity/UserPlace.java
color(기본 "GRAY")와 savedCount(기본 0) 필드 추가, increase/decrease count 및 title/color 업데이트 메서드 추가, 소프트 삭제 어노테이션 추가.
UserPlace 리포지토리 확장
src/main/java/com/wayble/server/user/repository/UserPlaceRepository.java, src/main/java/com/wayble/server/user/repository/UserPlaceWaybleZoneMappingRepository.java
사용자별 정렬 조회·소유 검증용 조회 메서드 추가, 매핑 존재 확인/삭제 메서드 추가. 장소별 WaybleZone 페이징 조회용 JPQL 쿼리 추가.
User 에러코드 보강
src/main/java/com/wayble/server/user/exception/UserErrorCase.java
PLACE_NOT_FOUND, PLACE_MAPPING_NOT_FOUND 에러 코드 추가.
WaybleZone 안전 가드
src/main/java/com/wayble/server/wayblezone/entity/WaybleZone.java
addLikes 호출 후 likes가 음수가 되지 않도록 0 미만 시 0으로 보정하는 가드 추가.

Sequence Diagram(s)

sequenceDiagram
  participant C as 클라이언트
  participant RC as ReviewController
  participant Sec as SecurityContextHolder
  participant RS as ReviewService
  C->>RC: POST /zones/{id}/reviews (dto)
  RC->>Sec: Authentication 조회
  Sec-->>RC: userId
  RC->>RS: registerReview(zoneId, userId, dto)
  RS-->>C: 200 OK
Loading
sequenceDiagram
  participant C as 클라이언트
  participant UPC as UserPlaceController
  participant Sec as SecurityContextHolder
  participant UPS as UserPlaceService
  C->>UPC: GET /user/places?sort=latest
  UPC->>Sec: Authentication 조회
  Sec-->>UPC: userId
  UPC->>UPS: getMyPlaceSummaries(userId, sort)
  UPS-->>C: List<UserPlaceSummaryDto>
Loading
sequenceDiagram
  participant C as 클라이언트
  participant UPC as UserPlaceController
  participant Sec as SecurityContextHolder
  participant UPS as UserPlaceService
  C->>UPC: DELETE /user/places (body: placeId, waybleZoneId)
  UPC->>Sec: Authentication 조회
  Sec-->>UPC: userId
  UPC->>UPS: removeZoneFromPlace(userId, placeId, waybleZoneId)
  UPS-->>C: "삭제되었습니다"
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

💡 feature

Suggested reviewers

  • hyoinYang
  • KiSeungMin
  • wonjun-lee-fcwj245

Poem

(\_/) 깡총깡총, 토끼 한 마리
(•ᴗ•) SecurityContext로 길을 비켜요
헤더는 벗겨내고, DTO는 가볍게
장소는 요약해 주고, 좋아요는 음수 금지 🐇
머지빛 당근을 향해 홱!

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/seungin

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

@seung-in-Yoo seung-in-Yoo linked an issue Aug 16, 2025 that may be closed by this pull request
3 tasks
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 (25)
src/main/java/com/wayble/server/wayblezone/entity/WaybleZone.java (1)

101-105: 음수 방지 가드는 👍; 가독성과 의미를 더 명확히 하도록 포화(saturating) 처리로 단순화 제안

현재 구현은 충분히 의도(0 미만 방지)를 달성합니다. 다만 표현을 단일 식으로 단순화하면 읽기/유지보수성이 좋아집니다. 또한 long 상수 표기를 명시적으로 사용하면 타입 의도를 더 분명히 할 수 있습니다.

다음과 같이 변경을 제안드립니다:

-    public void addLikes(long count) {
-        this.likes += count;
-        if (this.likes < 0) this.likes = 0;
-        this.markAsModified(); // 변경 시 자동으로 수정 시간 갱신
-    }
+    public void addLikes(long count) {
+        // 음수 값이 들어올 수 있으므로 0 미만으로 내려가지 않도록 포화(saturating) 처리
+        this.likes = Math.max(0L, this.likes + count);
+        this.markAsModified(); // 변경 시 자동으로 수정 시간 갱신
+    }

추가로, 동시 다발 요청에서 좋아요 수 증감이 자주 발생한다면 낙관적 락(@Version) 도입 또는 DB 레벨 증감 쿼리(UPDATE ... SET likes = GREATEST(0, likes + :delta))로 경쟁 상태에 따른 잃어버린 업데이트를 방지하는 것도 고려해볼 만합니다. 이는 현재 PR 범위를 넘는 선택 사항입니다.

src/main/java/com/wayble/server/user/dto/UserPlaceRequestDto.java (1)

5-9: color 필드 유효성 검증 및 허용 팔레트 제약 추가 권장

서비스 계층(UserPlaceService)과 엔티티(UserPlace)에서 기본값 "GRAY" 보정이 이미 적용되고 있음을 확인했습니다.
다만, DTO 수준에서는 color가 여전히 자유 문자열로 남아 있어 클라이언트/서버 간 불일치나 의도치 않은 값 저장 가능성이 있습니다. 아래 개선 방안을 고려해 주세요.

  • 허용된 색상 목록을 Enum으로 정의 (예: PlaceColor)하고 DTO/엔티티 필드를 해당 Enum 타입으로 선언
  • 최소한 DTO(UserPlaceRequestDto)의 color 필드에 @pattern, @SiZe(max=20) 등 제약 어노테이션 추가
  • 클라이언트에도 동일한 제약을 안내하여 프론트·백엔드 간 일관된 값 사용 보장

[src/main/java/com/wayble/server/user/dto/UserPlaceRequestDto.java]

public record UserPlaceRequestDto(
    @NotNull Long waybleZoneId,
    @NotNull String title,
    @Size(max = 20) @Pattern(regexp = "GRAY|BLUE|GREEN|…") String color
) {}

[optional_refactors_recommended]

src/main/java/com/wayble/server/user/dto/UserPlaceRemoveRequestDto.java (1)

1-8: ID 유효성 강화를 위해 @positive 추가 제안

식별자는 0 또는 음수가 될 수 없으므로 @positive를 추가하면 방어적 검증이 강화됩니다.

아래 변경을 권장드립니다:

 package com.wayble.server.user.dto;

 import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Positive;

 public record UserPlaceRemoveRequestDto(
-        @NotNull Long placeId,
-        @NotNull Long waybleZoneId
+        @NotNull @Positive Long placeId,
+        @NotNull @Positive Long waybleZoneId
 ) {}
src/main/java/com/wayble/server/user/dto/UserPlaceSummaryDto.java (1)

5-11: savedCount 타입 정합성 확인 완료: 엔티티와 DTO가 모두 int
엔티티(UserPlace)의 savedCountint이므로 DTO(UserPlaceSummaryDto)의 int savedCount와 일치해 오버플로 위험이 없습니다. 현재대로 유지해도 무방합니다.

Enum 기반 색상 제한을 도입할 계획이 있다면, color 필드를 해당 Enum으로 일관화하는 리팩터링을 고려해주세요.
[optional_refactors_recommended]

src/main/java/com/wayble/server/user/repository/UserPlaceRepository.java (1)

11-13: 사용자 장소 수가 많은 경우 List 반환의 잠재적 부하 검토

요약 리스트를 비페이징으로 반환하는 설계라면 유저가 수백/수천 개의 장소를 저장했을 때 부하가 발생할 수 있습니다. 요구사항상 의도된 경우라면 유지해도 되지만, 상한(limit) 도입이나 경량 DTO(이미 적용됨) 유지 전략을 검토해 주세요.

src/main/java/com/wayble/server/review/service/ReviewService.java (2)

43-46: rating null 안정성 보강 제안

현재 DTO에서 rating이 NotNull이라면 문제 없지만, 향후 완화 가능성까지 고려하면 NPE 방지 가드가 안전합니다. 또한 리뷰 수를 지역 변수로 담아 연산을 명확히 하세요.

다음 변경을 제안합니다:

-        double newRating = ((zone.getRating() * zone.getReviewCount()) + dto.rating()) / (zone.getReviewCount() + 1);
-        zone.updateRating(newRating);
-        zone.addReviewCount(1);
+        Double rating = (dto.rating() != null) ? dto.rating() : 0.0;
+        long prevCount = zone.getReviewCount();
+        double newRating = ((zone.getRating() * prevCount) + rating) / (prevCount + 1);
+        zone.updateRating(newRating);
+        zone.addReviewCount(1);

53-54: 중복 save 호출 제거 권장 — JPA 더티 체킹 활용

동일 트랜잭션 내에서 zone.updateRating()/addReviewCount() 이후 flush 시점에 자동 반영됩니다. 명시적 save(zone)는 불필요한 SQL을 유발할 수 있습니다.

다음과 같이 정리하세요:

-        waybleZoneRepository.save(zone);
+        // 트랜잭션 종료 시점의 더티 체킹으로 반영됨
src/main/java/com/wayble/server/user/entity/UserPlace.java (3)

26-31: DB 기본값(columnDefinition) 의존 최소화 권장

애플리케이션 레벨에서 @Builder.Default로 기본값을 주고 있어 DB columnDefinition = "int default 0"은 중복이며, 벤더 종속을 유발할 수 있습니다. 팀 규약에 따라 단일 소스로 기본값을 유지하는 것을 추천합니다.

가능한 정리:

-    @Column(name = "saved_count", nullable = false, columnDefinition = "int default 0")
-    @Builder.Default
-    private int savedCount = 0; // 리스트에 담긴 웨이블존 수
+    @Column(name = "saved_count", nullable = false)
+    @Builder.Default
+    private int savedCount = 0; // 리스트에 담긴 웨이블존 수

38-43: 카운트 증감/업데이트 메서드 명확하고 안전합니다

음수 방지 가드가 들어가 있어 일관성 유지에 도움이 됩니다. 타이틀/컬러 업데이트는 서비스 레벨에서 추가 검증(공백/길이 등)을 병행하면 더 안전합니다.


11-17: 소프트 삭제 일관성 확보 제안

user_place 테이블에 deleted_at이 존재한다면, 엔티티에 @SQLDelete/@SQLRestriction을 부여해 리포지토리 전반에서 자동 필터링되도록 하는 것이 안전합니다. 현재 UserPlace에는 해당 애노테이션이 보이지 않습니다.

예시:

@SQLDelete(sql = "UPDATE user_place SET deleted_at = now() WHERE id = ?")
@SQLRestriction("deleted_at IS NULL")
src/main/java/com/wayble/server/review/controller/ReviewController.java (2)

61-81: 인증 주입 단순화: @AuthenticationPrincipal 사용으로 보일러플레이트 제거

SecurityContext에서 수동 파싱 대신 @AuthenticationPrincipal Long userId(혹은 커스텀 Principal)를 사용하면 예외 처리/파싱 로직을 제거할 수 있고, 보안 컨피그 변경에도 탄력적입니다. 또한 예외는 도메인 표준 예외로 매핑하는 것이 응답 일관성에 유리합니다.

다음과 같이 변경을 제안합니다:

-    public CommonResponse<String> registerReview(
-            @PathVariable Long waybleZoneId,
-            @RequestBody @Valid ReviewRegisterDto dto
-    ) {
-        Long userId = extractUserId(); // 토큰에서 유저 ID 추출
-        reviewService.registerReview(waybleZoneId, userId, dto);
-        return CommonResponse.success("리뷰가 등록되었습니다.");
-    }
+    public CommonResponse<String> registerReview(
+            @PathVariable Long waybleZoneId,
+            @org.springframework.security.core.annotation.AuthenticationPrincipal Long userId,
+            @RequestBody @Valid ReviewRegisterDto dto
+    ) {
+        reviewService.registerReview(waybleZoneId, userId, dto);
+        return CommonResponse.success("리뷰가 등록되었습니다.");
+    }

그리고 extractUserId() 메서드는 제거 가능합니다.
추가로, Swagger에 보안 스키마를 노출하려면 아래 애노테이션도 고려해 주세요(클래스 혹은 메서드):

+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
...
-@RequestMapping("/api/v1/wayble-zones/{waybleZoneId}/reviews")
+@RequestMapping("/api/v1/wayble-zones/{waybleZoneId}/reviews")
+@SecurityRequirement(name = "bearerAuth")

14-16: 불필요한 SecurityContext 직접 접근 제거 제안

위의 방식으로 대체 시 SecurityContextHolder/Authentication 임포트는 필요 없어집니다.

-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
src/main/java/com/wayble/server/user/repository/UserPlaceWaybleZoneMappingRepository.java (3)

23-36: 정렬 중복: JPQL의 ORDER BY가 Pageable.sort를 무시합니다

현재 쿼리에서 order by m.id desc를 명시했기 때문에, 서비스에서 전달하는 PageRequest의 Sort 설정은 적용되지 않습니다. 의도대로 매핑 생성 역순을 유지하려면 JPQL의 ORDER BY만 유지하고, 서비스 쪽 PageRequest는 정렬 없이 생성하는 편이 더 명확합니다. 또한 정렬/페이징 성능을 위해 (user_place_id, id desc) 복합 인덱스 추가를 권장합니다.

서비스 측 제안 (UserPlaceService.getZonesInPlace):

- Pageable pageable = PageRequest.of(zeroBased, size, Sort.by(Sort.Direction.DESC, "id"));
+ Pageable pageable = PageRequest.of(zeroBased, size); // 정렬은 JPQL의 order by m.id desc에 일임

20-20: 삭제 결과 확인을 위해 반환 타입을 long으로 변경 권장

void deleteByUserPlace_IdAndWaybleZone_Id(...)는 실제 삭제된 행 수를 알 수 없어, 동시성 상황에서 존재 확인 후 삭제 사이에 생길 수 있는 레이스를 안전하게 처리하기 어렵습니다. 반환 타입을 long으로 바꾸고, 서비스에서 해당 값으로 삭제 성공/실패를 판정하는 게 안전합니다.

- void deleteByUserPlace_IdAndWaybleZone_Id(Long placeId, Long zoneId);
+ long deleteByUserPlace_IdAndWaybleZone_Id(Long placeId, Long zoneId);

서비스 반영 예시는 UserPlaceService 코멘트(라인 123-129 제안)를 참고하세요.


36-36: N+1 가능성 점검(검증 요청)

Page<WaybleZone>로 조회 시 카드에 필요한 필드가 모두 WaybleZone의 컬럼에서 해결되면 문제 없지만, 만약 mainImageUrl 등이 지연 로딩 연관을 통해 계산된다면 N+1이 발생할 수 있습니다. 그런 경우 @EntityGraph로 필요한 연관만 선별 로딩하는 것을 고려해 주세요.

src/main/java/com/wayble/server/user/controller/UserPlaceController.java (5)

40-41: userId 추출 로직 통일: extractUserId() 사용 권장

여기만 직접 캐스팅을 사용하고 있고, 아래에 extractUserId() 헬퍼가 이미 있습니다. 일관성과 안전성을 위해 동일 헬퍼를 사용해 주세요.

-        Long userId = (Long) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+        Long userId = extractUserId();

52-58: sort 파라미터 허용값을 명시적으로 제한/검증하세요

현재 임의 문자열이 들어오면 기본 정렬로 처리되지만, API 사용성을 위해 latest | name 등 허용값을 스키마/검증으로 고정하는 것이 좋습니다. 예: enum 또는 @pattern 사용.

예시:

  • enum 도입: SortType { LATEST, NAME }로 교체
  • 또는 간단히 정규식:
-    public CommonResponse<List<UserPlaceSummaryDto>> getMyPlaceSummaries(
-            @RequestParam(name = "sort", defaultValue = "latest") String sort
-    ) {
+    public CommonResponse<List<UserPlaceSummaryDto>> getMyPlaceSummaries(
+            @RequestParam(name = "sort", defaultValue = "latest")
+            @jakarta.validation.Pattern(regexp = "latest|name", message = "sort는 latest|name만 허용됩니다.")
+            String sort
+    ) {

69-77: page/size 유효성 검증 추가 및 최대 크기 제한 권장

페이지는 1부터 시작하도록 문서화되어 있으므로, 음수/0 입력 방지를 위한 검증(@min)을 추가하는 것이 안전합니다. size에도 상한(예: 최대 50~100)을 두면 과도한 페이지 크기를 예방할 수 있습니다.

-    public CommonResponse<Page<WaybleZoneListResponseDto>> getZonesInPlace(
-            @RequestParam Long placeId,
-            @RequestParam(defaultValue = "1") Integer page,
-            @RequestParam(defaultValue = "20") Integer size
-    ) {
+    public CommonResponse<Page<WaybleZoneListResponseDto>> getZonesInPlace(
+            @RequestParam Long placeId,
+            @RequestParam(defaultValue = "1") @jakarta.validation.Min(1) Integer page,
+            @RequestParam(defaultValue = "20") @jakarta.validation.Min(1) @jakarta.validation.Max(100) Integer size
+    ) {

79-93: DELETE 요청은 경로 변수로 식별자 전달 권장(DELETE Body 지양)

HTTP 스펙상 DELETE 본문은 허용되지만, 클라이언트/프록시 호환성 및 관례 측면에서 경로 변수 사용을 권장합니다. 또한 REST 리소스 모델링에도 더 자연스럽습니다.

-    @DeleteMapping
-    public CommonResponse<String> removeZoneFromPlace(@RequestBody @Valid UserPlaceRemoveRequestDto request) {
-        Long userId = extractUserId();
-        userPlaceService.removeZoneFromPlace(userId, request.placeId(), request.waybleZoneId());
-        return CommonResponse.success("제거되었습니다.");
-    }
+    @DeleteMapping("/{placeId}/zones/{waybleZoneId}")
+    public CommonResponse<String> removeZoneFromPlace(
+            @PathVariable Long placeId,
+            @PathVariable Long waybleZoneId
+    ) {
+        Long userId = extractUserId();
+        userPlaceService.removeZoneFromPlace(userId, placeId, waybleZoneId);
+        return CommonResponse.success("제거되었습니다.");
+    }

기존 DTO는 다른 곳에서 재사용되지 않는다면 제거 대상입니다.


96-121: System.err 대신 로거 사용 및 민감정보 노출 주의

표준 에러 출력 대신 로거를 사용해 주세요. 또한 예외 메시지에 Principal 전체가 노출되면 불필요한 정보 노출이 있을 수 있습니다(일부만 로그). WARN 레벨로 축약 로깅 권장.

-                System.err.println("Principal 문자열을 Long으로 변환할 수 없습니다: " + s);
+                log.warn("Principal 문자열을 Long으로 변환할 수 없습니다: (length: {})", s != null ? s.length() : -1);

파일 상단/클래스에 다음 보일러플레이트가 없다면 추가 필요합니다:

// import
import lombok.extern.slf4j.Slf4j;

// class
@Slf4j
@RequiredArgsConstructor
public class UserPlaceController {
    ...
}

원하시면 제가 전체 패치를 준비해 드리겠습니다.

src/main/java/com/wayble/server/user/service/UserPlaceService.java (5)

52-61: 기존 장소 재사용 시 color 업데이트 옵션 고려

현재는 기존 UserPlace가 있으면 요청의 color를 무시합니다. 사용자가 색상을 수정하기 원할 수 있으므로, color가 전달되었고 공백이 아니면 업데이트하는 옵션을 고려해 주세요.

예시:

 UserPlace userPlace = userPlaceRepository.findByUser_IdAndTitle(userId, request.title())
         .orElseGet(() -> userPlaceRepository.save(
                 UserPlace.builder()
                         .title(request.title())
                         .color(color)
                         .user(user)
                         .build()
         ));
+
+ // 기존 place가 있고, color가 유효하게 들어왔다면 갱신
+ if (request.color() != null && !request.color().isBlank()
+         && !request.color().equals(userPlace.getColor())) {
+     userPlace.setColor(request.color()); // setter 또는 별도 업데이트 메서드 필요
+     userPlaceRepository.save(userPlace);
+ }

Setter가 없다면 엔티티에 전용 업데이트 메서드를 추가하는 방식을 권장합니다.


100-101: 정렬 일원화: 리포지토리 JPQL에 정렬이 있으므로 PageRequest 정렬 제거

리포지토리의 @Queryorder by m.id desc를 강제하므로, 여기서의 Sort는 무시됩니다. 혼동을 줄이기 위해 제거하는 편이 좋습니다.

- Pageable pageable = PageRequest.of(zeroBased, size, Sort.by(Sort.Direction.DESC, "id"));
+ Pageable pageable = PageRequest.of(zeroBased, size);

103-114: 지연 로딩 접근 여부 점검(주소/이미지/부가필드)

매핑 중 address, mainImageUrl, contactNumber 접근이 지연 로딩 연관을 트리거하지 않는지 확인해 주세요. 만약 연관 엔티티 접근이 필요하다면 해당 연관만 @EntityGraph로 선별 페치하는 방식을 권장합니다.


123-129: 존재 확인 후 삭제의 경쟁 상태 개선: 삭제 건수 기반 처리 권장

exists()delete() 사이에 다른 트랜잭션이 삭제하면 0건 삭제가 되지만 카운트/좋아요는 감소할 수 있습니다. deleteBy...를 long 반환으로 바꾸고, 그 결과에 따라 후처리를 수행하면 안전합니다.

Repository 변경(별도 코멘트 참고) 후, 여기 수정:

-        if (!mappingRepository.existsByUserPlace_IdAndWaybleZone_Id(placeId, waybleZoneId)) {
-            throw new ApplicationException(UserErrorCase.PLACE_MAPPING_NOT_FOUND);
-        }
-
-        mappingRepository.deleteByUserPlace_IdAndWaybleZone_Id(placeId, waybleZoneId);
+        long deleted = mappingRepository.deleteByUserPlace_IdAndWaybleZone_Id(placeId, waybleZoneId);
+        if (deleted == 0) {
+            throw new ApplicationException(UserErrorCase.PLACE_MAPPING_NOT_FOUND);
+        }

추가로, decreaseCount()가 0 미만으로 내려가지 않도록 방어(클램프) 로직이 없다면 보강을 고려해 주세요.


129-135: 카운터/좋아요 음수 방지 및 일관성 보장

저장/삭제에 따른 savedCount/likes는 동시성 상황에서 음수가 될 여지가 있으므로, 내부적으로 0 미만을 허용하지 않도록 클램프하거나 DB 제약/체크를 추가하는 방안을 권장합니다. 또한 카운터 기반은 데이터 정합성 이슈가 누적될 수 있으니, 정기적으로 재계산 배치(또는 DB 트리거/뷰) 도입도 고려해 보세요.

📜 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 cfbf03f and bbb4827.

📒 Files selected for processing (14)
  • src/main/java/com/wayble/server/review/controller/ReviewController.java (3 hunks)
  • src/main/java/com/wayble/server/review/dto/ReviewRegisterDto.java (0 hunks)
  • src/main/java/com/wayble/server/review/service/ReviewService.java (2 hunks)
  • src/main/java/com/wayble/server/user/controller/UserPlaceController.java (2 hunks)
  • src/main/java/com/wayble/server/user/dto/UserPlaceRemoveRequestDto.java (1 hunks)
  • src/main/java/com/wayble/server/user/dto/UserPlaceRequestDto.java (1 hunks)
  • src/main/java/com/wayble/server/user/dto/UserPlaceSummaryDto.java (1 hunks)
  • src/main/java/com/wayble/server/user/dto/UserPlaceZonesResponseDto.java (1 hunks)
  • src/main/java/com/wayble/server/user/entity/UserPlace.java (1 hunks)
  • src/main/java/com/wayble/server/user/exception/UserErrorCase.java (1 hunks)
  • src/main/java/com/wayble/server/user/repository/UserPlaceRepository.java (1 hunks)
  • src/main/java/com/wayble/server/user/repository/UserPlaceWaybleZoneMappingRepository.java (2 hunks)
  • src/main/java/com/wayble/server/user/service/UserPlaceService.java (2 hunks)
  • src/main/java/com/wayble/server/wayblezone/entity/WaybleZone.java (1 hunks)
💤 Files with no reviewable changes (1)
  • src/main/java/com/wayble/server/review/dto/ReviewRegisterDto.java
🧰 Additional context used
🧬 Code Graph Analysis (11)
src/main/java/com/wayble/server/wayblezone/entity/WaybleZone.java (1)
src/main/java/com/wayble/server/wayblezone/repository/WaybleZoneRepositoryImpl.java (2)
  • Override (27-61)
  • WaybleZoneRepositoryImpl (19-140)
src/main/java/com/wayble/server/user/dto/UserPlaceZonesResponseDto.java (2)
src/main/java/com/wayble/server/user/dto/UserPlaceListResponseDto.java (2)
  • Builder (7-22)
  • Builder (13-21)
src/main/java/com/wayble/server/wayblezone/dto/WaybleZoneListResponseDto.java (1)
  • Builder (6-17)
src/main/java/com/wayble/server/user/repository/UserPlaceRepository.java (1)
src/main/java/com/wayble/server/admin/repository/AdminUserRepository.java (1)
  • AdminUserRepository (14-101)
src/main/java/com/wayble/server/user/dto/UserPlaceSummaryDto.java (2)
src/main/java/com/wayble/server/user/dto/UserPlaceListResponseDto.java (2)
  • Builder (7-22)
  • Builder (13-21)
src/main/java/com/wayble/server/direction/dto/request/PlaceSaveRequest.java (1)
  • Builder (13-17)
src/main/java/com/wayble/server/user/repository/UserPlaceWaybleZoneMappingRepository.java (3)
src/main/java/com/wayble/server/user/entity/UserPlaceWaybleZoneMapping.java (1)
  • Entity (10-29)
src/main/java/com/wayble/server/wayblezone/repository/WaybleZoneRepository.java (1)
  • WaybleZoneRepository (12-34)
src/main/java/com/wayble/server/wayblezone/repository/WaybleZoneFacilityRepository.java (1)
  • WaybleZoneFacilityRepository (8-11)
src/main/java/com/wayble/server/user/exception/UserErrorCase.java (4)
src/main/java/com/wayble/server/wayblezone/exception/WaybleZoneErrorCase.java (1)
  • Getter (7-18)
src/main/java/com/wayble/server/user/entity/UserPlaceWaybleZoneMapping.java (1)
  • Entity (10-29)
src/main/java/com/wayble/server/wayblezone/service/WaybleZoneService.java (1)
  • WaybleZoneErrorCase (66-66)
src/main/java/com/wayble/server/admin/exception/AdminErrorCase.java (1)
  • Getter (7-17)
src/main/java/com/wayble/server/review/service/ReviewService.java (4)
src/main/java/com/wayble/server/review/dto/ReviewRegisterDto.java (1)
  • Schema (8-36)
src/main/java/com/wayble/server/review/entity/Review.java (1)
  • Entity (14-65)
src/main/java/com/wayble/server/review/dto/ReviewResponseDto.java (1)
  • ReviewResponseDto (6-14)
src/main/java/com/wayble/server/review/repository/ReviewRepository.java (1)
  • ReviewRepository (9-16)
src/main/java/com/wayble/server/user/entity/UserPlace.java (3)
src/main/java/com/wayble/server/user/entity/UserPlaceWaybleZoneMapping.java (1)
  • Entity (10-29)
src/main/java/com/wayble/server/user/dto/UserPlaceListResponseDto.java (1)
  • Builder (7-22)
src/main/java/com/wayble/server/user/entity/User.java (1)
  • Getter (14-134)
src/main/java/com/wayble/server/user/service/UserPlaceService.java (2)
src/main/java/com/wayble/server/user/dto/UserPlaceListResponseDto.java (1)
  • Builder (7-22)
src/main/java/com/wayble/server/user/entity/UserPlaceWaybleZoneMapping.java (1)
  • Entity (10-29)
src/main/java/com/wayble/server/review/controller/ReviewController.java (1)
src/main/java/com/wayble/server/review/dto/ReviewRegisterDto.java (1)
  • Schema (8-36)
src/main/java/com/wayble/server/user/controller/UserPlaceController.java (4)
src/main/java/com/wayble/server/common/config/security/jwt/JwtAuthenticationFilter.java (1)
  • RequiredArgsConstructor (13-43)
src/main/java/com/wayble/server/user/dto/UserPlaceListResponseDto.java (1)
  • Builder (7-22)
src/main/java/com/wayble/server/user/entity/UserPlaceWaybleZoneMapping.java (1)
  • Entity (10-29)
src/main/java/com/wayble/server/wayblezone/controller/WaybleZoneController.java (1)
  • RestController (21-65)
🔇 Additional comments (8)
src/main/java/com/wayble/server/user/exception/UserErrorCase.java (1)

23-25: 에러 케이스 추가 적절합니다

PLACE_NOT_FOUND, PLACE_MAPPING_NOT_FOUND 추가로 사용자 장소 및 매핑 삭제/조회 플로우에서 일관된 404 처리에 도움이 됩니다. 코드/메시지 컨벤션도 기존과 일치합니다.

src/main/java/com/wayble/server/user/dto/UserPlaceZonesResponseDto.java (1)

8-15: DTO 설계 적절 — 요약 정보 + 존 리스트 구성이 목적에 부합합니다.

placeId/title/color/savedCount와 zones를 함께 반환하는 구조가 새 엔드포인트의 응답 성격과 잘 맞습니다. 레코드 + @builder 조합도 적합합니다.

src/main/java/com/wayble/server/user/repository/UserPlaceRepository.java (1)

12-12: 소유자 가드용 조회 시그니처 추가 적절

findByIdAndUser_Id 추가로 소유자 검증을 리포지토리 레벨에서 일관되게 처리할 수 있어 서비스단 가독성과 안전성이 향상됩니다.

src/main/java/com/wayble/server/review/service/ReviewService.java (2)

47-51: 이미지 처리 조건 강화 LGTM

null/빈 리스트 체크로 불필요한 레코드 생성 방지. 반복 저장 로직도 직관적입니다.


33-38: ReviewRegisterDto와 Swagger 예시에서 userId 제거 확인됨

  • src/main/java/com/wayble/server/review/dto/ReviewRegisterDto.java 정의(record)에 userId 필드나 검증 애노테이션이 없습니다.
  • src/main/java/com/wayble/server/review/controller/ReviewController.javaregisterReview API (@RequestBody ReviewRegisterDto dto)에도 userId가 노출되지 않습니다.

추가 조치가 필요하지 않습니다.

src/main/java/com/wayble/server/review/controller/ReviewController.java (1)

39-45: 해결: ReviewRegisterDto에 userId 필드가 없습니다

  • rg 검색 결과 ReviewRegisterDtouserId 필드가 존재하지 않음이 확인되었습니다.
  • 따라서 토큰에서 추출한 userId를 DTO에 포함하지 않아도 검증 오류가 발생하지 않습니다.
  • 추가 조치 불필요합니다.
src/main/java/com/wayble/server/user/repository/UserPlaceWaybleZoneMappingRepository.java (1)

19-19: 중복 체크 범위 의도 확인 필요

existsByUserPlace_IdAndWaybleZone_Id가 아닌 existsByUserPlace_User_IdAndWaybleZone_Id(사용자 단위)로 중복을 판정하고 있어, 동일 유저의 “다른 장소”에도 같은 웨이블존을 저장할 수 없게 됩니다. 비즈니스 의도가 “유저 단위 중복 금지”인지, “장소 단위 중복 금지”인지 확인 부탁드립니다.

src/main/java/com/wayble/server/user/service/UserPlaceService.java (1)

47-50: 중복 저장 기준 확인(사용자 전체 vs. 장소별)

existsByUserPlace_User_IdAndWaybleZone_Id로 검사하여 “사용자 전체” 기준으로 중복을 막고 있습니다. 동일 유저가 서로 다른 장소에 동일 웨이블존을 넣을 수 없게 되는데, 기획 의도라면 OK고, “장소별 중복만 막기”가 의도라면 existsByUserPlace_IdAndWaybleZone_Id(+ placeId) 기준으로 바꿔야 합니다.

Comment on lines +11 to +13
List<UserPlace> findAllByUser_IdOrderByCreatedAtDesc(Long userId); // 사용자 리스트 전체(최신순)
Optional<UserPlace> findByIdAndUser_Id(Long placeId, Long userId);
List<UserPlace> findAllByUser_IdOrderByTitleAsc(Long userId);
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

소프트 삭제(soft-delete) 행 필터링 여부 확인 필요

Admin 쪽에서 user_place.deleted_at을 사용하는 복구 쿼리가 존재합니다. 현재 파생 메서드들은 deleted_at IS NULL 조건을 자동으로 걸지 않으므로, 소프트 삭제된 행이 포함될 수 있습니다. 엔티티에 @SQLRestriction("deleted_at IS NULL")가 없거나 글로벌 필터가 없다면, 사용자 리스트/조회에 삭제된 레코드가 섞일 수 있습니다.

다음 스크립트로 UserPlace 엔티티에 @SQLDelete/@SQLRestriction이 적용되어 있는지 확인해 주세요.

필요 시, UserPlace 엔티티에 아래와 같이 추가하는 것을 권장합니다(참고용):

@SQLDelete(sql = "UPDATE user_place SET deleted_at = now() WHERE id = ?")
@SQLRestriction("deleted_at IS NULL")

🏁 Script executed:

#!/bin/bash
# UserPlace 소프트삭제 설정 존재 여부 탐색
rg -n -C2 'class\s+UserPlace\b' --type=java
rg -n -C2 '@SQLDelete|@SQLRestriction' --type=java | rg -n -C1 'UserPlace|user_place'

Length of output: 557


소프트 삭제 필터링 적용 필요: UserPlace 엔티티에 @SQLDelete/@SQLRestriction 추가

현재 UserPlace 엔티티에 소프트 삭제 관련 어노테이션이 없어, deleted_at IS NULL 조건이 자동으로 붙지 않습니다. 이로 인해 findAllByUser_Id… 계열 메서드 호출 시 삭제된 레코드가 조회될 수 있습니다.

수정 사항:

  • 아래 어노테이션을 src/main/java/com/wayble/server/user/entity/UserPlace.java 클래스 선언부 바로 위에 추가해주세요.
@SQLDelete(sql = "UPDATE user_place SET deleted_at = NOW() WHERE id = ?")
@SQLRestriction("deleted_at IS NULL")
@Table(name = "user_place")  // 기존 어노테이션
public class UserPlace extends BaseEntity {
    // ...
}

위 설정으로 Hibernate가 소프트 삭제 시 deleted_at을 업데이트하고, 조회 시 자동으로 deleted_at IS NULL 필터를 적용합니다.

🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/user/entity/UserPlace.java around the class
declaration, UserPlace lacks Hibernate soft-delete annotations so deleted
records are still returned by repository queries; add the @SQLDelete(sql =
"UPDATE user_place SET deleted_at = NOW() WHERE id = ?") and
@SQLRestriction("deleted_at IS NULL") annotations immediately above the class
(retaining the existing @Table) and add the necessary imports from
org.hibernate.annotations; ensure the entity has the deleted_at column mapped
(or inherited) and that imports compile so Hibernate will set deleted_at on
delete and automatically filter out soft-deleted rows during queries.

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 (6)
src/main/java/com/wayble/server/user/entity/UserPlace.java (6)

18-19: 소프트 삭제 설정 적절. 다만 now() 표기 일관성과 영속성 컨텍스트 동기화 보완 제안

  • 같은 프로젝트의 User 엔티티는 now()(소문자)를 사용하고 있어 표기 일관성을 맞추는 편이 좋습니다.
  • @SQLDelete는 DB에 직접 UPDATE를 날리므로, 삭제 직후 영속성 컨텍스트의 deletedAt 필드는 여전히 null일 수 있습니다. 삭제 직후 엔티티 필드를 참조하는 로직이 있다면 혼선이 생길 수 있으므로 @PreRemove에서 this.softDelete()를 호출해 메모리 상태도 동기화하는 것을 권장합니다.

아래처럼 표기만 일치시키는 최소 변경을 권장합니다:

-@SQLDelete(sql = "UPDATE user_place SET deleted_at = NOW() WHERE id = ?")
+@SQLDelete(sql = "UPDATE user_place SET deleted_at = now() WHERE id = ?")

영속성 컨텍스트 동기화를 위한 선택지(참고용, 변경 범위 외 코드):

@PreRemove
protected void onRemove() {
    this.softDelete(); // BaseEntity.softDelete()로 메모리 상태 갱신
}

20-20: 주석 오타 수정 제안: ‘유져’ → ‘유저’

-@Table(name = "user_place") // 유져가 저장한 장소
+@Table(name = "user_place") // 유저가 저장한 장소

20-21: (user_id, title) 유니크 제약 권장 — 중복 장소명 방지

  • 서비스 레이어에서 중복 검사를 하더라도, DB 레벨 유니크 제약이 없으면 레이스 컨디션에 취약합니다.
  • 마이그레이션 동반 필요.
-@Table(name = "user_place") // 유저가 저장한 장소
+@Table(
+    name = "user_place",
+    uniqueConstraints = @UniqueConstraint(columnNames = {"user_id", "title"})
+) // 유저가 저장한 장소

원하시면 DDL 마이그레이션 스크립트도 함께 제안드리겠습니다.


30-31: color 컬럼은 null 비허용 권장 + 명시적 컬럼 이름

  • 런타임 기본값(@Builder.Default)만으로는 null 삽입을 100% 차단하지 못합니다(예: 직접 엔티티 필드에 null 세팅).
  • DB 제약으로도 방어하면 데이터 무결성이 강화됩니다.
-@Column(length = 20) @Builder.Default
+@Column(name = "color", length = 20, nullable = false) @Builder.Default
 private String color = "GRAY";

추가로, updateColor에서 길이/공백 검증을 해주면 런타임 오류를 더 일찍 차단할 수 있습니다(아래 45-46 라인 코멘트 참조).


45-46: 도메인 메서드에 입력값 검증 추가 권장(공백/길이 체크)
DB 제약 위반으로 flush 시점에 예외가 터지기 전에 도메인 레벨에서 빠르게 방어하는 편이 디버깅과 UX에 유리합니다.

-public void updateTitle(String title) { this.title = title; }
-public void updateColor(String color) { this.color = color; }
+public void updateTitle(String title) {
+    if (title == null || title.isBlank()) {
+        throw new IllegalArgumentException("title must not be blank");
+    }
+    this.title = title;
+}
+public void updateColor(String color) {
+    if (color == null || color.isBlank()) {
+        throw new IllegalArgumentException("color must not be blank");
+    }
+    if (color.length() > 20) {
+        throw new IllegalArgumentException("color length must be <= 20");
+    }
+    this.color = color;
+}

추가적으로 FE와 색상 표준을 합의할 수 있다면 Enum으로의 치환도 고려해볼 만합니다.


33-36: saved_count 기본값 설정·무결성·동시성 강화 제안

  • src/main/java/com/wayble/server/user/entity/UserPlace.java (33–36행)
    columnDefinition = "int default 0" 제거 후 Hibernate @ColumnDefault("0") 사용
  • src/main/java/com/wayble/server/user/service/UserPlaceService.java
    • 67행 userPlace.increaseCount()
    • 129행 place.decreaseCount()
    동시성 경쟁 시 카운트 유실 위험이 존재하므로 낙관적 락(@Version) 또는 원자적 UPDATE 쿼리(SET saved_count = saved_count ± 1) 검토 권장

권장 최소 변경:

-    @Column(name = "saved_count", nullable = false, columnDefinition = "int default 0")
+    @Column(name = "saved_count", nullable = false)
+    @org.hibernate.annotations.ColumnDefault("0")
     @Builder.Default
     private int savedCount = 0;

DB 레벨 무결성 강화 (마이그레이션 예시):

ALTER TABLE user_place
  ADD CONSTRAINT chk_user_place_saved_count_non_negative
  CHECK (saved_count >= 0);

[optional_refactors_recommended]

📜 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 bbb4827 and c45ad40.

📒 Files selected for processing (1)
  • src/main/java/com/wayble/server/user/entity/UserPlace.java (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/main/java/com/wayble/server/user/entity/UserPlace.java (9)
src/main/java/com/wayble/server/common/response/CommonResponse.java (1)
  • Builder (8-42)
src/main/java/com/wayble/server/user/entity/UserPlaceWaybleZoneMapping.java (1)
  • Entity (10-29)
src/main/java/com/wayble/server/user/repository/UserPlaceRepository.java (1)
  • UserPlaceRepository (8-10)
src/main/java/com/wayble/server/admin/repository/AdminUserRepository.java (1)
  • Modifying (82-88)
src/main/java/com/wayble/server/user/entity/User.java (1)
  • Getter (14-134)
src/main/java/com/wayble/server/user/service/UserPlaceService.java (2)
  • Service (22-96)
  • mapping (73-94)
src/main/java/com/wayble/server/user/controller/UserPlaceController.java (1)
  • RestController (20-59)
src/main/java/com/wayble/server/common/entity/BaseEntity.java (1)
  • MappedSuperclass (13-36)
src/main/java/com/wayble/server/user/dto/UserPlaceListResponseDto.java (1)
  • Builder (7-22)
🔇 Additional comments (1)
src/main/java/com/wayble/server/user/entity/UserPlace.java (1)

42-44: 음수 방지 가드 좋습니다
decreaseCount()에서 0 이하로 내려가지 않도록 한 가드가 실사용에서 유용합니다.

@seung-in-Yoo seung-in-Yoo merged commit 12708cc into develop Aug 16, 2025
1 check passed
Copy link
Member

@KiSeungMin KiSeungMin left a comment

Choose a reason for hiding this comment

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

수고 많으셨어요!!!

return CommonResponse.success(reviewService.getReviews(waybleZoneId, sort));
}

private Long extractUserId() {
Copy link
Member

Choose a reason for hiding this comment

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

토큰에서 id 추출하는 과정을 이렇게 상세하게 구현한 이유가 궁금합니다...!

Copy link
Member Author

Choose a reason for hiding this comment

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

밑에 답변 참고해주세요!



// SecurityContext에서 userId 추출하는 로직
private Long extractUserId() {
Copy link
Member

Choose a reason for hiding this comment

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

ReviewController랑 여기에 모두 동일한 로직을 넣은 이유도 궁금합니다!
토큰 id 정책이 바뀌면 모든 컨트롤러의 로직을 변경하게 될텐데, 차라리 id에서 토큰을 검증하는 서비스 하나 만들거나, jwtTokenService 같은 곳에서 처리하는게 낫겠다는 생각이 들어서요!

Copy link
Member Author

Choose a reason for hiding this comment

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

지금 작성한 pr에 대한 코드를 짤때 생각보다 api 자체를 많이 바꿔야해서 개발 후에 테스트에 좀 더 신경을 썼었는데, 제가 테스트를 여러번 할때에 Authentication.getPrincipal() 타입이 일관되게 들어오지 않는것 같더라구요. 그렇게된다면 컨트롤러에서 에러가 날수도 있다고 생각해서 아예 컨트롤러쪽에 토큰을 추출하는 메서드를 추가하였습니다. 하지만 말씀해주신것처럼 토큰 정책이 바뀌면 컨트롤러마다 수정해야 하는 리스크가 있다는것에 동의합니다! 중복 제거 및 공통화에 대해서 리팩토링 해보겠습니다 감사합니다 ㅎㅎ

}

public void addLikes(long count) {
this.likes += count;
Copy link
Member

Choose a reason for hiding this comment

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

시간 여유로우실 때 좋아요 관련 동시성 처리 해보는 것도 좋을 것 같아요!
(제가 짠 로직도 적용해야 하는데 바빠서 못 하는중이에요 ㅠㅠ)

Copy link
Member Author

Choose a reason for hiding this comment

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

테스트코드 작성하면서 동시성 처리도 한번 작업해보겠습니다 감사합니다!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🛠️ fix 기능 오류 및 코드 개선이 필요한 곳 수정 🔧 refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[REFACTOR] 유저가 저장한 웨이블존 조회 관련 리팩토링

3 participants