@startuml
!theme mono

title AI Service 내부 시퀀스 - Todo자동추출

participant "TodoController" as Controller
participant "TodoExtractionService" as Service
participant "LLMClient" as LLM
participant "TodoRepository" as Repo
participant "MeetingServiceClient<<E>>" as MeetingClient
database "Azure OpenAI<<E>>" as OpenAI
database "PostgreSQL<<E>>" as DB

== API 요청 수신 ==

note over Controller
  POST /todos/extract
  Request Body:
  - meetingId
  - userId
  - minutesContent (회의록 전체 내용)
end note

Controller -> Service: extractTodos(request)
activate Service
note right
  Request 데이터:
  - meetingId
  - userId
  - minutesContent
end note

== 입력 데이터 검증 ==

Service -> Service: 회의록 내용 검증
note right
  검증 항목:
  - minutesContent 필수 확인
  - 최소 길이 검증 (50자 이상)
  - meetingId 형식 검증 (UUID)
end note

alt 검증 실패
    Service --> Controller: 400 Bad Request
    note right
      에러 메시지:
      - "회의록 내용이 필요합니다"
      - "회의록이 너무 짧습니다"
    end note
end

== 회의록 내용 파싱 ==

Service -> Service: 회의록에서 참석자 추출
note right
  Markdown 파싱:
  - "## 참석자" 섹션 파싱
  - 참석자 목록 추출
  - 담당자 매칭에 활용
end note

== LLM 기반 Todo 추출 ==

Service -> Service: Todo 추출 프롬프트 생성
note right
  시스템 프롬프트:
  - 역할: Todo 추출 전문가
  - 지시사항: 액션 아이템 식별,
    담당자 및 마감일 추출

  사용자 프롬프트:
  - 회의록 전체 내용
  - 참석자 목록
  - 추출 기준:
    * "~하기로 함", "~까지 완료"
    * "~담당", "제가 하겠습니다"
    * 명령형 문장
end note

Service -> LLM: extractActionItems(prompt, minutesContent, participants)
activate LLM

LLM -> OpenAI: POST /chat/completions
activate OpenAI
note right
  요청 파라미터:
  - model: gpt-4o
  - temperature: 0.2
  - response_format: json_object

  응답 형식:
  {
    "todos": [
      {
        "content": "Todo 내용",
        "assignee": "담당자명",
        "dueDate": "YYYY-MM-DD",
        "priority": "HIGH|MEDIUM|LOW",
        "section": "관련 섹션"
      }
    ]
  }
end note

OpenAI -> OpenAI: 회의록 분석
note right
  1. 액션 아이템 키워드 탐지
  2. 명령형 문장 분석
  3. 담당자 식별
     - 발언 내용 기반
     - 직책/역할 기반
  4. 마감일 추출
  5. 우선순위 판단
end note

OpenAI --> LLM: Todo 목록 (JSON)
deactivate OpenAI

LLM --> Service: extractedTodos
deactivate LLM

== Todo 데이터 저장 및 검증 ==

Service -> Service: Todo 데이터 검증
note right
  검증 항목:
  - content 필수
  - assignee가 참석자 목록에 있는지
  - dueDate 형식 검증
  - priority 유효성 검증
end note

loop 각 Todo 항목마다

    Service -> Repo: saveTodo(meetingId, todoData)
    activate Repo

    Repo -> DB: Todo 정보 저장
    activate DB
    note right
      저장 데이터:
      - meeting_id
      - content
      - assignee
      - due_date
      - priority
      - section_reference
      - status: PENDING
      - extracted_at
    end note

    DB --> Repo: todoId
    deactivate DB

    Repo --> Service: todoId
    deactivate Repo

end

== Meeting Service에 Todo 전송 ==

Service -> Service: Todo 목록 준비
note right
  전송 데이터 구성:
  - Todo 내용
  - 담당자 정보
  - 마감일
  - 우선순위
  - 관련 회의록 섹션 링크
end note

Service -> MeetingClient: POST /meetings/{meetingId}/todos
activate MeetingClient
note right
  요청 바디:
  {
    "meetingId": "{meetingId}",
    "todos": [
      {
        "content": "Todo 내용",
        "assignee": "담당자",
        "dueDate": "2025-01-30",
        "priority": "HIGH",
        "sectionReference": "결정사항 #3"
      }
    ]
  }
end note

MeetingClient -> MeetingClient: Todo 생성 및 할당 처리
note right
  Meeting Service 내부 처리:
  - Todo 테이블에 저장
  - 회의록 섹션 링크 연결
  - TodoCreated 이벤트 발행
  - 담당자에게 알림 발송
end note

MeetingClient --> Service: 200 OK (Todo 생성 완료)
deactivate MeetingClient

== 처리 상태 업데이트 ==

Service -> Repo: updateExtractionStatus(meetingId, "COMPLETED")
activate Repo

Repo -> DB: 추출 상태 업데이트
activate DB

DB --> Repo: 업데이트 완료
deactivate DB

Repo --> Service: 완료
deactivate Repo

Service --> Controller: Todo 추출 완료
deactivate Service

Controller -> Controller: TodoExtractionCompleted 이벤트 발행 (내부 로깅)

note over Controller, DB
처리 시간:
- 입력 검증: 10-50ms
- 회의록 파싱: 50-100ms
- LLM Todo 추출: 3-5초
- 저장 처리: 200-500ms
- Meeting Service 전송: 500ms-1초
총 처리 시간: 약 4-7초
(외부 API 호출 제거로 500ms 단축)
end note

@enduml
