Skip to content

푸시 알림 설정

작성: 0chil

푸시 알림은 회원별 하위 항목으로 관리한다. 전체 ON/OFF 설정은 사용하지 않으며, 기기 권한은 실제 FCM 전송 가능 여부에만 영향을 준다.

  • 항목: member_push_notification_item(member_id, type, enabled)
  • 빈도·쿨다운: member_push_notification_item_frequency(member_push_notification_item_id, frequency, cooldown_time_starts_at, cooldown_time_ends_at)

항목은 (member_id, type)으로 구별한다. 전체 설정의 ID를 참조하지 않는다. 빈도·쿨다운은 항목 ID를 PK로 사용한다.

항목기본 활성화기본 빈도
NEW_ARRIVALONONCE
LIKED_SELLER_NEW_ARRIVALONONCE
FAVORITE_STYLE_NEW_ARRIVALOFFONCE
CART_REMINDERON미지원
CART_PRICE_OFFON미지원
LIKED_PRODUCT_DISCOUNTON미지원

PushNotificationDefaults가 지원 항목과 기본값을 관리한다. 알림 타입을 else 없는 when으로 분류하므로 타입 추가 시 설정 지원 여부도 명시해야 한다. 일반 알림과 옷장정리 진행·정산 알림은 항목 설정 대상이 아니다.

신규 회원의 NewMemberEvent를 가입 트랜잭션의 BEFORE_COMMIT에서 동기 처리하여 하위 항목과 빈도를 생성한다. 기기 등록이나 권한 허용이 필요하지 않다. 초기화는 누락된 행만 생성하고 기존 ON/OFF·빈도·쿨다운을 보존한다. 첫 쿨다운은 NULL이다. 기존 유효 회원의 누락된 행은 배포 전 수동 SQL로 보완한다. 조회는 행을 생성하지 않으며, 없는 항목은 OFF로 반환하고 없는 빈도만 코드 기본값으로 읽는다.

모든 API는 인증된 본인만 대상으로 한다.

메서드경로동작
GET/push-notifications하위 항목의 활성화 여부·빈도 조회
PUT/push-notifications/{type}{"enabled":true}로 선택 항목 변경
PUT/push-notifications/{type}/frequency{"frequency":"ONCE"}로 빈도 변경
GET/push-notifications/favorite-styles선호 스타일 조회
PUT/push-notifications/favorite-styles선호 스타일 변경

PUT /push-notifications는 제거했다. 조회 응답에는 전체 enabled가 없다.

{
"items": [
{"type":"NEW_ARRIVAL","enabled":true,"frequency":"ONCE"},
{"type":"LIKED_SELLER_NEW_ARRIVAL","enabled":true,"frequency":"ONCE"},
{"type":"FAVORITE_STYLE_NEW_ARRIVAL","enabled":false,"frequency":"ONCE"},
{"type":"CART_REMINDER","enabled":true,"frequency":null},
{"type":"CART_PRICE_OFF","enabled":true,"frequency":null},
{"type":"LIKED_PRODUCT_DISCOUNT","enabled":true,"frequency":null}
]
}

빈도 미지원 항목은 frequency: null을 명시적으로 반환한다. 설정 미지원 타입의 ON/OFF·빈도 변경과 빈도 미지원 항목의 빈도 변경은 저장 전에 400으로 거부한다. 빈도 미지원 항목에 잘못 저장된 빈도가 있으면 조회 시 오류로 처리한다.

항목 OFF는 빈도·쿨다운을 보존한다. 신상품 항목 ON은 저장된 빈도를 사용하고, 빈도가 없으면 ONCE를 생성한다. 기존 쿨다운이 있으면 다시 시작하며 첫 발송 전에는 생성하지 않는다. 빈도 변경도 활성화 여부를 보존하고 기존 쿨다운만 새 빈도로 다시 시작한다. 항목이 없는 상태에서 빈도만 변경하면 항목을 OFF로 생성한다. 빈도 변경은 항목 존재 여부를 조회하고, 없는 항목만 INSERT한 뒤 SELECT ... FOR UPDATE로 항목을 잠그고 빈도를 upsert한다.

기기 등록·권한 변경은 해당 기기의 권한과 거절 사유만 저장한다. 미등록·허용·거절 사이의 어떤 전이도 알림 항목을 생성하거나 ON/OFF를 변경하지 않는다. FCM의 UNREGISTERED 응답은 해당 기기만 비활성화하며 하위 설정은 유지한다.

장바구니·찜 상품 이벤트와 신상품 스케줄은 하위 항목 ON 여부로 대상을 선정한다. 새 전체 설정 테이블이나 구형 전체 구독의 활성화 여부는 조회하지 않는다. 실제 발송 직전에도 설정 대상 6종의 ON을 확인한다. 큐·예약 등록 후 OFF로 바뀌면 전송과 내역 생성을 생략한다. 전송이 이미 시작된 뒤의 변경은 진행 중인 전송을 취소하지 않는다. ON 항목은 허용된 기기가 없어도 사용자 알림 내역을 생성한다. 기기 없음·전부 실패·FCM 호출 오류는 발송 성공 개수 0으로 남는다. 자세한 저장·조회 계약은 푸시 알림 내역을 참고한다.

신상품 3종은 각 항목의 빈도·쿨다운을 독립적으로 적용한다. 쿨다운이 없거나 종료 시각이 현재보다 이른 항목을 ID 순으로 1,000건씩 스캔하며, 청크 처리 시 ON/OFF와 쿨다운을 다시 확인한다. 빈도 행이 없으면 코드 기본값을 적용한다. 첫 발송 집계는 현재에서 해당 빈도의 쿨다운 길이만큼 이전부터, 기존 쿨다운이 있으면 그 시작부터다. 전체 신상품 20개 이상, 찜한 셀러·선호 스타일은 각각 10개 이상일 때 발송 작업을 생성한다. 작업을 큐에 넣은 항목만 쿨다운을 저장한다. 조회 후 빈도가 바뀌었다면 이전 빈도로 덮어쓰지 않는다. 항목의 (type, enabled) 인덱스와 InnoDB의 PK 확장으로 종류·활성화·ID 범위 조회를 지원한다.

GET /notifications/subscriptions는 memberId, subscriptions를 반환한다. 전체 id, isEnabled 필드와 루트 PUT·DELETE /notifications/subscriptions는 제거했다. 각 구독의 ID·활성화·빈도는 새 하위 설정을 사용하며, 항목이 없으면 ID는 0이다.

구버전 API동작
CART_REMINDER, CART_PRICE_OFF, LIKED_PRODUCT_DISCOUNT PUT / DELETE대응 항목 ON / OFF
NEW_ARRIVALS PUT전체·찜한 셀러 신상품 ON, 선호 스타일 OFF
NEW_ARRIVALS DELETE신상품 3종 OFF
NEW_ARRIVALS/RANGE PUT구형 구독에 범위 저장. 새 항목의 ON/OFF·빈도 유지
NEW_ARRIVALS/FREQUENCY PUT구형 구독의 선택 범위에 대응하는 새 항목 빈도만 변경

신상품 3종 중 하나라도 ON이면 구버전 NEW_ARRIVALS는 ON이다. 범위는 기존 구독에 저장된 값을 우선하며, 없으면 ON 항목을 전체 → 찜한 셀러 → 선호 스타일 순으로 선택한다. 모두 OFF이면 전체 신상품 범위와 해당 빈도(없으면 ONCE)를 반환한다. 구버전 범위·빈도 변경은 기존 신상품 구독이 없으면 저장 전에 거부한다.

구형 MemberPushSubscription과 구독 초기화는 구버전 범위 API 호환용으로 유지한다. 구형 ProductNewArrival*Range 스케줄·청크 작업과 전용 poller는 제거했다. 기존 구형 큐가 모두 소진된 상태를 전제로 하며, alias·호환 어댑터·큐 삭제 처리는 추가하지 않는다. 현재 신상품 발송은 push.newarrivals.job의 새 3종만 사용한다.

운영은 ddl-auto=validate이므로 다음 순서를 지킨다. SQL은 애플리케이션 시작 시 자동 실행하지 않는다.

  1. sent_device_count 컬럼 추가를 한 번 적용한다. 기존 sent_count를 이미 추가한 DB는 대신 컬럼명 변경을 적용한다. 두 파일 중 하나만 실행하며 기존 값과 과거 내역의 NULL은 유지한다.
  2. 가입·설정 변경·발송 처리를 중단한 전환 구간에 누락 항목·빈도 보완을 같은 DB 세션에서 실행한다. 오류 시 중단하고 ROLLBACK하며 mysql --force는 사용하지 않는다.
  3. 모든 애플리케이션 인스턴스를 새 버전으로 배포한 뒤 처리를 재개한다.
  4. 구버전 인스턴스가 더 이상 없을 때 새 전체 설정 테이블 삭제를 적용한다.

보완 SQL은 member.is_valid = true인 회원만 대상으로 하고 재실행 시 기존 값과 시각을 보존한다. 전체 OFF 사용자의 하위 ON도 그대로 유지하므로 전환 후 발송 대상이 된다. 기존 하위 OFF를 일괄 ON으로 바꾸는 소급 처리는 없다. 구형 member_push_subscription과 관련 테이블은 삭제하지 않는다.