Skip to content

Fix/398 거래시작 위시리스트 알림 - #399

Merged
jung32111 merged 1 commit into
developfrom
fix/398-거래시작-위시리스트-알림
Aug 13, 2026

Hidden character warning

The head ref may contain hidden characters: "fix/398-\uac70\ub798\uc2dc\uc791-\uc704\uc2dc\ub9ac\uc2a4\ud2b8-\uc54c\ub9bc"
Merged

Fix/398 거래시작 위시리스트 알림#399
jung32111 merged 1 commit into
developfrom
fix/398-거래시작-위시리스트-알림

Conversation

@jung32111

Copy link
Copy Markdown
Collaborator

🔗 관련 이슈
#398

📌 작업 내용
상품 거래 시작 시 위시리스트 사용자에게 PRODUCT_TRADING_STARTED 알림 발송
NotificationType에 PRODUCT_TRADING_STARTED 추가
NotificationFactory에 거래 시작 알림 생성 메서드 추가
ProductService에 기존 위시 알림 로직을 재사용하는 notifyWishersTradingStarted() 메서드 추가
구매 요청 수락으로 TRADING 전환 시 위시리스트 알림 발송
거래를 수락받은 구매자 본인은 위시리스트 알림 수신 대상에서 제외
notifications.type CHECK 제약에 PRODUCT_TRADING_STARTED 추가를 위한 V28 마이그레이션 추가
거래 수락 및 위시리스트 알림 관련 단위 테스트 추가

📌 변경된 API
외부 API 변경 없음


✅ 체크리스트

  • 기능 요구사항을 충족했는가?
  • API 응답 형식이 통일되어 있는가?
  • 예외 상황이 적절히 처리되었는가?
  • 인증/인가 검증이 누락되지 않았는가?
  • Entity를 직접 응답하지 않았는가?
  • 중복 코드가 과도하지 않은가?
  • 메서드와 클래스의 역할이 명확한가?
  • 테스트가 필요한 핵심 로직에 테스트가 작성되었는가?

@github-actions

Copy link
Copy Markdown

Gemini 파일 단위 요약 리뷰

src/main/java/com/tenure/domain/notification/service/NotificationFactory.java

변경 요약

  • 관심 등록된 아이템의 거래가 시작되었을 때 발송할 알림 객체(Notification)를 생성하는 팩토리 메서드 productTradingStarted가 추가되었습니다.

영향 범위

  • 기능: 관심 아이템 거래 시작 알림 발송 기능
  • 계층 및 흐름: 알림 도메인 서비스 계층(NotificationFactory)에 추가되어, 향후 거래 시작 관련 비즈니스 로직(Service 계층)에서 호출되어 사용될 예정입니다.

확인 필요

  • NotificationType.PRODUCT_TRADING_STARTED 상수가 NotificationType Enum 클래스에 정의되어 있는지 확인이 필요합니다. (DB에 해당 타입을 저장하는 경우, Flyway 마이그레이션 스크립트 반영 여부도 함께 확인해야 합니다.)

제안

  • 없음

src/main/java/com/tenure/domain/product/service/ProductService.java

변경 요약

  • 특정 사용자(excludeUserId)를 제외하고 아이템 위시 등록 사용자들에게 거래 시작 알림을 보낼 수 있는 notifyWishersTradingStarted 메서드가 추가되었습니다.
  • 기존의 notifyWishedUsers 메서드가 excludeUserId 매개변수를 지원하도록 오버로딩되었으며, 필터링 후 알림 목록이 비어있을 때 조기 리턴(Early Return)하는 로직이 추가되었습니다.

영향 범위

  • 기능: 상품 거래 시작 시 위시 등록 사용자에 대한 알림 발송 기능
  • 계층 및 실행 흐름: ProductService 비즈니스 로직 계층 내 알림 생성 및 NotificationService 저장 흐름

확인 필요

  • 트랜잭션 전파 및 외부 시스템 연동 분리: notifyWishersTradingStarted@Transactional이 적용되어 있습니다. 알림 발송/저장 로직이 핵심 거래 트랜잭션 내에서 동기적으로 처리될 경우, 알림 처리 지연이 핵심 비즈니스(거래 시작) 트랜잭션에 영향을 줄 수 있습니다. 향후 알림 저장 및 발송 로직은 비동기(Event Listener 등)로 분리하는 설계가 고려되었는지 확인이 필요합니다.

제안

  • 스트림 가독성 개선: notifyWishedUsers 내 필터 조건인 receiver -> excludeUserId == null || !receiver.getId().equals(excludeUserId) 부분을 User 도메인 객체 내부 메서드(예: isSameUser(Long userId))를 활용하여 가독성을 높이는 것을 제안합니다.
  • Repository 반환 타입 확인: wishRepository.findNotificationReceiversByItemId가 Null을 반환할 가능성이 없다면(일반적인 Spring Data JPA는 빈 컬렉션을 반환함), receivers == null 검증을 제거하여 코드를 간결하게 유지할 수 있습니다.

src/main/java/com/tenure/domain/trade/service/PurchaseIntentAcceptService.java

변경 요약

  • ItemRepository.findByIdForUpdate 호출 결과를 Item item 지역 변수로 바인딩하도록 변경
  • ProductService 의존성을 주입받아, 구매 제안 수락 프로세스 마지막 단계에 위시 유저 대상 거래 시작 알림 발송 로직(productService.notifyWishersTradingStarted) 추가

영향 범위

  • 구매 제안 수락 API: 구매 제안이 수락되는 과정에서 위시리스트에 등록한 사용자들에게 실시간 또는 배치성 알림이 발송되는 흐름이 추가됨
  • 트랜잭션 및 DB 커넥션 유지: 알림 발송 로직이 데이터베이스 트랜잭션 및 비관적 락(ForUpdate) 범위 안에서 실행되도록 흐름이 변경됨

확인 필요

  • 외부 연동 및 알림 처리 시 트랜잭션/락 점유 지연 리스크: notifyWishersTradingStarted가 동기(Synchronous) 방식으로 동작하거나 외부 알림 플랫폼 API(FCM, Alimtalk 등)를 호출하는 경우, 알림 전송이 완료될 때까지 findByIdForUpdate로 획득한 DB Row 락과 커넥션이 유지됩니다. 이는 동시 요청이 많을 때 커넥션 풀 고갈 및 데드락 위험을 높입니다.
  • 예외 발생 시 롤백 정합성: 주석에 언급된 것처럼 noRollbackFor = CustomException 설정이 있더라도, DB Commit 시점의 제약 조건 위반이나 기타 RuntimeException으로 인해 최종 롤백이 발생할 가능성이 있습니다. 이 경우 알림은 이미 발송되었으나 실제 거래 데이터는 롤백되는 정합성 불일치 문제가 발생할 수 있습니다.

제안

  • 이벤트 기반 비동기 알림 처리 적용: 비즈니스 로직과 알림 도메인의 결합도를 낮추고 트랜잭션 대기 시간을 줄이기 위해 Spring의 ApplicationEventPublisher를 사용하는 방향을 제안합니다.
    • 구매 제안 수락 완료 시 TradingStartedEvent를 발행합니다.
    • 알림 리스너에서 @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)@Async를 적용하여, 트랜잭션이 최종 커밋된 직후 비동기로 알림이 발송되도록 구현하면 DB 락 점유 시간을 줄이고 알림 실패가 비즈니스 트랜잭션에 영향을 주지 않도록 격리할 수 있습니다.

src/main/resources/db/migration/V28__add_product_trading_started_to_notification_type.sql

변경 요약

  • notifications 테이블의 기존 ck_notifications_type CHECK 제약 조건을 삭제하고 재설정
  • 허용되는 알림 타입 목록에 'PRODUCT_TRADING_STARTED' 값을 새로 추가

영향 범위

  • 데이터베이스 계층: notifications 테이블의 type 필드에 'PRODUCT_TRADING_STARTED' 문자열 저장이 가능해짐
  • 알림 기능 흐름: 상품 거래가 시작되는 시점에 알림을 생성하고 DB에 정상적으로 저장할 수 있는 실행 흐름 지원

확인 필요

  • Enum 클래스 동기화: Java 코드 내 NotificationType Enum 클래스에 PRODUCT_TRADING_STARTED 상수가 누락 없이 추가되어 있는지 확인이 필요합니다. 코드가 동기화되지 않은 경우 JPA 저장이나 조회 시 예외가 발생할 수 있습니다.
  • 기존 데이터 정합성: PostgreSQL은 ADD CONSTRAINT ... CHECK 실행 시 테이블 내 기존 데이터를 모두 검증합니다. 현재 타겟 DB(테스트/스테이징 등)의 notifications 테이블에 이번 CHECK 제약 조건 목록에 명시되지 않은 과거의 알림 타입 데이터가 남아 있다면 마이그레이션이 실패할 수 있으므로 사전 확인이 필요합니다.

제안

  • 제약 조건 관리 방식 개선 제안: 알림 타입이 추가될 때마다 매번 DDL 변경(DROP & ADD CONSTRAINT) 마이그레이션 파일을 생성해야 하는 번거로움이 있습니다. 데이터베이스 수준의 엄격한 제약이 필수적이지 않다면, DB 컬럼은 일반 VARCHAR로 유지하고 애플리케이션 계층(Spring Boot/JPA Enum)에서 검증을 전담하도록 단순화하는 방안을 제안합니다.

src/test/java/com/tenure/domain/product/service/ProductServiceTest.java

변경 요약

  • 거래 시작 시 위시리스트 등록 사용자들에게 알림을 발송하는 ProductService.notifyWishersTradingStarted 메서드에 대한 단위 테스트 2건이 추가되었습니다.
  • 알림 수신 대상 중 구매자(Buyer)를 제외한 나머지 사용자들에게만 PRODUCT_TRADING_STARTED 타입의 알림이 생성 및 저장되는지 검증하는 테스트가 추가되었습니다.
  • 알림 수신 대상이 없을 경우 알림 저장 로직(notificationService.saveAll)이 호출되지 않고 조기 종료되는지 검증하는 테스트가 추가되었습니다.

영향 범위

  • 테스트 계층: ProductServiceTest 클래스 내 테스트 커버리지가 확대되었습니다.
  • 기능 흐름: 거래 시작 시점의 알림 발송 흐름(구매자 필터링, 빈 수신자 목록 처리)에 대한 비즈니스 규칙 검증이 강화되었습니다.

확인 필요

  • buyerId Null 가능성 검증: notifyWishersTradingStarted(item, 70L) 호출 시, 비즈니스 흐름상 buyerIdnull로 넘어올 수 있는 예외적인 시나리오가 존재하는지 확인이 필요합니다. 만약 buyerIdnull이 될 수 있다면 프로덕션 코드에서 NPE(NullPointerException)가 발생할 수 있으므로, 이에 대한 Null safe 처리와 buyerIdnull일 때의 테스트 케이스 추가를 검토해야 합니다.

제안

  • @Captor 어노테이션 활용: ArgumentCaptor.forClass(List.class) 사용으로 인한 타입 캐스팅 경고와 @SuppressWarnings("unchecked") 사용을 피하기 위해, Mockito에서 제공하는 @Captor 어노테이션을 테스트 클래스 필드 레벨에 선언하여 사용하는 방식을 권장합니다.
    @Captor
    private ArgumentCaptor<List<Notification>> notificationListCaptor;

src/test/java/com/tenure/domain/trade/service/PurchaseIntentAcceptServiceTest.java

변경 요약

  • PurchaseIntentAcceptServiceProductService 의존성이 추가됨에 따라, 테스트 코드 내 Mock 객체 생성 및 생성자 주입 코드 수정
  • 구매 제안 수락 성공 시, 구매자를 제외한 위시 등록 사용자들에게 거래 시작 알림이 전송되는지 검증하는 신규 테스트 케이스 추가
  • 상품 상태가 판매 중이 아니어서 수락이 실패할 때, 알림 발송 메서드가 호출되지 않는지(never()) 검증하는 로직을 기존 예외 테스트에 추가

영향 범위

  • 기능: 구매 제안 수락 시 연관된 위시 등록자 대상 알림 전송 기능 흐름
  • 계층: 서비스 계층(Service Layer)의 단위 테스트 및 의존성 구성
  • 실행 흐름: PurchaseIntentAcceptService.acceptPurchaseIntent() 실행 시 조건 충족 여부에 따른 ProductService.notifyWishersTradingStarted() 호출 여부

확인 필요

  • 순환 참조(Circular Dependency) 리스크: PurchaseIntentAcceptServiceProductService를 의존하게 되었습니다. 만약 ProductService 혹은 ProductService가 의존하는 다른 컴포넌트가 PurchaseIntentAcceptService를 간접적으로라도 의존하고 있다면 순환 참조가 발생할 수 있으므로, 실제 빈(Bean) 등록 및 의존성 관계 확인이 필요합니다.

제안

  • 테스트 격리 및 중복 코드 개선: 각 테스트 메서드마다 setUpService()를 수동으로 호출하고 있습니다. JUnit의 @BeforeEach를 활용하여 Mockito 초기화와 서비스 인스턴스 생성을 생성을 공통 분리하면 테스트 메서드 내부의 중복 코드를 줄일 수 있습니다. (다만, 기존 테스트 코드 스타일을 유지해야 하는 상황이라면 무시해도 무방합니다.)

@jung32111
jung32111 merged commit 3810922 into develop Aug 13, 2026
2 checks passed
@jung32111
jung32111 deleted the fix/398-거래시작-위시리스트-알림 branch August 13, 2026 02:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants