Skip to content

[REFACTOR] 팔로우 알림 이벤트 방식으로 변경#200

Merged
Be-HinD merged 1 commit intomainfrom
refactor/noti-follow
Jan 2, 2026
Merged

[REFACTOR] 팔로우 알림 이벤트 방식으로 변경#200
Be-HinD merged 1 commit intomainfrom
refactor/noti-follow

Conversation

@Be-HinD
Copy link
Member

@Be-HinD Be-HinD commented Jan 2, 2026

📝 Pull Request

📌 PR 종류

해당하는 항목에 체크해주세요.

  • 기능 추가 (Feature)
  • 버그 수정 (Fix)
  • 문서 수정 (Docs)
  • 코드 리팩터링 (Refactor)
  • 테스트 추가 (Test)
  • 기타 변경 (Chore)

✨ 변경 내용

  • 기존 팔로우 알림이 Service 트랜잭션 -> 이벤트 기반 분리된 트랜잭션으로 변경되었습니다.

  • UserSummary 이너 클래스 분리하여 팔로우 도메인에서 재활용가능하도록 조치하였습니다.


🔍 관련 이슈

해당 PR이 해결하는 이슈가 있다면 연결해주세요.


🧪 테스트

변경된 기능에 대한 테스트 범위 또는 테스트 결과를 작성해주세요.

  • 유닛 테스트 추가 / 수정
  • 통합 테스트 검증
  • 수동 테스트 완료

프론트 통합 테스트 진행 예정

🚨 확인해야 할 사항 (Checklist)

PR을 제출하기 전에 아래 항목들을 확인해주세요.

  • 코드 포매팅 완료
  • 불필요한 파일/코드 제거
  • 로직 검증 완료
  • 프로젝트 빌드 성공
  • 린트/정적 분석 통과 (해당 시)

🙋 기타 참고 사항

리뷰어가 참고하면 좋을 만한 추가 설명이 있다면 적어주세요.

Summary by CodeRabbit

릴리스 노트

  • New Features

    • 팔로우 알림 기능 추가
  • Refactor

    • 팔로우 알림 시스템을 이벤트 기반 아키텍처로 개선하여 더욱 안정적이고 신뢰성 있는 알림 전송 구현
    • 응답 데이터 구조 개선으로 코드 재사용성 향상

✏️ Tip: You can customize this high-level summary in your review settings.

@Be-HinD Be-HinD self-assigned this Jan 2, 2026
@Be-HinD Be-HinD added the ✨enhancement New feature or request label Jan 2, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 2, 2026

개요

팔로우 알림 기능을 이벤트 기반 아키텍처로 리팩토링했습니다. FollowService에서 직접 알림을 생성하는 대신 FollowEvent를 발행하고, FollowEventListener가 이를 수신하여 NotificationDispatcher를 통해 알림을 처리합니다. 또한 UserSummary를 내부 클래스에서 독립적인 DTO로 추출했습니다.

변경 사항

응집 / 파일(들) 변경 요약
이벤트 기반 알림 아키텍처
src/main/java/team/wego/wegobackend/user/application/FollowService.java, src/main/java/team/wego/wegobackend/user/application/event/FollowEvent.java, src/main/java/team/wego/wegobackend/user/application/listener/FollowEventListener.java
팔로우 발생 시 ApplicationEventPublisher를 통해 FollowEvent를 발행하는 방식으로 변경. FollowEventListener가 트랜잭션 커밋 후 이벤트를 수신하여 NotificationDispatcher에 위임
팔로우 알림 디스패처
src/main/java/team/wego/wegobackend/notification/application/dispatcher/NotificationDispatcher.java
팔로우 타입 알림을 생성·저장하고 SSE를 통해 전송하는 새로운 dispatch(User follower, User follow) 메서드 추가
팔로우 알림 응답 DTO
src/main/java/team/wego/wegobackend/notification/application/dto/response/NotificationFollowResponse.java
팔로우 알림 데이터(id, user summary, type, timestamps, message)를 캡슐화하는 새로운 DTO 클래스 추가
UserSummary 추출
src/main/java/team/wego/wegobackend/notification/application/dto/response/NotificationItemResponse.java, src/main/java/team/wego/wegobackend/notification/application/dto/response/UserSummary.java
NotificationItemResponse의 내부 클래스 UserSummary를 제거하고 독립적인 DTO 클래스로 추출·재사용

시퀀스 다이어그램

sequenceDiagram
    participant FollowService as FollowService
    participant EventPublisher as ApplicationEventPublisher
    participant FollowEventListener as FollowEventListener
    participant NotificationDispatcher as NotificationDispatcher
    participant NotificationRepository as NotificationRepository
    participant SseEmitterService as SseEmitterService

    FollowService->>FollowService: follow(follower, follow)
    FollowService->>EventPublisher: publishEvent(FollowEvent)
    Note over EventPublisher: Transaction commit 대기
    
    EventPublisher->>FollowEventListener: handleFollowEvent(FollowEvent)<br/>(AFTER_COMMIT phase)
    FollowEventListener->>NotificationDispatcher: dispatch(follower, follow)
    
    NotificationDispatcher->>NotificationDispatcher: createFollowNotification(follow, follower)
    NotificationDispatcher->>NotificationRepository: save(notification)
    NotificationDispatcher->>SseEmitterService: sendNotification(NotificationFollowResponse)
    SseEmitterService-->>SseEmitterService: SSE 전송 완료
Loading

예상 코드 리뷰 난이도

🎯 3 (보통) | ⏱️ ~25분

관련될 수 있는 PR

🐰 팔로우의 기쁜 소식이 이제 이벤트를 탄다네,
리스너가 귀 쫑긋 귀울며 알림을 챙기고,
디스패처는 묵묵히 메시지를 전하리,
사용자 정보는 이제 새집에 살게 되어,
코드는 더욱 깔끔하고 우아하게~ ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 변경 사항의 주요 내용을 정확하게 설명하고 있습니다. 팔로우 알림을 이벤트 방식으로 변경한다는 내용이 명확하게 전달됩니다.
✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 00e6acc and d7a06fb.

📒 Files selected for processing (7)
  • src/main/java/team/wego/wegobackend/notification/application/dispatcher/NotificationDispatcher.java
  • src/main/java/team/wego/wegobackend/notification/application/dto/response/NotificationFollowResponse.java
  • src/main/java/team/wego/wegobackend/notification/application/dto/response/NotificationItemResponse.java
  • src/main/java/team/wego/wegobackend/notification/application/dto/response/UserSummary.java
  • src/main/java/team/wego/wegobackend/user/application/FollowService.java
  • src/main/java/team/wego/wegobackend/user/application/event/FollowEvent.java
  • src/main/java/team/wego/wegobackend/user/application/listener/FollowEventListener.java
💤 Files with no reviewable changes (1)
  • src/main/java/team/wego/wegobackend/notification/application/dto/response/NotificationItemResponse.java
🧰 Additional context used
🧬 Code graph analysis (1)
src/main/java/team/wego/wegobackend/notification/application/dto/response/UserSummary.java (2)
src/main/java/team/wego/wegobackend/notification/application/dto/response/NotificationFollowResponse.java (1)
  • Getter (8-30)
src/main/java/team/wego/wegobackend/notification/application/dto/response/NotificationItemResponse.java (2)
  • Getter (12-98)
  • Getter (30-40)
🔇 Additional comments (6)
src/main/java/team/wego/wegobackend/user/application/event/FollowEvent.java (1)

5-7: 이벤트 레코드 구조가 적절합니다.

팔로우 이벤트를 표현하는 간단하고 명확한 레코드입니다. 불변 객체로 설계되어 이벤트의 안정성이 보장됩니다.

src/main/java/team/wego/wegobackend/user/application/FollowService.java (2)

41-41: 이벤트 발행을 위한 의존성이 올바르게 주입되었습니다.

ApplicationEventPublisher가 적절하게 추가되어 이벤트 기반 아키텍처를 지원합니다.


66-67: 이벤트 리스너 설정이 올바르게 구성되어 있습니다.

FollowEventListener의 handleFollowEvent 메서드가 @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)으로 정확하게 구성되어 있어, 팔로우 트랜잭션 커밋 후에만 알림이 발송됩니다. 이벤트 발행을 통한 리팩토링으로 팔로우 서비스의 책임이 명확해졌으며, 동시성 문제를 효과적으로 방지하고 있습니다.

src/main/java/team/wego/wegobackend/notification/application/dto/response/UserSummary.java (1)

6-13: 내부 클래스를 독립적인 DTO로 적절하게 추출했습니다.

UserSummary를 별도 클래스로 분리하여 팔로우 도메인에서 재사용할 수 있게 되었습니다. 불변 객체로 설계되어 있고 구조가 명확합니다.

src/main/java/team/wego/wegobackend/notification/application/dto/response/NotificationFollowResponse.java (1)

8-30: 팔로우 알림을 위한 응답 DTO가 적절하게 구현되었습니다.

NotificationFollowResponse는 팔로우 알림에 필요한 데이터를 명확하게 표현하고 있으며, 추출된 UserSummary를 활용하여 일관성을 유지합니다. NotificationTypeMapper를 통한 타입 변환도 기존 패턴을 따르고 있습니다.

src/main/java/team/wego/wegobackend/user/application/listener/FollowEventListener.java (1)

16-21: dispatch() 메서드에 이미 @Transactional 주석이 있습니다

검증 결과, NotificationDispatcher.dispatch(User follower, User follow) 메서드는 @Transactional 어노테이션으로 이미 표시되어 있으므로 트랜잭션 경계는 올바르게 처리됩니다. AFTER_COMMIT 단계 이후에도 새로운 트랜잭션 컨텍스트가 생성되어 알림 영속화가 안전합니다.

다만, 코드 일관성 측면에서 개선 가능한 부분이 있습니다. 같은 클래스의 다른 dispatch() 메서드들은 SSE 발송 결과를 확인하여 로깅하지만(boolean ok = sseEmitterService.sendNotificationIfConnected(...)), 팔로우 알림 발송 메서드는 반환값을 확인하지 않습니다. SSE 발송 실패를 명시적으로 처리하도록 일관성을 맞추는 것이 좋습니다.

Comment on lines +97 to +110
@Transactional
public void dispatch(
User follower,
User follow
) {

Notification notification = Notification.createFollowNotification(follow, follower);

notificationRepository.save(notification);


sseEmitterService.sendNotificationIfConnected(follow.getId(), new NotificationFollowResponse(notification, follower));

}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

트랜잭션 전파 설정이 기존 메서드와 일관되지 않습니다.

기존의 다른 dispatch 메서드들(26-61, 63-95번 줄)은 모두 @Transactional(propagation = Propagation.REQUIRES_NEW)를 사용하여 독립적인 트랜잭션에서 알림을 저장합니다.

새로 추가된 메서드가 기본 전파 설정(REQUIRED)을 사용하면 호출자의 트랜잭션에 참여하게 되어, 호출 컨텍스트에 따라 예상치 못한 동작이 발생할 수 있습니다. 이벤트 리스너가 AFTER_COMMIT으로 설정되어 있더라도, 일관성을 위해 동일한 전파 설정을 사용하는 것이 좋습니다.

🔎 일관된 트랜잭션 전파 설정 적용
-    @Transactional
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
     public void dispatch(
         User follower,
         User follow
     ) {
📝 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
@Transactional
public void dispatch(
User follower,
User follow
) {
Notification notification = Notification.createFollowNotification(follow, follower);
notificationRepository.save(notification);
sseEmitterService.sendNotificationIfConnected(follow.getId(), new NotificationFollowResponse(notification, follower));
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void dispatch(
User follower,
User follow
) {
Notification notification = Notification.createFollowNotification(follow, follower);
notificationRepository.save(notification);
sseEmitterService.sendNotificationIfConnected(follow.getId(), new NotificationFollowResponse(notification, follower));
}
🤖 Prompt for AI Agents
In
src/main/java/team/wego/wegobackend/notification/application/dispatcher/NotificationDispatcher.java
around lines 97 to 110, the dispatch method uses the default @Transactional
(REQUIRED) whereas the other dispatch methods (lines 26-61 and 63-95) use
@Transactional(propagation = Propagation.REQUIRES_NEW); update this method to
use @Transactional(propagation = Propagation.REQUIRES_NEW) so notification save
runs in an independent transaction consistent with the other methods, and ensure
the appropriate Propagation import is present.

@Be-HinD Be-HinD merged commit 7b87491 into main Jan 2, 2026
1 check passed
@Be-HinD Be-HinD deleted the refactor/noti-follow branch January 2, 2026 10:29
@github-project-automation github-project-automation bot moved this from Backlog to Done in WeGo-Together Backend Jan 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant