[BE-76] 연락 검토 요청 알림 (FR-94)
작업 내용 (설계 의도)
근거 TDD: 20260808-지원관리-확장-tdd.md — “API 계약 3단계”, “방안 11(멱등 키 확장)“
변경 사항
- “연락 검토 요청” 알림을 신설합니다 — 후보 계산이 끝난 연락 이벤트를 사용자에게 알리고, 검토 화면으로 이동하는 링크를 포함합니다(FR-94).
- 멱등 키는 기존 규칙을 그대로 확장합니다(FR-94 B-27) —
CONTACT_EVENT:{contactEventId}:CONTACT_REVIEW_REQUEST:1.dispatch_sequence는 항상 1(1회성 발송)입니다. - 링크는 터널 공개 호스트명 기준입니다(FR-71·94 A-3) —
recruitment.contact.review-base-url설정값 + 이벤트 id. 사용자가 외출 중에도 알림을 받아 즉시 처리할 수 있어야 한다는 것이 이 알림의 존재 이유입니다. - 발송 시점은 09:00 배치가 아니라 후보 계산 직후입니다 — 연락은 실시간성이 요구됩니다(면접 일정 회신 등). Layer 1 리스너(BE-75)가 후보 계산 후 곧바로 발송 UseCase를 호출합니다.
- 메시지는 발신자·제목·최상위 후보 요약·링크를 300자 이내로 조립합니다(
message_summaryVARCHAR(300) 상한). - 파싱 실패·후보 0건이어도 발송합니다 — 사용자가 원문을 보고 판단해야 하기 때문입니다.
- 피처 플래그
notification.contact-review-request가 OFF면 발송하지 않습니다(이벤트는PENDING으로 남아 검토 화면에서 확인 가능).
롤백: 플래그 OFF.
의존
- BE-68 (
NotificationType.CONTACT_REVIEW_REQUEST·TargetType.CONTACT_EVENTenum·플래그) - BE-75 (후보 계산 — 리스너에서 호출)
다이어그램
처리 흐름
sequenceDiagram participant L as ContactEventReceivedListener participant A as AnalyzeContactEventUseCase participant N as SendContactReviewNotificationUseCase participant D as NotificationDispatchDomainService participant G as DiscordWebhookGateway L->>A: 후보 계산 완료 A->>N: execute(contactEventId) N->>D: dispatchOne(ContactReviewTarget) D->>D: 멱등 키 CONTACT_EVENT:{id}:CONTACT_REVIEW_REQUEST:1 alt 이미 발송 D-->>N: SKIPPED else 미발송 D->>G: send(검토 링크 포함 메시지) G-->>D: Delivered / Rejected (백오프 3회) D-->>N: SENT / FAILED end
클래스 의존
flowchart LR subgraph Application["application/notification"] UC[SendContactReviewNotificationUseCase] end subgraph Domain["domain/notification"] DS[NotificationDispatchDomainService] Target[ContactReviewTarget] Key[IdempotencyKey] Gateway[DiscordWebhookGateway] Flag[FeatureFlagGateway] end UC --> DS DS --> Target DS --> Key DS --> Gateway DS --> Flag
테스트 케이스
- 후보 계산이 끝나면 검토 요청 알림이 1건 발송된다
- 메시지에 검토 화면 링크가 포함되고 터널 공개 호스트명 기준이다
- 같은 이벤트에 대해 두 번 발송을 시도하면 두 번째는 SKIPPED다 (멱등)
- 후보가 0건이어도 알림이 발송된다
- 파싱이 실패해도 알림이 발송된다
- 최상위 후보의 회사명이 메시지 요약에 포함된다
- 메시지 요약이 300자를 넘지 않는다 (컬럼 상한)
- 발송 실패 시
idempotency_key가 NULL로 남는다 - 발송이 5xx면 지수 백오프로 최대 3회 재시도한다
- 피처 플래그 OFF면 발송하지 않고 이벤트는
PENDING으로 남는다 - 알림 발송 실패가 연락 이벤트 저장을 롤백하지 않는다
- 기존 알림 3종 동작이 변경되지 않는다 (회귀)