푸시알림 설계 - depromeet/Took-BE GitHub Wiki

FCM + 스케쥴러 통해 특정 시간에 알림 전송하는 플로우로 구현 예정

역할 정의

  • 이벤트 + 비동기 : 알림 예약 역할
  • 스케쥴러 : 알림 전송 트리거 역할
  • FCM : 알림 전송 역할

푸시알림 종류

  1. 흥미로운 알림
    • 명함 받은 시점에 예약 → 특정 시점(스케쥴러)에 전송
  2. 한줄메모 알림
    • 명함 받은 시점에 예약 → 특정 시점(스케쥴러)에 전송
  3. 시스템 알림 (사용자 전체 대상)
    • 기능 추가되는 시점에 tokens 방식으로 전체 알림 전송

image

image

알림 전송까지의 플로우

  1. [명함 받기] POST /api/card/receive 명함을 받음 → ReceivedCard 테이블에 (user, card) 저장
  2. [알림 예약] 이벤트 + 비동기 Notification 테이블에 (user, received_card, type, willSendAt, createdAt) 저장
    1. type 설정 기준
      1. 타입 “흥미-공통점” = 관심도메인, 세부직군, 소속정보 중 둘 이상이 같은 경우
      2. 타입 “흥미-상세-관심도메인” = 관심도메인 하나만 같은 경우
      3. 타입 “흥미-상세-세부직군” = 세부직군 하나만 같은 경우
      4. 타입 “흥미-상세-소속정보” = 소속정보 하나만 같은 경우
      5. 타입 “한줄메모” = 관심도메인, 세부직군, 소속정보 모두 다른 경우
    2. willSendAt 설정 기준
      1. 받은 시각이 00시 ~ 06시라면 → 오늘 10시에 전송
      2. 받은 시각이 06시 ~ 21시라면 → 오늘 22시에 전송
      3. 받은 시각이 21시 ~ 00시라면 → 내일 10시에 전송
  3. [알림 전송] 스케쥴러 돌려서 특정 시간에 알림 전송
    • 확장 가능성 고려
      • 기존: 10:00, 22:00 알림 발송
      • 확장: 하루 1번 알림 수신 & 사용자가 시간 설정 가능 (1시간 단위로 합의)
    1. 10:00
      1. Notification에서 willSendAt이 10:00인 Notification 조회

      2. Notification의 User의 UserDevice 대상으로 푸시알림 허용인 디바이스에만 FCM 알림 전송 (type에 따라 내용 결정)

        타입 "흥미-상세-ㅇㅇㅇ" : 방금 나와 ‘ㅇㅇㅇ’이(가) 같은 사람을 발견했어요! 어떤 사람인지 살펴보세요
        
        타입 "흥미-공통점" : 방금 나와 공통점이 같은 사람을 발견했어요! 어떤 사람인지 살펴보세요
        
        타입 "한줄메모" : 오늘 공유한 명함을 특별하게 만들어 볼까요?\n다음 만남이 훨씬 자연스러워질 거예요
        
      3. FCM 알림 전송 시점을 Notification sendAt 필드에 저장

    2. 22:00
      1. Notification에서 willSendAt이 22:00인 Notification 조회

      2. Notification의 User의 UserDevice 대상으로 푸시알림 허용인 디바이스에만 FCM 알림 전송 (type에 따라 내용 결정)

        타입 "흥미-상세-ㅇㅇㅇ" : 방금 나와 ‘ㅇㅇㅇ’이(가) 같은 사람을 발견했어요! 어떤 사람인지 살펴보세요
        
        타입 "흥미-공통점" : 방금 나와 공통점이 같은 사람을 발견했어요! 어떤 사람인지 살펴보세요
        
        타입 "한줄메모" : 오늘 공유한 명함을 특별하게 만들어 볼까요?\n다음 만남이 훨씬 자연스러워질 거예요
        
      3. FCM 알림 전송 시점을 Notification sendAt 필드에 저장

흥미로운 명함 페이지 조회 방법

플로우

  1. 사용자가 페이지 조회

  2. 현재 시간에 따라 sendAt 기반으로 조회

    ex) 오늘 19:00라면 → 전날 22시 알림 + 당일 10시 알림

    ex) 오늘 23:00라면 → 전날 22시 알림 + 당일 10시 알림 + 당일 22시 알림

흥미로운 명함 정보 제거 시점

  • 23:59
    • 전날 22:00에 전송한 흥미로운명함정보 제거
    • 오늘 10:00에 전송한 흥미로운명함정보 제거

알림 내역

  • Notification에서 User 기반으로 30일간 명함 조회

image

테이블 설계

Notification

  • id
    • PK
  • user
    • user 저장하고 나중에 user의 device 조회해서 보내는 게 나을 듯
  • receivedCard
    • (받은명함Id, 받은명함주인Id)
  • type
    • 흥미-공통점, 흥미-상세-관심도메인, 흥미-상세-세부직군, 흥미-상세-소속정보, 한줄메모
  • willSendAt
    • 알림이 전송될 시점
  • sendAt
    • 실제 알림이 전송된 시점
  • createdAt
    • 알림을 예약한 시점
  • updatedAt

고민포인트

[흥미로운 명함 페이지] 관리 장소

  1. notification + received_card
  2. 별도 테이블

결론: 기존 테이블 재활용!

  • 하루이틀 조회될 데이터를 별도 테이블로 관리하는 것은 리소스 낭비라고 생각함

image

[전송 예정 시점] 알림 예약할 때 vs 스케쥴러 돌릴 때 ?

  1. 알림 예약할 때

    notification 저장할 때 10:00인지 22:00인지 미리 계산해서 wil_send_at 필드에 저장

    → 나중에 사용자 지정 시점으로 기획 변경되면 사용자 지정 시점(user의 필드)을 저장

    • 장점: 스케쥴러 알림 전송이 빠름
    • 단점: 알림 예약이 빠름 (그런데 비동기라 크게 상관 없음) & send_at과 약간의 중복
  2. 스케쥴러 돌릴 때

    10:00와 22:00에 스케쥴러 돌릴 때 createdAt 범위로 조회하기

    → 나중에 사용자 지정 시점으로 기획 변경되면 1시간에 한번씩 사용자 지정 시점을 user와의 join을 통해 조회

    • 장점: 알림 예약이 빠름
    • 단점: 스케쥴러 알림 전송이 느림

결론: 알림 예약할 때!

  • 스케쥴러에게는 오직! 알림을 전송하는 역할만 부여하자.
  • 사용자 지정 시점으로 기획이 변경되면, 스케쥴러가 userRepository에 대한 의존성 가짐
  • 알림 예약은 비동기이므로 예약 속도에 영향을 끼치지 않음

나중에 Spring Batch 도입할래!!!


알림 설정 페이지

That was quick - Ringtones, message tones and other sounds