Fix : 수정

This commit is contained in:
lsh9672 2025-06-13 01:03:11 +09:00
parent 4f173d2982
commit a13ca2e4be
9 changed files with 55 additions and 270 deletions

View File

@ -1,41 +1,20 @@
package com.ktds.hi.recommend.biz.domain; package com.ktds.hi.recommend.biz.domain;
import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
/**
* 추천 히스토리 도메인 클래스
* 사용자의 추천 기록을 담는 도메인 객체
*/
@Getter @Getter
@Builder @Builder
@NoArgsConstructor
@AllArgsConstructor
public class RecommendHistory { public class RecommendHistory {
private Long id; private Long id;
private Long memberId; private Long memberId;
private List<Long> recommendedStoreIds; private Long storeId;
private RecommendType recommendType; private String recommendType;
private String criteria; private Double score;
private LocalDateTime createdAt; private String reason;
private LocalDateTime recommendedAt;
/** private Boolean clicked;
* 추천 기준 업데이트 private Boolean visited;
*/ }
public RecommendHistory updateCriteria(String newCriteria) {
return RecommendHistory.builder()
.id(this.id)
.memberId(this.memberId)
.recommendedStoreIds(this.recommendedStoreIds)
.recommendType(this.recommendType)
.criteria(newCriteria)
.createdAt(this.createdAt)
.build();
}
}

View File

@ -1,69 +1,24 @@
package com.ktds.hi.recommend.biz.domain; package com.ktds.hi.recommend.biz.domain;
import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.List; import java.util.List;
/**
* 추천 매장 도메인 클래스
* 추천된 매장 정보를 담는 도메인 객체
*/
@Getter @Getter
@Builder @Builder
@NoArgsConstructor
@AllArgsConstructor
public class RecommendStore { public class RecommendStore {
private Long storeId; private Long storeId;
private String storeName; private String storeName;
private String address; private String address;
private String category; private String category;
private List<String> tags; private Double latitude;
private Double longitude;
private Double rating; private Double rating;
private Integer reviewCount; private Integer reviewCount;
private Double distance; private List<String> tags;
private Double recommendScore;
private RecommendType recommendType;
private String recommendReason; private String recommendReason;
private Double recommendScore;
/** private Double distance;
* 추천 점수 업데이트 private String priceRange;
*/ }
public RecommendStore updateRecommendScore(Double newScore) {
return RecommendStore.builder()
.storeId(this.storeId)
.storeName(this.storeName)
.address(this.address)
.category(this.category)
.tags(this.tags)
.rating(this.rating)
.reviewCount(this.reviewCount)
.distance(this.distance)
.recommendScore(newScore)
.recommendType(this.recommendType)
.recommendReason(this.recommendReason)
.build();
}
/**
* 추천 이유 업데이트
*/
public RecommendStore updateRecommendReason(String newReason) {
return RecommendStore.builder()
.storeId(this.storeId)
.storeName(this.storeName)
.address(this.address)
.category(this.category)
.tags(this.tags)
.rating(this.rating)
.reviewCount(this.reviewCount)
.distance(this.distance)
.recommendScore(this.recommendScore)
.recommendType(this.recommendType)
.recommendReason(newReason)
.build();
}
}

View File

@ -1,52 +1,20 @@
package com.ktds.hi.recommend.biz.domain; package com.ktds.hi.recommend.biz.domain;
import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map;
/**
* 취향 프로필 도메인 클래스
* 사용자의 취향 분석 결과를 담는 도메인 객체
*/
@Getter @Getter
@Builder @Builder
@NoArgsConstructor
@AllArgsConstructor
public class TasteProfile { public class TasteProfile {
private Long id; private Long id;
private Long memberId; private Long memberId;
private List<TasteCategory> preferredCategories; private List<String> cuisinePreferences;
private Map<String, Double> categoryScores; private String priceRange;
private List<String> preferredTags; private Integer distancePreference;
private Map<String, Object> behaviorPatterns; private List<String> tasteTags;
private Double pricePreference;
private Double distancePreference;
private LocalDateTime createdAt; private LocalDateTime createdAt;
private LocalDateTime updatedAt; private LocalDateTime updatedAt;
}
/**
* 취향 프로필 업데이트
*/
public TasteProfile updateProfile(List<TasteCategory> categories, Map<String, Double> scores,
List<String> tags, Map<String, Object> patterns,
Double pricePreference, Double distancePreference) {
return TasteProfile.builder()
.id(this.id)
.memberId(this.memberId)
.preferredCategories(categories)
.categoryScores(scores)
.preferredTags(tags)
.behaviorPatterns(patterns)
.pricePreference(pricePreference)
.distancePreference(distancePreference)
.createdAt(this.createdAt)
.updatedAt(LocalDateTime.now())
.build();
}
}

View File

@ -1,28 +1,18 @@
package com.ktds.hi.recommend.biz.usecase.out; package com.ktds.hi.recommend.biz.usecase.out;
import com.ktds.hi.recommend.biz.domain.RecommendStore; import com.ktds.hi.recommend.biz.domain.RecommendStore;
import com.ktds.hi.recommend.biz.domain.TasteProfile;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
/**
* AI 추천 리포지토리 인터페이스
* AI 기반 추천 기능을 정의
*/
public interface AiRecommendRepository { public interface AiRecommendRepository {
/**
* AI 기반 매장 추천
*/
List<RecommendStore> recommendStoresByAI(Long memberId, Map<String, Object> preferences); List<RecommendStore> recommendStoresByAI(Long memberId, Map<String, Object> preferences);
/**
* 유사 사용자 기반 추천
*/
List<RecommendStore> recommendStoresBySimilarUsers(Long memberId); List<RecommendStore> recommendStoresBySimilarUsers(Long memberId);
/**
* 협업 필터링 추천
*/
List<RecommendStore> recommendStoresByCollaborativeFiltering(Long memberId); List<RecommendStore> recommendStoresByCollaborativeFiltering(Long memberId);
}
// 추가 필요한 메서드들
List<RecommendStore> filterByPreferences(List<RecommendStore> stores, TasteProfile tasteProfile, String tags);
String getStoreSummary(Long storeId);
}

View File

@ -5,29 +5,12 @@ import com.ktds.hi.recommend.biz.domain.RecommendStore;
import java.util.List; import java.util.List;
/**
* 위치 기반 서비스 리포지토리 인터페이스
* 위치 정보 처리 기능을 정의
*/
public interface LocationRepository { public interface LocationRepository {
/**
* 위치 정보 저장
*/
Location saveLocation(Location location); Location saveLocation(Location location);
/**
* 반경 매장 조회
*/
List<RecommendStore> findStoresWithinRadius(Double latitude, Double longitude, Integer radius);
/**
* 거리 계산
*/
Double calculateDistance(Double lat1, Double lon1, Double lat2, Double lon2); Double calculateDistance(Double lat1, Double lon1, Double lat2, Double lon2);
/**
* 주소를 좌표로 변환
*/
Location geocodeAddress(String address); Location geocodeAddress(String address);
}
// 수정된 메서드명 (Controller에서 호출하는 것과 일치)
List<RecommendStore> findStoresWithinDistance(Double latitude, Double longitude, Integer radius);
}

View File

@ -1,34 +1,23 @@
package com.ktds.hi.recommend.biz.usecase.out; package com.ktds.hi.recommend.biz.usecase.out;
import com.ktds.hi.recommend.biz.domain.RecommendHistory; import com.ktds.hi.recommend.biz.domain.RecommendHistory;
import com.ktds.hi.recommend.biz.domain.RecommendStore;
import com.ktds.hi.recommend.biz.domain.TasteProfile; import com.ktds.hi.recommend.biz.domain.TasteProfile;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
/**
* 추천 리포지토리 인터페이스
* 추천 관련 데이터 영속성 기능을 정의
*/
public interface RecommendRepository { public interface RecommendRepository {
/** // 기존 메서드들
* 추천 히스토리 저장
*/
RecommendHistory saveRecommendHistory(RecommendHistory history); RecommendHistory saveRecommendHistory(RecommendHistory history);
/**
* 회원 ID로 추천 히스토리 조회
*/
List<RecommendHistory> findRecommendHistoriesByMemberId(Long memberId); List<RecommendHistory> findRecommendHistoriesByMemberId(Long memberId);
/**
* 취향 프로필 저장
*/
TasteProfile saveTasteProfile(TasteProfile profile); TasteProfile saveTasteProfile(TasteProfile profile);
/**
* 회원 ID로 취향 프로필 조회
*/
Optional<TasteProfile> findTasteProfileByMemberId(Long memberId); Optional<TasteProfile> findTasteProfileByMemberId(Long memberId);
}
// 추가로 필요한 메서드들
Optional<RecommendStore> findStoreById(Long storeId);
List<RecommendStore> findPopularStores(String category, Integer limit);
void logStoreClick(Long memberId, Long storeId);
void logRecommendation(Long memberId, List<Long> storeIds, String context);
}

View File

@ -6,29 +6,10 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
/**
* 사용자 선호도 리포지토리 인터페이스
* 사용자 취향 데이터 처리 기능을 정의
*/
public interface UserPreferenceRepository { public interface UserPreferenceRepository {
/**
* 회원 취향 정보 조회
*/
Optional<TasteProfile> getMemberPreferences(Long memberId); Optional<TasteProfile> getMemberPreferences(Long memberId);
/**
* 회원의 리뷰 기반 취향 분석
*/
Map<String, Object> analyzePreferencesFromReviews(Long memberId); Map<String, Object> analyzePreferencesFromReviews(Long memberId);
/**
* 유사한 취향의 사용자 조회
*/
List<Long> findSimilarTasteMembers(Long memberId); List<Long> findSimilarTasteMembers(Long memberId);
/**
* 취향 프로필 업데이트
*/
TasteProfile updateTasteProfile(Long memberId, Map<String, Object> analysisData); TasteProfile updateTasteProfile(Long memberId, Map<String, Object> analysisData);
} }

View File

@ -1,47 +1,29 @@
package com.ktds.hi.recommend.infra.dto.request; package com.ktds.hi.recommend.infra.dto.request;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.*; import jakarta.validation.constraints.NotNull;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import java.util.List;
/**
* 매장 추천 요청 DTO
*/
@Getter @Getter
@Setter @Setter
@NoArgsConstructor
@Schema(description = "매장 추천 요청") @Schema(description = "매장 추천 요청")
public class RecommendStoreRequest { public class RecommendStoreRequest {
@NotNull(message = "위도는 필수입니다") @NotNull
@DecimalMin(value = "-90.0", message = "위도는 -90도 이상이어야 합니다") @Schema(description = "위도", example = "37.5665", required = true)
@DecimalMax(value = "90.0", message = "위도는 90도 이하여야 합니다")
@Schema(description = "위도", example = "37.5665")
private Double latitude; private Double latitude;
@NotNull(message = "경도는 필수입니다") @NotNull
@DecimalMin(value = "-180.0", message = "경도는 -180도 이상이어야 합니다") @Schema(description = "경도", example = "126.9780", required = true)
@DecimalMax(value = "180.0", message = "경도는 180도 이하여야 합니다")
@Schema(description = "경도", example = "126.9780")
private Double longitude; private Double longitude;
@Min(value = 100, message = "반경은 최소 100m 이상이어야 합니다") @Schema(description = "반경(미터)", example = "3000", defaultValue = "3000")
@Max(value = 50000, message = "반경은 최대 50km 이하여야 합니다") private Integer radius = 3000;
@Schema(description = "검색 반경 (미터)", example = "5000")
private Integer radius = 5000;
@Schema(description = "카테고리 필터", example = "한식") @Schema(description = "선택된 태그들 (콤마 구분)", example = "매운맛,혼밥")
private String tags;
@Schema(description = "카테고리", example = "한식")
private String category; private String category;
@Schema(description = "취향 태그 목록", example = "[\"매운맛\", \"혼밥\"]")
private List<String> tags;
@Min(value = 1, message = "최소 1개 이상의 결과가 필요합니다")
@Max(value = 50, message = "최대 50개까지 조회 가능합니다")
@Schema(description = "결과 개수", example = "10")
private Integer limit = 10;
} }

View File

@ -6,9 +6,6 @@ import lombok.Getter;
import java.util.List; import java.util.List;
/**
* 매장 상세 정보 응답 DTO
*/
@Getter @Getter
@Builder @Builder
@Schema(description = "매장 상세 정보 응답") @Schema(description = "매장 상세 정보 응답")
@ -29,54 +26,15 @@ public class StoreDetailResponse {
@Schema(description = "평점", example = "4.5") @Schema(description = "평점", example = "4.5")
private Double rating; private Double rating;
@Schema(description = "리뷰 수", example = "256")
private Integer reviewCount;
@Schema(description = "거리(미터)", example = "500") @Schema(description = "거리(미터)", example = "500")
private Integer distance; private Integer distance;
@Schema(description = "태그 목록", example = "[\"맛집\", \"혼밥\", \"가성비\"]") @Schema(description = "태그 목록", example = "[\"맛집\", \"혼밥\", \"가성비\"]")
private List<String> tags; private List<String> tags;
@Schema(description = "매장 이미지 URL 목록")
private List<String> images;
@Schema(description = "매장 설명")
private String description;
@Schema(description = "개인화된 추천 이유", example = "당신이 좋아하는 '매운맛' 특성을 가진 매장입니다") @Schema(description = "개인화된 추천 이유", example = "당신이 좋아하는 '매운맛' 특성을 가진 매장입니다")
private String personalizedReason; private String personalizedReason;
@Schema(description = "AI 요약", example = "고객들이 매운맛과 친절한 서비스를 칭찬하는 매장입니다") @Schema(description = "AI 요약", example = "고객들이 매운맛과 친절한 서비스를 칭찬하는 매장입니다")
private String aiSummary; private String aiSummary;
@Schema(description = "운영 시간")
private String operatingHours;
@Schema(description = "전화번호")
private String phoneNumber;
@Schema(description = "메뉴 정보")
private List<MenuInfo> menuList;
/**
* 메뉴 정보 내부 클래스
*/
@Getter
@Builder
@Schema(description = "메뉴 정보")
public static class MenuInfo {
@Schema(description = "메뉴명", example = "김치찌개")
private String menuName;
@Schema(description = "가격", example = "8000")
private Integer price;
@Schema(description = "메뉴 설명", example = "매콤한 김치찌개")
private String description;
@Schema(description = "인기 메뉴 여부", example = "true")
private Boolean isPopular;
}
} }