hgzero/design/backend/api/meeting-service-api.yaml
2025-10-23 13:31:47 +09:00

2020 lines
56 KiB
YAML

openapi: 3.0.0
info:
title: Meeting Service API
description: |
회의록 작성 및 공유 개선 서비스의 Meeting Service API
**주요 기능:**
- 회의 관리 (예약, 시작, 종료)
- 회의록 관리 (생성, 수정, 확정, 조회)
- Todo 관리 (할당, 진행, 완료)
- 실시간 협업 (동기화, 충돌해결, 검증)
- 템플릿 관리
- 대시보드
version: 1.0.0
contact:
name: HGZero Team
email: support@hgzero.com
servers:
- url: https://api.hgzero.com/meeting/v1
description: Production server
- url: https://dev-api.hgzero.com/meeting/v1
description: Development server
- url: http://localhost:8080/api
description: Local development server
tags:
- name: Dashboard
description: 대시보드 관련 API
- name: Meeting
description: 회의 관리 API
- name: Minutes
description: 회의록 관리 API
- name: Todo
description: Todo 관리 API
- name: Collaboration
description: 실시간 협업 API
- name: Template
description: 템플릿 관리 API
- name: WebSocket
description: WebSocket 엔드포인트
paths:
# ==================== Dashboard APIs ====================
/dashboard:
get:
tags:
- Dashboard
summary: 대시보드 데이터 조회
description: |
사용자별 맞춤 대시보드 정보를 조회합니다.
- 예정된 회의 목록
- 진행 중 Todo 목록
- 최근 회의록 목록
- 공유받은 회의록 목록
- 통계 정보
operationId: getDashboard
x-user-story: AFR-USER-020
x-controller: DashboardController
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/UserIdHeader'
- $ref: '#/components/parameters/UserNameHeader'
- $ref: '#/components/parameters/UserEmailHeader'
responses:
'200':
description: 대시보드 데이터 조회 성공
content:
application/json:
schema:
$ref: '#/components/schemas/DashboardResponse'
example:
upcomingMeetings:
- meetingId: "550e8400-e29b-41d4-a716-446655440000"
title: "Q1 전략 회의"
startTime: "2025-01-25T14:00:00Z"
endTime: "2025-01-25T16:00:00Z"
location: "회의실 A"
participantCount: 5
status: "SCHEDULED"
- meetingId: "550e8400-e29b-41d4-a716-446655440001"
title: "주간 스크럼"
startTime: "2025-01-26T10:00:00Z"
endTime: "2025-01-26T10:30:00Z"
location: "온라인"
participantCount: 8
status: "SCHEDULED"
activeTodos:
- todoId: "660e8400-e29b-41d4-a716-446655440000"
content: "API 설계 문서 작성"
dueDate: "2025-01-30"
priority: "HIGH"
status: "IN_PROGRESS"
minutesId: "770e8400-e29b-41d4-a716-446655440000"
- todoId: "660e8400-e29b-41d4-a716-446655440001"
content: "데이터베이스 스키마 설계"
dueDate: "2025-02-05"
priority: "MEDIUM"
status: "IN_PROGRESS"
minutesId: "770e8400-e29b-41d4-a716-446655440001"
myMinutes:
- minutesId: "770e8400-e29b-41d4-a716-446655440000"
title: "아키텍처 설계 회의"
meetingDate: "2025-01-23T14:00:00Z"
status: "FINALIZED"
participantCount: 6
lastModified: "2025-01-23T16:30:00Z"
statistics:
upcomingMeetingsCount: 2
activeTodosCount: 5
todoCompletionRate: 68.5
'401':
$ref: '#/components/responses/UnauthorizedError'
'500':
$ref: '#/components/responses/InternalServerError'
# ==================== Meeting APIs ====================
/meetings:
post:
tags:
- Meeting
summary: 회의 예약
description: |
새로운 회의를 예약하고 참석자를 초대합니다.
- 회의 정보 저장
- 참석자 목록 관리
- 초대 이메일 자동 발송
- 리마인더 스케줄링
operationId: createMeeting
x-user-story: UFR-MEET-010
x-controller: MeetingController
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/UserIdHeader'
- $ref: '#/components/parameters/UserNameHeader'
- $ref: '#/components/parameters/UserEmailHeader'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateMeetingRequest'
example:
title: "Q1 전략 회의"
startTime: "2025-01-25T14:00:00Z"
endTime: "2025-01-25T16:00:00Z"
location: "회의실 A"
agenda: "1. Q1 목표 달성 현황 검토\n2. Q2 전략 방향 논의\n3. 주요 이슈 및 리스크 검토"
participants:
- "user1@example.com"
- "user2@example.com"
- "user3@example.com"
responses:
'201':
description: 회의 예약 성공
content:
application/json:
schema:
$ref: '#/components/schemas/MeetingResponse'
example:
meetingId: "550e8400-e29b-41d4-a716-446655440000"
title: "Q1 전략 회의"
startTime: "2025-01-25T14:00:00Z"
endTime: "2025-01-25T16:00:00Z"
location: "회의실 A"
participants:
- userId: "user1"
email: "user1@example.com"
name: "김철수"
role: "ORGANIZER"
- userId: "user2"
email: "user2@example.com"
name: "이영희"
role: "PARTICIPANT"
status: "SCHEDULED"
createdAt: "2025-01-23T10:00:00Z"
'400':
$ref: '#/components/responses/BadRequestError'
'409':
$ref: '#/components/responses/ConflictError'
'401':
$ref: '#/components/responses/UnauthorizedError'
'500':
$ref: '#/components/responses/InternalServerError'
/meetings/{meetingId}/template:
put:
tags:
- Meeting
summary: 회의록 템플릿 선택
description: |
회의에 회의록 템플릿을 적용합니다.
- 템플릿 유형: 일반 회의, 스크럼, 프로젝트 킥오프, 주간 회의
- 섹션 커스터마이징 가능
operationId: applyTemplate
x-user-story: UFR-MEET-020
x-controller: MeetingController
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/MeetingIdPath'
- $ref: '#/components/parameters/UserIdHeader'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ApplyTemplateRequest'
example:
templateId: "general-meeting"
customizations:
- section: "discussion"
title: "주요 논의사항"
order: 1
- section: "decision"
title: "결정사항"
order: 2
responses:
'200':
description: 템플릿 적용 성공
content:
application/json:
schema:
$ref: '#/components/schemas/MeetingResponse'
'400':
$ref: '#/components/responses/BadRequestError'
'404':
$ref: '#/components/responses/NotFoundError'
'401':
$ref: '#/components/responses/UnauthorizedError'
/meetings/{meetingId}/start:
post:
tags:
- Meeting
summary: 회의 시작
description: |
회의를 시작하고 세션을 생성합니다.
- 회의 세션 생성
- 음성 녹음 준비
- 회의록 초안 생성
- 실시간 협업 WebSocket 준비
operationId: startMeeting
x-user-story: UFR-MEET-030
x-controller: MeetingController
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/MeetingIdPath'
- $ref: '#/components/parameters/UserIdHeader'
- $ref: '#/components/parameters/UserNameHeader'
responses:
'201':
description: 회의 시작 성공
content:
application/json:
schema:
$ref: '#/components/schemas/SessionResponse'
example:
sessionId: "660e8400-e29b-41d4-a716-446655440000"
meetingId: "550e8400-e29b-41d4-a716-446655440000"
status: "IN_PROGRESS"
startedAt: "2025-01-25T14:00:00Z"
minutesId: "770e8400-e29b-41d4-a716-446655440000"
'404':
$ref: '#/components/responses/NotFoundError'
'409':
$ref: '#/components/responses/ConflictError'
'401':
$ref: '#/components/responses/UnauthorizedError'
/meetings/{meetingId}/end:
post:
tags:
- Meeting
summary: 회의 종료
description: |
회의를 종료하고 통계를 생성합니다.
- 음성 녹음 중지
- 회의 통계 생성
- AI 제안 데이터 회의록에 반영
- 참석자에게 종료 알림
- 검증 완료 화면 데이터 반환
operationId: endMeeting
x-user-story: UFR-MEET-040
x-controller: MeetingController
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/MeetingIdPath'
- $ref: '#/components/parameters/UserIdHeader'
requestBody:
required: false
content:
application/json:
schema:
$ref: '#/components/schemas/EndMeetingRequest'
example:
finalAgenda: "1. Q1 목표 달성률 85% 확인\n2. 신규 기능 우선순위 결정\n3. 다음 주 개발 일정 조율"
applyAiSuggestions: true
responses:
'200':
description: 회의 종료 성공
content:
application/json:
schema:
$ref: '#/components/schemas/MeetingEndResponse'
example:
meetingId: "550e8400-e29b-41d4-a716-446655440000"
sessionId: "660e8400-e29b-41d4-a716-446655440000"
status: "ENDED"
endedAt: "2025-01-25T16:00:00Z"
statistics:
duration: 120
participantCount: 5
utteranceCount: 87
minutesId: "770e8400-e29b-41d4-a716-446655440000"
aiEnhancement:
merged: true
suggestionsApplied: 8
sections:
discussion: 3
decision: 2
todo: 3
verificationStatus:
totalSections: 4
verifiedSections: 2
verificationRate: 50
sections:
- sectionId: "880e8400-e29b-41d4-a716-446655440000"
sectionType: "DISCUSSION"
title: "회의 개요"
isVerified: true
isLocked: false
verifiers:
- userId: "user1"
name: "김민준"
verifiedAt: "2025-01-25T15:30:00Z"
- userId: "user2"
name: "박서연"
verifiedAt: "2025-01-25T15:35:00Z"
- sectionId: "880e8400-e29b-41d4-a716-446655440001"
sectionType: "DECISION"
title: "논의 사항"
isVerified: true
isLocked: true
verifiers:
- userId: "user1"
name: "김민준"
verifiedAt: "2025-01-25T15:40:00Z"
- userId: "user2"
name: "박서연"
verifiedAt: "2025-01-25T15:42:00Z"
- userId: "user3"
name: "이준호"
verifiedAt: "2025-01-25T15:45:00Z"
- sectionId: "880e8400-e29b-41d4-a716-446655440002"
sectionType: "TODO"
title: "결정 사항"
isVerified: false
isLocked: false
verifiers:
- userId: "user2"
name: "박서연"
verifiedAt: "2025-01-25T15:50:00Z"
- sectionId: "880e8400-e29b-41d4-a716-446655440003"
sectionType: "TODO"
title: "액션 아이템"
isVerified: false
isLocked: false
verifiers: []
'404':
$ref: '#/components/responses/NotFoundError'
'409':
$ref: '#/components/responses/ConflictError'
'401':
$ref: '#/components/responses/UnauthorizedError'
# ==================== Minutes APIs ====================
/minutes:
get:
tags:
- Minutes
summary: 회의록 목록 조회
description: |
회의록 목록을 조회하고 필터링합니다.
- 상태별 필터링 (전체/작성중/확정완료)
- 카테고리별 필터링 (전체/공유받은/참석한/생성한)
- 정렬 옵션 (최신순/회의일시순/제목순)
- 검색 기능
operationId: getMinutesList
x-user-story: UFR-MEET-046
x-controller: MinutesController
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/UserIdHeader'
- name: page
in: query
schema:
type: integer
default: 0
minimum: 0
description: 페이지 번호 (0부터 시작)
- name: size
in: query
schema:
type: integer
default: 20
minimum: 1
maximum: 100
description: 페이지 크기
- name: status
in: query
schema:
type: string
enum: [ALL, DRAFT, FINALIZED]
default: ALL
description: 회의록 상태 필터
- name: category
in: query
schema:
type: string
enum: [ALL, SHARED, ATTENDED, CREATED]
default: ALL
description: 카테고리 필터
- name: sort
in: query
schema:
type: string
enum: [LATEST, MEETING_DATE, TITLE]
default: LATEST
description: 정렬 옵션
- name: keyword
in: query
schema:
type: string
description: 검색 키워드 (제목, 참석자, 키워드)
responses:
'200':
description: 회의록 목록 조회 성공
content:
application/json:
schema:
$ref: '#/components/schemas/MinutesListResponse'
example:
content:
- minutesId: "770e8400-e29b-41d4-a716-446655440000"
title: "아키텍처 설계 회의"
meetingDate: "2025-01-23T14:00:00Z"
participantCount: 6
status: "FINALIZED"
verificationRate: 100
isReadOnly: false
lastModified: "2025-01-23T16:30:00Z"
- minutesId: "770e8400-e29b-41d4-a716-446655440001"
title: "주간 스프린트 리뷰"
meetingDate: "2025-01-22T10:00:00Z"
participantCount: 8
status: "DRAFT"
verificationRate: 65
isReadOnly: true
lastModified: "2025-01-22T11:30:00Z"
pageable:
page: 0
size: 20
sort: "LATEST"
totalElements: 45
totalPages: 3
statistics:
total: 45
draft: 12
finalized: 33
'401':
$ref: '#/components/responses/UnauthorizedError'
/minutes/{minutesId}:
get:
tags:
- Minutes
summary: 회의록 상세 조회
description: |
회의록의 상세 정보를 조회합니다.
- 기본 정보 (제목, 일시, 참석자)
- 섹션별 상세 내용
- AI 요약 정보
- 관련 회의록 (최대 3개)
- 권한 정보
operationId: getMinutesDetail
x-user-story: UFR-MEET-047
x-controller: MinutesController
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/MinutesIdPath'
- $ref: '#/components/parameters/UserIdHeader'
responses:
'200':
description: 회의록 상세 조회 성공
content:
application/json:
schema:
$ref: '#/components/schemas/MinutesDetailResponse'
'403':
$ref: '#/components/responses/ForbiddenError'
'404':
$ref: '#/components/responses/NotFoundError'
'401':
$ref: '#/components/responses/UnauthorizedError'
patch:
tags:
- Minutes
summary: 회의록 수정
description: |
회의록 내용을 수정합니다.
- 제목, 섹션별 내용, AI 요약 수정 가능
- 잠긴 섹션은 수정 불가
- 확정된 회의록은 작성중으로 상태 변경
- 실시간 동기화
operationId: updateMinutes
x-user-story: UFR-MEET-055
x-controller: MinutesController
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/MinutesIdPath'
- $ref: '#/components/parameters/UserIdHeader'
- $ref: '#/components/parameters/UserNameHeader'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateMinutesRequest'
responses:
'200':
description: 회의록 수정 성공
content:
application/json:
schema:
$ref: '#/components/schemas/MinutesUpdateResponse'
'400':
$ref: '#/components/responses/BadRequestError'
'403':
$ref: '#/components/responses/ForbiddenError'
'404':
$ref: '#/components/responses/NotFoundError'
/minutes/{minutesId}/finalize:
post:
tags:
- Minutes
summary: 회의록 확정
description: |
최종 회의록을 확정하고 버전을 생성합니다.
- 필수 항목 검증
- 확정 버전 생성
- AI Todo 자동 추출
- 참석자에게 확정 알림
operationId: finalizeMinutes
x-user-story: UFR-MEET-050
x-controller: MinutesController
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/MinutesIdPath'
- $ref: '#/components/parameters/UserIdHeader'
responses:
'200':
description: 회의록 확정 성공
content:
application/json:
schema:
$ref: '#/components/schemas/MinutesFinalizeResponse'
'400':
$ref: '#/components/responses/BadRequestError'
'409':
$ref: '#/components/responses/ConflictError'
'404':
$ref: '#/components/responses/NotFoundError'
/minutes/{minutesId}/sections/{sectionId}/verify:
post:
tags:
- Minutes
summary: 섹션 검증 완료
description: |
회의록 섹션을 검증하고 완료 표시를 합니다.
- 검증자 정보 기록
- 검증 상태 업데이트
- 실시간 동기화
- 전체 메일 알림
operationId: verifySection
x-user-story: UFR-COLLAB-030
x-controller: MinutesController
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/MinutesIdPath'
- name: sectionId
in: path
required: true
schema:
type: string
format: uuid
description: 섹션 ID
- $ref: '#/components/parameters/UserIdHeader'
- $ref: '#/components/parameters/UserNameHeader'
responses:
'200':
description: 섹션 검증 완료
content:
application/json:
schema:
$ref: '#/components/schemas/SectionVerifyResponse'
'404':
$ref: '#/components/responses/NotFoundError'
/minutes/{minutesId}/sections/{sectionId}/lock:
post:
tags:
- Minutes
summary: 섹션 잠금
description: |
검증 완료된 섹션을 잠급니다. (회의 생성자만 가능)
- 잠긴 섹션은 수정 불가
- 실시간 동기화
operationId: lockSection
x-user-story: UFR-COLLAB-030
x-controller: MinutesController
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/MinutesIdPath'
- name: sectionId
in: path
required: true
schema:
type: string
format: uuid
- $ref: '#/components/parameters/UserIdHeader'
responses:
'200':
description: 섹션 잠금 성공
'403':
$ref: '#/components/responses/ForbiddenError'
'404':
$ref: '#/components/responses/NotFoundError'
delete:
tags:
- Minutes
summary: 섹션 잠금 해제
description: |
잠긴 섹션의 잠금을 해제합니다. (회의 생성자만 가능)
operationId: unlockSection
x-user-story: UFR-MEET-055
x-controller: MinutesController
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/MinutesIdPath'
- name: sectionId
in: path
required: true
schema:
type: string
format: uuid
- $ref: '#/components/parameters/UserIdHeader'
responses:
'200':
description: 섹션 잠금 해제 성공
'403':
$ref: '#/components/responses/ForbiddenError'
'404':
$ref: '#/components/responses/NotFoundError'
# ==================== Todo APIs ====================
/todos:
get:
tags:
- Todo
summary: Todo 목록 조회
description: |
사용자별 Todo 목록을 조회하고 필터링합니다.
- 상태별 필터링 (전체/진행중/완료/마감임박)
- 우선순위별 정렬
- 통계 정보 포함
operationId: getTodoList
x-user-story: UFR-TODO-020
x-controller: TodoController
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/UserIdHeader'
- name: status
in: query
schema:
type: string
enum: [ALL, IN_PROGRESS, COMPLETED, URGENT]
default: ALL
description: |
Todo 상태 필터
- ALL: 전체
- IN_PROGRESS: 진행중
- COMPLETED: 완료
- URGENT: 마감 임박 (3일 이내)
- name: sort
in: query
schema:
type: string
enum: [DUE_DATE, PRIORITY, CREATED_AT]
default: DUE_DATE
description: 정렬 기준
responses:
'200':
description: Todo 목록 조회 성공
content:
application/json:
schema:
$ref: '#/components/schemas/TodoListResponse'
example:
statistics:
total: 12
inProgress: 8
completed: 4
urgent: 3
completionRate: 33.3
todos:
- todoId: "660e8400-e29b-41d4-a716-446655440000"
content: "API 설계 문서 작성"
assignee:
userId: "user1"
email: "user@example.com"
name: "김민준"
dueDate: "2025-01-30"
priority: "HIGH"
status: "IN_PROGRESS"
progress: 60
minutesId: "770e8400-e29b-41d4-a716-446655440000"
meetingTitle: "아키텍처 설계 회의"
createdAt: "2025-01-23T10:00:00Z"
- todoId: "660e8400-e29b-41d4-a716-446655440001"
content: "데이터베이스 스키마 설계"
assignee:
userId: "user1"
email: "user@example.com"
name: "김민준"
dueDate: "2025-02-05"
priority: "MEDIUM"
status: "IN_PROGRESS"
progress: 30
minutesId: "770e8400-e29b-41d4-a716-446655440001"
meetingTitle: "주간 스프린트 리뷰"
createdAt: "2025-01-22T14:00:00Z"
'401':
$ref: '#/components/responses/UnauthorizedError'
post:
tags:
- Todo
summary: Todo 할당
description: |
Todo를 생성하고 담당자에게 할당합니다.
- 회의록과 양방향 연결
- 담당자에게 즉시 알림 발송
- 캘린더 이벤트 생성
- 리마인더 설정
operationId: createTodo
x-user-story: UFR-TODO-010
x-controller: TodoController
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/UserIdHeader'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateTodoRequest'
example:
content: "API 설계 문서 작성"
assignee: "user@example.com"
dueDate: "2025-01-30"
priority: "HIGH"
minutesId: "770e8400-e29b-41d4-a716-446655440000"
sectionId: "880e8400-e29b-41d4-a716-446655440000"
responses:
'201':
description: Todo 생성 성공
content:
application/json:
schema:
$ref: '#/components/schemas/TodoResponse'
'400':
$ref: '#/components/responses/BadRequestError'
'404':
$ref: '#/components/responses/NotFoundError'
/todos/{todoId}/complete:
patch:
tags:
- Todo
summary: Todo 완료 처리
description: |
Todo를 완료 상태로 변경합니다.
- 담당자만 완료 가능
- 회의록에 완료 상태 실시간 반영
- 완료 알림 발송
- 모든 Todo 완료 시 전체 완료 알림
operationId: completeTodo
x-user-story: UFR-TODO-030
x-controller: TodoController
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/TodoIdPath'
- $ref: '#/components/parameters/UserIdHeader'
responses:
'200':
description: Todo 완료 처리 성공
content:
application/json:
schema:
$ref: '#/components/schemas/TodoCompleteResponse'
'403':
$ref: '#/components/responses/ForbiddenError'
'409':
$ref: '#/components/responses/ConflictError'
'404':
$ref: '#/components/responses/NotFoundError'
# ==================== Template APIs ====================
/templates:
get:
tags:
- Template
summary: 템플릿 목록 조회
description: |
사용 가능한 회의록 템플릿 목록을 조회합니다.
각 템플릿의 섹션 정보를 포함하여 반환합니다.
- 일반 회의
- 스크럼 회의
- 프로젝트 킥오프
- 주간 회의
operationId: getTemplates
x-user-story: UFR-MEET-020
x-controller: TemplateController
security:
- bearerAuth: []
responses:
'200':
description: 템플릿 목록 조회 성공
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/TemplateResponse'
example:
- templateId: "general-meeting"
name: "일반 회의"
description: "기본 회의록 형식"
icon: "📋"
category: "GENERAL"
sections:
- sectionType: "DISCUSSION"
title: "회의 개요"
order: 1
isRequired: true
- sectionType: "DISCUSSION"
title: "논의 사항"
order: 2
isRequired: true
- sectionType: "DECISION"
title: "결정 사항"
order: 3
isRequired: true
- sectionType: "TODO"
title: "액션 아이템"
order: 4
isRequired: true
- templateId: "scrum-meeting"
name: "스크럼 회의"
description: "데일리 스탠드업 형식"
icon: "🏃"
category: "SCRUM"
sections:
- sectionType: "DISCUSSION"
title: "어제 한 일"
order: 1
isRequired: true
- sectionType: "TODO"
title: "오늘 할 일"
order: 2
isRequired: true
- sectionType: "CUSTOM"
title: "블로커/이슈"
order: 3
isRequired: true
# ==================== WebSocket Endpoints ====================
/ws/minutes/{minutesId}:
get:
tags:
- WebSocket
summary: 회의록 실시간 협업 WebSocket
description: |
WebSocket 연결을 통한 실시간 협업 기능
- 회의록 실시간 수정 동기화
- 충돌 감지 및 해결
- 검증 완료 상태 동기화
- Todo 상태 변경 동기화
**연결 URL:** ws://localhost:8080/ws/minutes/{minutesId}
**메시지 타입:**
- MINUTES_UPDATED: 회의록 수정
- TODO_COMPLETED: Todo 완료
- SECTION_VERIFIED: 섹션 검증 완료
- CONFLICT_DETECTED: 충돌 감지
operationId: connectMinutesWebSocket
x-user-story: UFR-COLLAB-010
x-controller: CollaborationController
parameters:
- $ref: '#/components/parameters/MinutesIdPath'
- name: userId
in: query
required: true
schema:
type: string
description: 사용자 ID
- name: token
in: query
required: true
schema:
type: string
description: JWT 토큰
responses:
'101':
description: WebSocket 연결 성공
'401':
description: 인증 실패
'403':
description: 권한 없음
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: JWT 토큰을 Authorization 헤더에 포함
parameters:
UserIdHeader:
name: X-User-Id
in: header
required: true
schema:
type: string
description: 사용자 ID
UserNameHeader:
name: X-User-Name
in: header
required: true
schema:
type: string
description: 사용자 이름
UserEmailHeader:
name: X-User-Email
in: header
required: true
schema:
type: string
format: email
description: 사용자 이메일
MeetingIdPath:
name: meetingId
in: path
required: true
schema:
type: string
format: uuid
description: 회의 ID
MinutesIdPath:
name: minutesId
in: path
required: true
schema:
type: string
format: uuid
description: 회의록 ID
TodoIdPath:
name: todoId
in: path
required: true
schema:
type: string
format: uuid
description: Todo ID
schemas:
# ==================== Dashboard Schemas ====================
DashboardResponse:
type: object
properties:
upcomingMeetings:
type: array
items:
$ref: '#/components/schemas/UpcomingMeeting'
description: 예정된 회의 목록
activeTodos:
type: array
items:
$ref: '#/components/schemas/ActiveTodo'
description: 진행 중 Todo 목록
myMinutes:
type: array
items:
$ref: '#/components/schemas/MyMinutes'
description: 내 회의록 목록
statistics:
$ref: '#/components/schemas/DashboardStatistics'
description: 통계 정보
required:
- statistics
UpcomingMeeting:
type: object
properties:
meetingId:
type: string
format: uuid
title:
type: string
startTime:
type: string
format: date-time
endTime:
type: string
format: date-time
location:
type: string
participantCount:
type: integer
status:
type: string
enum: [SCHEDULED, IN_PROGRESS]
required:
- meetingId
- title
- startTime
- status
ActiveTodo:
type: object
properties:
todoId:
type: string
format: uuid
content:
type: string
dueDate:
type: string
format: date
priority:
type: string
enum: [HIGH, MEDIUM, LOW]
status:
type: string
enum: [IN_PROGRESS]
minutesId:
type: string
format: uuid
required:
- todoId
- content
- priority
- status
MyMinutes:
type: object
properties:
minutesId:
type: string
format: uuid
title:
type: string
meetingDate:
type: string
format: date-time
status:
type: string
enum: [DRAFT, FINALIZED]
participantCount:
type: integer
lastModified:
type: string
format: date-time
required:
- minutesId
- title
- meetingDate
- status
DashboardStatistics:
type: object
properties:
upcomingMeetingsCount:
type: integer
activeTodosCount:
type: integer
todoCompletionRate:
type: number
format: double
description: Todo 완료율 (%)
required:
- upcomingMeetingsCount
- activeTodosCount
- todoCompletionRate
# ==================== Meeting Schemas ====================
CreateMeetingRequest:
type: object
properties:
title:
type: string
maxLength: 100
description: 회의 제목
startTime:
type: string
format: date-time
description: 회의 시작 시간
endTime:
type: string
format: date-time
description: 회의 종료 시간
location:
type: string
maxLength: 200
description: 회의 장소
agenda:
type: string
maxLength: 1000
description: 회의 안건 (선택 사항)
participants:
type: array
items:
type: string
format: email
minItems: 1
description: 참석자 이메일 목록
required:
- title
- startTime
- endTime
- participants
MeetingResponse:
type: object
properties:
meetingId:
type: string
format: uuid
title:
type: string
startTime:
type: string
format: date-time
endTime:
type: string
format: date-time
location:
type: string
participants:
type: array
items:
$ref: '#/components/schemas/Participant'
status:
type: string
enum: [SCHEDULED, IN_PROGRESS, ENDED]
createdAt:
type: string
format: date-time
required:
- meetingId
- title
- startTime
- endTime
- participants
- status
Participant:
type: object
properties:
userId:
type: string
email:
type: string
format: email
name:
type: string
role:
type: string
enum: [ORGANIZER, PARTICIPANT]
required:
- userId
- email
- name
- role
ApplyTemplateRequest:
type: object
properties:
templateId:
type: string
description: 템플릿 ID
customizations:
type: array
items:
$ref: '#/components/schemas/SectionCustomization'
required:
- templateId
SectionCustomization:
type: object
properties:
section:
type: string
title:
type: string
order:
type: integer
required:
- section
- title
- order
SessionResponse:
type: object
properties:
sessionId:
type: string
format: uuid
meetingId:
type: string
format: uuid
status:
type: string
enum: [IN_PROGRESS]
startedAt:
type: string
format: date-time
minutesId:
type: string
format: uuid
required:
- sessionId
- meetingId
- status
- startedAt
- minutesId
MeetingEndResponse:
type: object
properties:
meetingId:
type: string
format: uuid
sessionId:
type: string
format: uuid
status:
type: string
enum: [ENDED]
endedAt:
type: string
format: date-time
statistics:
$ref: '#/components/schemas/MeetingStatistics'
minutesId:
type: string
format: uuid
aiEnhancement:
$ref: '#/components/schemas/AIEnhancement'
required:
- meetingId
- sessionId
- status
- endedAt
- statistics
- minutesId
MeetingStatistics:
type: object
properties:
duration:
type: integer
description: 회의 진행 시간 (분)
participantCount:
type: integer
description: 참석자 수
utteranceCount:
type: integer
description: 발언 횟수
required:
- duration
- participantCount
- utteranceCount
AIEnhancement:
type: object
properties:
merged:
type: boolean
description: AI 제안 병합 여부
suggestionsApplied:
type: integer
description: 적용된 AI 제안 수
sections:
type: object
properties:
discussion:
type: integer
decision:
type: integer
todo:
type: integer
required:
- merged
- suggestionsApplied
# ==================== Minutes Schemas ====================
MinutesListResponse:
type: object
properties:
content:
type: array
items:
$ref: '#/components/schemas/MinutesSummary'
pageable:
$ref: '#/components/schemas/Pageable'
totalElements:
type: integer
totalPages:
type: integer
statistics:
$ref: '#/components/schemas/MinutesStatistics'
required:
- content
- pageable
- totalElements
- totalPages
- statistics
MinutesSummary:
type: object
properties:
minutesId:
type: string
format: uuid
title:
type: string
meetingDate:
type: string
format: date-time
participantCount:
type: integer
status:
type: string
enum: [DRAFT, FINALIZED]
verificationRate:
type: integer
description: 검증 완료율 (%)
isReadOnly:
type: boolean
description: 조회 전용 여부
lastModified:
type: string
format: date-time
required:
- minutesId
- title
- meetingDate
- status
Pageable:
type: object
properties:
page:
type: integer
size:
type: integer
sort:
type: string
required:
- page
- size
- sort
MinutesStatistics:
type: object
properties:
total:
type: integer
draft:
type: integer
finalized:
type: integer
required:
- total
- draft
- finalized
MinutesDetailResponse:
type: object
properties:
minutesId:
type: string
format: uuid
meeting:
$ref: '#/components/schemas/MeetingInfo'
participants:
type: array
items:
$ref: '#/components/schemas/Participant'
sections:
type: array
items:
$ref: '#/components/schemas/MinutesSection'
description: 섹션별 내용 (AI 요약 및 관련 회의록 포함)
permissions:
$ref: '#/components/schemas/MinutesPermissions'
status:
type: string
enum: [DRAFT, FINALIZED]
version:
type: string
required:
- minutesId
- meeting
- participants
- sections
- permissions
- status
MeetingInfo:
type: object
properties:
meetingId:
type: string
format: uuid
title:
type: string
startTime:
type: string
format: date-time
endTime:
type: string
format: date-time
location:
type: string
duration:
type: integer
description: 소요 시간 (분)
required:
- meetingId
- title
- startTime
MinutesSection:
type: object
properties:
sectionId:
type: string
format: uuid
sectionType:
type: string
enum: [DISCUSSION, DECISION, TODO, SCHEDULE, RESOURCE, CUSTOM]
title:
type: string
content:
type: string
order:
type: integer
isLocked:
type: boolean
isVerified:
type: boolean
verifiedBy:
type: string
verifiedAt:
type: string
format: date-time
aiSummary:
$ref: '#/components/schemas/AISummary'
description: 이 섹션의 AI 요약
relatedMinutes:
type: array
items:
$ref: '#/components/schemas/RelatedMinutes'
description: 이 섹션과 관련된 회의록 목록 (최대 3개)
required:
- sectionId
- sectionType
- title
- content
- order
- isLocked
- isVerified
AISummary:
type: object
properties:
summaryId:
type: string
format: uuid
content:
type: string
description: AI가 생성한 요약 내용
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
required:
- summaryId
- content
RelatedMinutes:
type: object
properties:
minutesId:
type: string
format: uuid
title:
type: string
meetingDate:
type: string
format: date-time
relevanceScore:
type: number
format: double
description: 관련도 점수 (0-100%)
summary:
type: string
required:
- minutesId
- title
- meetingDate
- relevanceScore
MinutesPermissions:
type: object
properties:
canEdit:
type: boolean
canShare:
type: boolean
required:
- canEdit
- canShare
UpdateMinutesRequest:
type: object
properties:
title:
type: string
sections:
type: array
items:
$ref: '#/components/schemas/SectionUpdate'
SectionUpdate:
type: object
properties:
sectionId:
type: string
format: uuid
content:
type: string
aiSummary:
type: string
relatedMinutesIds:
type: array
items:
type: string
format: uuid
description: 이 섹션과 연결할 관련 회의록 ID 목록 (최대 3개)
maxItems: 3
required:
- sectionId
MinutesUpdateResponse:
type: object
properties:
minutesId:
type: string
format: uuid
status:
type: string
enum: [DRAFT, FINALIZED]
updatedAt:
type: string
format: date-time
updatedBy:
type: string
version:
type: string
required:
- minutesId
- status
- updatedAt
- updatedBy
MinutesFinalizeResponse:
type: object
properties:
minutesId:
type: string
format: uuid
status:
type: string
enum: [FINALIZED]
version:
type: string
finalizedAt:
type: string
format: date-time
finalizedBy:
type: string
required:
- minutesId
- status
- version
- finalizedAt
- finalizedBy
SectionVerifyResponse:
type: object
properties:
sectionId:
type: string
format: uuid
isVerified:
type: boolean
verifiedBy:
type: string
verifiedAt:
type: string
format: date-time
required:
- sectionId
- isVerified
# ==================== Todo Schemas ====================
TodoListResponse:
type: object
properties:
statistics:
$ref: '#/components/schemas/TodoStatistics'
todos:
type: array
items:
$ref: '#/components/schemas/TodoDetail'
required:
- statistics
- todos
TodoStatistics:
type: object
properties:
total:
type: integer
description: 전체 Todo 개수
inProgress:
type: integer
description: 진행 중 Todo 개수
completed:
type: integer
description: 완료된 Todo 개수
urgent:
type: integer
description: 마감 임박 Todo 개수 (3일 이내)
completionRate:
type: number
format: double
description: 완료율 (%)
required:
- total
- inProgress
- completed
- urgent
- completionRate
TodoDetail:
type: object
properties:
todoId:
type: string
format: uuid
content:
type: string
assignee:
$ref: '#/components/schemas/TodoAssignee'
dueDate:
type: string
format: date
priority:
type: string
enum: [HIGH, MEDIUM, LOW]
status:
type: string
enum: [IN_PROGRESS, COMPLETED]
progress:
type: integer
minimum: 0
maximum: 100
description: 진행률 (%)
minutesId:
type: string
format: uuid
meetingTitle:
type: string
description: 관련 회의 제목
createdAt:
type: string
format: date-time
required:
- todoId
- content
- assignee
- priority
- status
- minutesId
- meetingTitle
TodoAssignee:
type: object
properties:
userId:
type: string
email:
type: string
format: email
name:
type: string
required:
- userId
- email
- name
CreateTodoRequest:
type: object
properties:
content:
type: string
maxLength: 500
assignee:
type: string
format: email
dueDate:
type: string
format: date
priority:
type: string
enum: [HIGH, MEDIUM, LOW]
default: MEDIUM
minutesId:
type: string
format: uuid
sectionId:
type: string
format: uuid
required:
- content
- assignee
- minutesId
TodoResponse:
type: object
properties:
todoId:
type: string
format: uuid
content:
type: string
assignee:
type: string
format: email
dueDate:
type: string
format: date
priority:
type: string
enum: [HIGH, MEDIUM, LOW]
status:
type: string
enum: [IN_PROGRESS, COMPLETED]
minutesId:
type: string
format: uuid
sectionId:
type: string
format: uuid
calendarEventId:
type: string
createdAt:
type: string
format: date-time
required:
- todoId
- content
- assignee
- priority
- status
- minutesId
TodoCompleteResponse:
type: object
properties:
todoId:
type: string
format: uuid
status:
type: string
enum: [COMPLETED]
completedAt:
type: string
format: date-time
completedBy:
type: string
minutesId:
type: string
format: uuid
allTodosCompleted:
type: boolean
required:
- todoId
- status
- completedAt
- completedBy
- allTodosCompleted
# ==================== Template Schemas ====================
TemplateResponse:
type: object
properties:
templateId:
type: string
name:
type: string
description:
type: string
icon:
type: string
description: 템플릿 아이콘 (이모지)
category:
type: string
enum: [GENERAL, SCRUM, KICKOFF, WEEKLY]
sections:
type: array
items:
$ref: '#/components/schemas/TemplateSection'
description: 템플릿 섹션 목록
required:
- templateId
- name
- category
- sections
TemplateSection:
type: object
properties:
sectionType:
type: string
title:
type: string
order:
type: integer
isRequired:
type: boolean
required:
- sectionType
- title
- order
- isRequired
# ==================== Error Schemas ====================
ErrorResponse:
type: object
properties:
error:
$ref: '#/components/schemas/Error'
required:
- error
Error:
type: object
properties:
code:
type: string
description: 에러 코드
message:
type: string
description: 에러 메시지
details:
type: string
description: 상세 설명
timestamp:
type: string
format: date-time
description: 발생 시간
path:
type: string
description: 요청 경로
required:
- code
- message
- timestamp
responses:
BadRequestError:
description: 잘못된 요청
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
error:
code: "BAD_REQUEST"
message: "잘못된 요청입니다"
details: "요청 데이터의 형식이 올바르지 않습니다"
timestamp: "2025-10-23T12:00:00Z"
path: "/api/meetings"
UnauthorizedError:
description: 인증 실패
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
error:
code: "UNAUTHORIZED"
message: "인증이 필요합니다"
details: "유효한 JWT 토큰을 제공해주세요"
timestamp: "2025-10-23T12:00:00Z"
path: "/api/dashboard"
ForbiddenError:
description: 권한 없음
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
error:
code: "FORBIDDEN"
message: "권한이 없습니다"
details: "해당 리소스에 접근할 권한이 없습니다"
timestamp: "2025-10-23T12:00:00Z"
path: "/api/minutes/{minutesId}"
NotFoundError:
description: 리소스를 찾을 수 없음
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
error:
code: "NOT_FOUND"
message: "리소스를 찾을 수 없습니다"
details: "요청한 리소스가 존재하지 않습니다"
timestamp: "2025-10-23T12:00:00Z"
path: "/api/meetings/{meetingId}"
ConflictError:
description: 충돌 발생
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
error:
code: "CONFLICT"
message: "충돌이 발생했습니다"
details: "중복된 회의 시간이 존재합니다"
timestamp: "2025-10-23T12:00:00Z"
path: "/api/meetings"
InternalServerError:
description: 서버 내부 오류
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
error:
code: "INTERNAL_SERVER_ERROR"
message: "서버 내부 오류가 발생했습니다"
details: "잠시 후 다시 시도해주세요"
timestamp: "2025-10-23T12:00:00Z"
path: "/api/dashboard"
security:
- bearerAuth: []