배경 및 목표

그 동안 채용담당자는 지원자에 대해 특정 이벤트가 발생하면, 수동으로 알림을 발생시키거나 멘션을 통해 평가자들에게 알림을 발생시켜 왔습니다. 알림 워크플로우는 특정 이벤트를 트리거로 하여 채용담당자가 지정해놓은 수신자 그룹들에게 자동으로 알림을 발생시켜주는 과제입니다.

알림 설정과 로직 일원화

도메인별로 알림 설정과 발송 로직이 곳곳에 흩어져 있었습니다.

  • 도메인 A, B, C 마다 별도의 알림 테이블(N개)이 존재해, 알림을 한 곳에서 조회하고 관리하기 어려웠습니다.
  • 도메인 로직이 알림을 직접(동기) 호출해 발송까지 책임지면서, 알림 로직에 강하게 결합, 종속되어 알림 변경이 도메인 코드로 번졌습니다.
  • 발송 플로우(메일, 슬랙, 인앱)도 도메인마다 중복 구현(N개)되어, 새 알림을 추가할 때마다 채널별 발송 코드를 다시 작성해야 했습니다.
  • 새로운 알림 유형이나 발송 채널을 추가할 때마다 테이블과 발송 코드를 계속 늘려야 하는 구조였습니다.

왜 중요했는가

알림은 채용담당자가 시스템 밖에서 상태 변화를 인지하는 유일한 경로입니다. 도메인마다 테이블과 발송 코드가 따로 있으니, 알림 하나를 고치려면 어느 도메인에 붙어 있는지부터 찾아야 했고, 새 채널을 붙이려면 모든 도메인의 알림 로직을 확인해야 했습니다.

제약

제약선택지에 미친 영향
기존 알림 테이블 마이그레이션 비용도메인별 테이블을 단일 테이블로 흡수해야 해서, 마이그레이션 비용이 존재합니다.
운영 중 알림 중단 불가사용자가 기능 사용에 불편을 겪지 않는 것이 1원칙이라, 테이블 전환 중에도 발송이 계속돼야 했습니다.
도메인 코드 수정 범위도메인이 이미 발송을 직접 호출하고 있어, 이벤트 발행으로 바꾸려면 기존 코드들을 건드려야 했습니다.
채널별 스펙 상이메일, 슬랙, 인앱의 전송 규격이 달라 공통 플로우로 묶으려면 채널 전략을 분리해야 했습니다

목표

  • 도메인별로 흩어진 알림 테이블을 단일 테이블로 통합해 일관되게 관리합니다.
  • 도메인 이벤트를 받아 채널로 발송하는 공통 알림 워크플로우를 만듭니다.
  • 새 알림 워크플로우를 기존 코드 수정 없이 확장할 수 있는 인터페이스를 설계합니다.

맡은 역할과 판단

구분내용
담당 범위팀원과 함께 설계를 진행했습니다. 전환 검증은 검증 쿼리로 직접 확인했습니다.
직접 내린 판단1. 도메인별 테이블 유지 대신 단일 테이블 통합
2. 도메인이 발송을 호출하지 않고 이벤트만 발행하도록 결합 제거
3. Workflow 인터페이스로 신규 알림을 기존 코드 수정 없이 확장
협업, 합의도메인별 담당자가 따로 없었기에 추후 담당자가 생겨도 영역을 쉽게 분리할 수 있도록 이벤트를 event.{domain}.{sub-domain} 형태로 나눠뒀습니다.

해결 방법과 해결 후보군

후보군 비교

방식설명한계
도메인별 개별 유지각 도메인이 자체 테이블과 발송 로직 보유중복 심화, 신규 알림마다 재구현
공통 워크플로우 + 테이블 통합 (채택)단일 테이블 + 이벤트 기반 공통 플로우 + 구독자 인터페이스초기 설계와 마이그레이션 비용은 있으나 확장 비용 최소

기존 테이블을 통합 테이블로 흡수하려면 마이그레이션 비용이 들지만, 여러 알림 유형을 하나의 스키마와 플로우로 표현하면 이후 알림 유형과 채널 확장 비용이 크게 줄어든다고 판단해 통합안을 채택했습니다.

1. 알림 테이블 단일화

도메인 A, B, C의 개별 알림 테이블을 하나의 통합 알림 테이블로 합쳤습니다. 도메인 구분은 컬럼(유형, 범위 등)으로 표현하고, 설정, 수신자, 발송 조건, 예약, 이력을 공통 스키마로 정규화했습니다.

수신자 그룹도 하나의 유형 컬럼으로 여러 그룹을 표현하고, 유형별로 실제 대상을 다르게 확장합니다.

수신자 유형확장 방식
개인지정된 사용자 목록을 그대로 조회
그룹 전체그룹 구성원 전체로 확장
담당자배정 관계를 따라 담당자로 확장
역할해당 역할 보유자로 확장

2. 이벤트 기반 공통 워크플로우 (Workflow 인터페이스)

도메인은 알림을 직접 발송하지 않고 Kafka로 도메인 이벤트만 발행합니다. 알림 워커 서버가 consumer group으로 이 토픽을 구독하고, 최상위 Workflow 인터페이스가 이벤트를 소비해 이를 구현한 AWorkflow, BWorkflow 등으로 확장합니다. 워크플로우는 이벤트를 받아 알림 설정 조회부터 콘텐츠 구성, 발송까지 공통 플로우로 처리합니다.

도메인 서비스와 알림 워커 서버가 Kafka를 사이에 두고 분리되므로, 알림 처리가 지연되거나 실패해도 도메인 트랜잭션에 영향을 주지 않습니다.

sequenceDiagram
    participant D as 도메인 (A/B/C)
    participant K as Kafka
    participant W as 알림 워커 (AWorkflow)
    participant SET as 알림 설정 조회
    participant CT as 콘텐츠 구성자
    participant SEND as 발송자
    D->>K: 도메인 이벤트 발행
    K->>W: consumer group 구독
    W->>SET: 유형/수신자/조건/시점/채널 조회
    SET->>CT: 발송 조건 통과분만 콘텐츠 구성
    CT->>SEND: 채널별 발송

발송자는 채널별 발송 전략(메일, 슬랙, 인앱)으로 분리해, 새 채널을 독립적으로 추가할 수 있게 했습니다.

3. 무중단 전환

알림을 멈추지 않고 테이블을 통합하기 위해 dual write로 신규 테이블에 데이터를 계속 적재했습니다. FE 릴리즈 이후 feature toggle을 전환해 읽기 경로를 신규 테이블로 넘기는 방식으로 무중단 배포를 마쳤습니다.

4. 즉시 발송과 예약 발송 분리

발송 시점을 즉시와 예약으로 나눕니다. 즉시는 단건 콘텐츠 구성자로 바로 발송하고, 예약은 예약 테이블에 적재한 뒤 정각 배치가 처리합니다. 배치는 예약 데이터를 최신 상태로 클렌징한 후 복수 콘텐츠 구성자로 묶어 발송합니다.


결과

항목기존개선
알림 테이블도메인별 N개단일 1개
발송 플로우도메인마다 중복 구현공통 워크플로우 1개
신규 알림 추가채널별 코드 재작성이벤트 구독 후 신규 알림 구현체 등록
채널 확장도메인마다 수정채널 전략 추가로 독립 확장
예약 발송건별 N회 발송묶음 1회 발송
테이블 전환-발송 중단 0건, 데이터 손실 0건