배경
기획 "알림 문구" 표에서 정해진 시각에 조건을 보고 보내는 알림 4종이 서버에 없다. 현재 @Scheduled는 채팅 생명주기(매분)·매칭 배치(목 05:00)·purge 2종뿐이라 월·수·금에 도는 스케줄러가 없다.
#210(이벤트 기반 알림)의 후속. 유형·문구·notifier 패턴은 그 PR을 따른다.
태스크 (커밋 단위)
결정 사항
- 앱은 로컬 푸시를 보내지 않는다(2026-09-24 확인). cron 기본 활성.
- 발송 시각은 표의 사건 시각(오픈 월 00:00). 사건 시각이 없는 마감 임박·평가 리마인드는 각각 수 18:00·월 09:00 기본값, 프로퍼티(
notification.*.cron)로 조정.
- 평가 리마인드는 마감 개념을 만들지 않는다. 표의 "마감 전(월)"은 발송 요일이고 문구에 남은 시간이 없으므로,
available_at이 최근 7일인 미완료 평가에 한 번 독촉한다. 제출은 계속 열어둔다. REVIEW_REQUEST는 ONCE_PER_TARGET이라 재사용 불가 → 새 유형.
QUIZ_OPENED·QUIZ_CLOSING_SOON의 target_id는 그 주 활성 셋 중 id 최소(대표 셋). 1:1·그룸 셋이 나란히 열려도 알림은 하나. 마감 임박은 어느 셋이든 하나라도 끝냈으면 참여자로 본다.
QUIZ_OPENED 문구의 "12문항"은 실제 문항 수로 채운다. 셋마다 다를 수 있다.
- 시각 트리거 알림은 수렴 루프가 아니다. 월 00:00에 활성 셋이 없으면 그 주 오픈 알림은 없다.
- 매분 도는 후보 조회(
CHAT_NO_MESSAGE·CHAT_ENDING_SOON)는 이미 알린 방을 쿼리에서 뺀다(notification anti-join).
참고
- 퀴즈 기간 SSOT:
QuizResponsePeriod(월 00:00 ~ 수 23:59:59), QuizSet.startDate/endDate
- 채팅방 개방 지점:
ChatRoomEndService.openDue
- 스케줄 판단 시각은
ServerTimeProvider(어드민 오버라이드 반영), 저장·중복 판정은 실제 시각 — ChatRoomLifecycleScheduler KDoc의 원칙을 따른다. cron 알림은 MatchingScheduler처럼 실제 시각.
배경
기획 "알림 문구" 표에서 정해진 시각에 조건을 보고 보내는 알림 4종이 서버에 없다. 현재
@Scheduled는 채팅 생명주기(매분)·매칭 배치(목 05:00)·purge 2종뿐이라 월·수·금에 도는 스케줄러가 없다.#210(이벤트 기반 알림)의 후속. 유형·문구·notifier 패턴은 그 PR을 따른다.
태스크 (커밋 단위)
WeeklyNotificationScheduler, cron 3개 — 프로퍼티로 조정)QUIZ_OPENED— 퀴즈 오픈(월 00:00). 대상: 활성 회원 전원. 문항 없는 셋은 미발송QUIZ_CLOSING_SOON— 퀴즈 마감 6시간 전(수 18:00). 대상: 이번 주 어느 셋도COMPLETED아닌 활성 회원CHAT_NO_MESSAGE— 채팅 오픈 12시간 후 무대화(금 정오). SYSTEM 메시지는 대화로 치지 않음. 매분 수렴 루프, 6시간 창REVIEW_REMINDER— 월 09:00, 최근 7일 안에 열린 미완료 평가. 방마다 한 번docs/domains/notification.md·review.md·ADR 0018 갱신CHAT_ENDING_SOON후보 조회에도 이미 알린 방 anti-join — 매분 존재 검사 반복 제거결정 사항
notification.*.cron)로 조정.available_at이 최근 7일인 미완료 평가에 한 번 독촉한다. 제출은 계속 열어둔다.REVIEW_REQUEST는ONCE_PER_TARGET이라 재사용 불가 → 새 유형.QUIZ_OPENED·QUIZ_CLOSING_SOON의target_id는 그 주 활성 셋 중 id 최소(대표 셋). 1:1·그룸 셋이 나란히 열려도 알림은 하나. 마감 임박은 어느 셋이든 하나라도 끝냈으면 참여자로 본다.QUIZ_OPENED문구의 "12문항"은 실제 문항 수로 채운다. 셋마다 다를 수 있다.CHAT_NO_MESSAGE·CHAT_ENDING_SOON)는 이미 알린 방을 쿼리에서 뺀다(notificationanti-join).참고
QuizResponsePeriod(월 00:00 ~ 수 23:59:59),QuizSet.startDate/endDateChatRoomEndService.openDueServerTimeProvider(어드민 오버라이드 반영), 저장·중복 판정은 실제 시각 —ChatRoomLifecycleSchedulerKDoc의 원칙을 따른다. cron 알림은MatchingScheduler처럼 실제 시각.