diff --git a/analytics/src/main/java/com/ktds/hi/analytics/biz/service/AnalyticsService.java b/analytics/src/main/java/com/ktds/hi/analytics/biz/service/AnalyticsService.java index 615492b..0cf749c 100644 --- a/analytics/src/main/java/com/ktds/hi/analytics/biz/service/AnalyticsService.java +++ b/analytics/src/main/java/com/ktds/hi/analytics/biz/service/AnalyticsService.java @@ -251,7 +251,49 @@ public class AnalyticsService implements AnalyticsUseCase { throw new RuntimeException("AI 피드백 요약 조회에 실패했습니다.", e); } } - + + @Override + // @Cacheable(value = "customerPositiveFeedback", key = "#storeId") + public CustomerPositiveReviewResponse getPositiveIFeedbackSummary(Long storeId) { + + try { + // 1. 캐시에서 먼저 확인 (타입 안전성 보장) + String cacheKey = "customerPositiveFeedback:store:" + storeId; + var cachedResult = cachePort.getAnalyticsCache(cacheKey); + if (cachedResult.isPresent()) { + Object cached = cachedResult.get(); + if (cached instanceof CustomerPositiveReviewResponse) { + log.info("캐시에서 AI 긍정 피드백 반환: storeId={}", storeId); + return (CustomerPositiveReviewResponse) cached; + } + log.debug("AI 긍정 피드백 캐시 데이터 타입 불일치, DB에서 조회: storeId={}", storeId); + } + + // 1. 기존 AI 피드백 조회 + var aiFeedback = analyticsPort.findPositiveAIFeedbackByStoreId(storeId); + + if (aiFeedback.isEmpty()) { + // 2. AI 피드백이 없으면 새로 생성 + throw new RuntimeException("AI 긍정 피드백 요약 조회 실패"); + } + + + // 3. 응답 생성 + var response = CustomerPositiveReviewResponse.builder() + .storeId(aiFeedback.get().getStoreId()) + .positiveSummary(aiFeedback.get().getPositiveSummary()) + .analyzedAt(aiFeedback.get().getCreatedAt()) + .build(); + + return response; + + } catch (Exception e) { + log.error("AI 피드백 조회 중 오류 발생: storeId={}", storeId, e); + throw new RuntimeException("AI 피드백 조회에 실패했습니다.", e); + } + + } + @Override public ReviewAnalysisResponse getReviewAnalysis(Long storeId, int days) { log.info("리뷰 분석 조회 시작: storeId={}", storeId); diff --git a/analytics/src/main/java/com/ktds/hi/analytics/biz/usecase/in/AnalyticsUseCase.java b/analytics/src/main/java/com/ktds/hi/analytics/biz/usecase/in/AnalyticsUseCase.java index a3d85a5..5617fd3 100644 --- a/analytics/src/main/java/com/ktds/hi/analytics/biz/usecase/in/AnalyticsUseCase.java +++ b/analytics/src/main/java/com/ktds/hi/analytics/biz/usecase/in/AnalyticsUseCase.java @@ -30,6 +30,12 @@ public interface AnalyticsUseCase { * AI 피드백 요약 조회 */ AiFeedbackSummaryResponse getAIFeedbackSummary(Long storeId); + + + /** + * AI 긍정 피드백 요약 조회(고객용) + */ + CustomerPositiveReviewResponse getPositiveIFeedbackSummary(Long storeId); /** * 리뷰 분석 조회 diff --git a/analytics/src/main/java/com/ktds/hi/analytics/biz/usecase/out/AnalyticsPort.java b/analytics/src/main/java/com/ktds/hi/analytics/biz/usecase/out/AnalyticsPort.java index f8a44a0..ce77a32 100644 --- a/analytics/src/main/java/com/ktds/hi/analytics/biz/usecase/out/AnalyticsPort.java +++ b/analytics/src/main/java/com/ktds/hi/analytics/biz/usecase/out/AnalyticsPort.java @@ -26,6 +26,12 @@ public interface AnalyticsPort { */ Optional findAIFeedbackByStoreId(Long storeId); + /** + * 매장 ID로 AI 긍정 피드백 조회(고객용) + */ + Optional findPositiveAIFeedbackByStoreId(Long storeId); + + /** * AI 피드백 ID로 조회 (추가된 메서드) */ diff --git a/analytics/src/main/java/com/ktds/hi/analytics/infra/controller/AnalyticsController.java b/analytics/src/main/java/com/ktds/hi/analytics/infra/controller/AnalyticsController.java index 032b07f..b456f78 100644 --- a/analytics/src/main/java/com/ktds/hi/analytics/infra/controller/AnalyticsController.java +++ b/analytics/src/main/java/com/ktds/hi/analytics/infra/controller/AnalyticsController.java @@ -64,7 +64,7 @@ public class AnalyticsController { return ResponseEntity.ok(SuccessResponse.of(response, "AI 피드백 상세 조회 성공")); } - + /** * 매장 통계 조회 */ @@ -102,6 +102,24 @@ public class AnalyticsController { return ResponseEntity.ok(SuccessResponse.of(response, "AI 피드백 요약 조회 성공")); } + + /** + * AI 긍정 피드백 요약 조회(고객용) + */ + @Operation(summary = "AI 긍정 피드백 요약 조회", description = "매장의 AI 긍정 피드백 요약 정보를 조회합니다.") + @GetMapping("/stores/{storeId}/customer/summary") + public ResponseEntity> getCustomerAIFeedbackSummary( + @Parameter(description = "매장 ID", required = true) + @PathVariable @NotNull Long storeId) { + + log.info("AI 피드백 요약 조회 요청: storeId={}", storeId); + + CustomerPositiveReviewResponse response = analyticsUseCase.getPositiveIFeedbackSummary(storeId); + + return ResponseEntity.ok(SuccessResponse.of(response, "AI 피드백 요약 조회 성공")); + } + + /** * 리뷰 분석 조회 diff --git a/analytics/src/main/java/com/ktds/hi/analytics/infra/dto/CustomerPositiveReviewResponse.java b/analytics/src/main/java/com/ktds/hi/analytics/infra/dto/CustomerPositiveReviewResponse.java index f0f5927..b12f898 100644 --- a/analytics/src/main/java/com/ktds/hi/analytics/infra/dto/CustomerPositiveReviewResponse.java +++ b/analytics/src/main/java/com/ktds/hi/analytics/infra/dto/CustomerPositiveReviewResponse.java @@ -25,10 +25,6 @@ public class CustomerPositiveReviewResponse { @Schema(description = "긍정적인 리뷰 요약") private String positiveSummary; - - @Schema(description = "분석된 총 리뷰 수") - private Integer totalReviewsAnalyzed; - @Schema(description = "분석 일시") private LocalDateTime analyzedAt; } diff --git a/analytics/src/main/java/com/ktds/hi/analytics/infra/gateway/AnalyticsRepositoryAdapter.java b/analytics/src/main/java/com/ktds/hi/analytics/infra/gateway/AnalyticsRepositoryAdapter.java index e08d601..db51540 100644 --- a/analytics/src/main/java/com/ktds/hi/analytics/infra/gateway/AnalyticsRepositoryAdapter.java +++ b/analytics/src/main/java/com/ktds/hi/analytics/infra/gateway/AnalyticsRepositoryAdapter.java @@ -48,7 +48,13 @@ public class AnalyticsRepositoryAdapter implements AnalyticsPort { return aiFeedbackJpaRepository.findLatestByStoreId(storeId) .map(this::toAiFeedbackDomain); } - + + @Override + public Optional findPositiveAIFeedbackByStoreId(Long storeId) { + return aiFeedbackJpaRepository.findLatestByStoreId(storeId) + .map(this::toAiFeedbackDomain); + } + @Override public AiFeedback saveAIFeedback(AiFeedback feedback) { AiFeedbackEntity entity = toAiFeedbackEntity(feedback);