@startuml
!theme mono

title 알림 발송 내부 시퀀스 (Event-Driven)

queue "Event Hub<<E>>" as EventHub
participant "NotificationListener" as Listener
participant "NotificationService" as Service
participant "NotificationRouter" as Router
participant "EmailNotifier" as EmailNotifier
participant "Email Service<<E>>" as Email
participant "NotificationRepository" as Repository
database "PostgreSQL<<E>>" as DB

EventHub -> Listener: consume(NotificationRequest)
activate Listener
note right
  NotificationRequest 이벤트:
  - channel: 발송수단 (EMAIL, SMS)
  - recipients: 대상자 목록
  - message: 메시지 내용
  - metadata: 추가 정보 (회의정보 등)

  Consumer Group:
  - notification-service-group
end note

Listener -> Service: processNotification(event)
activate Service

Service -> Repository: checkDuplicateNotification(eventId)
activate Repository
Repository -> DB: 알림 중복 확인 조회\n(이벤트ID 기준)
note right
  중복 발송 방지:
  - Event ID 기반
  - Idempotency 보장
end note

alt 중복 이벤트
    DB --> Repository: notification exists
    Repository --> Service: duplicate
    Service --> Listener: skip (already processed)
    deactivate Service
    Listener --> EventHub: ACK
    deactivate Listener

else 신규 이벤트
    DB --> Repository: not found
    Repository --> Service: proceed
    deactivate Repository

    Service -> Service: parseEventPayload(event)
    note right
      이벤트 파싱:
      - userId
      - notificationType
      - templateId
      - templateData
    end note

    Service -> Repository: getUserPreferences(userId)
    activate Repository
    Repository -> DB: 사용자 알림 설정 조회\n(사용자ID 기준)
    note right
      사용자 설정 확인:
      - 알림 채널 (email/sms)
      - 알림 활성화 여부
      - 수신 시간대
    end note
    DB --> Repository: preferences
    Repository --> Service: NotificationPreference
    deactivate Repository

    alt 알림 비활성화
        Service --> Listener: skip (user preference)
        deactivate Service
        Listener --> EventHub: ACK
        deactivate Listener

    else 알림 활성화
        Service -> Router: routeNotification(event, preferences)
        activate Router

        Router -> Router: determineChannel(preferences)
        note right
          채널 선택:
          - 이메일 우선
          - SMS 백업
        end note

        alt 이메일 알림
            Router -> EmailNotifier: sendEmail(notification)
            activate EmailNotifier

            EmailNotifier -> EmailNotifier: loadTemplate(templateId)
            note right
              템플릿 로드:
              - 회의 초대
              - 할일 배정
              - 회의 알림
              - 요약 완료
            end note

            EmailNotifier -> EmailNotifier: renderTemplate(templateData)
            note right
              템플릿 렌더링:
              - 제목 생성
              - 본문 생성
              - 다이나믹 데이터 삽입
            end note

            EmailNotifier -> Email: send(to, subject, body)
            note right
              이메일 발송:
              - SMTP 프로토콜
              - 재시도 로직
              - Timeout: 10s
            end note

            alt 발송 성공
                Email --> EmailNotifier: success
                EmailNotifier --> Router: sent
                deactivate EmailNotifier

            else 발송 실패
                Email --> EmailNotifier: failure
                EmailNotifier -> EmailNotifier: scheduleRetry()
                note right
                  재시도 전략:
                  - Max retry: 3
                  - Backoff: exponential
                  - 1m, 5m, 15m
                end note
                EmailNotifier --> Router: retry scheduled
                deactivate EmailNotifier
            end
        end

        Router --> Service: notification result
        deactivate Router

        Service -> Repository: saveNotificationLog(notification)
        activate Repository
        Repository -> DB: 알림 이력 저장\n(이벤트ID, 사용자ID, 유형, 채널, 상태, 발송일시)
        note right
          알림 로그 저장:
          - 발송 이력
          - 채널 정보
          - 성공/실패 상태
        end note
        DB --> Repository: saved
        Repository --> Service: saved
        deactivate Repository

        Service -> Repository: updateUserActivity(userId, "NOTIFICATION_SENT")
        activate Repository
        Repository -> DB: 사용자 활동 이력 저장\n(사용자ID, 활동유형, 상세내용)
        DB --> Repository: saved
        Repository --> Service: updated
        deactivate Repository

        Service --> Listener: processed
        deactivate Service

        Listener --> EventHub: ACK
        deactivate Listener
    end
end

@enduml
