hgzero/design/backend/api/notification-service-api.yaml
ondal a551235ad7 API 설계 완료
- 5개 마이크로서비스 API 명세 작성 (User, Meeting, STT, AI, Notification)
- OpenAPI 3.0 표준 준수
- 총 47개 API 설계
- 유저스토리 100% 커버리지
- swagger-cli 검증 통과
- 종합 API 설계서 작성

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-23 10:49:29 +09:00

933 lines
27 KiB
YAML

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