Skip to content

feat(notify): FCM 기반 푸시 알림 기능 구현#116

Open
coldsunn wants to merge 13 commits intodevelopfrom
feat/fcm-basic-infra
Open

feat(notify): FCM 기반 푸시 알림 기능 구현#116
coldsunn wants to merge 13 commits intodevelopfrom
feat/fcm-basic-infra

Conversation

@coldsunn
Copy link
Collaborator

@coldsunn coldsunn commented Feb 28, 2026

📝 요약(Summary)

FCM 기반 푸시 알림 시스템을 구축했습니다. 총 10가지 알림 타입(일일 작성, 미답변, 리포트 완성/제작 가능, 친구 요청/수락)을 이벤트 기반과 스케줄러 기반으로 구현했으며, 알림함 저장, FCM 발송, 재시도 로직, 뱃지 관리까지 전체 알림 인프라를 완성했습니다.

🔗 Related Issue

💬 공유사항

백엔드 구현 설계

1. 알림 발송 아키텍처

이벤트 기반 + 스케줄러 기반 하이브리드 설계

  • 즉시 알림 (친구 요청/수락, 리포트 완성): 도메인 이벤트 발행 → 비동기
    리스너가 즉시 발송
  • 정시 알림 (일일 작성, 리포트 제작 가능): 스케줄러가 조건 충족 사용자 조회 후
    발송
  • 재시도/복구: 별도 스케줄러가 실패/지연 알림 자동 재처리 -> 이거 스케줄러가 10초, 1분마다 실행되는데 클로드 피셜 월에 0.5달러 이하로 비용이 든다네요

트랜잭션 분리로 성능 최적화
T1: 알림 생성 (PENDING)
↓ AFTER_COMMIT
T2: PENDING → SENDING (낙관적 잠금)
FCM 발송 (트랜잭션 밖) -> 이게 오래 걸려서 이렇게 나눴고, 중복 발송, 재시도 로직을 위해서 상태 기반으로 제어했습니다.
T3: SENDING → SENT/FAILED

2. 조건부 UPDATE 쿼리 사용 이유: 중복 발송 완전 차단

  • WHERE 조건으로 상태 검증 → 동시성 환경에서도 1번만 발송
  • fcmSent 플래그로 FCM 발송 후 DB 실패 시에도 재발송 방지
  • return 값(affected rows)으로 성공 여부 즉시 확인

3. 배치 쿼리 사용 이유: 대량 사용자 쿼리를 위해

  • 스케줄러는 매분/매일 실행 → 성능 중요
  • 대량 사용자 처리 시 쿼리 100배 이상 감소

4. 각 케이스 구현

일일 작성 알림 (매분 실행)

  • LocalTime 직접 비교로 분 단위 정확한 발송
  • 오늘 답변 여부 체크 (AnswerEntry 존재 시 제외)
  • 푸시만 발송, 실제 unreadCount 조회로 뱃지 유지

미답변 알림 (매일 22시)

  • 마지막 답변일 기준 2일 이상 조회
  • 7일 미만/이상 랜덤 메시지 (MessageFactory)
  • 중복 발송 방지 (ConcurrentHashMap)

리포트 완성 (이벤트 기반)

  • confirmWeekly() 성공 후 이벤트 발행
  • 알림함 저장 + FCM 발송
  • idempotencyKey로 중복 방지

리포트 제작 가능 (스케줄러 + 이벤트)

  • 주간/월간: 스케줄러가 조건 충족 사용자 조회
  • 유형: DailyReportCompleted 이벤트 수신 → 30/50/전체 체크 → 즉시 발송

친구 요청/수락 (이벤트 기반)

  • sendFriendRequest() → 이벤트 발행
  • 비동기 리스너가 즉시 처리
  • {senderName} 파라미터 치환

5. 기존 로직 통합

  • 도메인 이벤트만 발행, 알림 처리는 리스너가 독립적으로 수행
  • 알림 실패해도 비즈니스 로직에 영향 없음 (트랜잭션 분리)

6. 메시지 템플릿 중앙화

  • 개발자는 이벤트만 발행, 메시지는 YAML에서 관리
  • 기획 변경 시 YAML만 수정 (코드 변경 불필요)
  • 일단 환경변수에 추가 완료, prod에는 아직 추가X

✅ PR Checklist

PR이 다음 요구 사항을 충족하는지 확인하세요.

  • PR 제목을 커밋 메시지 컨벤션에 맞게 작성했습니다.

coldsunn added 13 commits March 1, 2026 04:05
Firebase Admin SDK 9.7.1 의존성, Spring Retry + AOP 의존성 추가,환경 변수 Base64 방식의 FirebaseConfig 구현, CI/CD에
FIREBASE_ADMIN_KEY 환경 변수 추가

# Conflicts:
#	build.gradle
Notification, NotificationSetting, UserDevice 엔티티 추가 및 마이그레이션 추가
상태 기반 처리를 위한 쿼리들에 대해 원자성을 보장하기 위해 더티체킹보다는 조건부 쿼리를 이용, Modifying 어노테이션을 이용한 배치 쿼리 추가
FCM 배치 발송 및 Invalid Token 자동 정리, 이벤트 기반 즉시 발송, fcm 호출과의 트랜잭션 분리로 db 커넥션 확보, fcmsent 필드 이용 중복 발송 방지
PENDING/FAILED 재시도 (Exponential Backoff), SENDING 타임아웃 복구 (fcmSent 체크), 조건부 update로 동시성 제어
알림 생성, 읽음, 삭제 API, 알림 설정 관리 API, 토큰 등록/삭제 API, 테스트 알림 발송 API 구현 완료
YAML 기반 메시지 템플릿 관리, 환경별 로딩 전략 (Local: 파일, Dev/Prod: 환경변수 Base64), NotificationMessageFactory로 템플릿 파싱
및 파라미터 치환, CI/CD 스크립트에 환경변수 추가
Friend 이벤트 정의 및 발행, FriendNotificationEventListener로 알림 생성
기존 로직과 새로운 로직 모두 비동기 방식으로 변경, 필요한 쿼리 추가
매일 밤 22시 2일 이상 미답변 사용자에게 푸시 알림 발송, 알림 테이블 저장x, 메모리 기반 중복 방지, fcmclient 직접 호출, 필요한 쿼리 추가
매분 실행, 사용자 설정 시간(분 단위)에 정확히 푸시 발송, 알림 테이블에 저장x, 필요한 쿼리 추가
트랜잭션 제거 후 NotificationTransactionHelper에게 트랜잭션 위임
@1Seob
Copy link
Collaborator

1Seob commented Mar 1, 2026

머지 고고~
수고하셨어요!

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