Skip to content

Conversation

@jaepar
Copy link
Member

@jaepar jaepar commented Jan 3, 2026

#️⃣연관된 이슈

#105

📝작업 내용

새로 등록된 매장(2주 안에 생성된 매장)을 조회할 수 있는 기능을 구현했습니다.
사용자의 좌표(위도, 경도)값을 기준으로 매장과의 거리를 공간 인덱스로 계산하여 응답하도록 구현했습니다.
사용자의 좌표값을 받지 않은 경우(null)에는 거리 계산을 하지 않고 2주 안에 새로 등록된 매장에 관한 정보만 반환하도록 구현했습니다.

스크린샷 2026-01-03 오후 11 12 46

💬리뷰 요구사항(선택)

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능
    • 새로 등록된 레스토랑을 조회할 수 있는 새로운 기능 추가
    • 레스토랑명, 주소, 평점, 리뷰 수, 콜키지 요금, 콜키지 옵션, 영업시간, 이미지 등의 상세 정보 제공
    • 위치 정보 제공 시 거리 기반 필터링 지원

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

@coderabbitai
Copy link

coderabbitai bot commented Jan 3, 2026

Walkthrough

새로운 "신규 음식점" 조회 엔드포인트를 추가합니다. 사용자 위치 기반 거리 계산이 선택적으로 지원되며, 최근 14일 이내에 등록된 음식점을 반환합니다. 관련 DTO, 매퍼, 리포지토리 메서드 및 서비스 로직이 추가되었습니다.

Changes

집단 / 파일(들) 변경 요약
컨트롤러 및 요청/응답 DTO
src/main/java/konkuk/corkCharge/domain/restaurant/controller/RestaurantController.java, src/main/java/konkuk/corkCharge/domain/restaurant/dto/request/GetNewRestaurantRequest.java, src/main/java/konkuk/corkCharge/domain/restaurant/dto/response/GetNewRestaurantResponse.java
GET /restaurants/new 엔드포인트 추가. GetNewRestaurantRequest (lat/lon 필드 및 hasUserLocation() 헬퍼) 및 GetNewRestaurantResponse 레코드(음식점 ID, 이름, 주소, 평점, 리뷰 수, 콜키지 가격, 옵션, 거리, 이미지 URL, 영업시간) 도입.
리포지토리 및 프로젝션
src/main/java/konkuk/corkCharge/domain/restaurant/repository/RestaurantRepository.java, src/main/java/konkuk/corkCharge/domain/restaurant/repository/NewRestaurantDistanceProjection.java
findByCreatedAtGreaterThanEqualOrderByCreatedAtDesc() 및 findNewRestaurantsWithDistance() 메서드 추가(네이티브 SQL로 거리 계산). NewRestaurantDistanceProjection 인터페이스 추가(restaurantId, distanceKm 게터).
서비스 및 매퍼
src/main/java/konkuk/corkCharge/domain/restaurant/service/RestaurantService.java, src/main/java/konkuk/corkCharge/domain/restaurant/dto/mapper/NewRestaurantResponseMapper.java
getNewRestaurants(GetNewRestaurantRequest) 메서드 추가. 위치 기반/비기반 조건부 로직, NEW_RESTAURANT_DAYS(14) 상수 추가. NewRestaurantResponseMapper 컴포넌트 추가(RestaurantSummary 및 거리를 GetNewRestaurantResponse로 변환, 비트마스크 옵션 디코딩).
캐시 키 수정
src/main/java/konkuk/corkCharge/domain/restaurant/service/RestaurantSummaryService.java
getSummary 메서드 캐시 키 표현식을 #restaurantId에서 #p0(위치 파라미터)로 변경.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Poem

🐰 새로운 음식점들이 떴다, 후루룩!
거리 계산하고 옵션 디코딩,
14일의 신선함을 담아,
사용자의 위치에 맞춰 반짝!
콜키지 정보, 평점 가득,
음식점 탐방의 새 시작이네! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% 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

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.

@jaepar jaepar requested a review from simchaehyeon January 3, 2026 14:20
@jaepar jaepar linked an issue Jan 3, 2026 that may be closed by this pull request
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: 5

🧹 Nitpick comments (4)
src/main/java/konkuk/corkCharge/domain/restaurant/repository/RestaurantRepository.java (1)

51-70: 공간 쿼리가 올바르게 구현되었으나, 거리 필터링 및 페이지네이션 추가를 권장합니다.

네이티브 쿼리가 잘 구현되었습니다:

  • ST_Distance_Sphere를 사용한 거리 계산이 정확합니다 (미터 단위 → km 변환)
  • SRID 4326 사용이 적절합니다
  • 잘못된 좌표(0,0) 필터링이 좋습니다
  • 파라미터 바인딩이 안전합니다

다음 개선사항을 고려해보세요:

  1. 거리 제한: 매우 먼 거리의 식당까지 반환될 수 있습니다. HAVING distanceKm <= ? 조건 추가를 권장합니다.
  2. 페이지네이션: 결과 수가 많을 경우 성능 및 사용자 경험 문제가 발생할 수 있습니다. Pageable 파라미터 추가를 권장합니다.
🔎 개선 제안
@Query(value = """
    SELECT
        r.restaurant_id AS restaurantId,
        ROUND(
            ST_Distance_Sphere(
                r.location,
                ST_SRID(POINT(:lon, :lat), 4326)
            ) / 1000,
            1
        ) AS distanceKm
    FROM restaurant r
    WHERE r.created_at >= :from
      AND ST_X(r.location) != 0 AND ST_Y(r.location) != 0
    HAVING distanceKm <= :maxDistanceKm
    ORDER BY r.created_at DESC
    LIMIT :limit OFFSET :offset
    """, nativeQuery = true)
List<NewRestaurantDistanceProjection> findNewRestaurantsWithDistance(
        @Param("from") LocalDateTime from,
        @Param("lat") double lat,
        @Param("lon") double lon,
        @Param("maxDistanceKm") double maxDistanceKm,
        @Param("limit") int limit,
        @Param("offset") int offset
);

또는 Spring Data의 Pageable을 활용할 수 있습니다 (네이티브 쿼리에서는 제한적이지만 가능).

src/main/java/konkuk/corkCharge/domain/restaurant/service/RestaurantSummaryService.java (1)

36-36: 캐시 키 표현식을 더 명시적으로 변경해주세요.

현재 캐시 키가 #p0(위치 기반 참조)로 설정되어 있습니다. 메서드의 파라미터명이 restaurantId이므로, #restaurantId를 사용하는 것이 더 명시적이고 가독성이 좋습니다. 위치 기반 참조는 향후 파라미터 순서가 변경될 경우 오류가 발생할 수 있으므로, 다음과 같이 수정하기를 권장합니다:

@Cacheable(cacheNames = "restaurantSummary", key = "#restaurantId")
src/main/java/konkuk/corkCharge/domain/restaurant/service/RestaurantService.java (2)

258-262: 불필요한 distanceMap 생성을 제거할 수 있습니다.

Lines 258-262에서 distanceMap을 별도로 구성한 후 Lines 264-271에서 다시 rows를 순회하며 map에서 거리를 조회하고 있습니다. 이는 불필요한 중간 자료구조이며, row에서 직접 getDistanceKm()을 호출하는 것이 더 효율적입니다.

🔎 코드 간소화 제안
     if (request.hasUserLocation()) {
         List<NewRestaurantDistanceProjection> rows =
                 restaurantRepository.findNewRestaurantsWithDistance(from, request.lat(), request.lon());

-        Map<Long, Double> distanceMap = rows.stream()
-                .collect(Collectors.toMap(
-                        NewRestaurantDistanceProjection::getRestaurantId,
-                        NewRestaurantDistanceProjection::getDistanceKm
-                ));
-
         return rows.stream()
                 .map(row -> {
                     Long id = row.getRestaurantId();
                     RestaurantSummary summary = restaurantSummaryService.getSummary(id);

-                    return newRestaurantResponseMapper.toResponse(summary, distanceMap.get(id));
+                    return newRestaurantResponseMapper.toResponse(summary, row.getDistanceKm());
                 })
                 .toList();
     }

264-284: 중복된 매핑 로직을 헬퍼 메서드로 추출하는 것을 고려하세요.

Lines 265-270과 Lines 278-282에서 거의 동일한 매핑 로직이 반복되고 있습니다. 헬퍼 메서드를 추출하면 코드 중복을 줄이고 가독성을 높일 수 있습니다.

🔎 리팩토링 제안
+private GetNewRestaurantResponse mapToNewRestaurantResponse(Long restaurantId, Double distanceKm) {
+    RestaurantSummary summary = restaurantSummaryService.getSummary(restaurantId);
+    return newRestaurantResponseMapper.toResponse(summary, distanceKm);
+}
+
 @Transactional(readOnly = true)
 public List<GetNewRestaurantResponse> getNewRestaurants(GetNewResaurantRequest request) {
     LocalDateTime from = LocalDateTime.now().minusDays(NEW_RESTAURANT_DAYS);

     // 사용자 좌표가 있는 경우
     if (request.hasUserLocation()) {
         List<NewRestaurantDistanceProjection> rows =
                 restaurantRepository.findNewRestaurantsWithDistance(from, request.lat(), request.lon());

         return rows.stream()
-                .map(row -> {
-                    Long id = row.getRestaurantId();
-                    RestaurantSummary summary = restaurantSummaryService.getSummary(id);
-
-                    return newRestaurantResponseMapper.toResponse(summary, row.getDistanceKm());
-                })
+                .map(row -> mapToNewRestaurantResponse(row.getRestaurantId(), row.getDistanceKm()))
                 .toList();
     }

     // 사용자 좌표가 없는 경우
     List<Restaurant> restaurants = restaurantRepository.findByCreatedAtGreaterThanEqualOrderByCreatedAtDesc(from);

     return restaurants.stream()
-            .map(r -> {
-                Long id = r.getRestaurantId();
-                RestaurantSummary summary = restaurantSummaryService.getSummary(id);
-
-                return newRestaurantResponseMapper.toResponse(summary, null);
-            })
+            .map(r -> mapToNewRestaurantResponse(r.getRestaurantId(), null))
             .toList();
 }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c7b3489 and c9bb26e.

📒 Files selected for processing (8)
  • src/main/java/konkuk/corkCharge/domain/restaurant/controller/RestaurantController.java
  • src/main/java/konkuk/corkCharge/domain/restaurant/dto/mapper/NewRestaurantResponseMapper.java
  • src/main/java/konkuk/corkCharge/domain/restaurant/dto/request/GetNewResaurantRequest.java
  • src/main/java/konkuk/corkCharge/domain/restaurant/dto/response/GetNewRestaurantResponse.java
  • src/main/java/konkuk/corkCharge/domain/restaurant/repository/NewRestaurantDistanceProjection.java
  • src/main/java/konkuk/corkCharge/domain/restaurant/repository/RestaurantRepository.java
  • src/main/java/konkuk/corkCharge/domain/restaurant/service/RestaurantService.java
  • src/main/java/konkuk/corkCharge/domain/restaurant/service/RestaurantSummaryService.java
⏰ 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 (4)
src/main/java/konkuk/corkCharge/domain/restaurant/repository/NewRestaurantDistanceProjection.java (1)

3-7: LGTM!

프로젝션 인터페이스 설계가 명확하고 적절합니다. 네이티브 쿼리 결과를 타입 안전하게 매핑하기 위한 좋은 접근 방식입니다.

src/main/java/konkuk/corkCharge/domain/restaurant/dto/response/GetNewRestaurantResponse.java (1)

5-17: LGTM!

응답 DTO 설계가 명확하고 적절합니다. distance 필드에 대한 주석(km 단위, 위치 정보 없을 시 null)이 유용하며, nullable Double 타입 사용이 적절합니다.

src/main/java/konkuk/corkCharge/domain/restaurant/repository/RestaurantRepository.java (1)

48-48: LGTM!

Spring Data JPA 파생 쿼리 메서드가 올바르게 정의되었습니다. 메서드명이 명확하고 정렬 순서도 적절합니다.

src/main/java/konkuk/corkCharge/domain/restaurant/dto/mapper/NewRestaurantResponseMapper.java (1)

16-34: 매핑 로직이 올바르게 구현되었습니다.

RestaurantSummary를 GetNewRestaurantResponse로 변환하는 로직이 정확합니다. 특히 Line 27에서 reviewCount가 null일 경우 0으로 기본값 처리하는 방어 로직이 잘 적용되어 있습니다.

Comment on lines 75 to 80
@GetMapping("/new")
public BaseResponse<List<GetNewRestaurantResponse>> getNewRestaurant(
@RequestBody GetNewResaurantRequest request
) {
return BaseResponse.ok(restaurantService.getNewRestaurants(request));
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

GET 요청에서 @RequestBody 사용은 REST 모범 사례에 위배됩니다.

GET 요청은 멱등성(idempotent)을 가지며 요청 본문(body)을 포함하지 않는 것이 HTTP 표준입니다. 일부 HTTP 클라이언트, 프록시, 캐시 서버는 GET 요청의 본문을 무시하거나 거부할 수 있습니다. 위도/경도와 같은 선택적 파라미터는 @RequestParam을 사용하거나, POST 엔드포인트로 변경하는 것을 권장합니다.

🔎 REST API 디자인 개선 제안

방안 1 (권장): @RequestParam 사용

 @GetMapping("/new")
 public BaseResponse<List<GetNewRestaurantResponse>> getNewRestaurant(
-        @RequestBody GetNewResaurantRequest request
+        @RequestParam(required = false) Double lat,
+        @RequestParam(required = false) Double lon
         ) {
-    return BaseResponse.ok(restaurantService.getNewRestaurants(request));
+    return BaseResponse.ok(restaurantService.getNewRestaurants(lat, lon));
 }

방안 2: POST 엔드포인트로 변경

-@GetMapping("/new")
+@PostMapping("/new")
 public BaseResponse<List<GetNewRestaurantResponse>> getNewRestaurant(
         @RequestBody GetNewResaurantRequest request
         ) {
     return BaseResponse.ok(restaurantService.getNewRestaurants(request));
 }
📝 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
@GetMapping("/new")
public BaseResponse<List<GetNewRestaurantResponse>> getNewRestaurant(
@RequestBody GetNewResaurantRequest request
) {
return BaseResponse.ok(restaurantService.getNewRestaurants(request));
}
@PostMapping("/new")
public BaseResponse<List<GetNewRestaurantResponse>> getNewRestaurant(
@RequestBody GetNewResaurantRequest request
) {
return BaseResponse.ok(restaurantService.getNewRestaurants(request));
}
🤖 Prompt for AI Agents
In
src/main/java/konkuk/corkCharge/domain/restaurant/controller/RestaurantController.java
around lines 75–80, the controller currently uses @RequestBody on a GET
endpoint; change this to follow REST best practices by using @RequestParam for
the query parameters (preferred) or convert the endpoint to POST if a body is
required. Replace the single @RequestBody parameter with explicit method
parameters annotated with @RequestParam (e.g., latitude, longitude, page, size),
mark optional params required=false or provide defaultValue as needed, update
the @GetMapping signature accordingly, pass those values into
restaurantService.getNewRestaurants(...) and remove the @RequestBody import;
alternatively, if you decide to accept a complex request body, change
@GetMapping to @PostMapping and keep @RequestBody. Ensure imports are updated
and unit/integration tests adjusted for the new contract.

Comment on lines +36 to +47
private List<String> decodeOptions(Integer optionBits, String etcContent) {
if (optionBits == null || optionBits == 0)
return List.of();

int bits = optionBits;

return Stream.of(OptionType.values())
.filter(type -> (bits & (1 << type.ordinal())) != 0)
.map(type -> type == ETC ? etcContent : type.getLabel())
.filter(opt -> opt != null && !opt.isBlank())
.toList();
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find OptionType enum definition
fd -t f "OptionType.java" -o -name "*OptionType*"

Repository: CorkCharge/CorkCharge-BE

Length of output: 298


🏁 Script executed:

# Search for OptionType enum in the codebase
rg -t java "enum OptionType" -A 20

Repository: CorkCharge/CorkCharge-BE

Length of output: 1496


🏁 Script executed:

# Also check for any bitmask constants or ordinal-related patterns
rg -t java "OptionType\." | head -20

Repository: CorkCharge/CorkCharge-BE

Length of output: 1272


🏁 Script executed:

# Search for where the bitmask is encoded/created
rg -t java "<<.*type.*ordinal|ordinal.*<<" -B 3 -A 3

Repository: CorkCharge/CorkCharge-BE

Length of output: 4560


🏁 Script executed:

# Look for integer bit encoding related to OptionType
rg -t java "OptionType" -B 5 -A 5 | grep -A 10 -B 10 "1 <<\|bit"

Repository: CorkCharge/CorkCharge-BE

Length of output: 14738


🏁 Script executed:

# Check RestaurantDetailResponseMapper for encoding logic
cat src/main/java/konkuk/corkCharge/domain/restaurant/dto/mapper/RestaurantDetailResponseMapper.java

Repository: CorkCharge/CorkCharge-BE

Length of output: 2924


🏁 Script executed:

# Check ClusterListResponseMapper for encoding logic
cat src/main/java/konkuk/corkCharge/domain/restaurant/dto/mapper/ClusterListResponseMapper.java

Repository: CorkCharge/CorkCharge-BE

Length of output: 3358


ordinal() 기반 비트마스크를 명시적 값으로 변경하세요.

OptionType enum이 암시적 ordinal 값(0-5)을 사용하여 비트마스킹을 수행하는데, optionBits 데이터가 데이터베이스에 영구 저장되므로 enum 순서 변경이나 새로운 값 추가 시 기존 데이터와의 호환성이 깨집니다.

현재 enum 순서: GLASS_PROVIDED(0), ICE_PROVIDED(1), ONE_BOTTLE_FREE(2), TWO_BOTTLE_FREE(3), WINE_GLASS_PROVIDED(4), ETC(5)

권장 해결책:

  1. enum에 명시적 비트 값을 정의: GLASS_PROVIDED(1), ICE_PROVIDED(2), ONE_BOTTLE_FREE(4), ...
  2. addOptionBits(), 인코딩 로직, 디코딩 로직에서 type.ordinal() 대신 이 명시적 값 사용
  3. 향후 enum 수정 시에도 기존 비트 값은 변경되지 않음

영향받는 파일: CorkageStore.addOptionBits(), CorkageStoreService 인코딩 로직, NewRestaurantResponseMapper, RestaurantDetailResponseMapper, ClusterListResponseMapper의 디코딩 로직

🤖 Prompt for AI Agents
In
src/main/java/konkuk/corkCharge/domain/restaurant/dto/mapper/NewRestaurantResponseMapper.java
around lines 36-47, the decoder uses OptionType.ordinal() to test bit flags
which breaks compatibility if enum order changes; update the code and related
places to use explicit bit values instead: add an explicit int bit value to each
OptionType constant (e.g. 1,2,4,8,...), provide a getter like getBitValue() on
the enum, then replace all uses of (1 << type.ordinal()) with the explicit bit
value (type.getBitValue()) in this mapper and the other decoders
(RestaurantDetailResponseMapper, ClusterListResponseMapper) and update encoding
logic in CorkageStore.addOptionBits() and CorkageStoreService to build masks
using the new enum bit values rather than ordinal shifts so stored optionBits
remain stable across enum changes.

Comment on lines 3 to 10
public record GetNewResaurantRequest(
Double lat,
Double lon
) {
public boolean hasUserLocation() {
return lat != null && lon != null;
}
}
Copy link

@coderabbitai coderabbitai bot Jan 3, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

클래스명의 오타를 수정해야 합니다.

클래스명이 GetNewResaurantRequest로 되어 있습니다. "Resaurant" 대신 "Restaurant"가 올바른 철자입니다. 이는 파일명과 클래스명 모두에 영향을 미치며, 코드베이스 전체에서 일관성 문제를 야기합니다.

🔎 수정 제안
  1. 파일명을 GetNewRestaurantRequest.java로 변경
  2. 클래스명을 수정:
-public record GetNewResaurantRequest(
+public record GetNewRestaurantRequest(
         Double lat,
         Double lon
 ) {
  1. 이 클래스를 사용하는 모든 곳에서 import와 참조를 업데이트해야 합니다.
📝 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 record GetNewResaurantRequest(
Double lat,
Double lon
) {
public boolean hasUserLocation() {
return lat != null && lon != null;
}
}
public record GetNewRestaurantRequest(
Double lat,
Double lon
) {
public boolean hasUserLocation() {
return lat != null && lon != null;
}
}
🤖 Prompt for AI Agents
In
src/main/java/konkuk/corkCharge/domain/restaurant/dto/request/GetNewResaurantRequest.java
around lines 3 to 10, the class and filename contain a typo: "Resaurant" should
be "Restaurant". Rename the file to GetNewRestaurantRequest.java and rename the
record to GetNewRestaurantRequest (keeping the same fields and method), then
update all imports and references across the codebase (IDE refactor/rename is
recommended) so callers, tests, and package declarations reference the new class
name.

Copy link
Collaborator

Choose a reason for hiding this comment

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

이 부분 Restaurant로 오타 수정해서 다시 올려주시면 될 것 같습니다.

Copy link

Choose a reason for hiding this comment

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

@simchaehyeon 네, 맞습니다. GetNewResaurantRequestGetNewRestaurantRequest로 수정해야 합니다.

PR 작성자분께서 다음 사항을 수정해주셔야 합니다:

  1. 파일명: GetNewResaurantRequest.javaGetNewRestaurantRequest.java
  2. 클래스명과 모든 참조 업데이트

IDE의 리팩토링 기능(Rename)을 사용하시면 관련된 모든 import와 참조가 자동으로 업데이트됩니다.

@simchaehyeon
Copy link
Collaborator

코드래빗 리뷰 아래에 리플라이 남겨둔 부분 확인 부탁드립니다. 수고하셨습니다!

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

♻️ Duplicate comments (1)
src/main/java/konkuk/corkCharge/domain/restaurant/controller/RestaurantController.java (1)

75-80: GET 요청에 @RequestBody 사용은 REST 표준에 위배됩니다.

이전 리뷰에서도 지적된 사항입니다. GET 요청에 request body를 사용하는 것은 HTTP 표준을 위반하며, 일부 클라이언트, 프록시, 캐시 서버에서 body를 무시하거나 거부할 수 있습니다.

위도/경도와 같은 선택적 파라미터는 @RequestParam을 사용하거나, POST 엔드포인트로 변경하는 것을 권장합니다.

🔎 수정 방안

방안 1 (권장): @RequestParam 사용

 @GetMapping("/new")
 public BaseResponse<List<GetNewRestaurantResponse>> getNewRestaurant(
-        @RequestBody GetNewRestaurantRequest request
+        @RequestParam(required = false) Double lat,
+        @RequestParam(required = false) Double lon
         ) {
-    return BaseResponse.ok(restaurantService.getNewRestaurants(request));
+    GetNewRestaurantRequest request = new GetNewRestaurantRequest(lat, lon);
+    return BaseResponse.ok(restaurantService.getNewRestaurants(request));
 }

방안 2: POST 엔드포인트로 변경

-@GetMapping("/new")
+@PostMapping("/new")
 public BaseResponse<List<GetNewRestaurantResponse>> getNewRestaurant(
         @RequestBody GetNewRestaurantRequest request
         ) {
     return BaseResponse.ok(restaurantService.getNewRestaurants(request));
 }
🧹 Nitpick comments (1)
src/main/java/konkuk/corkCharge/domain/restaurant/dto/request/GetNewRestaurantRequest.java (1)

3-9: 부분 좌표 입력에 대한 검증 추가를 고려하세요.

현재 hasUserLocation() 메서드는 latlon이 모두 null이 아닐 때만 true를 반환합니다. 그러나 하나만 null인 경우(부분 좌표)에 대한 명시적인 검증이 없습니다. 클라이언트가 실수로 한 좌표만 전송하면 조용히 "위치 없음"으로 처리되어 예상치 못한 동작이 발생할 수 있습니다.

부분 좌표 입력을 명시적으로 거부하려면 검증 로직 추가를 고려하세요.

🔎 검증 로직 추가 제안
 public record GetNewRestaurantRequest(
         Double lat,
         Double lon
 ) {
     public boolean hasUserLocation() {
         return lat != null && lon != null;
     }
+    
+    public boolean hasPartialLocation() {
+        return (lat == null) != (lon == null);
+    }
 }

컨트롤러나 서비스 레이어에서 hasPartialLocation()이 true일 때 적절한 에러를 반환할 수 있습니다.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c9bb26e and a498168.

📒 Files selected for processing (3)
  • src/main/java/konkuk/corkCharge/domain/restaurant/controller/RestaurantController.java
  • src/main/java/konkuk/corkCharge/domain/restaurant/dto/request/GetNewRestaurantRequest.java
  • src/main/java/konkuk/corkCharge/domain/restaurant/service/RestaurantService.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/konkuk/corkCharge/domain/restaurant/service/RestaurantService.java
⏰ 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

@jaepar jaepar merged commit 8d98609 into develope Jan 3, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 신규등록매장 조회 기능 개발

3 participants