Skip to content

Conversation

@KiSeungMin
Copy link
Member

@KiSeungMin KiSeungMin commented Aug 12, 2025

✔️ 연관 이슈

📝 작업 내용

  • 진행상황을 main 브랜치에 반영 및 프로덕션 서버에 배포합니다.

스크린샷 (선택)

Summary by CodeRabbit

  • 신기능
    • 주변 편의시설 검색 API 추가(필터: RAMP, ELEVATOR). 결과 리스트 반환.
  • 변경사항
    • 사용자 장소 API 경로를 /api/v1/users/places로 통합하고, 인증 사용자 기반으로 동작.
    • 사용자 장소 응답 필드명을 camelCase로 정비(placeId, waybleZone 등).
    • 경로 탐색 로직 조정: 램프 가중 페널티, 마커 우대 적용 및 30km 초과 시 오류 반환.
    • 근접 노드 탐색을 반경 1km로 제한해 매칭 정확도 개선.
    • 오류 로그 보존 강화(시작 시 히스토리 삭제 중단).
  • 테스트
    • 편의시설 검색 통합 테스트 및 보행 경로 유닛 테스트 추가.
  • 기타(Chores)
    • CI 워크플로우 정리 및 배포 디스코드 알림 제거.

zyovn and others added 29 commits August 12, 2025 12:29
[REFACTOR] 웨이블존 추천 경로 리팩토링
[feat] 지도에서 경사로, 엘리베이터를 거리순으로 조회하는 로직 구현
[REFACTOR] 웨이블존 추천 경로 30km 이상 예외 처리
[fix] 배포 시 에러 로그 사라지는 버그 수정, 예외 디스코드 알림 범위 수정, 프론트 요구사항 반영
@KiSeungMin KiSeungMin self-assigned this Aug 12, 2025
@KiSeungMin KiSeungMin added the release 프로덕션 서버에 배포 label Aug 12, 2025
@coderabbitai
Copy link

coderabbitai bot commented Aug 12, 2025

Walkthrough

CI/CD 스크립트에 호스트 로그 디렉터리 관리와 Docker prune 옵션 조정, Discord 웹훅 제거 및 트리거 단순화가 적용되었습니다. 서버 예외 처리에서 Discord 알림 필터링이 추가되고, 보행 경로 계산은 폴리라인·허용거리(30km) 검증으로 변경되었습니다. 시설 검색(엘리베이터/경사로) API가 추가되었고, 사용자 장소/추천 컨트롤러는 보안 컨텍스트 기반으로 변경되었습니다.

Changes

Cohort / File(s) Summary
CI/CD 및 로깅 구성
.github/workflows/cd-develop.yml, Dockerfile, src/main/resources/logback-spring.xml
호스트 로그 디렉터리 생성/권한 설정, 컨테이너 로그 가시화 추가, Docker prune에서 볼륨 제외, Discord 웹훅 및 추가 트리거 제거. Dockerfile에 /app/logs 생성과 WORKDIR=/app 설정. logback ERROR_FILE cleanHistoryOnStart=false로 변경.
예외 처리/알림
src/main/java/.../common/exception/GlobalExceptionHandler.java
Discord 알림 스킵 로직(경로/봇/예외 유형 필터) 추가, Validation 처리 단순화 및 warn 로깅, 일부 Discord 전송 경로 제거. 메서드 시그니처(handleValidException) 변경.
보행 경로/그래프
src/main/java/.../direction/exception/WalkingErrorCase.java, .../direction/init/GraphInit.java, .../direction/service/WalkingService.java, .../direction/service/WaybleDijkstraService.java, src/main/resources/wayble_markers.json, src/test/java/.../direction/service/WalkingServiceTest.java
30km 초과 에러 케이스 추가, 그래프 거리 계산에 램프 패널티/마커 할인 도입, 노드 후보 탐색 반경(1km) 제한, 폴리라인 기반 거리 계산·중복 좌표 제거 및 거리 상한 예외 처리, 일부 마커 타입을 RAMP로 변경, 경로 테스트 추가.
시설 검색 기능(Elasticsearch)
src/main/java/.../explore/controller/WaybleFacilitySearchController.java, .../explore/dto/facility/*, .../explore/entity/FacilityType.java, .../explore/entity/WaybleFacilityDocument.java, .../explore/repository/facility/*, .../explore/service/WaybleFacilityDocumentService.java, src/test/java/.../explore/WaybleFacilityApiIntegrationTest.java
시설 검색 엔드포인트(/api/v1/facilities/search) 추가, DTO/응답/등록 정의, ES 문서/리포지토리/쿼리 리포지토리/서비스 도입, 타입 enum 추가(ELEVATOR,RAMP), 통합 테스트로 데이터 시딩·거리순 정렬 검증.
사용자 장소/추천 컨트롤러
src/main/java/.../user/controller/UserPlaceController.java, .../explore/controller/WaybleZoneRecommendController.java, .../explore/dto/recommend/WaybleZoneRecommendConditionDto.java, .../user/dto/UserPlaceListResponseDto.java, .../user/service/UserPlaceService.java
사용자 ID를 경로/DTO에서 제거하고 SecurityContext에서 추출하도록 변경, 추천 조건 DTO의 userId 제거, 응답 DTO 및 빌더의 필드명을 snake_case→camelCase로 변경.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client
  participant Controller as FacilitySearchController
  participant Service as FacilityDocumentService
  participant Repo as QuerySearchRepository
  participant ES as Elasticsearch

  Client->>Controller: GET /api/v1/facilities/search?lat,lon,facilityType
  Controller->>Service: findNearbyFacilityDocuments(dto)
  Service->>Repo: findNearbyFacilitiesByType(dto)
  Repo->>ES: geo_distance + term(facilityType?) query (size=50, sort by _geo_distance)
  ES-->>Repo: hits (WaybleFacilityDocument)
  Repo-->>Service: List<WaybleFacilityResponseDto>
  Service-->>Controller: List<WaybleFacilityResponseDto>
  Controller-->>Client: 200 OK (CommonResponse)
Loading
sequenceDiagram
  autonumber
  participant Client
  participant WalkingService
  participant Dijkstra as WaybleDijkstraService
  participant Graph as GraphInit

  Client->>WalkingService: findWayblePath(startLat, startLon, endLat, endLon)
  WalkingService->>Graph: getNodeMap()/adjacencyList (반경 1km 내 노드 탐색)
  WalkingService->>Dijkstra: createWayblePath(startNode, endNode)
  Dijkstra->>Dijkstra: 폴리라인 생성/중복제거
  Dijkstra->>Dijkstra: Haversine 총거리 계산
  alt 총거리 >= 30000m
    Dijkstra-->>WalkingService: throw DISTANCE_LIMIT_EXCEEDED
  else
    Dijkstra-->>WalkingService: WayblePathResponse
    WalkingService-->>Client: 200 OK (경로/거리/시간)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

💡 feature, 🤔 test, 🐛 bug fix

Suggested reviewers

  • seung-in-Yoo
  • hyoinYang
  • zyovn
  • wonjun-lee-fcwj245

Poem

(•̀ᴗ•́)و bunny says:
로그 굴리고 램프 점프, 지도 위 춤을 춘다!
삼만 미터 넘으면 멈칫—귀가 쫑긋 신호 받다.
엘리베이터, 램프 찾아, 핫스팟 콕 집어주고,
아이디는 주머니에—보안 숲에서 꺼내온다.
삐빅! 오늘도 경로는 깔끔, 폴리라인처럼 반짝! 🥕

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

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.

@KiSeungMin KiSeungMin changed the title [release[ 진행상황 main branch에 반영 [release]진행상황 main branch에 반영 Aug 12, 2025
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: 15

🔭 Outside diff range comments (3)
src/main/java/com/wayble/server/explore/controller/WaybleZoneRecommendController.java (1)

24-27: size 파라미터에 경계 유효성 검증을 추가하세요

현재 size는 제한 없이 전달되어 리포지토리에서 limit(size)에 그대로 반영됩니다. 과도한 size로 인한 과부하를 막기 위해 최소/최대값을 제한하는 것이 안전합니다(예: 1~100).

적용 예시:

@@
-import jakarta.validation.Valid;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
@@
-    public CommonResponse<List<WaybleZoneRecommendResponseDto>> getWaybleZonePersonalRecommend(
-            @Valid @ModelAttribute WaybleZoneRecommendConditionDto conditionDto,
-            @RequestParam(name = "size", defaultValue = "1") int size) {
+    public CommonResponse<List<WaybleZoneRecommendResponseDto>> getWaybleZonePersonalRecommend(
+            @Valid @ModelAttribute WaybleZoneRecommendConditionDto conditionDto,
+            @Min(1) @Max(100) @RequestParam(name = "size", defaultValue = "1") int size) {
src/main/java/com/wayble/server/user/service/UserPlaceService.java (2)

41-62: 중복 저장 레이스 컨디션 가능성 및 고유성 보장 전략 필요

exists 체크 → 저장 흐름은 동시에 요청이 들어오면 중복 저장이 발생할 수 있습니다. 현재 스키마(매핑 테이블이 user_place_id, wayble_zone_id를 참조)에서는 “유저+웨이블존” 단위의 DB 유니크 제약을 직접 걸기 어렵습니다. 아래 중 하나를 고려해 주세요.

  • 매핑 테이블에 user_id 컬럼을 추가하고 (user_id, wayble_zone_id) 유니크 인덱스 부여
  • 또는 저장 시 PESSIMISTIC WRITE 락(SELECT … FOR UPDATE)으로 레이스 방지
  • 또는 애그리게이트 재구성(유저-존 단일 엔티티로 모델링)으로 중복 상태 자체를 배제

65-95: N+1 쿼리 가능성: fetch join으로 조회 최적화 제안

mappingRepository.findAllByUserPlace_User_Id(userId) 호출 후 LAZY 연관(userPlace, waybleZone)을 순회하며 접근해 N+1이 발생할 수 있습니다. fetch join 메서드로 교체를 권장합니다.

예시(리포지토리 추가):

@Query("""
select m from UserPlaceWaybleZoneMapping m
join fetch m.userPlace up
join fetch m.waybleZone wz
where up.user.id = :userId
""")
List<UserPlaceWaybleZoneMapping> findAllByUserIdWithFetchJoin(@Param("userId") Long userId);

그리고 서비스에서 해당 메서드 사용으로 교체.

🧹 Nitpick comments (26)
src/main/java/com/wayble/server/explore/controller/WaybleZoneRecommendController.java (1)

28-31: SecurityContext에서 Long 캐스팅은 환경에 따라 ClassCastException 위험이 있습니다

JwtAuthentication의 principal이 Long인 전제에서는 동작하지만, 익명/타 인증 경로(예: OAuth2User, "anonymousUser")에서는 ClassCastException이 날 수 있습니다. 타입 체크를 추가하거나, 더 바람직하게는 @AuthenticationPrincipal로 주입받는 방식을 권장합니다.

옵션 A) 최소 변경으로 타입 안전성 보강:

@@
-import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.access.AccessDeniedException;
@@
-        Long userId = (Long) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+        if (!(principal instanceof Long userId)) {
+            throw new AccessDeniedException("Unauthenticated or invalid principal");
+        }

옵션 B) 권장: @AuthenticationPrincipal 사용으로 테스트 용이성과 타입 안정성 개선:

@@
-import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
@@
-    public CommonResponse<List<WaybleZoneRecommendResponseDto>> getWaybleZonePersonalRecommend(
-            @Valid @ModelAttribute WaybleZoneRecommendConditionDto conditionDto,
-            @RequestParam(name = "size", defaultValue = "1") int size) {
-
-        Long userId = (Long) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+    public CommonResponse<List<WaybleZoneRecommendResponseDto>> getWaybleZonePersonalRecommend(
+            @AuthenticationPrincipal Long userId,
+            @Valid @ModelAttribute WaybleZoneRecommendConditionDto conditionDto,
+            @RequestParam(name = "size", defaultValue = "1") int size) {

참고: 엔드포인트가 반드시 인증 필요하도록 SecurityConfig 혹은 @PreAuthorize("isAuthenticated()")로 보강되어 있다면, A/B 모두 안정적으로 동작합니다. 없다면 인증 요구를 명시해 주세요.

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

88-88: Primitive double 언박싱 NPE 가능성 점검

waybleZone.getRating()이 Double일 경우 null이면 언박싱 시 NPE가 발생합니다. DTO 필드를 Double로 변경하거나, 기본값(예: 0.0d)으로 방어 코드를 두는 것을 고려해 주세요.

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

14-16: 불필요한 import 정리 제안

Authentication를 사용하지 않거나, 위 수정 반영 시 사용하게 됩니다. 최종 코드 기준으로 사용되지 않으면 제거해 주세요.

src/main/java/com/wayble/server/common/exception/GlobalExceptionHandler.java (5)

100-110: develop 프로파일 외 미전송 로직 적절, 웹훅 URL 유효성 체크 추가 권장

프로파일 게이트는 좋습니다. 추가로 discordWebhookUrl 미설정/공백일 때 조기 리턴하여 예외/로그 노이즈를 더 낮추는 것을 권장합니다.

다음과 같이 보완해 주세요:

     if (!env.acceptsProfiles(Profiles.of("develop"))) {
         log.info("현재 active 프로파일이 develop가 아니므로 Discord 알림을 보내지 않습니다.");
         return;
     }
 
-    // 특정 예외 타입 및 경로에 대한 Discord 알림 제외
+    if (discordWebhookUrl == null || discordWebhookUrl.isBlank()) {
+        log.debug("Discord webhook URL 미설정 - 알림 생략");
+        return;
+    }
+
+    // 특정 예외 타입 및 경로에 대한 Discord 알림 제외

140-168: 스킵 규칙 좋습니다. 케이스 민감도와 메시지/경로 정규화 제안

path/message를 소문자로 정규화하여 케이스 차이(favicon/Icon 등)에 안정적으로 대응하는 것을 권장합니다.

적용 예:

-    private boolean shouldSkipDiscordNotification(Exception ex, String path) {
-        String exceptionName = ex.getClass().getSimpleName();
-        String message = ex.getMessage();
+    private boolean shouldSkipDiscordNotification(Exception ex, String path) {
+        String exceptionName = ex.getClass().getSimpleName();
+        String message = ex.getMessage();
+        String normalizedPath = (path == null) ? "" : path.toLowerCase();
@@
-        if (isIgnoredPath(path)) {
+        if (isIgnoredPath(normalizedPath)) {
             return true;
         }
@@
-        if (isBotOrCrawlerRequest(message)) {
+        if (isBotOrCrawlerRequest(message)) {
             return true;
         }

그리고 아래 보조 메서드들도 케이스 비지정 매칭으로 맞춰주세요(아래 두 코멘트 참고).


173-196: 경로 스킵 규칙: 케이스 비지정 및 startsWith/equals 혼용 고려

contains는 오탐/미탐 가능성이 있어 경로 기준에 따라 startsWith/equals를 혼용하고, 소문자 비교로 보완하는 것을 권장합니다.

-    private boolean isIgnoredPath(String path) {
-        String[] ignoredPaths = {
+    private boolean isIgnoredPath(String path) {
+        if (path == null) return false;
+        String[] ignoredPaths = {
             "/favicon.ico",
             "/index.html", 
             "/robots.txt",
             "/sitemap.xml",
             "/apple-touch-icon",
             "/.well-known/",
             "/wp-admin/",
             "/admin/",
             "/phpmyadmin/",
             "/xmlrpc.php",
             "/.env",
             "/config.php"
         };
 
         for (String ignoredPath : ignoredPaths) {
-            if (path.contains(ignoredPath)) {
+            if (path.startsWith(ignoredPath) || path.equals(ignoredPath)) {
                 return true;
             }
         }
 
         return false;
     }

201-218: 봇/크롤러 메시지 판별: 케이스 비지정 및 토큰 확장 제안

메시지를 소문자로 정규화하고, 404 템플릿/정적리소스 누락 패턴을 약간 확장하는 것을 권장합니다.

-    private boolean isBotOrCrawlerRequest(String message) {
-        if (message == null) return false;
+    private boolean isBotOrCrawlerRequest(String message) {
+        if (message == null) return false;
+        String msg = message.toLowerCase();
 
         String[] botIndicators = {
-            "No static resource",
-            "Could not resolve view",
-            "favicon",
-            "robots.txt"
+            "no static resource",
+            "could not resolve view",
+            "favicon",
+            "robots.txt",
+            "not found",
+            "illegal character in path"
         };
 
         for (String indicator : botIndicators) {
-            if (message.contains(indicator)) {
+            if (msg.contains(indicator)) {
                 return true;
             }
         }
 
         return false;
     }

223-240: 무시 예외 확대 및 클래스 기반 체크 고려

예외명 문자열 비교 외에 IOException 계열(예: SocketTimeoutException, SocketException)의 클래스 기반 체크도 추가하면 안전합니다. 메시지 텍스트 매칭은 로케일/버전에 따라 변할 수 있습니다.

-    private boolean isIgnoredException(String exceptionName, String message) {
+    private boolean isIgnoredException(String exceptionName, String message) {
         // 클라이언트 연결 종료 관련
         if ("ClientAbortException".equals(exceptionName) || 
             "BrokenPipeException".equals(exceptionName)) {
             return true;
         }
 
         // 타임아웃 관련 (너무 빈번한 경우)
-        if (message != null && (
+        if (message != null && (
             message.contains("Connection timed out") ||
             message.contains("Read timed out") ||
             message.contains("Connection reset")
         )) {
             return true;
         }
 
+        // 클래스 기반 방어 (가능한 경우)
+        // if (ex instanceof java.net.SocketTimeoutException || ex instanceof java.net.SocketException) {
+        //     return true;
+        // }
+
         return false;
     }

원하시면 JUnit으로 스킵 규칙 유닛 테스트(경로/메시지/예외 케이스별) 템플릿을 제공하겠습니다.

src/main/java/com/wayble/server/explore/repository/facility/WaybleFacilityDocumentRepository.java (1)

8-10: 불필요한 findAll() 메서드 선언입니다.

ElasticsearchRepository를 확장하면 이미 findAll() 메서드가 제공됩니다. 명시적으로 선언할 필요가 없습니다.

-public interface WaybleFacilityDocumentRepository extends ElasticsearchRepository<WaybleFacilityDocument, String> {
-    List<WaybleFacilityDocument> findAll();
-}
+public interface WaybleFacilityDocumentRepository extends ElasticsearchRepository<WaybleFacilityDocument, String> {
+}
src/main/java/com/wayble/server/explore/service/WaybleFacilityDocumentService.java (2)

14-14: @transactional 어노테이션이 불필요합니다.

이 서비스는 읽기 전용 작업만 수행하므로 @Transactional 어노테이션이 불필요합니다. Elasticsearch 쿼리는 트랜잭션 관리가 필요하지 않습니다.

 @Service
 @RequiredArgsConstructor
-@Transactional
 public class WaybleFacilityDocumentService {

19-21: 서비스 레이어가 단순한 위임 역할만 합니다.

현재 서비스는 단순히 레포지토리 메서드를 호출하기만 합니다. 비즈니스 로직이 없다면 컨트롤러에서 직접 레포지토리를 호출하는 것을 고려해보세요.

src/main/java/com/wayble/server/explore/controller/WaybleFacilitySearchController.java (2)

24-29: API 문서화 어노테이션이 누락되었습니다.

다른 컨트롤러들과 일관성을 위해 API 문서화를 위한 어노테이션(예: @Operation, @ApiResponse)을 추가하는 것을 고려해보세요.


20-20: REST API 경로 설계를 검토해주세요.

현재 경로 /api/v1/facilities/search가 RESTful 설계 원칙에 부합하는지 검토가 필요합니다. 리소스 중심의 경로 /api/v1/facilities?latitude=...&longitude=...가 더 적절할 수 있습니다.

src/main/java/com/wayble/server/explore/repository/facility/WaybleFacilityQuerySearchRepository.java (2)

34-34: 하드코딩된 반경값을 설정 가능하게 만드세요.

반경값이 하드코딩되어 있습니다. 설정 파일이나 상수 클래스를 통해 관리하는 것이 좋습니다.

+    private static final double DEFAULT_RADIUS_KM = 10.0;
+    
     public List<WaybleFacilityResponseDto> findNearbyFacilitiesByType(
             WaybleFacilityConditionDto condition) {
         
-        double radius = 10.0; // 기본 반경 10km
+        double radius = DEFAULT_RADIUS_KM;

94-99: 스트림 처리 최적화가 가능합니다.

현재 코드는 각 hit에서 content를 추출한 후 DTO로 변환하고 있습니다. 메서드 레퍼런스를 사용하여 더 간결하게 작성할 수 있습니다.

        // 결과를 Document 리스트로 반환
        return hits.stream()
-                .map(hit -> {
-                    WaybleFacilityDocument doc = hit.getContent();
-                    return WaybleFacilityResponseDto.from(doc);
-                })
+                .map(hit -> WaybleFacilityResponseDto.from(hit.getContent()))
                 .toList();
src/main/java/com/wayble/server/explore/entity/WaybleFacilityDocument.java (4)

6-11: FieldType import 추가.

위의 매핑 수정과 함께 FieldType import가 필요합니다.

 import org.springframework.data.elasticsearch.annotations.Document;
 import org.springframework.data.elasticsearch.annotations.Field;
 import org.springframework.data.elasticsearch.annotations.GeoPointField;
+import org.springframework.data.elasticsearch.annotations.FieldType;
 import org.springframework.data.elasticsearch.core.geo.GeoPoint;

17-17: createIndex=true 운영 반영 여부 확인.

@Document(createIndex = true)는 애플리케이션 기동 시 인덱스 자동 생성을 시도합니다. 운영에서는 템플릿/마이그레이션으로 관리하는 경우가 많습니다. 환경별 설정 분리 또는 false로 전환을 검토해 주세요.


19-21: ES 문서 ID 중복 저장 가능성(메타 _id vs _source 필드).

@Id만으로 ES의 _id가 설정됩니다. 동시에 @Field(name = "id")_source에도 id를 저장하면 중복 정보가 됩니다. 특별한 이유가 없다면 제거를 권장합니다.

     @Id
-    @Field(name = "id")
     private String id;

12-16: 동등성/컬렉션 사용 대비 equals/hashCode 추가 제안.

도큐먼트를 Set/Map에 담아 다룰 가능성이 있다면 id 기반의 equals/hashCode를 추가하는 것이 안전합니다.

 @ToString
 @Builder
 @Getter
+@EqualsAndHashCode(of = "id")
 @AllArgsConstructor
 @NoArgsConstructor

(필요 시 Lombok import 추가: import lombok.EqualsAndHashCode;)

src/test/java/com/wayble/server/explore/WaybleFacilityApiIntegrationTest.java (3)

60-63: 테스트 런타임 최적화(시드 수 축소 제안).

SAMPLES=100은 ES/네트워크 환경에 따라 테스트가 무거워질 수 있습니다. 기능 검증에는 20~50개로도 충분할 가능성이 큽니다.

-    private static final int SAMPLES = 100;
+    private static final int SAMPLES = 30;

112-118: 테스트 출력(System.out) 제거 또는 로그로 대체.

불필요한 표준 출력은 CI 로그 노이즈만 증가시킵니다. 실패 시 디버깅이 필요한 로그만 Logger의 DEBUG 레벨로 남기는 것을 권장합니다.

-            System.out.println(doc);

138-140: 과도한 응답 전체 출력 제거 권장.

응답 JSON 전체 pretty print는 테스트 안정성과는 무관하며 로그를 비대하게 만듭니다. 실패 시에만 디버깅 용도로 출력하거나 제거하세요.

-        System.out.println("==== 응답 결과 ====");
-        System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(objectMapper.readTree(json)));

Also applies to: 196-198

src/main/java/com/wayble/server/direction/init/GraphInit.java (1)

73-78: 경로 가중치 로직 개선 제안

현재 RAMP와 일반 마커가 상호 배타적으로 처리되고 있습니다. 하지만 RAMP 타입도 마커의 일종이므로 로직이 중복될 수 있습니다.

-            boolean isWaybleMarker = markerMap.containsKey(edge.from()) || markerMap.containsKey(edge.to());
-            boolean isRamp = rampMarkers.contains(edge.from()) || rampMarkers.contains(edge.to());
-
-            double distance = edge.length();
-
-            if (isRamp) distance *= RAMP_PENALTY;
-            else if (isWaybleMarker) distance *= MARKER_DISCOUNT;
+            Type fromType = markerMap.get(edge.from());
+            Type toType = markerMap.get(edge.to());
+            
+            double distance = edge.length();
+            
+            if (fromType == Type.RAMP || toType == Type.RAMP) {
+                distance *= RAMP_PENALTY;
+            } else if (fromType != null || toType != null) {
+                distance *= MARKER_DISCOUNT;
+            }
src/test/java/com/wayble/server/direction/service/WalkingServiceTest.java (2)

30-30: Mock 필드에 접근 제어자 누락

WaybleDijkstraService Mock 필드에 private 접근 제어자가 누락되었습니다.

-    @Mock
-    WaybleDijkstraService waybleDijkstraService;
+    @Mock
+    private WaybleDijkstraService waybleDijkstraService;

73-74: 사용하지 않는 Mock 설정 제거 필요

주석 처리된 Mock 설정은 제거하는 것이 좋습니다.

         when(graphInit.getNodeMap()).thenReturn(nodeMap);
-        // when(graphInit.getMarkerMap()).thenReturn(markerMap);
-        // when(graphInit.getGraph()).thenReturn(adjacencyList);
         when(waybleDijkstraService.createWayblePath(anyLong(), anyLong()))
src/main/java/com/wayble/server/direction/service/WaybleDijkstraService.java (1)

83-97: 중복 좌표 제거 로직의 복잡성

deleteDuplicateCoords 메서드가 루프를 감지하고 제거하는 복잡한 로직을 포함하고 있습니다. 이 로직의 의도와 필요성을 문서화하는 것이 좋겠습니다.

+    /**
+     * 폴리라인에서 중복 좌표를 제거합니다.
+     * - 연속된 중복 좌표는 추가하지 않음
+     * - 이전에 방문한 좌표로 돌아가는 경우 루프를 제거
+     * 
+     * @param polyline 폴리라인 좌표 리스트
+     * @param coords 추가할 좌표
+     */
     private void deleteDuplicateCoords(List<double[]> polyline, double[] coords) {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 85fc998 and d7463c2.

📒 Files selected for processing (25)
  • .github/workflows/cd-develop.yml (2 hunks)
  • Dockerfile (1 hunks)
  • src/main/java/com/wayble/server/common/exception/GlobalExceptionHandler.java (4 hunks)
  • src/main/java/com/wayble/server/direction/exception/WalkingErrorCase.java (1 hunks)
  • src/main/java/com/wayble/server/direction/init/GraphInit.java (2 hunks)
  • src/main/java/com/wayble/server/direction/service/WalkingService.java (2 hunks)
  • src/main/java/com/wayble/server/direction/service/WaybleDijkstraService.java (6 hunks)
  • src/main/java/com/wayble/server/explore/controller/WaybleFacilitySearchController.java (1 hunks)
  • src/main/java/com/wayble/server/explore/controller/WaybleZoneRecommendController.java (2 hunks)
  • src/main/java/com/wayble/server/explore/dto/facility/WaybleFacilityConditionDto.java (1 hunks)
  • src/main/java/com/wayble/server/explore/dto/facility/WaybleFacilityRegisterDto.java (1 hunks)
  • src/main/java/com/wayble/server/explore/dto/facility/WaybleFacilityResponseDto.java (1 hunks)
  • src/main/java/com/wayble/server/explore/dto/recommend/WaybleZoneRecommendConditionDto.java (1 hunks)
  • src/main/java/com/wayble/server/explore/entity/FacilityType.java (1 hunks)
  • src/main/java/com/wayble/server/explore/entity/WaybleFacilityDocument.java (1 hunks)
  • src/main/java/com/wayble/server/explore/repository/facility/WaybleFacilityDocumentRepository.java (1 hunks)
  • src/main/java/com/wayble/server/explore/repository/facility/WaybleFacilityQuerySearchRepository.java (1 hunks)
  • src/main/java/com/wayble/server/explore/service/WaybleFacilityDocumentService.java (1 hunks)
  • src/main/java/com/wayble/server/user/controller/UserPlaceController.java (3 hunks)
  • src/main/java/com/wayble/server/user/dto/UserPlaceListResponseDto.java (1 hunks)
  • src/main/java/com/wayble/server/user/service/UserPlaceService.java (1 hunks)
  • src/main/resources/logback-spring.xml (1 hunks)
  • src/main/resources/wayble_markers.json (3 hunks)
  • src/test/java/com/wayble/server/direction/service/WalkingServiceTest.java (1 hunks)
  • src/test/java/com/wayble/server/explore/WaybleFacilityApiIntegrationTest.java (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (20)
src/main/java/com/wayble/server/explore/controller/WaybleFacilitySearchController.java (1)
src/main/java/com/wayble/server/explore/controller/WaybleZoneSearchController.java (2)
  • RestController (21-75)
  • PostMapping (70-74)
src/main/java/com/wayble/server/direction/service/WalkingService.java (2)
src/main/java/com/wayble/server/direction/service/util/HaversineUtil.java (1)
  • HaversineUtil (3-16)
src/main/java/com/wayble/server/direction/service/TransportationService.java (3)
  • n (79-81)
  • n (87-89)
  • n (86-86)
src/main/java/com/wayble/server/explore/repository/facility/WaybleFacilityDocumentRepository.java (2)
src/main/java/com/wayble/server/direction/repository/DirectionElasticsearchRepository.java (1)
  • DirectionElasticsearchRepository (6-7)
src/main/java/com/wayble/server/explore/repository/WaybleZoneDocumentRepository.java (2)
  • WaybleZoneDocumentRepository (9-12)
  • findAll (11-11)
src/main/java/com/wayble/server/direction/exception/WalkingErrorCase.java (2)
src/main/java/com/wayble/server/direction/exception/DirectionErrorCase.java (1)
  • Getter (7-19)
src/main/java/com/wayble/server/wayblezone/exception/WaybleZoneErrorCase.java (1)
  • Getter (7-18)
src/main/java/com/wayble/server/explore/dto/facility/WaybleFacilityRegisterDto.java (4)
src/main/java/com/wayble/server/admin/dto/wayblezone/AdminWaybleZoneCreateDto.java (1)
  • AdminWaybleZoneCreateDto (9-39)
src/main/java/com/wayble/server/wayblezone/dto/WaybleZoneRegisterDto.java (1)
  • Builder (8-21)
src/main/java/com/wayble/server/explore/dto/search/request/WaybleZoneSearchConditionDto.java (1)
  • Builder (10-30)
src/main/java/com/wayble/server/common/dto/FacilityDto.java (1)
  • Builder (5-13)
src/main/java/com/wayble/server/direction/init/GraphInit.java (1)
src/main/java/com/wayble/server/direction/service/TransportationService.java (2)
  • mergeConsecutiveRoutes (241-310)
  • buildGraph (312-334)
src/main/java/com/wayble/server/explore/entity/FacilityType.java (7)
src/main/java/com/wayble/server/direction/entity/transportation/Facility.java (1)
  • Entity (11-46)
src/main/java/com/wayble/server/direction/entity/transportation/Elevator.java (1)
  • Entity (6-26)
src/main/java/com/wayble/server/direction/entity/type/Type.java (1)
  • Getter (5-22)
src/main/java/com/wayble/server/direction/entity/transportation/Lift.java (1)
  • Entity (6-29)
src/main/java/com/wayble/server/admin/dto/wayblezone/AdminWaybleZoneDetailDto.java (1)
  • FacilityInfo (40-43)
src/main/java/com/wayble/server/common/dto/FacilityDto.java (1)
  • Builder (5-13)
src/main/java/com/wayble/server/explore/entity/EsWaybleZoneFacility.java (1)
  • ToString (6-34)
src/main/resources/wayble_markers.json (1)
src/main/java/com/wayble/server/direction/entity/WaybleMarker.java (1)
  • WaybleMarker (5-11)
src/main/java/com/wayble/server/explore/controller/WaybleZoneRecommendController.java (3)
src/main/java/com/wayble/server/explore/service/WaybleZoneRecommendService.java (2)
  • getWaybleZonePersonalRecommend (35-58)
  • Service (22-100)
src/main/java/com/wayble/server/explore/repository/recommend/WaybleZoneQueryRecommendRepository.java (1)
  • searchPersonalWaybleZones (48-162)
src/main/java/com/wayble/server/common/config/security/jwt/JwtAuthentication.java (1)
  • Override (18-18)
src/main/java/com/wayble/server/explore/dto/facility/WaybleFacilityConditionDto.java (3)
src/main/java/com/wayble/server/explore/dto/search/request/WaybleZoneSearchConditionDto.java (1)
  • Builder (10-30)
src/main/java/com/wayble/server/admin/dto/wayblezone/AdminWaybleZoneDetailDto.java (2)
  • FacilityInfo (40-43)
  • AdminWaybleZoneDetailDto (10-59)
src/main/java/com/wayble/server/admin/dto/wayblezone/AdminWaybleZoneCreateDto.java (1)
  • AdminWaybleZoneCreateDto (9-39)
src/test/java/com/wayble/server/direction/service/WalkingServiceTest.java (2)
src/main/java/com/wayble/server/direction/controller/WalkingController.java (3)
  • RestController (15-46)
  • Override (22-34)
  • Override (36-45)
src/main/java/com/wayble/server/direction/controller/swagger/WalkingSwagger.java (1)
  • Tag (12-49)
src/main/java/com/wayble/server/explore/dto/facility/WaybleFacilityResponseDto.java (5)
src/main/java/com/wayble/server/common/dto/FacilityDto.java (1)
  • Builder (5-13)
src/main/java/com/wayble/server/explore/dto/search/response/WaybleZoneSearchResponseDto.java (1)
  • Builder (8-22)
src/main/java/com/wayble/server/wayblezone/dto/WaybleZoneListResponseDto.java (1)
  • Builder (6-17)
src/main/java/com/wayble/server/wayblezone/dto/WaybleZoneDetailResponseDto.java (1)
  • Builder (9-28)
src/main/java/com/wayble/server/explore/dto/search/response/WaybleZoneDistrictResponseDto.java (1)
  • Builder (7-21)
src/main/java/com/wayble/server/user/controller/UserPlaceController.java (3)
src/main/java/com/wayble/server/user/entity/UserPlace.java (1)
  • Entity (11-29)
src/main/java/com/wayble/server/user/repository/UserPlaceRepository.java (2)
  • UserPlaceRepository (8-10)
  • findByUser_IdAndTitle (9-9)
src/main/java/com/wayble/server/user/controller/UserController.java (1)
  • PatchMapping (71-90)
src/main/java/com/wayble/server/user/service/UserPlaceService.java (1)
src/main/java/com/wayble/server/wayblezone/dto/WaybleZoneListResponseDto.java (1)
  • Builder (6-17)
src/main/java/com/wayble/server/explore/entity/WaybleFacilityDocument.java (2)
src/main/java/com/wayble/server/direction/entity/transportation/Facility.java (1)
  • Entity (11-46)
src/main/java/com/wayble/server/direction/entity/transportation/Elevator.java (1)
  • Entity (6-26)
src/main/java/com/wayble/server/user/dto/UserPlaceListResponseDto.java (5)
src/main/java/com/wayble/server/user/dto/UserPlaceRequestDto.java (1)
  • UserPlaceRequestDto (5-8)
src/main/java/com/wayble/server/wayblezone/dto/WaybleZoneListResponseDto.java (1)
  • Builder (6-17)
src/main/java/com/wayble/server/wayblezone/dto/WaybleZoneDetailResponseDto.java (1)
  • Builder (9-28)
src/main/java/com/wayble/server/explore/dto/common/WaybleZoneInfoResponseDto.java (1)
  • Builder (7-34)
src/main/java/com/wayble/server/explore/dto/search/response/WaybleZoneSearchResponseDto.java (1)
  • Builder (8-22)
src/main/java/com/wayble/server/explore/repository/facility/WaybleFacilityQuerySearchRepository.java (1)
src/main/java/com/wayble/server/explore/repository/search/WaybleZoneQuerySearchRepository.java (4)
  • Repository (23-126)
  • searchWaybleZonesByCondition (33-125)
  • loc (65-69)
  • f (62-72)
src/main/java/com/wayble/server/common/exception/GlobalExceptionHandler.java (1)
src/main/java/com/wayble/server/common/MainController.java (1)
  • RestController (9-36)
src/main/java/com/wayble/server/direction/service/WaybleDijkstraService.java (1)
src/main/java/com/wayble/server/direction/service/util/HaversineUtil.java (1)
  • HaversineUtil (3-16)
src/main/java/com/wayble/server/explore/dto/recommend/WaybleZoneRecommendConditionDto.java (3)
src/main/java/com/wayble/server/admin/dto/wayblezone/AdminWaybleZoneCreateDto.java (1)
  • AdminWaybleZoneCreateDto (9-39)
src/main/java/com/wayble/server/explore/dto/search/request/WaybleZoneSearchConditionDto.java (1)
  • Builder (10-30)
src/main/java/com/wayble/server/direction/dto/TransportationRequestDto.java (1)
  • Location (12-16)
🪛 YAMLlint (1.37.1)
.github/workflows/cd-develop.yml

[error] 193-193: trailing spaces

(trailing-spaces)

🔇 Additional comments (24)
src/main/java/com/wayble/server/explore/dto/recommend/WaybleZoneRecommendConditionDto.java (2)

15-19: 위치 파라미터 유효성 검증 구성 적절합니다

경도/위도에 대해 @DecimalMin/@DecimalMax와 @NotNull을 함께 사용한 구성이 일관적이고, 다른 DTO(WaybleZoneSearchConditionDto)와도 정책이 맞습니다. null이 들어올 경우 자동 언박싱 NPE를 사전에 차단할 수 있습니다.


17-18: AI 요약과 실제 코드가 불일치합니다 (경도 @NotNull 존재)

AI 요약에서는 경도의 @NotNull이 제거되었다고 되어 있으나, 실제 코드(Line 17)에는 @NotNull이 존재합니다. 문서/요약 업데이트가 필요해 보입니다.

src/main/java/com/wayble/server/explore/controller/WaybleZoneRecommendController.java (1)

29-35: 서비스 호출 시 파라미터 전달은 변경 사항과 일치합니다

DTO에서 userId 제거 → 컨트롤러에서 사용자 ID를 보안 컨텍스트에서 추출하여 서비스에 전달하는 흐름이 적절합니다. latitude/longitude는 DTO에서 가져와 double로 오토 언박싱되어 서비스 시그니처와도 일치합니다(유효성 검증으로 null 방지).

src/main/java/com/wayble/server/user/dto/UserPlaceListResponseDto.java (2)

9-12: API 응답 필드 네이밍 변경으로 인한 하위 호환성 영향 점검 필요

snake_case → camelCase 전환(place_id → placeId, wayble_zone → waybleZone)은 외부 응답 스키마를 변경합니다. 사용 중인 클라이언트/문서/계약 테스트가 모두 업데이트되었는지 확인해 주세요.


15-21: 내부 WaybleZoneDto 필드 리네이밍 정합성 확인 및 일관성 OK

wayble_zone_id → waybleZoneId, image_url → imageUrl 변경은 다른 DTO(WaybleZoneListResponseDto, WaybleZoneDetailResponseDto)의 naming과 일치합니다. 직렬화/스웨거 문서도 함께 반영되었는지 점검해 주세요.

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

81-94: Builder 메서드 camelCase 적용 일관성 양호

DTO 변경 사항(placeId, waybleZone, waybleZoneId, imageUrl)에 맞춘 Builder 사용이 정확합니다. 동명의 다른 DTO들과도 naming이 일치합니다.

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

21-21: 엔드포인트 경로 변경에 따른 외부 영향도 확인

/api/v1/users/{userId}/places → /api/v1/users/places로 변경은 클라이언트와 문서에 영향이 큽니다. 스웨거/문서/게이트웨이 라우팅/클라이언트 SDK가 모두 반영되었는지 확인 바랍니다.

src/main/resources/logback-spring.xml (1)

37-37: cleanHistoryOnStart=false 변경은 적절하나, 용량 상한과의 상호작용 확인 필요

리스타트 시 히스토리를 유지하므로 보존성이 올라갑니다. 현재 maxHistory=90, totalSizeCap=1GB, maxFileSize=50MB 조합에서는 size cap이 먼저 동작하여 약 20개 내외로 제한됩니다. 의도된 보존 정책(일수 vs 용량)이 맞는지 확인해 주세요. 문제 없으면 그대로 진행해도 됩니다.

.github/workflows/cd-develop.yml (2)

190-201: YAMLlint: 공백 트레일러(trailing spaces) 제거 필요

정적 분석이 Line 193의 trailing spaces를 지적했습니다. 워크플로우 파싱에는 문제 없지만 린트 에러이므로 제거를 권장합니다.

다음과 같이 공백 줄을 정리해 주세요:

   echo "=== Log Directory Status ==="
   ls -la /var/log/wayble/ || echo "Log directory not found"
-          
+
   if [ -f "/var/log/wayble/wayble-error.log" ]; then
     echo "✅ Error log file exists"
     echo "📊 Error log file size: $(du -h /var/log/wayble/wayble-error.log | cut -f1)"

202-219: PR 요약과 불일치: Discord 웹훅 스텝이 여전히 남아있습니다

AI 요약에는 배포 성공/실패 Discord 알림 제거로 기재되어 있으나, 해당 스텝이 존재합니다. 의도에 맞게 제거하거나, 조건을 조정해 주세요.

다음과 같이 제거할 수 있습니다:

-      # ✅ 배포 성공 알림 (Discord)
-      - name: Send success webhook to Discord
-        if: success()
-        run: |
-          curl -H "Content-Type: application/json" \
-               -X POST \
-               -d "{\"content\": \"✅ EC2 배포 성공!\"}" \
-               ${{ secrets.DISCORD_WEBHOOK_URL }}
-
-      # ❌ 배포 실패 알림 (Discord)
-      - name: Send failure webhook to Discord
-        if: failure()
-        run: |
-          curl -H "Content-Type: application/json" \
-               -X POST \
-               -d "{\"content\": \"❌ EC2 배포 실패! 확인이 필요합니다.\"}" \
-               ${{ secrets.DISCORD_WEBHOOK_URL }}

혹은 환경/브랜치 기준으로 제한하려면:

if: success() && github.ref == 'refs/heads/main' && startsWith(github.repository, 'Wayble-Project/')
src/main/java/com/wayble/server/common/exception/GlobalExceptionHandler.java (1)

39-53: 비즈니스 예외에 대해 Discord 알림을 제외한 점 적절

ApplicationException은 예측 가능한 비즈니스 오류이므로 알림 노이즈를 줄이는 방향이 타당합니다. 로그 레벨 WARN으로 기록하고 상태 코드를 그대로 반영하는 것도 OK입니다.

src/main/java/com/wayble/server/explore/entity/FacilityType.java (1)

3-6: 기존 Type enum 재사용 불필요 – 서로 다른 도메인에서 사용되는 별도 개념입니다.

com.wayble.server.direction.entity.type.Type은 길찾기 모듈에서 경로 구간의 타입(NONE, RAMP, ELEVATOR)을 정의하는 반면,
com.wayble.server.explore.entity.FacilityType은 시설 탐색 모듈에서 건물 내·외부 시설(계단 대신 경사로·엘리베이터)을 구분하기 위한 것입니다.
값이 겹치지만 도메인 맥락이 완전히 달라, 기존 Type을 재사용할 경우 모듈 간 의존성이 불필요하게 높아져 유지보수성이 저하됩니다.
따라서 두 enum은 그대로 유지하고, 필요 시 패키지·클래스명을 통해 역할을 명확히 구분하면 됩니다.

Likely an incorrect or invalid review comment.

src/main/java/com/wayble/server/explore/dto/facility/WaybleFacilityConditionDto.java (1)

19-19: FacilityType 필드에 검증 어노테이션이 누락되었습니다.

facilityType 필드가 선택적인지 필수인지 명확하지 않습니다. API 설계에 따라 적절한 검증 어노테이션을 추가해야 합니다.

시설 유형이 선택적 필터링 조건인지 필수 조건인지 확인이 필요합니다. 선택적이라면 현재 상태가 적절하지만, 필수라면 @NotNull 어노테이션을 추가해야 합니다.

src/test/java/com/wayble/server/explore/WaybleFacilityApiIntegrationTest.java (3)

124-131: 검색 반경 파라미터 확인(플레이키니스 방지).

테스트는 반경 20km 내로 데이터를 시드하지만, API의 기본 검색 반경이 더 작다면 빈 결과가 나올 수 있습니다. API가 radius 같은 파라미터를 지원한다면 명시적으로 전달해 주세요. 지원하지 않는다면 서비스 기본 반경이 20km 이상인지 확인이 필요합니다.


237-246: Haversine 구현 적절 — 승인합니다.

반지름 상수, 라디안 변환, 공식을 정확히 적용했습니다.


248-265: 무작위 점 생성 로직 적절 — 승인합니다.

반경 내 균일 분포(√u)와 경도 보정(cos(lat))을 적용한 점이 좋습니다.

src/main/resources/wayble_markers.json (1)

126-126: 타입 변경 영향 검토 필요

  • Type enum과 FacilityType enum 모두에 RAMP가 정상 정의되어 있어 JSON 상의 "RAMP" 값 매핑에는 문제가 없습니다.
  • Java 코드 및 테스트에서 Type.RAMP 사용 사례(WalkingServiceTest, WaybleFacilityApiIntegrationTest)가 확인되었고, WHEELCHAIR_LIFT/CHARGER 값은 코드 어디에서도 직접 참조되지 않습니다.
  • JSON을 파싱해 Type enum으로 변환하는 로직(Jackson 등)도 기존 enum 정의 범위 내에서 동작하므로 런타임 에러는 발생하지 않습니다.

그러나 이 변경이 외부 시스템(클라이언트, DB 스크립트, 타 서비스 등)에 배포된 기존 데이터나 API 스펙에 미치는 영향을 직접 점검해 주세요.

src/main/java/com/wayble/server/direction/exception/WalkingErrorCase.java (1)

15-15: 새로운 에러 케이스 추가 확인

30km 거리 제한 에러 케이스가 적절하게 추가되었습니다. 이 제한은 WaybleDijkstraService에서 사용됩니다.

src/main/java/com/wayble/server/direction/service/WalkingService.java (1)

30-30: 노드 검색 반경 제한 추가

1km 반경 내에서만 노드를 검색하도록 제한이 추가되었습니다. 이는 성능 향상과 더 정확한 노드 매칭에 도움이 됩니다.

Also applies to: 57-57

src/test/java/com/wayble/server/direction/service/WalkingServiceTest.java (1)

52-56: 테스트에서 사용하지 않는 변수 정의

markerMap 변수가 정의되었지만 실제로 Mock 설정에서는 사용되지 않습니다. 테스트 목적이 불분명합니다.

실제로 이 테스트가 RAMP 경로를 제대로 검증하는지 확인이 필요합니다. 현재는 단순히 미리 정의된 응답을 반환하는 것으로 보입니다.

src/main/java/com/wayble/server/direction/service/WaybleDijkstraService.java (4)

24-24: 거리 제한 상수 정의 확인

30km 거리 제한이 추가되었습니다. 이는 DirectionErrorCase.DISTANCE_TOO_FAR와 동일한 제한입니다.


30-36: 거리 계산 방식 변경 - 폴리라인 기반

Edge 길이 합산 방식에서 폴리라인 좌표 기반 Haversine 거리 계산으로 변경되었습니다. 이는 더 정확한 실제 거리를 제공합니다.


167-169: 좌표 비교 로직 개선

isClose 메서드가 부동소수점 비교를 위해 적절한 tolerance를 사용하고 있습니다.


124-128: 검토 완료: HaversineUtil 파라미터 매핑이 올바릅니다

polylinenew double[]{lon, lat} 순서로 저장된 뒤, 호출 시

  • polyline.get(i-1)[1] → lat1
  • polyline.get(i-1)[0] → lon1
  • polyline.get(i)[1] → lat2
  • polyline.get(i)[0] → lon2

로 전달하여 haversine(lat1, lon1, lat2, lon2) 메서드 시그니처와 완전히 일치합니다.
따라서 추가 수정이나 검토는 필요하지 않습니다.

Comment on lines +79 to 85
echo "📋 Ensuring log directory exists on host"
sudo mkdir -p /var/log/wayble
sudo chmod 755 /var/log/wayble
echo "🧯 Cleaning up unused Docker networks"
sudo docker system prune -f || true
echo "🧯 Cleaning up unused Docker networks (excluding volumes)"
sudo docker system prune -f --volumes=false || true
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

docker system prune 옵션 사용 수정 제안: --volumes=false는 비호환 가능성

Docker CLI의 boolean 플래그는 보통 지정 시 true, 미지정 시 false로 동작합니다. 일부 환경에서 --volumes=false가 인식되지 않을 수 있으니, 단순히 생략하는 것이 호환성이 좋습니다.

다음처럼 수정해 주세요:

-echo "🧯 Cleaning up unused Docker networks (excluding volumes)"
-sudo docker system prune -f --volumes=false || true
+echo "🧯 Cleaning up unused Docker resources (excluding volumes)"
+sudo docker system prune -f || true
📝 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
echo "📋 Ensuring log directory exists on host"
sudo mkdir -p /var/log/wayble
sudo chmod 755 /var/log/wayble
echo "🧯 Cleaning up unused Docker networks"
sudo docker system prune -f || true
echo "🧯 Cleaning up unused Docker networks (excluding volumes)"
sudo docker system prune -f --volumes=false || true
echo "📋 Ensuring log directory exists on host"
sudo mkdir -p /var/log/wayble
sudo chmod 755 /var/log/wayble
echo "🧯 Cleaning up unused Docker resources (excluding volumes)"
sudo docker system prune -f || true
🤖 Prompt for AI Agents
.github/workflows/cd-develop.yml around lines 79 to 85: the workflow uses `sudo
docker system prune -f --volumes=false` which may be incompatible in some Docker
CLI versions; remove the `--volumes=false` flag and run `sudo docker system
prune -f || true` so the command remains portable and still ignores errors.

Comment on lines +9 to +14
# 로그 디렉토리 생성 및 권한 설정
RUN mkdir -p /app/logs && chmod 755 /app/logs

# 작업 디렉토리 설정
WORKDIR /app

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

컨테이너를 비루트 사용자로 실행하고 로그 디렉터리 소유권을 명시적으로 설정하는 것을 권장

현재 로그 디렉터리는 755 권한만 설정되어 있고, 컨테이너는 루트로 실행됩니다. 보안/격리 강화를 위해 전용 사용자/그룹을 만들고 /app 전체(특히 /app/logs)의 소유권을 넘긴 뒤 USER를 전환하는 것을 권장합니다. 호스트 볼륨(/var/log/wayble)을 마운트하면 컨테이너 내부 권한과의 정합성도 중요합니다.

다음과 같이 RUN/USER를 보완해 주세요(선택지):

 # 로그 디렉토리 생성 및 권한 설정
-RUN mkdir -p /app/logs && chmod 755 /app/logs
+RUN mkdir -p /app/logs && chmod 755 /app/logs

 # 작업 디렉토리 설정
 WORKDIR /app
+
+# 비루트 사용자 생성 및 소유권 이전
+RUN groupadd -g 10001 app && useradd -r -u 10001 -g app app \
+    && chown -R app:app /app
+USER app

추가로, 이미지 슬림화가 필요하다면 베이스 이미지를 slim 변형으로 교체하는 것도 고려 가능합니다(선택):

-FROM openjdk:17
+FROM openjdk:17-jdk-slim
📝 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
# 로그 디렉토리 생성 및 권한 설정
RUN mkdir -p /app/logs && chmod 755 /app/logs
# 작업 디렉토리 설정
WORKDIR /app
# 로그 디렉토리 생성 및 권한 설정
RUN mkdir -p /app/logs && chmod 755 /app/logs
# 작업 디렉토리 설정
WORKDIR /app
# 비루트 사용자 생성 및 소유권 이전
RUN groupadd -g 10001 app && useradd -r -u 10001 -g app app \
&& chown -R app:app /app
USER app
🤖 Prompt for AI Agents
In Dockerfile around lines 9 to 14, the Docker image currently creates /app/logs
with chmod 755 but leaves the container running as root; create a dedicated
non-root user and group, chown /app and /app/logs to that user:group, and switch
to that user using USER so the container runs non-root; ensure any host-mounted
volume path (e.g., /var/log/wayble) has compatible ownership/permissions or
document that it must be owned by the same uid/gid or be writable by the
container user; optionally replace the base image with its slim variant to
reduce image size.

Comment on lines +55 to 72
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<CommonResponse> handleValidException(MethodArgumentNotValidException ex, WebRequest request) {
String message = ex.getBindingResult().getAllErrors().get(0).getDefaultMessage();

// 에러 로그 기록
String path = ((ServletWebRequest) request).getRequest().getRequestURI();
String method = ((ServletWebRequest) request).getRequest().getMethod();
String errorLocation = getErrorLocation(ex);

log.error("Validation Exception 발생 - Method: {}, Path: {}, Message: {}, Location: {}",
method, path, message, errorLocation, ex);
log.warn("Validation Exception - Method: {}, Path: {}, Message: {}, Location: {}",
method, path, message, errorLocation);

CommonResponse commonResponse = CommonResponse.error(400, message);

sendToDiscord(ex, request, HttpStatus.BAD_REQUEST);

return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(commonResponse);
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

❓ Verification inconclusive

Validation 메시지 추출 로직의 안전성 보강 및 상수화 권장

getAllErrors().get(0) 접근은 방어 로직이 없어 NPE/IOOBE 가능성이 있습니다(드물지만 안전하게). 또한 400을 매직넘버 대신 HttpStatus 상수로 일관 사용 권장.

다음처럼 보완해 주세요:

-    public ResponseEntity<CommonResponse> handleValidException(MethodArgumentNotValidException ex, WebRequest request) {
-        String message = ex.getBindingResult().getAllErrors().get(0).getDefaultMessage();
+    public ResponseEntity<CommonResponse> handleValidException(MethodArgumentNotValidException ex, WebRequest request) {
+        String message = null;
+        if (ex.getBindingResult() != null) {
+            if (!ex.getBindingResult().getFieldErrors().isEmpty()) {
+                message = ex.getBindingResult().getFieldErrors().get(0).getDefaultMessage();
+            } else if (!ex.getBindingResult().getAllErrors().isEmpty()) {
+                message = ex.getBindingResult().getAllErrors().get(0).getDefaultMessage();
+            }
+        }
+        if (message == null || message.isBlank()) {
+            message = "유효성 검사 실패";
+        }
@@
-        CommonResponse commonResponse = CommonResponse.error(400, message);
+        CommonResponse commonResponse = CommonResponse.error(HttpStatus.BAD_REQUEST.value(), message);

추가로, 시그니처 변경으로 import org.springframework.validation.BindingResult;가 더 이상 사용되지 않습니다. 정리해 주세요.

다음 코드에서 불필요한 import를 제거:

// 제거 대상
import org.springframework.validation.BindingResult;

#!/bin/bash
# Locate and display the imports in GlobalExceptionHandler.java
file_path=$(fd -e java GlobalExceptionHandler.java)
echo "File: $file_path"
sed -n '1,30p' "$file_path"

GlobalExceptionHandler.java의 상단 import 구문을 확인하여 org.springframework.validation.BindingResult가 실제로 불필요하게 선언되어 있는지 검증합니다.

#!/bin/bash
# GlobalExceptionHandler.java의 import 목록 출력
file=$(fd --extension java GlobalExceptionHandler.java)
echo "Analyzing: $file"
sed -n '1,50p' "$file"

GlobalExceptionHandler.java의 상단 import 구문과 getBindingResult() 호출부를 확인합니다.

#!/bin/bash
# 파일 경로 찾기
file=$(fd --extension java GlobalExceptionHandler.java)
echo "Analyzing: $file"
# 상단 1~50줄 출력 (import 및 메서드 시그니처 확인)
sed -n '1,50p' "$file"

Validation 메시지 안전 추출 및 HTTP 상태 코드 상수화 권장

아래 사항을 반영해주세요:

  • getAllErrors().get(0) 호출 전 방어 로직 추가
  • HTTP 상태 코드는 매직 넘버(400) 대신 HttpStatus.BAD_REQUEST.value() 사용
  • 사용되지 않는 org.springframework.validation.BindingResult import 제거
-    public ResponseEntity<CommonResponse> handleValidException(MethodArgumentNotValidException ex, WebRequest request) {
-        String message = ex.getBindingResult().getAllErrors().get(0).getDefaultMessage();
+    public ResponseEntity<CommonResponse> handleValidException(MethodArgumentNotValidException ex, WebRequest request) {
+        String message = null;
+        var bindingResult = ex.getBindingResult();
+        if (bindingResult != null) {
+            if (!bindingResult.getFieldErrors().isEmpty()) {
+                message = bindingResult.getFieldErrors().get(0).getDefaultMessage();
+            } else if (!bindingResult.getAllErrors().isEmpty()) {
+                message = bindingResult.getAllErrors().get(0).getDefaultMessage();
+            }
+        }
+        if (message == null || message.isBlank()) {
+            message = "유효성 검사 실패";
+        }
@@
-        CommonResponse commonResponse = CommonResponse.error(400, message);
+        CommonResponse commonResponse = CommonResponse.error(HttpStatus.BAD_REQUEST.value(), message);
// 제거 대상
-import org.springframework.validation.BindingResult;
🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/common/exception/GlobalExceptionHandler.java
around lines 55 to 72, add defensive checks before calling
ex.getBindingResult().getAllErrors().get(0) to avoid
IndexOutOfBounds/NullPointer (e.g., check that getBindingResult() and
getAllErrors() are non-null and not empty, and provide a safe default message if
none present), replace the hardcoded 400 with HttpStatus.BAD_REQUEST.value()
when constructing the CommonResponse, and remove the unused import
org.springframework.validation.BindingResult from the file.

Comment on lines +32 to +35
private Set<Long> rampMarkers = Collections.emptySet();

private static final double RAMP_PENALTY = 5.0;
private static final double MARKER_DISCOUNT = 0.5;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

초기화되지 않은 rampMarkers 필드

rampMarkers가 빈 Set으로 초기화되어 있어 실제로 RAMP 패널티가 적용되지 않습니다. wayble_markers.json에서 RAMP 타입 마커들을 로드하여 이 Set을 채워야 합니다.

 private Set<Long> rampMarkers = Collections.emptySet();
 
 private static final double RAMP_PENALTY = 5.0;
 private static final double MARKER_DISCOUNT = 0.5;
 
 @PostConstruct
 public void init() {
     ObjectMapper objectMapper = new ObjectMapper();
 
     try {
         // 그래프
         try (InputStream graphStream = getClass().getResourceAsStream("/seocho_pedestrian.json")) {
             if (graphStream == null) {
                 throw new ApplicationException(WalkingErrorCase.GRAPH_FILE_NOT_FOUND);
             }
             JsonNode root = objectMapper.readTree(graphStream);
             nodes = Arrays.asList(objectMapper.convertValue(root.get("nodes"), Node[].class));
             edges = Arrays.asList(objectMapper.convertValue(root.get("edges"), Edge[].class));
 
             nodeMap = nodes.stream().collect(Collectors.toMap(Node::id, node -> node));
         }
 
         // 웨이블 마커
         try (InputStream markerStream = getClass().getResourceAsStream("/wayble_markers.json")) {
             markers = markerStream != null
                     ? objectMapper.readValue(markerStream, new TypeReference<>() {})
                     : new ArrayList<>();
         }
         markerMap = findWaybleMarkers();
+        // RAMP 타입 마커들의 노드 ID를 rampMarkers Set에 추가
+        rampMarkers = markerMap.entrySet().stream()
+                .filter(entry -> entry.getValue() == Type.RAMP)
+                .map(Map.Entry::getKey)
+                .collect(Collectors.toSet());
         adjacencyList = buildAdjacencyList();
📝 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
private Set<Long> rampMarkers = Collections.emptySet();
private static final double RAMP_PENALTY = 5.0;
private static final double MARKER_DISCOUNT = 0.5;
markers = markerStream != null
? objectMapper.readValue(markerStream, new TypeReference<>() {})
: new ArrayList<>();
markerMap = findWaybleMarkers();
// RAMP 타입 마커들의 노드 ID를 rampMarkers Set에 추가
rampMarkers = markerMap.entrySet().stream()
.filter(entry -> entry.getValue() == Type.RAMP)
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
adjacencyList = buildAdjacencyList();
🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/direction/init/GraphInit.java around lines 32
to 35, rampMarkers is initialized to an empty Set so RAMP penalties never apply;
replace this by loading wayble_markers.json at initialization and populate
rampMarkers with the IDs of markers whose type == "RAMP" (e.g., in the class
constructor or init method used before graph computations), parsing the JSON
resource, collecting marker IDs into a Set<Long>, and assigning it (preferably
as an immutable/defensive copy). Ensure any IO/parsing exceptions are handled or
propagated appropriately so rampMarkers is reliably populated before use.

@NotNull(message = "경도 입력은 필수입니다.")
Double longitude,

FacilityType facilityType
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

FacilityType 필드에 검증 어노테이션이 누락되었습니다.

위도/경도에는 검증 어노테이션이 적용되어 있지만, facilityType 필드에는 @NotNull 검증이 없습니다. 시설 유형은 필수 정보이므로 검증이 필요합니다.

-        FacilityType facilityType
+        @NotNull(message = "시설 유형은 필수입니다.")
+        FacilityType facilityType
🤖 Prompt for AI Agents
In
src/main/java/com/wayble/server/explore/dto/facility/WaybleFacilityRegisterDto.java
around line 21, the facilityType field lacks a validation annotation; add
@NotNull to the facilityType declaration and import the appropriate annotation
(e.g., javax.validation.constraints.NotNull or
jakarta.validation.constraints.NotNull depending on project setup) so the DTO
enforces presence of facility type during validation.

Comment on lines +81 to +99
for(int i = 1; i <= SAMPLES; i++) {
Map<String, Double> points = makeRandomPoint();

WaybleFacilityDocument rampDocument = WaybleFacilityDocument.builder()
.id(UUID.randomUUID().toString())
.location(new GeoPoint(points.get("latitude"), points.get("longitude")))
.facilityType(FacilityType.RAMP)
.build();

WaybleFacilityDocument elevatorDocument = WaybleFacilityDocument.builder()
.id(UUID.randomUUID().toString())
.location(new GeoPoint(points.get("latitude"), points.get("longitude")))
.facilityType(FacilityType.ELEVATOR)
.build();

waybleFacilityDocumentRepository.save(rampDocument);
waybleFacilityDocumentRepository.save(elevatorDocument);
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

ES 색인 가시성/성능: 벌크 저장 + refresh 필요.

  • 현재 200건을 단건 save로 호출하여 느리고, ES refresh 정책에 따라 검색에서 바로 보이지 않아 테스트가 간헐적으로 실패할 수 있습니다.
  • 한 번에 모아 saveAll로 벌크 인덱싱 후 인덱스 refresh를 호출하세요.
-        for(int i = 1; i <= SAMPLES; i++) {
+        java.util.List<WaybleFacilityDocument> seed = new java.util.ArrayList<>(SAMPLES * 2);
+        for (int i = 1; i <= SAMPLES; i++) {
             Map<String, Double> points = makeRandomPoint();
 
             WaybleFacilityDocument rampDocument = WaybleFacilityDocument.builder()
                     .id(UUID.randomUUID().toString())
                     .location(new GeoPoint(points.get("latitude"), points.get("longitude")))
                     .facilityType(FacilityType.RAMP)
                     .build();
 
             WaybleFacilityDocument elevatorDocument = WaybleFacilityDocument.builder()
                     .id(UUID.randomUUID().toString())
                     .location(new GeoPoint(points.get("latitude"), points.get("longitude")))
                     .facilityType(FacilityType.ELEVATOR)
                     .build();
-            
-            waybleFacilityDocumentRepository.save(rampDocument);
-            waybleFacilityDocumentRepository.save(elevatorDocument);
+            seed.add(rampDocument);
+            seed.add(elevatorDocument);
         }
+        waybleFacilityDocumentRepository.saveAll(seed);
+        // 검색 일관성을 위해 인덱스 refresh
+        elasticsearchOperations.indexOps(WaybleFacilityDocument.class).refresh();

클래스 필드/의존성 추가(변경 범위 밖 참고):

// import
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;

// 필드
@Autowired
private ElasticsearchOperations elasticsearchOperations;

원하시면 위 변경을 반영한 전체 패치 제시 가능합니다.

🤖 Prompt for AI Agents
In src/test/java/com/wayble/server/explore/WaybleFacilityApiIntegrationTest.java
around lines 81 to 99, the test currently calls repository.save for each
document which is slow and can cause intermittent failures due to Elasticsearch
refresh; collect the documents into a list, call
waybleFacilityDocumentRepository.saveAll(...) to perform bulk indexing, then
trigger an index refresh via an injected ElasticsearchOperations (add import and
@Autowired private ElasticsearchOperations elasticsearchOperations) using
elasticsearchOperations.indexOps(WaybleFacilityDocument.class).refresh() so the
documents are immediately visible to subsequent search assertions.

Comment on lines +101 to +105
@AfterAll
public void teardown() {
waybleFacilityDocumentRepository.deleteAll();
userRepository.deleteById(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

테스트 데이터 정리 범위 축소 권장.

deleteAll()은 공유 인덱스의 다른 데이터까지 삭제할 위험이 있습니다. 생성한 문서 ID를 수집해 개별 삭제하거나, 테스트 전용 인덱스/alias를 사용하세요.


아래 스크립트로 WaybleFacilityDocumentRepository 정의 및 인덱스 설정을 확인하겠습니다.


🏁 Script executed:

#!/bin/bash
# WaybleFacilityDocumentRepository 인터페이스 정의와 @Document 어노테이션 검색
rg -n "interface WaybleFacilityDocumentRepository" -C3
rg -n "@Document" -C3 src/main/java

Length of output: 4532


테스트 데이터 정리 방식 개선 필요

현재 teardown()에서 waybleFacilityDocumentRepository.deleteAll()을 호출하면
인덱스명 "wayble_facility_document"에 있는 모든 문서를 삭제하게 되어
공유 인덱스의 다른 데이터(다른 테스트나 실제 데이터)에 영향을 줄 수 있습니다.

대안 제안:

  • 생성한 문서의 ID를 모아 deleteById(id)로 개별 삭제
  • 혹은 테스트 전용 인덱스(또는 alias)를 별도로 설정하여 사용

위치

  • 파일: src/test/java/com/wayble/server/explore/WaybleFacilityApiIntegrationTest.java
  • 메서드: @AfterAll public void teardown()

예시 변경안:

private static List<String> createdIds = new ArrayList<>();

@AfterEach
public void registerCreated(Document doc) {
    createdIds.add(doc.getId());
}

@AfterAll
public void teardown() {
    createdIds.forEach(waybleFacilityDocumentRepository::deleteById);
}

혹은 application-test.yml에 테스트 전용 인덱스 프리픽스 지정:

spring:
  data:
    elasticsearch:
      indices:
        prefix: test_

Comment on lines +136 to +137
JsonNode dataNode = root.get("data");

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

응답 구조 방어적 체크 추가 권장.

root.get("data")가 null일 경우 NPE 또는 잘못된 변환이 발생합니다. 명시적 검증을 추가해 주세요.

-        JsonNode dataNode = root.get("data");
+        JsonNode dataNode = root.get("data");
+        assertThat(dataNode)
+                .as("'data' 노드가 응답에 존재해야 합니다.")
+                .isNotNull();
📝 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
JsonNode dataNode = root.get("data");
JsonNode dataNode = root.get("data");
assertThat(dataNode)
.as("'data' 노드가 응답에 존재해야 합니다.")
.isNotNull();
🤖 Prompt for AI Agents
In src/test/java/com/wayble/server/explore/WaybleFacilityApiIntegrationTest.java
around lines 136-137, the code calls root.get("data") without checking for null
which can cause an NPE or invalid conversion; add a defensive null check after
obtaining dataNode (e.g., assertNotNull or throw a clear test failure with root
printed) and fail the test early if dataNode is null, or verify root.has("data")
before accessing and include a clear assertion message to aid debugging.

Comment on lines +141 to +144
List<WaybleFacilityResponseDto> dtoList = objectMapper.convertValue(
dataNode,
new TypeReference<>() {}
);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

TypeReference 제네릭 누락으로 컴파일 오류 발생.

new TypeReference<>() {}는 익명 클래스에서 다이아몬드 연산자를 사용할 수 없어 컴파일되지 않습니다. 제네릭 타입을 명시하세요.

-        List<WaybleFacilityResponseDto> dtoList = objectMapper.convertValue(
-                dataNode,
-                new TypeReference<>() {}
-        );
+        List<WaybleFacilityResponseDto> dtoList = objectMapper.convertValue(
+                dataNode,
+                new TypeReference<List<WaybleFacilityResponseDto>>() {}
+        );
📝 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
List<WaybleFacilityResponseDto> dtoList = objectMapper.convertValue(
dataNode,
new TypeReference<>() {}
);
List<WaybleFacilityResponseDto> dtoList = objectMapper.convertValue(
dataNode,
new TypeReference<List<WaybleFacilityResponseDto>>() {}
);
🤖 Prompt for AI Agents
In src/test/java/com/wayble/server/explore/WaybleFacilityApiIntegrationTest.java
around lines 141 to 144, the anonymous TypeReference is missing its generic type
which causes a compile error; replace the diamond/empty TypeReference with an
explicit generic TypeReference for List<WaybleFacilityResponseDto> so the
ObjectMapper knows the target type (i.e. use new
TypeReference<List<WaybleFacilityResponseDto>>() { }).

Comment on lines +199 to +202
List<WaybleFacilityResponseDto> dtoList = objectMapper.convertValue(
dataNode,
new TypeReference<>() {}
);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

(동일) TypeReference 제네릭 누락으로 컴파일 오류 발생.

위와 동일하게 수정 필요합니다.

-        List<WaybleFacilityResponseDto> dtoList = objectMapper.convertValue(
-                dataNode,
-                new TypeReference<>() {}
-        );
+        List<WaybleFacilityResponseDto> dtoList = objectMapper.convertValue(
+                dataNode,
+                new TypeReference<List<WaybleFacilityResponseDto>>() {}
+        );
📝 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
List<WaybleFacilityResponseDto> dtoList = objectMapper.convertValue(
dataNode,
new TypeReference<>() {}
);
List<WaybleFacilityResponseDto> dtoList = objectMapper.convertValue(
dataNode,
new TypeReference<List<WaybleFacilityResponseDto>>() {}
);
🤖 Prompt for AI Agents
In src/test/java/com/wayble/server/explore/WaybleFacilityApiIntegrationTest.java
around lines 199 to 202, the call to objectMapper.convertValue uses a raw
TypeReference which causes a compile error; replace the raw TypeReference with a
parameterized one matching the target type (e.g. new
TypeReference<List<WaybleFacilityResponseDto>>() {}) so the generic type is
provided and the conversion compiles correctly.

@KiSeungMin KiSeungMin merged commit d3ba937 into main Aug 12, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release 프로덕션 서버에 배포

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants