@startuml !theme mono title Notification Service - 리마인더발송 내부 시퀀스 participant "SchedulerJob" as Scheduler participant "ReminderService" as Service participant "EmailTemplateService" as TemplateService participant "NotificationRepository" as Repository participant "EmailClient" as EmailClient database "Notification DB" as DB participant "Email Service<>" as EmailService == 스케줄링된 작업 실행 (회의 시작 30분 전) == Scheduler -> Scheduler: 30분 전 알림 대상 회의 조회 activate Scheduler note right 조회 조건: - 회의 시작 시간 - 30분 = NOW - 회의 상태 = 예약됨 - 리마인더 미발송 end note Scheduler -> Service: sendMeetingReminders(meetingList) activate Service loop 각 회의별 Service -> Repository: checkReminderSent(meetingId) activate Repository Repository -> DB: 리마인더 알림 조회\n(회의ID, 유형='REMINDER') activate DB DB --> Repository: 조회 결과 deactivate DB Repository --> Service: 발송 여부 확인 deactivate Repository alt 이미 발송됨 Service -> Service: 스킵 else 미발송 == 리마인더 알림 생성 == Service -> Repository: createNotification(meetingId, "REMINDER", participants) activate Repository Repository -> DB: 리마인더 알림 생성\n(알림ID, 회의ID, 유형, 상태, 수신자, 생성일시) activate DB DB --> Repository: notificationId 반환 deactivate DB Repository --> Service: NotificationEntity 반환 deactivate Repository == 이메일 템플릿 생성 == Service -> TemplateService: generateReminderEmail(meetingData) activate TemplateService TemplateService -> TemplateService: 템플릿 로드 note right 템플릿 정보: - 제목: "[리마인더] {회의 제목} - 30분 후 시작" - 내용: 회의 정보 + 참여 링크 - 긴급도: 높음 end note TemplateService -> TemplateService: 데이터 바인딩 note right 바인딩 데이터: - 회의 제목 - 시작 시간 (30분 후) - 장소 - 회의 참여 링크 - 준비 사항 (있는 경우) end note TemplateService --> Service: EmailContent 반환 deactivate TemplateService == 참석자별 이메일 발송 == loop 각 참석자별 Service -> EmailClient: sendEmail(recipient, emailContent) activate EmailClient EmailClient -> EmailService: SMTP 이메일 발송 activate EmailService EmailService --> EmailClient: 발송 결과 deactivate EmailService alt 발송 성공 EmailClient --> Service: SUCCESS Service -> Repository: updateRecipientStatus(notificationId, recipient, "SENT") activate Repository Repository -> DB: 수신자별 알림 상태 업데이트\n(상태='발송완료', 발송일시=현재시각) activate DB DB --> Repository: 업데이트 완료 deactivate DB Repository --> Service: 완료 deactivate Repository else 발송 실패 EmailClient --> Service: FAILED Service -> Repository: updateRecipientStatus(notificationId, recipient, "FAILED") activate Repository Repository -> DB: 수신자별 알림 상태 업데이트\n(상태='발송실패') activate DB DB --> Repository: 업데이트 완료 deactivate DB Repository --> Service: 완료 deactivate Repository Service -> Service: 재시도 큐에 추가 end deactivate EmailClient end == 알림 상태 업데이트 == Service -> Repository: updateNotificationStatus(notificationId, finalStatus) activate Repository Repository -> DB: 알림 최종 상태 업데이트\n(상태, 완료일시, 발송건수, 실패건수) activate DB DB --> Repository: 업데이트 완료 deactivate DB Repository --> Service: 완료 deactivate Repository end end Service --> Scheduler: 전체 리마인더 발송 완료\n(총 발송 건수, 성공/실패 통계) deactivate Service Scheduler -> Scheduler: 다음 스케줄 대기 deactivate Scheduler note over Scheduler, EmailService 스케줄링 정책: - 실행 주기: 1분마다 - 대상: 30분 후 시작 회의 - 중복 발송 방지: DB 체크 처리 시간: - 대상 회의 조회: ~200ms - 이메일 발송 (per recipient): ~500ms - 총 처리 시간: 회의 및 참석자 수에 비례 end note @enduml