@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: SELECT * FROM notifications\nWHERE meeting_id='{meetingId}'\nAND type='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: INSERT INTO notifications\n(notification_id, meeting_id,\ntype='REMINDER',\nstatus='PENDING',\nrecipients,\ncreated_at) 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: UPDATE notification_recipients\nSET status='SENT', sent_at=NOW() activate DB DB --> Repository: 업데이트 완료 deactivate DB Repository --> Service: 완료 deactivate Repository else 발송 실패 EmailClient --> Service: FAILED Service -> Repository: updateRecipientStatus(notificationId, recipient, "FAILED") activate Repository Repository -> DB: UPDATE notification_recipients\nSET status='FAILED' 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: UPDATE notifications\nSET status='{finalStatus}',\ncompleted_at=NOW(),\nsent_count={sentCount},\nfailed_count={failedCount} 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