Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public CommonResponse<UserPlaceCreateResponseDto> createPlaceList(
}

@GetMapping
@Operation(summary = "내 장소 리스트 요약 조회", description = "장소 관련 목록(리스트)만 반환합니다(개수 포함).")
@Operation(summary = "내가 저장한 리스트 요약 조회", description = "장소 관련 목록(리스트)만 반환합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "유저를 찾을 수 없음"),
Expand All @@ -69,42 +69,25 @@ public CommonResponse<List<UserPlaceSummaryDto>> getMyPlaceSummaries(
return CommonResponse.success(summaries);
}

@DeleteMapping
@Operation(
summary = "장소에서 웨이블존 제거",
description = "RequestBody로 placeId, waybleZoneId를 받아 지정한 장소에서 웨이블존을 제거합니다."
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "제거 성공"),
@ApiResponse(responseCode = "404", description = "장소 또는 매핑 정보를 찾을 수 없음"),
@ApiResponse(responseCode = "403", description = "권한이 없습니다.")
})
public CommonResponse<String> removeZoneFromPlace(
@Parameter(hidden = true) @CurrentUser Long userId,
@RequestBody @Valid UserPlaceRemoveRequestDto request
) {
userPlaceService.removeZoneFromPlace(userId, request.placeId(), request.waybleZoneId());
return CommonResponse.success("제거되었습니다.");
}

@PostMapping("/zones")
@Operation(summary = "리스트에 웨이블존 추가",
description = "placeId와 waybleZoneId 배열을 받아 여러 웨이블존을 리스트에 추가합니다.")
@Operation(summary = "웨이블존에 저장한 리스트 추가 (여러 개 가능)",
description = "웨이블존에 사용자가 요청한 리스트들을 추가합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "웨이블존 추가 성공"),
@ApiResponse(responseCode = "200", description = "웨이블존에 리스트 추가 성공"),
@ApiResponse(responseCode = "404", description = "유저/리스트/웨이블존을 찾을 수 없음")
Comment on lines +74 to 78
Copy link

@coderabbitai coderabbitai bot Aug 20, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

API 문서 방향이 실제 동작과 반대입니다: ‘웨이블존에 리스트 추가’ → ‘리스트에 웨이블존 추가’로 수정 필요

서비스 호출은 웨이블존을 여러 리스트에 추가하는 동작(addZoneToPlaces)인데, 현재 문구는 “웨이블존에 리스트를 추가”로 반대로 서술되어 있어 오해의 소지가 큽니다. Swagger 문구를 아래처럼 교정해 주세요.

-    @Operation(summary = "웨이블존에 저장한 리스트 추가 (여러 개 가능)",
-            description = "웨이블존에 사용자가 요청한 리스트들을 추가합니다.")
+    @Operation(summary = "저장한 리스트에 웨이블존 추가 (여러 개 가능)",
+            description = "사용자가 지정한 웨이블존을 요청한 저장한 리스트들(placeIds)에 추가합니다.")
@@
-            @ApiResponse(responseCode = "200", description = "웨이블존에 리스트 추가 성공"),
+            @ApiResponse(responseCode = "200", description = "리스트에 웨이블존 추가 성공"),
📝 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
@Operation(summary = "웨이블존에 저장한 리스트 추가 (여러 개 가능)",
description = "웨이블존에 사용자가 요청한 리스트들을 추가합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "웨이블존 추가 성공"),
@ApiResponse(responseCode = "200", description = "웨이블존에 리스트 추가 성공"),
@ApiResponse(responseCode = "404", description = "유저/리스트/웨이블존을 찾을 수 없음")
@Operation(summary = "저장한 리스트에 웨이블존 추가 (여러 개 가능)",
description = "사용자가 지정한 웨이블존을 요청한 저장한 리스트들(placeIds)에 추가합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "리스트에 웨이블존 추가 성공"),
@ApiResponse(responseCode = "404", description = "유저/리스트/웨이블존을 찾을 수 없음")
🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/user/controller/UserPlaceController.java
around lines 74 to 78, the Swagger Operation summary/description currently reads
as if lists are being added to a zone, but the service actually adds a zone to
multiple lists (addZoneToPlaces); update the Operation.summary and
Operation.description text to reflect "리스트에 웨이블존 추가" (or similar phrasing: "사용자
요청한 리스트들에 웨이블존을 추가합니다") so the documentation matches the behavior; ensure any
related messages in ApiResponses remain accurate (change the 200 description to
indicate successful addition of a zone to lists if present).

Copy link
Member Author

Choose a reason for hiding this comment

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

@coderabbitai 웨이블존에 리스트를 추가든 리스트에 웨이블존을 추가든 결국 디비에 placeId, waybleZoneId 매핑 레코드가 생겨서 결론은 둘이 동일한거 아니야? 서비스 로직에서 잘못된 부분 없는거같은데

Copy link

Choose a reason for hiding this comment

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

@seung-in-Yoo 맞습니다! 데이터베이스 관점에서는 결국 동일한 placeId, waybleZoneId 매핑 레코드가 생성되므로 기능적으로는 완전히 동일하네요.

제가 API 문서의 표현에 너무 세세하게 집착했던 것 같습니다. 현재 구현이 요구사항을 올바르게 충족하고 있고, 사용자 입장에서 혼란이 없다면 현재 상태로도 충분히 좋습니다.

서비스 로직도 정상적으로 구현되어 있어서 문제없어 보입니다! 🙂

})
public CommonResponse<String> addZonesToPlace(
public CommonResponse<String> addZoneToPlaces(
@Parameter(hidden = true) @CurrentUser Long userId,
@RequestBody @Valid UserPlaceAddZonesRequestDto request
) {
userPlaceService.addZonesToPlace(userId, request.placeId(), request.waybleZoneIds());
return CommonResponse.success("리스트에 웨이블존이 추가되었습니다.");
int added = userPlaceService.addZoneToPlaces(userId, request.placeIds(), request.waybleZoneId());
return CommonResponse.success(String.format("%d개 리스트에 추가되었습니다.", added));
}

@GetMapping("/zones")
@Operation(summary = "특정 장소 내 웨이블존 목록 조회(페이징)",
description = "placeId로 해당 장소 내부의 웨이블존 카드 목록을 반환합니다. (page는 0부터 시작.)")
@Operation(summary = "저장한 리스트 내 웨이블존 목록 조회(페이징)",
description = "placeId로 해당 장소 내부의 웨이블존 목록을 반환합니다. (page는 1부터 시작.)")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "유저/장소를 찾을 수 없음"),
Expand All @@ -113,10 +96,28 @@ public CommonResponse<String> addZonesToPlace(
public CommonResponse<Page<WaybleZoneListResponseDto>> getZonesInPlace(
@Parameter(hidden = true) @CurrentUser Long userId,
@RequestParam Long placeId,
@RequestParam(defaultValue = "0") @Min(0) Integer page,
@RequestParam(defaultValue = "1") @Min(1) Integer page,
@RequestParam(defaultValue = "20") @Min(1) @Max(100) Integer size
) {
Page<WaybleZoneListResponseDto> zones = userPlaceService.getZonesInPlace(userId, placeId, page, size);
return CommonResponse.success(zones);
}

@DeleteMapping("/zones")
@Operation(
summary = "내가 저장한 리스트에서 웨이블존 제거",
description = "RequestBody로 placeId, waybleZoneId를 받아 지정한 장소에서 웨이블존을 제거합니다."
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "제거 성공"),
@ApiResponse(responseCode = "404", description = "장소 또는 매핑 정보를 찾을 수 없음"),
@ApiResponse(responseCode = "403", description = "권한이 없습니다.")
})
public CommonResponse<String> removeZoneFromPlace(
@Parameter(hidden = true) @CurrentUser Long userId,
@RequestBody @Valid UserPlaceRemoveRequestDto request
) {
userPlaceService.removeZoneFromPlace(userId, request.placeId(), request.waybleZoneId());
return CommonResponse.success("성공적으로 제거되었습니다.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
import java.util.List;

public record UserPlaceAddZonesRequestDto(
@NotNull Long placeId,
@NotEmpty List<Long> waybleZoneIds
@NotEmpty List<@NotNull Long> placeIds,
@NotNull Long waybleZoneId
) {}

This file was deleted.

4 changes: 0 additions & 4 deletions src/main/java/com/wayble/server/user/dto/UserResponseDto.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public enum UserErrorCase implements ErrorCase {
NICKNAME_DUPLICATED(409,1013, "이미 사용 중인 닉네임입니다."),
PLACE_NOT_FOUND(404, 1014, "저장된 장소를 찾을 수 없습니다."),
PLACE_MAPPING_NOT_FOUND(404, 1015, "해당 장소에 해당 웨이블존이 없습니다."),
PLACE_TITLE_DUPLICATED(400, 1016, "동일한 이름의 리스트가 이미 있습니다.");
PLACE_TITLE_DUPLICATED(409, 1016, "동일한 이름의 리스트가 이미 있습니다.");

private final Integer httpStatusCode;
private final Integer errorCode;
Expand Down
32 changes: 18 additions & 14 deletions src/main/java/com/wayble/server/user/service/UserPlaceService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

import com.wayble.server.common.exception.ApplicationException;
import com.wayble.server.user.dto.UserPlaceCreateRequestDto;
import com.wayble.server.user.dto.UserPlaceRequestDto;
import com.wayble.server.user.dto.UserPlaceSummaryDto;
import com.wayble.server.user.entity.User;
import com.wayble.server.user.entity.UserPlace;
Expand Down Expand Up @@ -59,18 +58,21 @@ public Long createPlaceList(Long userId, UserPlaceCreateRequestDto request) {
}

@Transactional
public void addZonesToPlace(Long userId, Long placeId, List<Long> waybleZoneIds) {
UserPlace place = userPlaceRepository.findByIdAndUser_Id(placeId, userId)
.orElseThrow(() -> new ApplicationException(UserErrorCase.PLACE_NOT_FOUND));
public int addZoneToPlaces(Long userId, List<Long> placeIds, Long waybleZoneId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new ApplicationException(UserErrorCase.USER_NOT_FOUND));

WaybleZone zone = waybleZoneRepository.findById(waybleZoneId)
.orElseThrow(() -> new ApplicationException(UserErrorCase.WAYBLE_ZONE_NOT_FOUND));

Set<Long> uniqueIds = new LinkedHashSet<>(waybleZoneIds);
Set<Long> uniquePlaceIds = new LinkedHashSet<>(placeIds);

int added = 0;
for (Long zoneId : uniqueIds) {
WaybleZone zone = waybleZoneRepository.findById(zoneId)
.orElseThrow(() -> new ApplicationException(UserErrorCase.WAYBLE_ZONE_NOT_FOUND));
for (Long placeId : uniquePlaceIds) {
UserPlace place = userPlaceRepository.findByIdAndUser_Id(placeId, user.getId())
.orElseThrow(() -> new ApplicationException(UserErrorCase.PLACE_NOT_FOUND));

boolean exists = mappingRepository.existsByUserPlace_IdAndWaybleZone_Id(placeId, zoneId);
boolean exists = mappingRepository.existsByUserPlace_IdAndWaybleZone_Id(placeId, waybleZoneId);
if (exists) continue;

mappingRepository.save(UserPlaceWaybleZoneMapping.builder()
Expand All @@ -79,16 +81,18 @@ public void addZonesToPlace(Long userId, Long placeId, List<Long> waybleZoneIds)
.build());

place.increaseCount();
zone.addLikes(1);
waybleZoneRepository.save(zone);
userPlaceRepository.save(place);

zone.addLikes(1); // 리스트 하나에 추가될 때마다 +1
added++;
}

if (added > 0) userPlaceRepository.save(place);
if (added > 0) {
waybleZoneRepository.save(zone);
}
return added;
}


@Transactional(readOnly = true)
public List<UserPlaceSummaryDto> getMyPlaceSummaries(Long userId, String sort) {
userRepository.findById(userId)
Expand All @@ -113,7 +117,7 @@ public Page<WaybleZoneListResponseDto> getZonesInPlace(Long userId, Long placeId
UserPlace place = userPlaceRepository.findByIdAndUser_Id(placeId, userId)
.orElseThrow(() -> new ApplicationException(UserErrorCase.PLACE_NOT_FOUND));

Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "id"));
Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "id"));
Page<WaybleZone> zones = mappingRepository.findZonesByPlaceId(place.getId(), pageable);

return zones.map(z ->
Expand Down