Skip to content

[Feat/#115] 행사·사물함·공지 즉시 알림 발송 - #120

Open
tnals0924 wants to merge 5 commits into
feat/#114-notification-dispatchfrom
feat/#115-instant-notifications
Open

tnals0924 wants to merge 5 commits into
feat/#114-notification-dispatchfrom
feat/#115-instant-notifications

Conversation

@tnals0924

Copy link
Copy Markdown
Member

#️⃣연관된 이슈

🎯 해결하려는 문제가 무엇인가요?

사용자 행동 직후에 가는 즉시 알림 4종을 실제로 보냅니다. 이 PR부터 아웃박스 → 릴레이 → 리스너 → 발송이 한 줄로 이어집니다.

알림 트리거 수신자 이벤트
행사 신청 접수 EventApplicationServiceImpl.apply 신청자 EventApplied
행사 신청 취소 EventApplicationServiceImpl.cancelApplication 신청자 EventApplicationCanceled
사물함 배정 완료 LockerApplicationServiceImpl.apply 신청자 LockerAssigned
새 공지 등록 NoticeServiceImpl.create 활성 회원 전체 NoticeCreated

❓ 왜 해결해야 하나요?

#117(아웃박스)과 #118(발송 공통 처리)만으로는 이벤트를 기록하는 곳과 받는 곳이 없어 알림이 나가지 않습니다.

⭐ 어떻게 해결했나요?

  • 이벤트 (core:common common.event): 위 4종을 DomainEvent를 구현한 record로 추가했습니다. ID와 원시값만 담고, 행사명은 알림 문구에 쓰려고 발행 시점 값을 싣습니다(리스너가 event 모듈을 조회할 수 없어서).
  • 기록: 각 서비스가 OutboxWriter를 주입받아 저장 직후 같은 트랜잭션에서 이벤트를 기록합니다. 신청이 롤백되면 알림 기록도 함께 사라집니다.
    • NoticeServiceImpl.create에는 지금까지 @Transactional이 없었습니다(저장은 Spring Data save의 트랜잭션에만 의존). 공지 저장과 이벤트 기록이 함께 커밋되도록 @Transactional을 붙였습니다. OutboxWriter는 트랜잭션 밖에서 부르면 실패합니다.
  • 리스너 (NotificationEventListener, member notification/service/impl): 이벤트마다 NotificationType과 수신자를 정해 NotificationDispatcher를 부릅니다. 이동 대상 ID는 행사 → eventId, 사물함 → lockerPeriodId, 공지 → noticeId입니다.
  • 기존 테스트 수정: LockerApplicationServiceImplTest가 서비스 생성자를 직접 호출해서, 아무것도 하지 않는 OutboxWriter(event -> {})를 넘기도록 한 줄 고쳤습니다.

🧩 이 PR의 한계 & 트레이드오프

  • 빌릴게 대여·반납 신청 알림 없음: 문구("관리자가 확인할 때까지 기다려 주세요")가 지금 흐름(운영진 확인 단계 없음)과 맞지 않아 운영진 승인 흐름을 만들 때 붙이기로 했습니다.
  • 열린피드백 답변 알림 없음: 답변 등록 기능이 아직 없습니다.
  • 알림 지연: 릴레이 폴링 간격(최대 약 1초)만큼 늦게 갑니다.
  • 로컬 검증 범위: 컴파일과 전체 단위 테스트, ModularityTests·DomainImplAccessTests까지 확인했습니다. 로컬에 DB와 Docker가 없어 아웃박스부터 FCM까지 실제로 흐르는지는 확인하지 못했습니다. 이 스택에서 처음으로 끝까지 이어지는 PR이라 dev에서 아래를 확인해야 합니다.
    • PUSH_TYPE=log로 행사 신청 → outbox_events가 PUBLISHED가 되는지, notifications에 행이 생기는지, "푸시 발송(로그 모드)" 로그가 찍히는지
    • 알림 설정에서 행사 알림을 끄면 알림함 행은 생기고 푸시 로그는 없는지
    • 새 공지 등록 시 활성 회원 수만큼 알림함 행이 생기는지

⛓️ 기존 기능에 미치는 영향

  • 행사 신청·취소, 사물함 신청, 공지 등록 트랜잭션에 outbox_events INSERT가 한 건씩 늘어납니다. 응답과 API 형식은 그대로입니다.
  • 공지 등록이 이제 서비스 트랜잭션 안에서 실행됩니다. AdminNoticeWriteUseCase의 "파일 확인과 공지 저장을 한 트랜잭션으로 묶지 않는다"는 의도는 그대로입니다(UseCase에는 트랜잭션이 없음).

🔀 Edge Case & 실패 시나리오

상황 동작
신청 중 예외로 롤백 아웃박스 행도 롤백, 알림 없음
행사 신청 후 같은 행사 재신청(취소 후) 신청할 때마다 알림
알림 설정에서 해당 카테고리를 끈 회원 알림함 저장, 푸시 없음
토큰이 없거나 가입을 마치지 않은 회원 알림함 저장, 푸시 없음
리스너(알림함 저장) 실패 릴레이가 다시 발행, 5회 실패면 FAILED

📋 검토한 대안과 선택 이유

  • 컨트롤러나 UseCase에서 이벤트 기록: 기록이 비즈니스 쓰기와 같은 트랜잭션에 있어야 하는데, 행사·사물함 컨트롤러는 트랜잭션 없이 서비스를 부릅니다. 서비스 안에서 기록했습니다.
  • 리스너를 이벤트마다 클래스로 분리: 지금은 한 줄짜리 매핑 4개라 한 클래스에 모았습니다. #116에서 6개가 더 붙습니다.

💬 리뷰 포인트

  • NoticeServiceImpl.create에 @Transactional을 붙인 것
  • 이벤트에 행사명을 실은 것 (발행 시점 이름으로 알림이 감)

@tnals0924 tnals0924 self-assigned this Oct 14, 2026
@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 59 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: billilge/stream-server/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d8739a34-f2d4-46f1-99c3-ae019beb71bc
📥 Commits

Reviewing files that changed from the base of the PR and between a5c9eb5 and 60cb33b.

📒 Files selected for processing: 9
  • core/common/src/main/java/kr/ac/kookmin/stream/common/event/EventApplicationCanceled.java
  • core/common/src/main/java/kr/ac/kookmin/stream/common/event/EventApplied.java
  • core/common/src/main/java/kr/ac/kookmin/stream/common/event/LockerAssigned.java
  • core/common/src/main/java/kr/ac/kookmin/stream/common/event/NoticeCreated.java
  • core/domain/event/src/main/java/kr/ac/kookmin/stream/event/domain/event/service/impl/EventApplicationServiceImpl.java
  • core/domain/event/src/main/java/kr/ac/kookmin/stream/event/domain/locker/service/impl/LockerApplicationServiceImpl.java
  • core/domain/event/src/test/java/kr/ac/kookmin/stream/event/domain/locker/service/impl/LockerApplicationServiceImplTest.java
  • core/domain/member/src/main/java/kr/ac/kookmin/stream/member/domain/notification/service/impl/NotificationEventListener.java
  • core/domain/welfare/src/main/java/kr/ac/kookmin/stream/welfare/domain/notice/service/impl/NoticeServiceImpl.java
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

행사·사물함·공지 즉시 알림 발송

1 participant