[feat] 대중교통 길찾기 구현#99
Conversation
Walkthrough대중교통 길찾기 기능을 위해 신규 엔티티, DTO, 서비스, 컨트롤러가 대거 추가되었습니다. 다익스트라 기반 경로 탐색, 그래프 구성, 외부 API 연동, 접근성 정보 제공 등이 구현되었고, 관련 JPA 리포지토리 및 보안 설정도 보완되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant TransportationController
participant TransportationService
participant NodeRepository
participant EdgeRepository
participant FacilityService
participant FacilityRepository
participant RestTemplate (KRIC API)
Client->>TransportationController: GET /api/v1/directions/transportation (with request DTO)
TransportationController->>TransportationService: findRoutes(request DTO)
TransportationService->>NodeRepository: findAll()
TransportationService->>EdgeRepository: findAll()
TransportationService->>FacilityService: getNodeInfo(nodeId)
FacilityService->>FacilityRepository: findById(nodeId)
FacilityService->>RestTemplate (KRIC API): GET 화장실 정보
FacilityService-->>TransportationService: NodeInfo 반환
TransportationService-->>TransportationController: TransportationResponseDto 반환
TransportationController-->>Client: CommonResponse<TransportationResponseDto>
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes해당 변경사항 중 요구사항과 무관한 기능적 변경은 발견되지 않았습니다. Possibly related PRs
Suggested reviewers
Poem
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 17
🔭 Outside diff range comments (1)
src/main/java/com/wayble/server/direction/entity/Node.java (1)
1-8:Node레코드가 transportation 패키지의 JPANode엔티티와 이름이 충돌합니다.동일한 의미의 클래스를 서로 다른 패키지에 이중 정의하면
- 서비스 계층에서 실수로 잘못된
Node를 import 해 런타임 오류가 발생하거나,- ModelMapper·Jackson 등 자동 매퍼가 타입 식별에 실패할 수 있습니다.
작업 목적이 시험용 DTO라면 명칭을 변경하거나 삭제하고, 실제 사용 의도라면 한 곳으로 통합해 주세요.
🧹 Nitpick comments (16)
src/main/java/com/wayble/server/direction/entity/DirectionType.java (1)
6-8: 마지막 쉼표 및 주석 가독성 개선 제안Java enum 뒤에 쉼표를 두어도 컴파일 오류는 없지만 관행적으로 마지막 값 뒤 쉼표를 생략합니다.
또한 “길찾기에 사용” 주석은 enum 전체가 아닌 두 상수만을 지칭하므로 각 상수 위에 단일 라인 주석 형태(//)로 배치하면 더 명확합니다.src/main/java/com/wayble/server/direction/repository/EdgeRepository.java (1)
6-7: 기본 구현은 적절하지만 그래프 탐색을 위한 커스텀 메서드 고려 필요현재 구현은 표준 JPA 리포지토리로 충분하지만, 다익스트라 알고리즘 기반 경로 탐색에서 성능 최적화를 위해 다음과 같은 커스텀 쿼리 메서드들을 고려해보세요:
List<Edge> findByStartNodeId(Long startNodeId); List<Edge> findByEndNodeId(Long endNodeId); List<Edge> findByRouteId(Long routeId);src/main/java/com/wayble/server/direction/dto/toilet/KricToiletRawItem.java (2)
3-3: 불필요한 Lombok 어노테이션 제거레코드는 자동으로 접근자 메서드를 생성하므로
@Getter어노테이션이 불필요합니다.public record KricToiletRawItem( String stinCd, String toltNum ) {}
5-8: 필드명에 대한 문서화 필요
stinCd와toltNum필드가 각각 무엇을 의미하는지 명확하지 않습니다. JavaDoc이나 주석을 통해 설명을 추가해주세요./** * KRIC API의 화장실 정보 항목 * @param stinCd 역 코드 (Station Code) * @param toltNum 화장실 번호 (Toilet Number) */ public record KricToiletRawItem( String stinCd, String toltNum ) {}src/main/java/com/wayble/server/direction/service/EdgeService.java (1)
9-21: 메서드명과 구현의 명확성을 개선해보세요.현재 구현에서 몇 가지 개선점이 있습니다:
route를 명시적으로null로 설정하는 이유가 명확하지 않습니다. 이것이 의도된 비즈니스 로직인지 확인이 필요합니다.- 메서드명이
createEdge이지만 실제로는 데이터베이스에 저장하지 않고 객체만 생성합니다.buildEdge또는newEdge같은 이름이 더 적절할 수 있습니다.만약 이것이 임시 엣지 생성을 위한 의도된 구현이라면, JavaDoc으로 용도를 명시해주세요:
+ /** + * 라우팅 계산을 위한 임시 엣지를 생성합니다. + * 주의: 이 메서드는 데이터베이스에 저장하지 않습니다. + */ public Edge createEdge(Long id, Node startNode, Node endNode, DirectionType edgeType) {src/main/java/com/wayble/server/direction/entity/transportation/Lift.java (1)
6-29: LGTM! 잘 구현된 JPA 엔티티입니다.JPA 모범 사례를 잘 따르고 있습니다:
- 적절한 좌표 정밀도 설정 (DECIMAL(10,7))
- 지연 로딩을 통한 성능 최적화
- protected 생성자를 통한 JPA 요구사항 준수
참고:
exitNum필드가exit_num컬럼에 매핑되는데, 다른 엔티티들과의 네이밍 일관성을 위해@Column(name = "exitNum")을 고려해볼 수 있습니다.src/main/java/com/wayble/server/direction/dto/TransportationRequestDto.java (1)
5-17: LGTM! 잘 설계된 DTO입니다.Java record를 활용한 불변 DTO 구현이 우수하며, 중첩된 Location record로 구조화가 잘 되어 있습니다. Swagger 문서화도 적절합니다.
선택적 개선사항: 페이지네이션 필드(
cursor,size)에 대한 유효성 검증을 고려해보세요:@Schema(description = "길찾기 요청 DTO") public record TransportationRequestDto ( Location origin, Location destination, + @Schema(description = "페이지 커서", example = "0") Integer cursor, + @Schema(description = "페이지 크기", example = "10") Integer sizesrc/main/java/com/wayble/server/direction/entity/transportation/Node.java (2)
13-13: Builder 접근 레벨이 다른 엔티티들과 일치하지 않습니다.다른 transportation 엔티티들(
Edge,Facility)은 PUBLIC 또는 기본 접근 레벨을 사용하는 반면,Node만 PRIVATE를 사용합니다. 일관성을 위해 다른 엔티티들과 동일한 접근 레벨을 사용하는 것을 고려해보세요.
49-50: 필드명이 자바 네이밍 컨벤션을 따르지 않습니다.
facility_id필드명에 언더스코어가 포함되어 있어 자바 camelCase 컨벤션을 위반합니다.facilityId또는 단순히facility로 변경하는 것을 고려해보세요.- private Facility facility_id; + private Facility facility;src/main/java/com/wayble/server/direction/entity/transportation/Edge.java (1)
24-36: ManyToOne 관계에서 nullable 제약조건을 명시하는 것을 고려해보세요.
startNode,endNode,route관계에서nullable속성이 명시되지 않았습니다. 데이터 무결성을 위해 필수 관계인지 선택적 관계인지 명확히 하는 것이 좋습니다.// 출발 노드 @ManyToOne - @JoinColumn(name = "start_node_id") + @JoinColumn(name = "start_node_id", nullable = false) private Node startNode; // 도착 노드 @ManyToOne - @JoinColumn(name = "end_node_id") + @JoinColumn(name = "end_node_id", nullable = false) private Node endNode; // 해당 연결이 속한 노선 @ManyToOne - @JoinColumn(name = "route_id") + @JoinColumn(name = "route_id", nullable = false) private Route route;src/main/java/com/wayble/server/direction/entity/transportation/Facility.java (2)
5-7: 불필요한 import들을 제거해주세요.사용되지 않는
@Nullableimport와 현재 패키지를 import하는 불필요한 import문이 있습니다.-import org.springframework.lang.Nullable; - -import com.wayble.server.direction.entity.transportation.*;
25-25: 주석의 오타를 수정해주세요."toliet"는 "toilet"의 오타입니다.
- //for toliet + //for toiletsrc/main/java/com/wayble/server/direction/entity/transportation/Route.java (2)
4-4: 불필요한 wildcard import를 제거해주세요.현재 패키지의 wildcard import는 불필요합니다.
-import com.wayble.server.direction.entity.transportation.*;
28-35: ManyToOne 관계에서 nullable 제약조건을 명시하는 것을 고려해보세요.
startNode와endNode관계가 필수인지 선택적인지 명확히 하기 위해nullable속성을 명시하는 것이 좋습니다.// 기점 정류장 @ManyToOne - @JoinColumn(name = "start_node_id") + @JoinColumn(name = "start_node_id", nullable = false) private Node startNode; // 종점 정류장 @ManyToOne - @JoinColumn(name = "end_node_id") + @JoinColumn(name = "end_node_id", nullable = false) private Node endNode;src/main/java/com/wayble/server/direction/service/TransportationService.java (2)
59-119: 메서드 복잡도 개선
returnDijkstra메서드가 너무 복잡합니다. 그래프 준비, 가중치 계산, 경로 탐색을 별도 메서드로 분리하세요.다음과 같이 리팩토링을 고려하세요:
prepareGraphWithTemporaryNodes(): 임시 노드 추가 및 그래프 준비calculateEdgeWeights(): 엣지 가중치 계산findNearestNode(): 가장 가까운 노드 찾기
44-44: 기본값 처리 개선삼항 연산자 대신 Optional을 사용하여 가독성을 개선할 수 있습니다.
- int pageSize = request.size() != null ? request.size() : steps.size(); + int pageSize = Optional.ofNullable(request.size()).orElse(steps.size());
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (23)
src/main/java/com/wayble/server/common/config/RestTemplateConfig.java(1 hunks)src/main/java/com/wayble/server/common/config/SecurityConfig.java(1 hunks)src/main/java/com/wayble/server/direction/controller/TransportationController.java(1 hunks)src/main/java/com/wayble/server/direction/dto/TransportationRequestDto.java(1 hunks)src/main/java/com/wayble/server/direction/dto/TransportationResponseDto.java(1 hunks)src/main/java/com/wayble/server/direction/dto/toilet/KricToiletRawBody.java(1 hunks)src/main/java/com/wayble/server/direction/dto/toilet/KricToiletRawItem.java(1 hunks)src/main/java/com/wayble/server/direction/dto/toilet/KricToiletRawResponse.java(1 hunks)src/main/java/com/wayble/server/direction/entity/DirectionType.java(1 hunks)src/main/java/com/wayble/server/direction/entity/Node.java(1 hunks)src/main/java/com/wayble/server/direction/entity/transportation/Edge.java(1 hunks)src/main/java/com/wayble/server/direction/entity/transportation/Elevator.java(1 hunks)src/main/java/com/wayble/server/direction/entity/transportation/Facility.java(1 hunks)src/main/java/com/wayble/server/direction/entity/transportation/Lift.java(1 hunks)src/main/java/com/wayble/server/direction/entity/transportation/Node.java(1 hunks)src/main/java/com/wayble/server/direction/entity/transportation/Route.java(1 hunks)src/main/java/com/wayble/server/direction/exception/DirectionErrorCase.java(1 hunks)src/main/java/com/wayble/server/direction/repository/EdgeRepository.java(1 hunks)src/main/java/com/wayble/server/direction/repository/FacilityRepository.java(1 hunks)src/main/java/com/wayble/server/direction/repository/NodeRepository.java(1 hunks)src/main/java/com/wayble/server/direction/service/EdgeService.java(1 hunks)src/main/java/com/wayble/server/direction/service/FacilityService.java(1 hunks)src/main/java/com/wayble/server/direction/service/TransportationService.java(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: java에서 같은 패키지 내의 클래스들은 import 구문 없이 서로를 참조할 수 있다. com.wayble.server.user.entity 패키지 내의 클래스들은 명시적인 im...
Learnt from: seung-in-Yoo
PR: Wayble-Project/wayble-spring#37
File: src/main/java/com/wayble/server/user/entity/User.java:61-62
Timestamp: 2025-07-13T15:08:59.318Z
Learning: Java에서 같은 패키지 내의 클래스들은 import 구문 없이 서로를 참조할 수 있다. com.wayble.server.user.entity 패키지 내의 클래스들은 명시적인 import 없이 사용 가능하다.
Applied to files:
src/main/java/com/wayble/server/direction/entity/DirectionType.javasrc/main/java/com/wayble/server/direction/entity/transportation/Elevator.java
🧬 Code Graph Analysis (7)
src/main/java/com/wayble/server/direction/entity/transportation/Route.java (3)
src/main/java/com/wayble/server/direction/entity/transportation/Facility.java (1)
Entity(11-46)src/main/java/com/wayble/server/direction/entity/transportation/Edge.java (1)
Entity(8-37)src/main/java/com/wayble/server/direction/entity/transportation/Node.java (1)
Entity(11-71)
src/main/java/com/wayble/server/direction/entity/transportation/Lift.java (3)
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/transportation/Node.java (1)
Entity(11-71)
src/main/java/com/wayble/server/common/config/RestTemplateConfig.java (1)
src/main/java/com/wayble/server/common/config/SecurityConfig.java (1)
Configuration(22-75)
src/main/java/com/wayble/server/direction/service/EdgeService.java (2)
src/main/java/com/wayble/server/direction/service/FacilityService.java (1)
Service(23-100)src/main/java/com/wayble/server/direction/service/TransportationService.java (1)
Service(21-342)
src/main/java/com/wayble/server/direction/entity/transportation/Edge.java (2)
src/main/java/com/wayble/server/direction/entity/transportation/Route.java (1)
Entity(9-36)src/main/java/com/wayble/server/direction/entity/transportation/Node.java (1)
Entity(11-71)
src/main/java/com/wayble/server/direction/entity/transportation/Elevator.java (3)
src/main/java/com/wayble/server/direction/entity/transportation/Facility.java (1)
Entity(11-46)src/main/java/com/wayble/server/direction/entity/transportation/Node.java (1)
Entity(11-71)src/main/java/com/wayble/server/direction/entity/transportation/Lift.java (1)
Entity(6-29)
src/main/java/com/wayble/server/direction/entity/transportation/Facility.java (3)
src/main/java/com/wayble/server/direction/entity/transportation/Elevator.java (1)
Entity(6-26)src/main/java/com/wayble/server/direction/entity/transportation/Node.java (1)
Entity(11-71)src/main/java/com/wayble/server/direction/entity/transportation/Lift.java (1)
Entity(6-29)
🔇 Additional comments (12)
src/main/java/com/wayble/server/common/config/SecurityConfig.java (1)
48-50:/api/v1/directions/**엔드포인트의 무인증 허용이 요구사항에 부합하는지 확인 바랍니다.경로 탐색 API가 사용량이 많은 공개 서비스라면 문제없지만,
사용자 위치·이동 경로와 같은 민감 데이터를 포함한다면 인증 없이 열려 있는 것이 보안 정책을 위반할 수 있습니다. 기획 담당자와 의도 확인 후permitAll()유지 여부를 결정해 주세요.src/main/java/com/wayble/server/direction/dto/toilet/KricToiletRawResponse.java (1)
5-7: 심플 DTO 정의 확인 완료API 응답 래핑용 레코드 정의가 명확하며 문제점이 보이지 않습니다.
src/main/java/com/wayble/server/direction/exception/DirectionErrorCase.java (1)
11-11: 일관성 있는 에러 케이스 추가새로운
HISTORY_NOT_FOUND에러 케이스가 기존 패턴과 일관성 있게 추가되었습니다. HTTP 상태 코드, 에러 코드, 그리고 한국어 메시지가 모두 적절합니다.src/main/java/com/wayble/server/direction/dto/toilet/KricToiletRawBody.java (1)
5-7: KricToiletRawBody 레코드 검증 요청
KricToiletRawBody는 KRIC API 응답의item배열을 담도록 설계되어 있습니다.- 실제 API 응답이
{"body": {"item": […]}}형태로 전달되는지, 특히item필드명이 API 문서 또는 샘플 응답과 정확히 일치하는지 확인해주세요.- 이미
KricToiletRawResponse에서body로 감싸 매핑하고 있으므로, 응답 예시나 스펙을 참고해 아래 파일을 검증해 주시면 됩니다.• 검증 대상:
- src/main/java/com/wayble/server/direction/dto/toilet/KricToiletRawBody.java
src/main/java/com/wayble/server/direction/repository/NodeRepository.java (1)
1-8: LGTM! 표준적인 JPA 리포지토리 구현입니다.Spring Data JPA의 표준 패턴을 올바르게 따르고 있으며, Node 엔티티에 대한 기본 CRUD 작업을 제공합니다. 대중교통 라우팅 시스템에서 그래프 구성을 위한 노드 데이터 접근에 적합합니다.
src/main/java/com/wayble/server/direction/entity/transportation/Elevator.java (1)
1-26: LGTM! 엘리베이터 엔티티 구현이 적절합니다.JPA 매핑, Lombok 어노테이션 사용, 그리고 다른 transportation 엔티티들과의 일관된 패턴이 잘 구현되어 있습니다. 위도/경도를 DECIMAL(10,7)로 정의한 것도 적절합니다.
src/main/java/com/wayble/server/direction/entity/transportation/Node.java (2)
18-19: ID 생성 전략 확인이 필요합니다.
Node엔티티의 ID에@GeneratedValue어노테이션이 없어 수동으로 ID를 할당해야 합니다. 이것이 의도된 설계인지 확인해주세요. 다른 엔티티들(Elevator,Facility)은 auto-generation 전략을 사용합니다.
59-70: LGTM! equals와 hashCode 구현이 적절합니다.ID 기반의 equals/hashCode 구현이 JPA 엔티티에 적합하며, null 체크도 포함되어 있습니다.
src/main/java/com/wayble/server/direction/entity/transportation/Edge.java (1)
8-22: LGTM! Edge 엔티티의 핵심 구조가 적절합니다.ID 자동 생성, DirectionType enum 사용, 그리고 적절한 JPA 어노테이션 사용이 잘 구현되어 있습니다.
src/main/java/com/wayble/server/direction/entity/transportation/Facility.java (2)
41-44: LGTM! Node와의 일대일 관계 매핑이 적절합니다.
@MapsId와@JoinColumn(name = "id")조합으로 shared primary key 관계가 올바르게 구현되어 있습니다.
35-39: LGTM! 접근성 시설과의 관계 매핑이 적절합니다.Lift와 Elevator 엔티티와의 OneToMany 관계가 적절한 cascade와 fetch 전략으로 구현되어 있습니다.
src/main/java/com/wayble/server/direction/entity/transportation/Route.java (1)
17-25: LGTM! Route 엔티티의 핵심 필드들이 적절합니다.routeId, routeName, routeType 필드들이 적절한 JPA 어노테이션으로 잘 정의되어 있습니다. DirectionType enum 사용도 적절합니다.
| private List<Node> nodes; | ||
| private List<Edge> edges; |
There was a problem hiding this comment.
스레드 안전성 문제
인스턴스 변수 nodes와 edges는 스레드 간 공유될 수 있어 동시성 문제가 발생할 수 있습니다. 메서드 내 지역 변수로 변경하세요.
- private List<Node> nodes;
- private List<Edge> edges;Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/direction/service/TransportationService.java
at lines 29-30, the instance variables nodes and edges can cause concurrency
issues as they may be shared across threads. To fix this, remove these instance
variables and instead declare nodes and edges as local variables within the
methods that use them, ensuring thread safety by avoiding shared mutable state.
KiSeungMin
left a comment
There was a problem hiding this comment.
와우 로직이 엄청나네요....! 수고 많으셨습니다!!
| import org.springframework.web.client.RestTemplate; | ||
|
|
||
| @Configuration | ||
| public class RestTemplateConfig { |
There was a problem hiding this comment.
restTemplate은 요청마다 쓰레드를 생성해서 요청이 많아지면 성능 저하가 발생할 수 있는 걸로 알고 있어요!
추후에 webClient를 활용해서 외부 API를 호출하는 식으로 리팩토링해도 좋을 것 같습니다!
✔️ 연관 이슈
📝 작업 내용
스크린샷 (선택)
Summary by CodeRabbit
신규 기능
버그 수정
기타