@startuml meeting-회의예약
!theme mono

title Meeting Service - 회의예약 내부 시퀀스

participant "MeetingController" as Controller
participant "MeetingService" as Service
participant "MeetingRepository" as Repo
participant "ParticipantRepository" as ParticipantRepo
database "Meeting DB<<E>>" as DB
database "Redis Cache<<E>>" as Cache
queue "Azure Event Hubs<<E>>" as EventHub

[-> Controller: POST /meetings
activate Controller

note over Controller
요청 데이터:
{
  "title": "회의 제목",
  "startTime": "2025-01-23T14:00:00",
  "endTime": "2025-01-23T15:00:00",
  "location": "회의실 A",
  "participants": ["user1@example.com", ...]
}
사용자 정보: userId, userName, email
end note

Controller -> Controller: 입력 검증\n- 제목 필수 (최대 100자)\n- 날짜/시간 필수\n- 참석자 최소 1명

Controller -> Service: createMeeting(request, userId)
activate Service

note over Service
비즈니스 규칙 검증:
- 회의 시간 유효성 (시작 < 종료)
- 중복 회의 체크
- 참석자 유효성 검증
end note

Service -> Service: 회의 시간 유효성 검사

Service -> Repo: checkConflictingMeetings(userId, startTime, endTime)
activate Repo
Repo -> DB: 중복 회의 확인
activate DB
DB --> Repo: 중복 회의 개수
deactivate DB
Repo --> Service: int count
deactivate Repo

alt 중복 회의 존재
    Service --> Controller: 409 Conflict\n중복된 회의 시간
    note right
      에러 응답 형식:
      {
        "error": {
          "code": "MEETING_TIME_CONFLICT",
          "message": "중복된 회의 시간이 존재합니다",
          "details": "해당 시간대에 이미 예약된 회의가 있습니다",
          "timestamp": "2025-10-23T12:00:00Z",
          "path": "/api/meetings"
        }
      }
    end note
    return 409 Conflict
else 중복 없음
    Service -> Service: Meeting 엔티티 생성\n- 회의 ID 생성\n- 상태: SCHEDULED\n- 생성자 정보 설정

    ' 회의 정보 저장
    Service -> Repo: save(meeting)
    activate Repo
    Repo -> DB: 회의 정보 저장
    activate DB
    DB --> Repo: 회의 저장 완료
    deactivate DB
    Repo --> Service: Meeting
    deactivate Repo

    ' 참석자 저장
    Service -> ParticipantRepo: saveAll(participants)
    activate ParticipantRepo
    ParticipantRepo -> DB: 참석자 정보 저장
    activate DB
    DB --> ParticipantRepo: 참석자 저장 완료
    deactivate DB
    ParticipantRepo --> Service: List<Participant>
    deactivate ParticipantRepo

    ' 캐시 저장
    Service -> Cache: SET meeting:info:{meetingId}\n(TTL: 10분)
    activate Cache
    Cache --> Service: 캐싱 완료
    deactivate Cache

    Service -> Cache: SET meeting:participants:{meetingId}\n(TTL: 10분)
    activate Cache
    Cache --> Service: 캐싱 완료
    deactivate Cache

    note over Service
    비동기 이벤트 발행:
    - 참석자에게 초대 알림 발송
    - 캘린더 등록
    - 리마인더 스케줄링
    end note

    ' 이벤트 발행
    Service -> EventHub: publish(NotificationRequest)\n{\n  channel: EMAIL,\n  recipients: participants,\n  message: "회의 초대",\n  metadata: {\n    meetingId, title, startTime,\n    location\n  }\n}
    activate EventHub
    note right
      Notification Service가 구독:
      - Consumer Group: notification-service-group
      - 참석자 전원에게 초대 이메일 발송
    end note
    EventHub --> Service: 발행 완료
    deactivate EventHub

    Service --> Controller: MeetingResponse
    deactivate Service

    note over Controller
    응답 데이터:
    {
      "meetingId": "uuid",
      "title": "회의 제목",
      "startTime": "...",
      "endTime": "...",
      "location": "...",
      "participants": [...],
      "status": "SCHEDULED"
    }
    end note

    return 201 Created\nMeetingResponse
end

deactivate Controller

@enduml
