mirror of
https://github.com/hwanny1128/HGZero.git
synced 2025-12-06 16:06:23 +00:00
2098 lines
58 KiB
YAML
2098 lines
58 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'
|
|
verificationStatus:
|
|
$ref: '#/components/schemas/VerificationStatus'
|
|
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
|
|
|
|
EndMeetingRequest:
|
|
type: object
|
|
properties:
|
|
finalAgenda:
|
|
type: string
|
|
description: 최종 회의 안건
|
|
applyAiSuggestions:
|
|
type: boolean
|
|
default: true
|
|
description: AI 제안 자동 적용 여부
|
|
|
|
VerificationStatus:
|
|
type: object
|
|
properties:
|
|
totalSections:
|
|
type: integer
|
|
description: 전체 섹션 수
|
|
verifiedSections:
|
|
type: integer
|
|
description: 검증 완료된 섹션 수
|
|
verificationRate:
|
|
type: integer
|
|
description: 검증 완료율 (%)
|
|
sections:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/SectionVerificationInfo'
|
|
description: 섹션별 검증 상태
|
|
required:
|
|
- totalSections
|
|
- verifiedSections
|
|
- verificationRate
|
|
- sections
|
|
|
|
SectionVerificationInfo:
|
|
type: object
|
|
properties:
|
|
sectionId:
|
|
type: string
|
|
format: uuid
|
|
sectionType:
|
|
type: string
|
|
enum: [DISCUSSION, DECISION, TODO, SCHEDULE, RESOURCE, CUSTOM]
|
|
title:
|
|
type: string
|
|
isVerified:
|
|
type: boolean
|
|
isLocked:
|
|
type: boolean
|
|
verifiers:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Verifier'
|
|
required:
|
|
- sectionId
|
|
- sectionType
|
|
- title
|
|
- isVerified
|
|
- isLocked
|
|
- verifiers
|
|
|
|
Verifier:
|
|
type: object
|
|
properties:
|
|
userId:
|
|
type: string
|
|
name:
|
|
type: string
|
|
verifiedAt:
|
|
type: string
|
|
format: date-time
|
|
required:
|
|
- userId
|
|
- name
|
|
- verifiedAt
|
|
|
|
# ==================== 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: []
|