Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
8ce0faf
[chore] AWS 관련 의존성 추가
KiSeungMin Jul 19, 2025
45aa645
[feat] 웨이블존 상세 정보 조회 시 방문 기록 저장 기능 구현
KiSeungMin Jul 19, 2025
3a6af0d
[feat] 웨이블존 추천 기능 JWT 인증 추가
KiSeungMin Jul 19, 2025
469de36
[feat] soft delete된 필드를 되살리는 로직 추가
KiSeungMin Jul 19, 2025
5d74fb2
[fix] user 데이터 중복으로 인한 테스트 코드 오류 해결
KiSeungMin Jul 21, 2025
5243f3f
[chore] 웨이블존 추천 service 로직의 일부 메서드를 private로 수정
KiSeungMin Jul 21, 2025
00f1bb1
[chore] 테스트 코드에서 불필요한 출력 코드 제거
KiSeungMin Jul 21, 2025
841ccac
[feat] Elastic Search 웨이블존 객체 장애 시설 정보 엔티티 추가
KiSeungMin Jul 21, 2025
9467274
[feat] Elastic Search dto에 장애 시설 정보 엔티티 추가
KiSeungMin Jul 21, 2025
9a17da3
[feat] Wayble Zone mapping.json 파일에 장애 시설 정보 인덱스 추가
KiSeungMin Jul 21, 2025
47b220e
[feat] 검색, 추천 쿼리 로직에서 장애 시설 정보 추가
KiSeungMin Jul 21, 2025
350df6c
[feat] 장애 시설 정보 api 응답 테스트 완료
KiSeungMin Jul 21, 2025
f33972f
[feat] 장애 시설 정보 api 응답 테스트 완료
KiSeungMin Jul 21, 2025
49aac1a
[feat] 지도 검색 기반 검색 api의 엔드포인트에 /maps 추가
KiSeungMin Jul 21, 2025
7faeda1
Merge branch 'develop' into feature/seungmin
KiSeungMin Jul 21, 2025
8b70d24
[feat] WaybleZoneDocument의 썸네일 이미지를 웨이블존 엔티티로부터 전달받도록 구현
KiSeungMin Jul 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
implementation 'jakarta.servlet:jakarta.servlet-api:6.0.0'
implementation 'com.amazonaws:aws-java-sdk-core:1.12.698'
implementation 'com.amazonaws:aws-java-sdk-s3:1.12.698'
Comment on lines +38 to +39
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

중복된 AWS SDK 의존성 제거 필요

AWS SDK 의존성이 두 번 선언되어 있습니다 (라인 38-39와 48-49). 중복 선언을 제거해야 합니다.

다음 diff를 적용하여 중복을 제거하세요:

-	implementation 'com.amazonaws:aws-java-sdk-core:1.12.698'
-	implementation 'com.amazonaws:aws-java-sdk-s3:1.12.698'
 	runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
 	runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
 
 	runtimeOnly 'com.mysql:mysql-connector-j'
 	compileOnly 'org.projectlombok:lombok'
 	annotationProcessor 'org.projectlombok:lombok'
 
     //AWS S3
 	implementation 'com.amazonaws:aws-java-sdk-core:1.12.698'
 	implementation 'com.amazonaws:aws-java-sdk-s3:1.12.698'

Also applies to: 48-49

🤖 Prompt for AI Agents
In build.gradle around lines 38-39 and 48-49, the AWS SDK dependencies are
declared twice. Remove the duplicate implementation lines at 48-49 to keep only
one declaration of 'com.amazonaws:aws-java-sdk-core:1.12.698' and
'com.amazonaws:aws-java-sdk-s3:1.12.698' to avoid redundancy.

runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'

Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/wayble/server/common/entity/BaseEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@ public class BaseEntity {

@Column(name = "deleted_at")
private LocalDateTime deletedAt;

public void restore() {
this.deletedAt = null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class WaybleZoneSearchController {

private final WaybleZoneSearchService waybleZoneSearchService;

@GetMapping("")
@GetMapping("/maps")
public CommonResponse<SearchSliceDto<WaybleZoneSearchResponseDto>> findByCondition(
@Valid @ModelAttribute WaybleZoneSearchConditionDto conditionDto,
@RequestParam(name = "page", defaultValue = "0") int page,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.wayble.server.explore.dto;

import com.wayble.server.explore.entity.EsWaybleZoneFacility;
import lombok.Builder;

@Builder
public record FacilityResponseDto(
Boolean hasSlope,
Boolean hasNoDoorStep,
Boolean hasElevator,
Boolean hasTableSeat,
Boolean hasDisabledToilet,
String floorInfo
) {
public static FacilityResponseDto from(EsWaybleZoneFacility facility) {
if (facility == null) {
return null;
}

return FacilityResponseDto.builder()
.hasSlope(facility.isHasSlope())
.hasNoDoorStep(facility.isHasNoDoorStep())
.hasElevator(facility.isHasElevator())
.hasTableSeat(facility.isHasTableSeat())
.hasDisabledToilet(facility.isHasDisabledToilet())
.floorInfo(facility.getFloorInfo())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.wayble.server.explore.dto.recommend;

import com.wayble.server.explore.dto.FacilityResponseDto;
import com.wayble.server.explore.entity.WaybleZoneDocument;
import com.wayble.server.wayblezone.entity.WaybleZoneType;
import lombok.Builder;
Expand All @@ -23,6 +24,8 @@ public record WaybleZoneRecommendResponseDto(

Long reviewCount,

FacilityResponseDto facility,

Double distanceScore,

Double similarityScore,
Expand All @@ -42,6 +45,7 @@ public static WaybleZoneRecommendResponseDto from(WaybleZoneDocument waybleZoneD
.reviewCount(waybleZoneDocument.getReviewCount())
.latitude(waybleZoneDocument.getAddress().getLocation().getLat())
.longitude(waybleZoneDocument.getAddress().getLocation().getLon())
.facility(FacilityResponseDto.from(waybleZoneDocument.getFacility()))
.distanceScore(0.0)
.similarityScore(0.0)
.recencyScore(0.0)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.wayble.server.explore.dto.search;

import com.wayble.server.common.entity.Address;
import com.wayble.server.wayblezone.entity.WaybleZoneFacility;
import com.wayble.server.wayblezone.entity.WaybleZoneType;
import lombok.Builder;

Expand All @@ -11,6 +12,7 @@ public record WaybleZoneDocumentRegisterDto(
WaybleZoneType waybleZoneType,
String thumbnailImageUrl,
Address address,
WaybleZoneFacility facility,
Double averageRating,
Long reviewCount
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.wayble.server.explore.dto.search;

import com.wayble.server.explore.dto.FacilityResponseDto;
import com.wayble.server.explore.entity.WaybleZoneDocument;
import com.wayble.server.wayblezone.entity.WaybleZoneType;
import lombok.AccessLevel;
Expand All @@ -24,7 +25,9 @@ public record WaybleZoneSearchResponseDto(

Double averageRating,

Long reviewCount
Long reviewCount,

FacilityResponseDto facility
) {
public static WaybleZoneSearchResponseDto from(WaybleZoneDocument waybleZoneDocument, Double distance) {
return WaybleZoneSearchResponseDto.builder()
Expand All @@ -37,6 +40,7 @@ public static WaybleZoneSearchResponseDto from(WaybleZoneDocument waybleZoneDocu
.distance(distance)
.latitude(waybleZoneDocument.getAddress().getLocation().getLat())
.longitude(waybleZoneDocument.getAddress().getLocation().getLon())
.facility(FacilityResponseDto.from(waybleZoneDocument.getFacility()))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.wayble.server.explore.entity;

import com.wayble.server.wayblezone.entity.WaybleZoneFacility;
import lombok.*;

@ToString
@Builder(access = AccessLevel.PRIVATE)
@Getter
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class EsWaybleZoneFacility {

private boolean hasSlope;
private boolean hasNoDoorStep;
private boolean hasElevator;
private boolean hasTableSeat;
private boolean hasDisabledToilet;
private String floorInfo;

public static EsWaybleZoneFacility from(WaybleZoneFacility facility) {
if (facility == null) {
return null;
}

return EsWaybleZoneFacility.builder()
.hasSlope(facility.isHasSlope())
.hasNoDoorStep(facility.isHasNoDoorStep())
.hasElevator(facility.isHasElevator())
.hasTableSeat(facility.isHasTableSeat())
.hasDisabledToilet(facility.isHasDisabledToilet())
.floorInfo(facility.getFloorInfo())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ public class WaybleZoneDocument {
@Field(type = FieldType.Object)
private EsAddress address;

@Field(type = FieldType.Object)
private EsWaybleZoneFacility facility;

private double averageRating;

private long reviewCount;
Expand All @@ -42,8 +45,9 @@ public static WaybleZoneDocument fromEntity(WaybleZone waybleZone) {
.zoneId(waybleZone.getId())
.zoneName(waybleZone.getZoneName())
.zoneType(waybleZone.getZoneType())
.thumbnailImageUrl("thumbnail image url") // TODO: 이미지 경로 추가
.thumbnailImageUrl(waybleZone.getMainImageUrl() != null ? waybleZone.getMainImageUrl() : null) // TODO: 이미지 경로 추가
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

불필요한 삼항 연산자 사용

현재 로직은 waybleZone.getMainImageUrl() != null ? waybleZone.getMainImageUrl() : null인데, 이는 단순히 waybleZone.getMainImageUrl()과 동일합니다.

다음과 같이 수정하세요:

-.thumbnailImageUrl(waybleZone.getMainImageUrl() != null ? waybleZone.getMainImageUrl() : null)   // TODO: 이미지 경로 추가
+.thumbnailImageUrl(waybleZone.getMainImageUrl())   // TODO: 이미지 경로 추가
📝 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
.thumbnailImageUrl(waybleZone.getMainImageUrl() != null ? waybleZone.getMainImageUrl() : null) // TODO: 이미지 경로 추가
.thumbnailImageUrl(waybleZone.getMainImageUrl()) // TODO: 이미지 경로 추가
🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/explore/entity/WaybleZoneDocument.java at
line 48, the ternary operator checking if waybleZone.getMainImageUrl() is null
and returning it or null is redundant. Replace the entire expression with just
waybleZone.getMainImageUrl() to simplify the code without changing its behavior.

.address(EsAddress.from(waybleZone.getAddress()))
.facility(EsWaybleZoneFacility.from(waybleZone.getFacility()))
.averageRating(0.0)
.reviewCount(0L)
.build();
Expand All @@ -56,6 +60,7 @@ public static WaybleZoneDocument fromDto(WaybleZoneDocumentRegisterDto dto) {
.zoneType(dto.waybleZoneType())
.thumbnailImageUrl(dto.thumbnailImageUrl())
.address(EsAddress.from(dto.address()))
.facility(EsWaybleZoneFacility.from(dto.facility()))
.averageRating(dto.averageRating() != null ? dto.averageRating() : 0.0)
.reviewCount(dto.reviewCount() != null ? dto.reviewCount() : 0L)
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ public List<WaybleZoneRecommendResponseDto> searchPersonalWaybleZones(User user,
.longitude(zone.getAddress().getLocation().getLon())
.averageRating(zone.getAverageRating())
.reviewCount(zone.getReviewCount())
.facility(com.wayble.server.explore.dto.FacilityResponseDto.from(zone.getFacility()))
.distanceScore(distanceScore)
.similarityScore(similarityScore)
.recencyScore(recencyScore)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public List<WaybleZoneRecommendResponseDto> getWaybleZonePersonalRecommend(Long
return recommendResponseDtoList;
}

public Optional<WaybleZoneRecommendResponseDto> getTodayRecommendZone(Long userId) {
private Optional<WaybleZoneRecommendResponseDto> getTodayRecommendZone(Long userId) {
LocalDate today = LocalDate.now();
Optional<RecommendLogDocument> recommendLogDocument = recommendLogDocumentRepository.findByUserIdAndRecommendationDate(userId, today);

Expand All @@ -72,7 +72,7 @@ public Optional<WaybleZoneRecommendResponseDto> getTodayRecommendZone(Long userI
}
}

public void saveRecommendLog(Long userId, Long zoneId) {
private void saveRecommendLog(Long userId, Long zoneId) {
String logId = UUID.randomUUID().toString();
LocalDate dateNow = LocalDate.now();

Expand All @@ -88,7 +88,7 @@ public void saveRecommendLog(Long userId, Long zoneId) {
recommendLogDocumentRepository.save(recommendLogDocument);
}

public void updateRecommendLog(Long userId, Long zoneId) {
private void updateRecommendLog(Long userId, Long zoneId) {
RecommendLogDocument recommendLogDocument = recommendLogDocumentRepository.findByUserIdAndZoneId(userId, zoneId)
.orElseThrow(() -> new ApplicationException(RecommendErrorCase.RECOMMEND_LOG_NOT_EXIST));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.wayble.server.user.entity.LoginType;
import com.wayble.server.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
Comment on lines +6 to +7
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

사용되지 않는 import 구문일 가능성 확인 필요

@Query@Param annotation을 위한 import가 추가되었지만, 파일에서 실제 커스텀 쿼리 메서드는 보이지 않습니다. 만약 이 import들이 사용되지 않는다면 제거하는 것이 좋습니다.

다음 스크립트로 해당 annotation들이 실제로 사용되는지 확인해주세요:


🏁 Script executed:

#!/bin/bash
# UserRepository에서 @Query와 @Param이 실제로 사용되는지 확인
rg -A 10 "@Query|@Param" src/main/java/com/wayble/server/user/repository/UserRepository.java

Length of output: 94


사용되지 않는 import 제거 필요

UserRepository.java에서 @Query@Param 애노테이션이 실제로 사용되지 않으므로 해당 import 구문을 제거해주세요.

수정 위치:

  • src/main/java/com/wayble/server/user/repository/UserRepository.java
    제거할 라인: 6–7

제안된 diff:

- import org.springframework.data.jpa.repository.Query;
- import org.springframework.data.repository.query.Param;
📝 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
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/user/repository/UserRepository.java at lines
6 to 7, the imports for org.springframework.data.jpa.repository.Query and
org.springframework.data.repository.query.Param are unused. Remove these two
import statements to clean up the code and avoid unnecessary imports.


import java.util.Optional;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

import java.util.List;
Expand Down Expand Up @@ -57,7 +58,8 @@ public CommonResponse<WaybleZoneDetailResponseDto> getWaybleZoneDetail(
) {

// TODO: JWT에서 userId 추출해서 상세 조회 기록 남기기
// waybleZoneVisitLogService.saveVisitLog(null, waybleZoneId);
Long userId = (Long) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
waybleZoneVisitLogService.saveVisitLog(userId, waybleZoneId);
Comment on lines +61 to +62
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

JWT에서 사용자 ID 추출 시 안전성 검증 필요

SecurityContextHolder에서 principal을 Long으로 직접 캐스팅하는 것은 ClassCastException을 유발할 수 있습니다. JWT 토큰 검증과 타입 안전성을 보장하는 로직이 필요합니다.

다음과 같이 안전한 구현으로 수정하는 것을 권장합니다:

-        Long userId = (Long) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
-        waybleZoneVisitLogService.saveVisitLog(userId, waybleZoneId);
+        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+        if (authentication != null && authentication.getPrincipal() instanceof Long userId) {
+            waybleZoneVisitLogService.saveVisitLog(userId, waybleZoneId);
+        } else {
+            // 인증되지 않은 사용자의 경우 로그 처리 방식 결정 필요
+            waybleZoneVisitLogService.saveVisitLog(null, waybleZoneId);
+        }
📝 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
Long userId = (Long) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
waybleZoneVisitLogService.saveVisitLog(userId, waybleZoneId);
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof Long userId) {
waybleZoneVisitLogService.saveVisitLog(userId, waybleZoneId);
} else {
// 인증되지 않은 사용자의 경우 로그 처리 방식 결정 필요
waybleZoneVisitLogService.saveVisitLog(null, waybleZoneId);
}
🤖 Prompt for AI Agents
In
src/main/java/com/wayble/server/wayblezone/controller/WaybleZoneController.java
at lines 61-62, directly casting the principal from SecurityContextHolder to
Long risks ClassCastException and lacks JWT validation. Modify the code to
safely extract the user ID by first verifying the authentication object and its
principal type, then retrieving the user ID in a type-safe manner, ensuring JWT
token validation is performed before using the ID.

return CommonResponse.success(waybleZoneService.getWaybleZoneDetail(waybleZoneId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,29 @@
},
"address.location": {
"type": "geo_point"
},
"facility": {
"type": "object",
"properties": {
"hasSlope": {
"type": "boolean"
},
"hasNoDoorStep": {
"type": "boolean"
},
"hasElevator": {
"type": "boolean"
},
"hasTableSeat": {
"type": "boolean"
},
"hasDisabledToilet": {
"type": "boolean"
},
"floorInfo": {
"type": "keyword"
}
}
}
}
}
Loading
Loading