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: []