openapi: 3.0.3 info: title: Notification Service API description: | 회의록 작성 및 공유 개선 서비스의 알림 발송 및 리마인더 관리 API ## 주요 기능 - 이메일 알림 발송 (회의 초대, Todo 할당, 리마인더) - 알림 이력 조회 및 관리 - 사용자 알림 설정 관리 ## Event-Driven Architecture - 알림 발송은 Azure Event Hubs를 통한 이벤트 기반 처리 - 비동기 처리로 성능 최적화 - 재시도 메커니즘으로 신뢰성 보장 version: 1.0.0 contact: name: Backend Development Team email: backend@example.com servers: - url: https://api.hgzero.com/notification/v1 description: Production Server - url: https://dev-api.hgzero.com/notification/v1 description: Development Server - url: http://localhost:8083/api/v1 description: Local Development tags: - name: Notification description: 알림 발송 및 관리 API - name: Notification Settings description: 사용자 알림 설정 API - name: Internal description: 내부 서비스 간 통신 API (Event Handler) paths: # ======================================== # Notification APIs # ======================================== /notifications/invitation: post: summary: 회의 초대 알림 발송 (내부 API) description: | MeetingCreated 이벤트를 수신하여 참석자에게 회의 초대 이메일을 발송합니다. - Event-Driven 방식으로 Meeting Service에서 이벤트 발행 - 참석자별 병렬 이메일 발송 - 발송 이력 저장 및 재시도 메커니즘 operationId: sendMeetingInvitation x-user-story: UFR-MEET-010 x-controller: NotificationController tags: - Internal requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/MeetingInvitationRequest' example: meetingId: "MTG-20250123-001" title: "2025년 1분기 전략 회의" scheduledAt: "2025-01-30T14:00:00Z" location: "회의실 A" participants: - userId: "U001" userName: "김철수" email: "kim@example.com" - userId: "U002" userName: "이영희" email: "lee@example.com" creatorName: "박팀장" meetingLink: "https://meet.hgzero.com/MTG-20250123-001" calendarLink: "https://calendar.hgzero.com/add/MTG-20250123-001" responses: '200': description: 알림 발송 성공 content: application/json: schema: $ref: '#/components/schemas/NotificationResponse' example: notificationId: "NTF-20250123-001" status: "SENT" sentCount: 2 failedCount: 0 createdAt: "2025-01-23T10:00:00Z" '400': $ref: '#/components/responses/BadRequest' '500': $ref: '#/components/responses/InternalServerError' /notifications/todo: post: summary: Todo 할당 알림 발송 (내부 API) description: | TodoAssigned 이벤트를 수신하여 담당자에게 Todo 알림 이메일을 발송합니다. - 할당 즉시 알림 - 마감일 3일 전, 1일 전, 당일 리마인더 스케줄링 - 회의록 링크 포함 operationId: sendTodoNotification x-user-story: UFR-TODO-010 x-controller: NotificationController tags: - Internal requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TodoNotificationRequest' example: todoId: "TODO-20250123-001" meetingId: "MTG-20250123-001" assignee: userId: "U001" userName: "김철수" email: "kim@example.com" content: "API 설계서 작성 및 검토" dueDate: "2025-01-30T23:59:59Z" priority: "HIGH" minutesLink: "https://hgzero.com/minutes/MTG-20250123-001#section-3" meetingTitle: "2025년 1분기 전략 회의" responses: '200': description: 알림 발송 성공 content: application/json: schema: $ref: '#/components/schemas/NotificationResponse' example: notificationId: "NTF-20250123-002" status: "SENT" sentCount: 1 failedCount: 0 createdAt: "2025-01-23T10:05:00Z" '400': $ref: '#/components/responses/BadRequest' '500': $ref: '#/components/responses/InternalServerError' /notifications: get: summary: 사용자별 알림 이력 조회 description: | 사용자가 받은 알림 이력을 조회합니다. - 알림 유형별 필터링 (초대, Todo, 리마인더) - 상태별 필터링 (발송완료, 발송실패) - 페이징 지원 operationId: getNotifications x-user-story: AFR-USER-020 x-controller: NotificationController tags: - Notification parameters: - $ref: '#/components/parameters/UserIdHeader' - name: type in: query description: 알림 유형 필터 required: false schema: type: string enum: - INVITATION - TODO_ASSIGNED - REMINDER - TODO_REMINDER - name: status in: query description: 알림 상태 필터 required: false schema: type: string enum: - SENT - FAILED - PENDING - name: page in: query description: 페이지 번호 (0부터 시작) required: false schema: type: integer minimum: 0 default: 0 - name: size in: query description: 페이지당 항목 수 required: false schema: type: integer minimum: 1 maximum: 100 default: 20 responses: '200': description: 알림 이력 조회 성공 content: application/json: schema: $ref: '#/components/schemas/NotificationListResponse' example: notifications: - notificationId: "NTF-20250123-002" type: "TODO_ASSIGNED" title: "[TODO 할당] API 설계서 작성 및 검토" content: "Todo가 할당되었습니다. 마감일: 2025-01-30" status: "SENT" sentAt: "2025-01-23T10:05:00Z" relatedId: "TODO-20250123-001" - notificationId: "NTF-20250123-001" type: "INVITATION" title: "[회의 초대] 2025년 1분기 전략 회의" content: "회의에 초대되었습니다. 일시: 2025-01-30 14:00" status: "SENT" sentAt: "2025-01-23T10:00:00Z" relatedId: "MTG-20250123-001" pagination: currentPage: 0 pageSize: 20 totalElements: 2 totalPages: 1 '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalServerError' /notifications/{notificationId}: get: summary: 특정 알림 상세 조회 description: | 알림 ID로 특정 알림의 상세 정보를 조회합니다. - 발송 상태 - 수신자 정보 - 템플릿 정보 - 재시도 이력 operationId: getNotificationById x-user-story: AFR-USER-020 x-controller: NotificationController tags: - Notification parameters: - $ref: '#/components/parameters/UserIdHeader' - name: notificationId in: path description: 알림 ID required: true schema: type: string pattern: '^NTF-[0-9]{8}-[0-9]{3}$' example: "NTF-20250123-001" responses: '200': description: 알림 상세 조회 성공 content: application/json: schema: $ref: '#/components/schemas/NotificationDetailResponse' example: notificationId: "NTF-20250123-001" type: "INVITATION" title: "[회의 초대] 2025년 1분기 전략 회의" content: "회의에 초대되었습니다." status: "SENT" relatedId: "MTG-20250123-001" recipients: - email: "kim@example.com" status: "SENT" sentAt: "2025-01-23T10:00:05Z" - email: "lee@example.com" status: "SENT" sentAt: "2025-01-23T10:00:06Z" templateId: "meeting-invitation" createdAt: "2025-01-23T10:00:00Z" completedAt: "2025-01-23T10:00:10Z" retryCount: 0 '404': $ref: '#/components/responses/NotFound' '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalServerError' # ======================================== # Notification Settings APIs # ======================================== /notifications/settings: get: summary: 사용자 알림 설정 조회 description: | 사용자의 알림 설정을 조회합니다. - 알림 채널 설정 (이메일/SMS) - 알림 유형별 활성화 여부 - 수신 시간대 설정 operationId: getNotificationSettings x-user-story: AFR-USER-020 x-controller: NotificationSettingsController tags: - Notification Settings parameters: - $ref: '#/components/parameters/UserIdHeader' responses: '200': description: 알림 설정 조회 성공 content: application/json: schema: $ref: '#/components/schemas/NotificationSettingsResponse' example: userId: "U001" channels: email: true sms: false preferences: invitationEnabled: true todoEnabled: true reminderEnabled: true minutesUpdateEnabled: false quietHours: enabled: true startTime: "22:00" endTime: "08:00" timezone: "Asia/Seoul" '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalServerError' put: summary: 사용자 알림 설정 업데이트 description: | 사용자의 알림 설정을 변경합니다. - 부분 업데이트 지원 - 설정 변경 즉시 적용 operationId: updateNotificationSettings x-user-story: AFR-USER-020 x-controller: NotificationSettingsController tags: - Notification Settings parameters: - $ref: '#/components/parameters/UserIdHeader' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/NotificationSettingsUpdateRequest' example: channels: email: true sms: false preferences: invitationEnabled: true todoEnabled: true reminderEnabled: false minutesUpdateEnabled: false quietHours: enabled: true startTime: "23:00" endTime: "07:00" timezone: "Asia/Seoul" responses: '200': description: 알림 설정 업데이트 성공 content: application/json: schema: $ref: '#/components/schemas/NotificationSettingsResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalServerError' # ======================================== # Components # ======================================== components: schemas: # Request Schemas MeetingInvitationRequest: type: object required: - meetingId - title - scheduledAt - participants - creatorName properties: meetingId: type: string description: 회의 ID pattern: '^MTG-[0-9]{8}-[0-9]{3}$' example: "MTG-20250123-001" title: type: string description: 회의 제목 maxLength: 100 example: "2025년 1분기 전략 회의" scheduledAt: type: string format: date-time description: 회의 시작 일시 (ISO 8601) example: "2025-01-30T14:00:00Z" location: type: string description: 회의 장소 maxLength: 200 example: "회의실 A" participants: type: array description: 참석자 목록 minItems: 1 items: $ref: '#/components/schemas/Participant' creatorName: type: string description: 회의 생성자 이름 example: "박팀장" meetingLink: type: string format: uri description: 회의 참여 링크 example: "https://meet.hgzero.com/MTG-20250123-001" calendarLink: type: string format: uri description: 캘린더 추가 링크 example: "https://calendar.hgzero.com/add/MTG-20250123-001" TodoNotificationRequest: type: object required: - todoId - meetingId - assignee - content - dueDate - priority - minutesLink - meetingTitle properties: todoId: type: string description: Todo ID pattern: '^TODO-[0-9]{8}-[0-9]{3}$' example: "TODO-20250123-001" meetingId: type: string description: 관련 회의 ID pattern: '^MTG-[0-9]{8}-[0-9]{3}$' example: "MTG-20250123-001" assignee: $ref: '#/components/schemas/Participant' content: type: string description: Todo 내용 maxLength: 500 example: "API 설계서 작성 및 검토" dueDate: type: string format: date-time description: 마감일 (ISO 8601) example: "2025-01-30T23:59:59Z" priority: type: string description: 우선순위 enum: - HIGH - MEDIUM - LOW example: "HIGH" minutesLink: type: string format: uri description: 회의록 링크 (해당 섹션) example: "https://hgzero.com/minutes/MTG-20250123-001#section-3" meetingTitle: type: string description: 회의 제목 example: "2025년 1분기 전략 회의" NotificationSettingsUpdateRequest: type: object properties: channels: type: object description: 알림 채널 설정 properties: email: type: boolean description: 이메일 알림 활성화 sms: type: boolean description: SMS 알림 활성화 preferences: type: object description: 알림 유형별 활성화 설정 properties: invitationEnabled: type: boolean description: 회의 초대 알림 todoEnabled: type: boolean description: Todo 할당 알림 reminderEnabled: type: boolean description: 리마인더 알림 minutesUpdateEnabled: type: boolean description: 회의록 수정 알림 quietHours: type: object description: 방해 금지 시간대 설정 properties: enabled: type: boolean description: 방해 금지 시간대 활성화 startTime: type: string format: time description: 시작 시간 (HH:mm) example: "22:00" endTime: type: string format: time description: 종료 시간 (HH:mm) example: "08:00" timezone: type: string description: 타임존 example: "Asia/Seoul" # Response Schemas NotificationResponse: type: object required: - notificationId - status - sentCount - failedCount - createdAt properties: notificationId: type: string description: 알림 ID pattern: '^NTF-[0-9]{8}-[0-9]{3}$' example: "NTF-20250123-001" status: type: string description: 알림 전체 상태 enum: - SENT - PARTIAL - FAILED - PENDING example: "SENT" sentCount: type: integer description: 발송 성공 건수 minimum: 0 example: 2 failedCount: type: integer description: 발송 실패 건수 minimum: 0 example: 0 createdAt: type: string format: date-time description: 알림 생성 일시 example: "2025-01-23T10:00:00Z" NotificationListResponse: type: object required: - notifications - pagination properties: notifications: type: array items: $ref: '#/components/schemas/NotificationSummary' pagination: $ref: '#/components/schemas/PaginationInfo' NotificationSummary: type: object required: - notificationId - type - title - status - sentAt properties: notificationId: type: string description: 알림 ID example: "NTF-20250123-001" type: type: string description: 알림 유형 enum: - INVITATION - TODO_ASSIGNED - REMINDER - TODO_REMINDER example: "INVITATION" title: type: string description: 알림 제목 example: "[회의 초대] 2025년 1분기 전략 회의" content: type: string description: 알림 내용 요약 example: "회의에 초대되었습니다. 일시: 2025-01-30 14:00" status: type: string description: 발송 상태 enum: - SENT - FAILED - PENDING example: "SENT" sentAt: type: string format: date-time description: 발송 일시 example: "2025-01-23T10:00:00Z" relatedId: type: string description: 관련 객체 ID (회의 ID, Todo ID 등) example: "MTG-20250123-001" NotificationDetailResponse: type: object required: - notificationId - type - title - content - status - relatedId - recipients - createdAt properties: notificationId: type: string description: 알림 ID example: "NTF-20250123-001" type: type: string description: 알림 유형 enum: - INVITATION - TODO_ASSIGNED - REMINDER - TODO_REMINDER title: type: string description: 알림 제목 example: "[회의 초대] 2025년 1분기 전략 회의" content: type: string description: 알림 전체 내용 example: "회의에 초대되었습니다." status: type: string description: 알림 전체 상태 enum: - SENT - PARTIAL - FAILED - PENDING relatedId: type: string description: 관련 객체 ID example: "MTG-20250123-001" recipients: type: array description: 수신자별 발송 상태 items: type: object properties: email: type: string format: email description: 수신자 이메일 status: type: string enum: - SENT - FAILED - PENDING sentAt: type: string format: date-time description: 발송 일시 errorMessage: type: string description: 오류 메시지 (실패 시) templateId: type: string description: 사용된 템플릿 ID example: "meeting-invitation" createdAt: type: string format: date-time description: 알림 생성 일시 completedAt: type: string format: date-time description: 알림 완료 일시 retryCount: type: integer description: 재시도 횟수 minimum: 0 NotificationSettingsResponse: type: object required: - userId - channels - preferences properties: userId: type: string description: 사용자 ID example: "U001" channels: type: object description: 알림 채널 설정 required: - email - sms properties: email: type: boolean description: 이메일 알림 활성화 sms: type: boolean description: SMS 알림 활성화 preferences: type: object description: 알림 유형별 활성화 설정 required: - invitationEnabled - todoEnabled - reminderEnabled - minutesUpdateEnabled properties: invitationEnabled: type: boolean description: 회의 초대 알림 todoEnabled: type: boolean description: Todo 할당 알림 reminderEnabled: type: boolean description: 리마인더 알림 minutesUpdateEnabled: type: boolean description: 회의록 수정 알림 quietHours: type: object description: 방해 금지 시간대 설정 properties: enabled: type: boolean startTime: type: string format: time endTime: type: string format: time timezone: type: string # Common Schemas Participant: type: object required: - userId - userName - email properties: userId: type: string description: 사용자 ID example: "U001" userName: type: string description: 사용자 이름 example: "김철수" email: type: string format: email description: 이메일 주소 example: "kim@example.com" PaginationInfo: type: object required: - currentPage - pageSize - totalElements - totalPages properties: currentPage: type: integer description: 현재 페이지 번호 (0부터 시작) minimum: 0 example: 0 pageSize: type: integer description: 페이지당 항목 수 minimum: 1 example: 20 totalElements: type: integer description: 전체 항목 수 minimum: 0 example: 2 totalPages: type: integer description: 전체 페이지 수 minimum: 0 example: 1 ErrorResponse: type: object required: - code - message - timestamp properties: code: type: string description: 오류 코드 example: "INVALID_REQUEST" message: type: string description: 오류 메시지 example: "Invalid request parameters" timestamp: type: string format: date-time description: 오류 발생 시각 details: type: array description: 상세 오류 정보 items: type: object properties: field: type: string message: type: string parameters: UserIdHeader: name: X-User-Id in: header description: 사용자 ID (JWT 토큰에서 추출) required: true schema: type: string example: "U001" responses: BadRequest: description: 잘못된 요청 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: code: "INVALID_REQUEST" message: "Invalid request parameters" timestamp: "2025-01-23T10:00:00Z" details: - field: "meetingId" message: "Meeting ID is required" Unauthorized: description: 인증 실패 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: code: "UNAUTHORIZED" message: "Authentication required" timestamp: "2025-01-23T10:00:00Z" NotFound: description: 리소스를 찾을 수 없음 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: code: "NOT_FOUND" message: "Notification not found" timestamp: "2025-01-23T10:00:00Z" InternalServerError: description: 서버 내부 오류 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: code: "INTERNAL_SERVER_ERROR" message: "An unexpected error occurred" timestamp: "2025-01-23T10:00:00Z" securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT description: JWT 토큰 기반 인증 security: - BearerAuth: []