-
Notifications
You must be signed in to change notification settings - Fork 0
Feat: 어드민 인기 메뉴 기능 구현 #119
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Caution Review failedThe pull request is closed. """ Walkthrough이번 변경에서는 인기 메뉴 통계 기능이 추가되고, 주문 상태가 COOKED로 변경될 때 메뉴별 카운터가 Redis에 집계되는 이벤트 기반 구조가 도입되었습니다. 이를 위해 새로운 이벤트 모듈( Changes
Sequence Diagram(s)sequenceDiagram
participant AdminAPI as Admin API
participant OrderService
participant EventPublisher
participant RedisListener as CookingCompleteListener
participant MenuCounterService
participant Redis
AdminAPI->>OrderService: updateOrderStatus(orderId, COOKED, memberDetails)
OrderService->>EventPublisher: publish(CookingCompleteEvent)
EventPublisher-->>RedisListener: CookingCompleteEvent (AFTER_COMMIT)
RedisListener->>MenuCounterService: incrementMenuCounter(menuId, storeId, qty)
MenuCounterService->>Redis: ZINCRBY (store+date, menuId, qty)
sequenceDiagram
participant AdminAPI as Admin API
participant StatisticsController
participant PopularMenuRedisService
participant MenuCounterService
participant MenuRepository
participant Redis
AdminAPI->>StatisticsController: GET /popular-menu
StatisticsController->>PopularMenuRedisService: getTodayTop5(memberDetails)
PopularMenuRedisService->>MenuCounterService: getTopMenus(storeId, 5)
MenuCounterService->>Redis: ZREVRANGE (store+date, 0, 4, WITHSCORES)
PopularMenuRedisService->>MenuRepository: findById(menuId)
PopularMenuRedisService-->>StatisticsController: List<PopularMenuDto>
StatisticsController-->>AdminAPI: ResponseEntity (성공)
Possibly related PRs
Suggested reviewers
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (2)
✨ Finishing Touches
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. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
🧹 Nitpick comments (7)
nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/statistic/service/PopularMenuRedisService.java (1)
8-10: 인터페이스 설계 승인서비스 인터페이스가 단일 책임 원칙을 잘 따르고 있으며, 메서드명이 명확합니다.
MemberDetails파라미터를 통한 권한 컨텍스트 전달도 적절합니다.더 나은 문서화를 위해 JavaDoc 주석 추가를 고려해보세요:
+/** + * 인기 메뉴 조회를 위한 Redis 서비스 + */ public interface PopularMenuRedisService { + /** + * 오늘의 상위 5개 인기 메뉴를 조회합니다. + * + * @param memberDetails 회원 정보 (권한 및 매장 정보 포함) + * @return 인기 메뉴 목록 (최대 5개) + */ List<PopularMenuDto> getTodayTop5(MemberDetails memberDetails); }nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/statistic/dto/PopularMenuDto.java (1)
9-11: 필드 검증과 문서화 개선을 고려해보세요.현재 필드에 대한 검증 로직이나 문서화가 부족합니다. 데이터 무결성을 위해 다음과 같은 개선사항을 고려해보세요:
+import javax.validation.constraints.NotNull; +import javax.validation.constraints.PositiveOrZero; + +/** + * 인기 메뉴 정보를 담는 DTO + */ @Getter @AllArgsConstructor public class PopularMenuDto { + @NotNull private Long menuId; + @NotNull private String menuName; + @NotNull + @PositiveOrZero private Long soldCount; }nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/order/service/OrderService.java (1)
64-78: 이벤트 발행 로직 개선을 고려해보세요.COOKED 상태 변경 시 이벤트 발행 로직이 올바르게 구현되었지만, 몇 가지 개선사항을 고려해볼 수 있습니다:
if (OrderStatus.COOKED.equals(newStatus)) { - List<CookingCompleteEvent.Item> items = userOrder.getOrderItems().stream() - .map(item -> new CookingCompleteEvent.Item( - item.getMenu().getId(), - item.getQuantity() - )) - .toList(); - - publisher.publishEvent( - new CookingCompleteEvent( - userOrder.getStore().getStoreId(), - items - ) - ); + try { + CookingCompleteEvent event = createCookingCompleteEvent(userOrder); + publisher.publishEvent(event); + } catch (Exception e) { + // 이벤트 발행 실패 시 로깅 (비즈니스 로직에는 영향 없음) + log.warn("Failed to publish CookingCompleteEvent for order: {}", orderId, e); + } } + +private CookingCompleteEvent createCookingCompleteEvent(UserOrder userOrder) { + List<CookingCompleteEvent.Item> items = userOrder.getOrderItems().stream() + .map(item -> new CookingCompleteEvent.Item( + item.getMenu().getId(), + item.getQuantity() + )) + .toList(); + + return new CookingCompleteEvent( + userOrder.getStore().getStoreId(), + items + ); +}이렇게 하면 이벤트 생성 로직을 분리하고 예외 처리를 통해 안정성을 높일 수 있습니다.
nowait-domain/domain-redis/src/main/java/com/nowait/domaincoreredis/rank/service/MenuCounterService.java (1)
9-11: 메서드 문서화와 매개변수 검증 개선을 고려해보세요.인터페이스 메서드에 대한 문서화와 매개변수 검증을 추가하면 사용성이 향상됩니다:
+import javax.validation.constraints.NotNull; +import javax.validation.constraints.Positive; + public interface MenuCounterService { + /** + * 메뉴 카운터를 증가시킵니다. + * + * @param menuId 메뉴 ID + * @param storeId 매장 ID + * @param qty 증가시킬 수량 + */ - void incrementMenuCounter(Long menuId, Long storeId, int qty); + void incrementMenuCounter(@NotNull Long menuId, @NotNull Long storeId, @Positive int qty); + /** + * 상위 N개 메뉴를 조회합니다. + * + * @param storeId 매장 ID + * @param topN 조회할 상위 개수 + * @return 상위 메뉴 목록 (점수 포함) + */ - Set<ZSetOperations.TypedTuple<String>> getTopMenus(Long storeId, int topN); + Set<ZSetOperations.TypedTuple<String>> getTopMenus(@NotNull Long storeId, @Positive int topN);nowait-domain/domain-redis/src/main/java/com/nowait/domaincoreredis/common/util/RedisKeyUtils.java (1)
33-35: 메서드 네이밍과 문서화 개선을 고려해보세요.새로운 유틸리티 메서드들이 기존 패턴과 일관되게 구현되었지만, 명확성을 위해 다음과 같은 개선을 고려해보세요:
+ /** + * 메뉴 인기도 키 포맷을 반환합니다. + * 포맷: "popular:{storeId}:{yyyyMMdd}" + */ - public static String buildMenuKey() { return KEY_FMT; } + public static String buildMenuRankKeyFormat() { return KEY_FMT; } + /** + * 메뉴 날짜 키용 날짜 포맷터를 반환합니다. + * 패턴: "yyyyMMdd" + */ - public static DateTimeFormatter buildMenuDateKey() { return DTF; } + public static DateTimeFormatter getMenuDateFormatter() { return DTF; }또한 DTF 상수명을 더 명확하게 변경하는 것도 고려해보세요:
- private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyyMMdd"); + private static final DateTimeFormatter MENU_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");nowait-domain/domain-redis/src/main/java/com/nowait/domaincoreredis/rank/listener/CookingCompleteListener.java (1)
21-30: 오류 처리 및 성능 최적화 검토 필요현재 구현에서
incrementMenuCounter호출 시 예외가 발생하면 후속 아이템 처리가 중단됩니다. 또한 아이템을 순차적으로 처리하는 것보다 배치 처리를 고려할 수 있습니다.예외 처리를 개선하고 성능을 최적화하는 방안을 제안합니다:
public void onCookingComplete(CookingCompleteEvent event) { Long storeId = event.getStoreId(); for (CookingCompleteEvent.Item item : event.getItems()) { - menuCounterService.incrementMenuCounter( - item.getMenuId(), - storeId, - item.getQuantity() - ); + try { + menuCounterService.incrementMenuCounter( + item.getMenuId(), + storeId, + item.getQuantity() + ); + } catch (Exception e) { + log.error("Failed to increment menu counter for menuId: {}, storeId: {}", + item.getMenuId(), storeId, e); + // 개별 아이템 실패가 전체 처리를 중단하지 않도록 함 + } } }nowait-event/build.gradle (1)
44-49: QueryDSL 의존성 문제 해결 필요TODO 주석에 언급된 Q클래스 생성 오류를 해결해야 합니다. 이벤트 모듈에서는 QueryDSL이 필요하지 않을 수 있습니다.
QueryDSL 의존성이 이벤트 모듈에 정말 필요한지 검토하고, 필요하다면 다음과 같이 수정할 수 있습니다:
-//QueryDsl -// TODO Q클래스 생성시 오류 발생 해결 필요 -implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' -annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta" -annotationProcessor "jakarta.annotation:jakarta.annotation-api" -annotationProcessor "jakarta.persistence:jakarta.persistence-api" +// 이벤트 모듈에서는 QueryDSL 불필요 - 제거 권장만약 QueryDSL이 필요하다면 별도 이슈로 Q클래스 생성 오류를 해결하는 작업을 진행하시겠습니까?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
nowait-app-admin-api/build.gradle(1 hunks)nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/order/service/OrderService.java(4 hunks)nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/statistic/controller/StatisticsController.java(3 hunks)nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/statistic/dto/PopularMenuDto.java(1 hunks)nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/statistic/dto/StoreRankingDto.java(1 hunks)nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/statistic/service/PopularMenuRedisService.java(1 hunks)nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/statistic/service/impl/PopularMenuRedisServiceImpl.java(1 hunks)nowait-domain/domain-redis/build.gradle(1 hunks)nowait-domain/domain-redis/src/main/java/com/nowait/domaincoreredis/common/util/RedisKeyUtils.java(2 hunks)nowait-domain/domain-redis/src/main/java/com/nowait/domaincoreredis/rank/listener/CookingCompleteListener.java(1 hunks)nowait-domain/domain-redis/src/main/java/com/nowait/domaincoreredis/rank/service/MenuCounterService.java(1 hunks)nowait-domain/domain-redis/src/main/java/com/nowait/domaincoreredis/rank/service/MenuCounterServiceImpl.java(1 hunks)nowait-event/build.gradle(1 hunks)nowait-event/src/main/java/com/nowait/nowaitevent/order/event/CookingCompleteEvent.java(1 hunks)settings.gradle(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/statistic/service/impl/PopularMenuRedisServiceImpl.java (1)
nowait-domain/domain-admin-rdb/src/main/java/com/nowait/domainadminrdb/statistic/exception/StatisticViewUnauthorizedException.java (1)
StatisticViewUnauthorizedException(5-9)
🔇 Additional comments (14)
nowait-app-admin-api/build.gradle (1)
25-25: 의존성 추가 승인새로운
nowait-event모듈에 대한 의존성 추가가 적절합니다. 이벤트 기반 아키텍처 구현을 위해 필요한 변경사항입니다.nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/statistic/dto/StoreRankingDto.java (1)
7-7: 코드 포맷팅 개선 승인타입과 변수명 사이의 불필요한 공백이 제거되어 코드 가독성이 향상되었습니다.
Also applies to: 9-9, 12-12
settings.gradle (1)
10-10: 새 모듈 포함 승인
nowait-event모듈이 프로젝트에 적절히 추가되었습니다. 이벤트 기반 아키텍처 구현을 위한 필수 변경사항입니다.nowait-domain/domain-redis/build.gradle (1)
25-25: 이벤트 모듈 의존성 추가 승인
nowait-event모듈에 대한 의존성 추가가 적절합니다. 이를 통해 도메인 Redis 모듈에서 이벤트 리스너를 구현할 수 있습니다.nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/statistic/dto/PopularMenuDto.java (1)
1-12: 인기 메뉴 DTO 구조가 잘 설계되었습니다.클래스 구조와 Lombok 어노테이션 사용이 적절하며, 필드 타입도 올바르게 정의되었습니다.
nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/order/service/OrderService.java (2)
6-6: ApplicationEventPublisher 의존성 추가가 적절합니다.이벤트 기반 아키텍처를 위한 의존성 주입이 올바르게 구현되었습니다.
39-39: 이벤트 퍼블리셔 필드 추가가 적절합니다.ApplicationEventPublisher를 통한 이벤트 발행 구조가 잘 설계되었습니다.
nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/statistic/controller/StatisticsController.java (4)
13-13: PopularMenuDto import가 적절합니다.새로운 DTO 클래스 import가 올바르게 추가되었습니다.
15-15: PopularMenuRedisService import가 적절합니다.새로운 서비스 인터페이스 import가 올바르게 추가되었습니다.
34-34: PopularMenuRedisService 의존성 주입이 적절합니다.새로운 서비스 의존성이 올바르게 주입되었습니다.
65-79: 인기 메뉴 조회 엔드포인트가 잘 구현되었습니다.새로운
/popular-menu엔드포인트가 기존 패턴과 일관되게 구현되었습니다. Swagger 문서화와 응답 구조가 적절합니다.nowait-domain/domain-redis/src/main/java/com/nowait/domaincoreredis/rank/service/MenuCounterService.java (1)
1-12: MenuCounterService 인터페이스 설계가 적절합니다.Redis 기반 메뉴 카운터 서비스 인터페이스가 명확하고 간결하게 설계되었습니다.
nowait-domain/domain-redis/src/main/java/com/nowait/domaincoreredis/common/util/RedisKeyUtils.java (2)
3-3: DateTimeFormatter import가 적절합니다.새로운 날짜 포맷 기능을 위한 import가 올바르게 추가되었습니다.
12-14: 메뉴 랭킹 키 상수들이 적절합니다.메뉴 인기도 추적을 위한 Redis 키 포맷과 날짜 포맷터가 잘 정의되었습니다.
nowait-event/src/main/java/com/nowait/nowaitevent/order/event/CookingCompleteEvent.java
Show resolved
Hide resolved
...ain/java/com/nowait/applicationadmin/statistic/service/impl/PopularMenuRedisServiceImpl.java
Show resolved
Hide resolved
...ain/java/com/nowait/applicationadmin/statistic/service/impl/PopularMenuRedisServiceImpl.java
Show resolved
Hide resolved
...main-redis/src/main/java/com/nowait/domaincoreredis/rank/service/MenuCounterServiceImpl.java
Outdated
Show resolved
Hide resolved
...main-redis/src/main/java/com/nowait/domaincoreredis/rank/service/MenuCounterServiceImpl.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/statistic/service/impl/PopularMenuRedisServiceImpl.java(1 hunks)nowait-common/src/main/java/com/nowait/common/exception/ErrorMessage.java(1 hunks)nowait-domain/domain-redis/src/main/java/com/nowait/domaincoreredis/rank/exception/MenuCounterUpdateException.java(1 hunks)nowait-domain/domain-redis/src/main/java/com/nowait/domaincoreredis/rank/service/MenuCounterServiceImpl.java(1 hunks)nowait-event/build.gradle(1 hunks)nowait-event/src/main/java/com/nowait/nowaitevent/order/event/CookingCompleteEvent.java(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- nowait-common/src/main/java/com/nowait/common/exception/ErrorMessage.java
🚧 Files skipped from review as they are similar to previous changes (4)
- nowait-app-admin-api/src/main/java/com/nowait/applicationadmin/statistic/service/impl/PopularMenuRedisServiceImpl.java
- nowait-event/build.gradle
- nowait-domain/domain-redis/src/main/java/com/nowait/domaincoreredis/rank/service/MenuCounterServiceImpl.java
- nowait-event/src/main/java/com/nowait/nowaitevent/order/event/CookingCompleteEvent.java
작업 요약
Issue Link
#108
문제점 및 어려움
해결 방안
Reference
Summary by CodeRabbit
신규 기능
문서화
기타