mirror of
https://github.com/hwanny1128/HGZero.git
synced 2025-12-06 07:56:24 +00:00
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>
This commit is contained in:
parent
b4faf85c2b
commit
a551235ad7
115
claude/api-design.md
Normal file
115
claude/api-design.md
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
# STT Service API 설계 완료
|
||||||
|
|
||||||
|
## 작업 결과
|
||||||
|
|
||||||
|
### 생성된 파일
|
||||||
|
- **파일 경로**: `C:\Users\KTDS\home\workspace\HGZero\design\backend\api\stt-service-api.yaml`
|
||||||
|
- **형식**: OpenAPI 3.0.3
|
||||||
|
- **검증 상태**: ✅ 검증 완료 (swagger-cli)
|
||||||
|
|
||||||
|
### API 개요
|
||||||
|
|
||||||
|
#### 1. Recording API (음성 녹음 관리)
|
||||||
|
- `POST /recordings/prepare` - 회의 녹음 준비
|
||||||
|
- `POST /recordings/{recordingId}/start` - 음성 녹음 시작
|
||||||
|
- `POST /recordings/{recordingId}/stop` - 음성 녹음 중지
|
||||||
|
- `GET /recordings/{recordingId}` - 녹음 정보 조회
|
||||||
|
|
||||||
|
#### 2. Transcription API (음성-텍스트 변환)
|
||||||
|
- `POST /transcripts/stream` - 실시간 음성-텍스트 변환 (스트리밍)
|
||||||
|
- `POST /transcripts/batch` - 배치 음성-텍스트 변환
|
||||||
|
- `POST /transcripts/callback` - 배치 변환 완료 콜백
|
||||||
|
- `GET /transcripts/{recordingId}` - 변환 텍스트 전체 조회
|
||||||
|
|
||||||
|
#### 3. Speaker API (화자 식별 및 관리)
|
||||||
|
- `POST /speakers/identify` - 화자 식별
|
||||||
|
- `GET /speakers/{speakerId}` - 화자 정보 조회
|
||||||
|
- `PUT /speakers/{speakerId}` - 화자 정보 업데이트
|
||||||
|
- `GET /recordings/{recordingId}/speakers` - 녹음의 화자 목록 조회
|
||||||
|
|
||||||
|
### 주요 특징
|
||||||
|
|
||||||
|
#### 1. 유저스토리 매핑
|
||||||
|
모든 API는 유저스토리와 매핑되어 있습니다:
|
||||||
|
- **UFR-STT-010** (음성녹음인식): Recording API, Speaker API
|
||||||
|
- **UFR-STT-020** (텍스트변환): Transcription API
|
||||||
|
|
||||||
|
#### 2. 완전한 스키마 정의
|
||||||
|
- 25개의 스키마 정의
|
||||||
|
- 모든 Request/Response 모델 포함
|
||||||
|
- Example 데이터 포함으로 Swagger UI에서 즉시 테스트 가능
|
||||||
|
|
||||||
|
#### 3. Azure 통합
|
||||||
|
- Azure Speech Service 연동
|
||||||
|
- Azure Blob Storage 통합
|
||||||
|
- Azure Event Hubs 이벤트 발행
|
||||||
|
|
||||||
|
#### 4. 실시간 처리
|
||||||
|
- WebSocket 기반 스트리밍 지원
|
||||||
|
- 실시간 인식 지연: < 1초
|
||||||
|
- 화자 식별 정확도: > 90%
|
||||||
|
|
||||||
|
#### 5. 성능 정보
|
||||||
|
각 API의 예상 처리 시간 명시:
|
||||||
|
- 녹음 준비: ~1.1초
|
||||||
|
- 실시간 변환: 1-4초
|
||||||
|
- 배치 변환: 7-33초
|
||||||
|
|
||||||
|
### API 확인 방법
|
||||||
|
|
||||||
|
#### 1. Swagger Editor 사용
|
||||||
|
1. https://editor.swagger.io/ 접속
|
||||||
|
2. 생성된 YAML 파일 내용 복사하여 붙여넣기
|
||||||
|
3. 우측 패널에서 API 문서 확인 및 테스트
|
||||||
|
|
||||||
|
#### 2. 로컬 Swagger UI 실행
|
||||||
|
```bash
|
||||||
|
# Swagger UI Docker 실행
|
||||||
|
docker run -p 8080:8080 -e SWAGGER_JSON=/api/stt-service-api.yaml \
|
||||||
|
-v C:\Users\KTDS\home\workspace\HGZero\design\backend\api:/api \
|
||||||
|
swaggerapi/swagger-ui
|
||||||
|
|
||||||
|
# 브라우저에서 http://localhost:8080 접속
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. VS Code Extension
|
||||||
|
- **확장**: Swagger Viewer
|
||||||
|
- YAML 파일 열고 `Shift + Alt + P` 실행
|
||||||
|
- 미리보기에서 API 문서 확인
|
||||||
|
|
||||||
|
### 설계 원칙 준수
|
||||||
|
|
||||||
|
✅ **유저스토리 기반 설계**
|
||||||
|
- 모든 API에 x-user-story 필드 명시
|
||||||
|
- 불필요한 API 추가 없음
|
||||||
|
|
||||||
|
✅ **시퀀스 일관성**
|
||||||
|
- 내부 시퀀스 설계와 완전히 일치
|
||||||
|
- 모든 처리 흐름 반영
|
||||||
|
|
||||||
|
✅ **OpenAPI 3.0 표준**
|
||||||
|
- servers 섹션 필수 포함
|
||||||
|
- 완전한 스키마 정의
|
||||||
|
- JWT 인증 방식 명시
|
||||||
|
|
||||||
|
✅ **Example 데이터**
|
||||||
|
- 모든 스키마에 example 포함
|
||||||
|
- 실제 테스트 가능한 데이터
|
||||||
|
|
||||||
|
✅ **검증 완료**
|
||||||
|
- swagger-cli 자동 검증 통과
|
||||||
|
- YAML 구문 오류 없음
|
||||||
|
- 스키마 참조 유효성 확인
|
||||||
|
|
||||||
|
### 다음 단계
|
||||||
|
|
||||||
|
1. **Meeting Service API 설계** (회의, 회의록, Todo 통합)
|
||||||
|
2. **AI Service API 설계** (회의록 자동 작성, RAG 기능)
|
||||||
|
3. **User Service API 설계** (인증 전용)
|
||||||
|
4. **Notification Service API 설계** (알림 발송)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**작성자**: 준호 (Backend Developer)
|
||||||
|
**작성일**: 2025-01-23
|
||||||
|
**검증 도구**: swagger-cli v4.0.4
|
||||||
471
design/backend/api/API설계서.md
Normal file
471
design/backend/api/API설계서.md
Normal file
@ -0,0 +1,471 @@
|
|||||||
|
# API 설계서
|
||||||
|
|
||||||
|
회의록 작성 및 공유 개선 서비스
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 목차
|
||||||
|
|
||||||
|
1. [개요](#개요)
|
||||||
|
2. [API 설계 원칙](#api-설계-원칙)
|
||||||
|
3. [마이크로서비스별 API](#마이크로서비스별-api)
|
||||||
|
4. [공통 사항](#공통-사항)
|
||||||
|
5. [API 확인 방법](#api-확인-방법)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 개요
|
||||||
|
|
||||||
|
### 프로젝트 정보
|
||||||
|
- **프로젝트명**: 회의록 작성 및 공유 개선 서비스
|
||||||
|
- **설계 버전**: v2.0
|
||||||
|
- **설계일**: 2025-01-23
|
||||||
|
- **설계자**: 아키텍트(길동), Backend Developer(준호)
|
||||||
|
|
||||||
|
### 마이크로서비스 구성
|
||||||
|
본 서비스는 5개의 마이크로서비스로 구성됩니다:
|
||||||
|
|
||||||
|
1. **User Service** - 사용자 인증 (LDAP 연동, JWT 토큰 발급/검증)
|
||||||
|
2. **Meeting Service** - 회의, 회의록, Todo, 실시간 협업 통합 관리
|
||||||
|
3. **STT Service** - 음성 녹음 관리, 음성-텍스트 변환, 화자 식별
|
||||||
|
4. **AI Service** - AI 기반 회의록 자동화, Todo 추출, 지능형 검색 (RAG 통합)
|
||||||
|
5. **Notification Service** - 알림 발송 및 리마인더 관리
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API 설계 원칙
|
||||||
|
|
||||||
|
### 1. 설계 기준
|
||||||
|
- **유저스토리 기반**: 모든 API는 유저스토리와 매핑 (x-user-story 필드)
|
||||||
|
- **시퀀스 일치**: 외부/내부 시퀀스 설계서와 100% 일치
|
||||||
|
- **OpenAPI 3.0**: OpenAPI 3.0.3 표준 준수
|
||||||
|
- **컨트롤러 명시**: 각 API별 담당 컨트롤러 명시 (x-controller 필드)
|
||||||
|
|
||||||
|
### 2. 공통 표준
|
||||||
|
- **인증 방식**: JWT Bearer Token
|
||||||
|
- **요청 헤더**: 모든 API 요청에 사용자 정보 포함
|
||||||
|
- `X-User-Id`: 사용자 ID
|
||||||
|
- `X-User-Name`: 사용자 이름
|
||||||
|
- `X-User-Email`: 사용자 이메일
|
||||||
|
- **응답 형식**: JSON
|
||||||
|
- **에러 응답**: 표준화된 에러 응답 형식
|
||||||
|
|
||||||
|
### 3. 서비스 독립성
|
||||||
|
- **각 서비스별 독립적인 OpenAPI 명세**
|
||||||
|
- **서비스별 모든 스키마 포함**
|
||||||
|
- **중복 스키마 허용** (초기 단계)
|
||||||
|
- **독립 배포 가능**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 마이크로서비스별 API
|
||||||
|
|
||||||
|
### 1. User Service
|
||||||
|
|
||||||
|
#### 개요
|
||||||
|
- **파일**: `user-service-api.yaml`
|
||||||
|
- **베이스 URL**: `/api/v1`
|
||||||
|
- **주요 기능**: 사용자 인증 전용 (LDAP 인증, JWT 토큰 관리)
|
||||||
|
|
||||||
|
#### API 목록
|
||||||
|
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| POST | /auth/login | 사용자 로그인 | AFR-USER-010 | UserController |
|
||||||
|
| POST | /auth/refresh | Access Token 갱신 | AFR-USER-010 | UserController |
|
||||||
|
| POST | /auth/logout | 로그아웃 | AFR-USER-010 | UserController |
|
||||||
|
| GET | /auth/validate | 토큰 검증 | AFR-USER-010 | UserController |
|
||||||
|
|
||||||
|
#### 주요 특징
|
||||||
|
- LDAP 인증 (LDAPS, port 636)
|
||||||
|
- JWT 토큰 관리 (Access: 1시간, Refresh: 7일)
|
||||||
|
- 계정 잠금 기능 (5회 실패 시 30분)
|
||||||
|
- Redis 기반 Refresh Token 관리
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Meeting Service
|
||||||
|
|
||||||
|
#### 개요
|
||||||
|
- **파일**: `meeting-service-api.yaml`
|
||||||
|
- **베이스 URL**: `/api/v1`
|
||||||
|
- **주요 기능**: 회의, 회의록, Todo, 실시간 협업 통합 관리
|
||||||
|
|
||||||
|
#### API 목록
|
||||||
|
|
||||||
|
**Dashboard APIs (1개)**
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| GET | /dashboard | 대시보드 데이터 조회 | AFR-USER-020 | DashboardController |
|
||||||
|
|
||||||
|
**Meeting APIs (4개)**
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| POST | /meetings | 회의 예약 | UFR-MEET-010 | MeetingController |
|
||||||
|
| PUT | /meetings/{meetingId}/template | 템플릿 선택 | UFR-MEET-020 | MeetingController |
|
||||||
|
| POST | /meetings/{meetingId}/start | 회의 시작 | UFR-MEET-030 | MeetingController |
|
||||||
|
| POST | /meetings/{meetingId}/end | 회의 종료 | UFR-MEET-040 | MeetingController |
|
||||||
|
|
||||||
|
**Minutes APIs (7개)**
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| GET | /minutes | 회의록 목록 조회 | UFR-MEET-046 | MinutesController |
|
||||||
|
| GET | /minutes/{minutesId} | 회의록 상세 조회 | UFR-MEET-047 | MinutesController |
|
||||||
|
| PATCH | /minutes/{minutesId} | 회의록 수정 | UFR-MEET-055 | MinutesController |
|
||||||
|
| POST | /minutes/{minutesId}/finalize | 회의록 확정 | UFR-MEET-050 | MinutesController |
|
||||||
|
| POST | /minutes/{minutesId}/sections/{sectionId}/verify | 섹션 검증 완료 | UFR-COLLAB-030 | MinutesController |
|
||||||
|
| POST | /minutes/{minutesId}/sections/{sectionId}/lock | 섹션 잠금 | UFR-COLLAB-030 | MinutesController |
|
||||||
|
| DELETE | /minutes/{minutesId}/sections/{sectionId}/lock | 섹션 잠금 해제 | UFR-COLLAB-030 | MinutesController |
|
||||||
|
|
||||||
|
**Todo APIs (2개)**
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| POST | /todos | Todo 할당 | UFR-TODO-010 | TodoController |
|
||||||
|
| PATCH | /todos/{todoId}/complete | Todo 완료 처리 | UFR-TODO-030 | TodoController |
|
||||||
|
|
||||||
|
**Template APIs (2개)**
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| GET | /templates | 템플릿 목록 조회 | UFR-MEET-020 | TemplateController |
|
||||||
|
| GET | /templates/{templateId} | 템플릿 상세 조회 | UFR-MEET-020 | TemplateController |
|
||||||
|
|
||||||
|
**WebSocket Endpoints (1개)**
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| GET | /ws/minutes/{minutesId} | 실시간 협업 WebSocket | UFR-COLLAB-010 | WebSocketController |
|
||||||
|
|
||||||
|
#### 주요 특징
|
||||||
|
- WebSocket 기반 실시간 협업
|
||||||
|
- 충돌 해결 메커니즘 (Last Write Wins)
|
||||||
|
- 섹션별 검증 및 잠금 기능
|
||||||
|
- Todo와 회의록 양방향 연결
|
||||||
|
- 버전 관리
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. STT Service
|
||||||
|
|
||||||
|
#### 개요
|
||||||
|
- **파일**: `stt-service-api.yaml`
|
||||||
|
- **베이스 URL**: `/api/v1`
|
||||||
|
- **주요 기능**: 음성 녹음 관리, 음성-텍스트 변환, 화자 식별
|
||||||
|
|
||||||
|
#### API 목록
|
||||||
|
|
||||||
|
**Recording APIs (4개)**
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| POST | /recordings/prepare | 녹음 준비 | UFR-STT-010 | RecordingController |
|
||||||
|
| POST | /recordings/{recordingId}/start | 녹음 시작 | UFR-STT-010 | RecordingController |
|
||||||
|
| POST | /recordings/{recordingId}/stop | 녹음 중지 | UFR-STT-010 | RecordingController |
|
||||||
|
| GET | /recordings/{recordingId} | 녹음 정보 조회 | UFR-STT-010 | RecordingController |
|
||||||
|
|
||||||
|
**Transcription APIs (4개)**
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| POST | /transcriptions/stream | 실시간 스트리밍 변환 | UFR-STT-020 | TranscriptionController |
|
||||||
|
| POST | /transcriptions/batch | 배치 변환 | UFR-STT-020 | TranscriptionController |
|
||||||
|
| POST | /transcriptions/callback | 변환 완료 콜백 | UFR-STT-020 | TranscriptionController |
|
||||||
|
| GET | /transcriptions/{recordingId}/full | 전체 텍스트 조회 | UFR-STT-020 | TranscriptionController |
|
||||||
|
|
||||||
|
**Speaker APIs (4개)**
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| POST | /speakers/identify | 화자 식별 | UFR-STT-010 | SpeakerController |
|
||||||
|
| GET | /speakers/{speakerId} | 화자 정보 조회 | UFR-STT-010 | SpeakerController |
|
||||||
|
| PATCH | /speakers/{speakerId} | 화자 정보 수정 | UFR-STT-010 | SpeakerController |
|
||||||
|
| GET | /recordings/{recordingId}/speakers | 녹음별 화자 목록 | UFR-STT-010 | SpeakerController |
|
||||||
|
|
||||||
|
#### 주요 특징
|
||||||
|
- WebSocket 기반 실시간 스트리밍 (< 1초 지연)
|
||||||
|
- 화자 식별 정확도 90% 이상
|
||||||
|
- Azure Speech Service 통합
|
||||||
|
- Azure Blob Storage 연동
|
||||||
|
- Azure Event Hubs 비동기 처리
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. AI Service
|
||||||
|
|
||||||
|
#### 개요
|
||||||
|
- **파일**: `ai-service-api.yaml`
|
||||||
|
- **베이스 URL**: `/api/v1`
|
||||||
|
- **주요 기능**: AI 기반 회의록 자동화, Todo 추출, 지능형 검색 (RAG 통합)
|
||||||
|
|
||||||
|
#### API 목록
|
||||||
|
|
||||||
|
**Transcript Processing APIs (2개)**
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| POST | /transcripts/process | 회의록 자동 작성 | UFR-AI-010 | TranscriptController |
|
||||||
|
| POST | /transcripts/{meetingId}/improve | 회의록 개선 (프롬프팅) | UFR-AI-030 | TranscriptController |
|
||||||
|
|
||||||
|
**Todo APIs (1개)**
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| POST | /todos/extract | Todo 자동 추출 | UFR-AI-020 | TodoController |
|
||||||
|
|
||||||
|
**Related Minutes APIs (1개)**
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| GET | /transcripts/{meetingId}/related | 관련 회의록 연결 | UFR-AI-040 | TranscriptController |
|
||||||
|
|
||||||
|
**Term Explanation APIs (2개)**
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| POST | /terms/detect | 전문용어 감지 | UFR-RAG-010 | TermController |
|
||||||
|
| GET | /terms/{term}/explain | 맥락 기반 용어 설명 | UFR-RAG-020 | TermController |
|
||||||
|
|
||||||
|
**Suggestion APIs (2개)**
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| POST | /suggestions/discussion | 논의사항 제안 | UFR-AI-010 | SuggestionController |
|
||||||
|
| POST | /suggestions/decision | 결정사항 제안 | UFR-AI-010 | SuggestionController |
|
||||||
|
|
||||||
|
#### 주요 특징
|
||||||
|
- LLM 기반 회의록 자동 작성
|
||||||
|
- 7가지 프롬프트 유형 지원
|
||||||
|
- 1Page 요약, 핵심 요약, 상세 보고서
|
||||||
|
- 의사결정 중심, 액션 아이템 중심
|
||||||
|
- 경영진 보고용, 커스텀
|
||||||
|
- RAG 기반 관련 회의록 검색 (벡터 유사도 70% 이상)
|
||||||
|
- 맥락 기반 전문용어 설명
|
||||||
|
- 실시간 논의사항/결정사항 제안
|
||||||
|
|
||||||
|
#### 차별화 포인트
|
||||||
|
1. **맥락 기반 용어 설명**: 단순 정의가 아닌 조직 내 실제 사용 맥락 제공
|
||||||
|
2. **프롬프팅 기반 개선**: 다양한 형식의 회의록 생성
|
||||||
|
3. **실시간 추천**: AI 기반 논의사항/결정사항 자동 제안
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. Notification Service
|
||||||
|
|
||||||
|
#### 개요
|
||||||
|
- **파일**: `notification-service-api.yaml`
|
||||||
|
- **베이스 URL**: `/api/v1`
|
||||||
|
- **주요 기능**: 알림 발송 및 리마인더 관리
|
||||||
|
|
||||||
|
#### API 목록
|
||||||
|
|
||||||
|
**Internal APIs (2개) - 이벤트 핸들러**
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| POST | /notifications/invitation | 회의 초대 알림 발송 | UFR-MEET-010 | NotificationController |
|
||||||
|
| POST | /notifications/todo | Todo 할당 알림 발송 | UFR-TODO-010 | NotificationController |
|
||||||
|
|
||||||
|
**Public APIs (2개)**
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| GET | /notifications | 사용자별 알림 이력 조회 | AFR-USER-020 | NotificationController |
|
||||||
|
| GET | /notifications/{notificationId} | 알림 상세 조회 | AFR-USER-020 | NotificationController |
|
||||||
|
|
||||||
|
**Settings APIs (2개)**
|
||||||
|
| Method | Endpoint | 설명 | 유저스토리 | 컨트롤러 |
|
||||||
|
|--------|----------|------|-----------|----------|
|
||||||
|
| GET | /notifications/settings | 알림 설정 조회 | AFR-USER-020 | NotificationSettingsController |
|
||||||
|
| PUT | /notifications/settings | 알림 설정 업데이트 | AFR-USER-020 | NotificationSettingsController |
|
||||||
|
|
||||||
|
#### 주요 특징
|
||||||
|
- Azure Event Hubs 기반 비동기 처리
|
||||||
|
- 이메일 템플릿 렌더링
|
||||||
|
- 중복 발송 방지 (Idempotency)
|
||||||
|
- 재시도 메커니즘 (최대 3회, exponential backoff)
|
||||||
|
- 알림 설정 관리 (채널, 유형, 방해 금지 시간대)
|
||||||
|
|
||||||
|
#### 이메일 템플릿
|
||||||
|
- **회의 초대**: 회의 정보 + 참여 링크 + 캘린더 추가
|
||||||
|
- **Todo 할당**: Todo 상세 + 회의록 링크
|
||||||
|
- **리마인더**: 회의 시작 30분 전 자동 발송
|
||||||
|
- **Todo 리마인더**: 마감일 3일 전, 1일 전, 당일
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 공통 사항
|
||||||
|
|
||||||
|
### 인증 및 권한
|
||||||
|
|
||||||
|
#### JWT 토큰 구조
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"userId": "string",
|
||||||
|
"userName": "string",
|
||||||
|
"email": "string",
|
||||||
|
"exp": 1234567890
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 인증 헤더
|
||||||
|
```
|
||||||
|
Authorization: Bearer {access_token}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 사용자 정보 헤더 (모든 API 요청)
|
||||||
|
```
|
||||||
|
X-User-Id: {userId}
|
||||||
|
X-User-Name: {userName}
|
||||||
|
X-User-Email: {userEmail}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 에러 응답 형식
|
||||||
|
|
||||||
|
#### 공통 에러 응답
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "error",
|
||||||
|
"code": "ERROR_CODE",
|
||||||
|
"message": "에러 메시지",
|
||||||
|
"details": {
|
||||||
|
"field": "필드명",
|
||||||
|
"reason": "상세 사유"
|
||||||
|
},
|
||||||
|
"timestamp": "2025-01-23T10:00:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### HTTP 상태 코드
|
||||||
|
- **200**: 성공
|
||||||
|
- **201**: 생성 성공
|
||||||
|
- **400**: 잘못된 요청
|
||||||
|
- **401**: 인증 실패
|
||||||
|
- **403**: 권한 없음
|
||||||
|
- **404**: 리소스 없음
|
||||||
|
- **409**: 충돌 (동시 수정 등)
|
||||||
|
- **500**: 서버 오류
|
||||||
|
|
||||||
|
### 페이징 표준
|
||||||
|
|
||||||
|
#### 요청 파라미터
|
||||||
|
```
|
||||||
|
page: 페이지 번호 (default: 0)
|
||||||
|
size: 페이지 크기 (default: 20, max: 100)
|
||||||
|
sort: 정렬 기준 (예: createdAt,desc)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 응답 형식
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"content": [...],
|
||||||
|
"pageable": {
|
||||||
|
"page": 0,
|
||||||
|
"size": 20,
|
||||||
|
"totalElements": 100,
|
||||||
|
"totalPages": 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API 확인 방법
|
||||||
|
|
||||||
|
### 1. Swagger Editor에서 확인
|
||||||
|
|
||||||
|
1. **Swagger Editor 접속**
|
||||||
|
- https://editor.swagger.io/
|
||||||
|
|
||||||
|
2. **각 서비스 YAML 파일 확인**
|
||||||
|
- `design/backend/api/user-service-api.yaml`
|
||||||
|
- `design/backend/api/meeting-service-api.yaml`
|
||||||
|
- `design/backend/api/stt-service-api.yaml`
|
||||||
|
- `design/backend/api/ai-service-api.yaml`
|
||||||
|
- `design/backend/api/notification-service-api.yaml`
|
||||||
|
|
||||||
|
3. **파일 내용 붙여넣기**
|
||||||
|
- 좌측 패널에 YAML 내용 붙여넣기
|
||||||
|
- 우측 패널에서 API 문서 확인
|
||||||
|
|
||||||
|
4. **API 테스트**
|
||||||
|
- "Try it out" 버튼으로 API 테스트
|
||||||
|
- Example 데이터로 요청/응답 시뮬레이션
|
||||||
|
|
||||||
|
### 2. 로컬에서 검증
|
||||||
|
|
||||||
|
#### swagger-cli 설치
|
||||||
|
```bash
|
||||||
|
npm install -g @apidevtools/swagger-cli
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 검증 실행
|
||||||
|
```bash
|
||||||
|
# 개별 파일 검증
|
||||||
|
swagger-cli validate design/backend/api/user-service-api.yaml
|
||||||
|
|
||||||
|
# 전체 파일 검증
|
||||||
|
swagger-cli validate design/backend/api/*.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 검증 결과
|
||||||
|
```
|
||||||
|
design/backend/api/user-service-api.yaml is valid
|
||||||
|
design/backend/api/meeting-service-api.yaml is valid
|
||||||
|
design/backend/api/stt-service-api.yaml is valid
|
||||||
|
design/backend/api/ai-service-api.yaml is valid
|
||||||
|
design/backend/api/notification-service-api.yaml is valid
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 통계
|
||||||
|
|
||||||
|
### API 개수 요약
|
||||||
|
|
||||||
|
| 서비스 | API 개수 | 주요 기능 |
|
||||||
|
|--------|---------|----------|
|
||||||
|
| User Service | 4 | 사용자 인증 |
|
||||||
|
| Meeting Service | 17 | 회의, 회의록, Todo, 실시간 협업 |
|
||||||
|
| STT Service | 12 | 음성 녹음, 변환, 화자 식별 |
|
||||||
|
| AI Service | 8 | AI 회의록, Todo 추출, RAG 검색 |
|
||||||
|
| Notification Service | 6 | 알림 발송, 설정 관리 |
|
||||||
|
| **합계** | **47** | |
|
||||||
|
|
||||||
|
### 유저스토리 커버리지
|
||||||
|
|
||||||
|
- **전체 유저스토리**: 25개
|
||||||
|
- **API로 구현된 유저스토리**: 25개
|
||||||
|
- **커버리지**: 100%
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 문서 이력
|
||||||
|
|
||||||
|
| 버전 | 작성일 | 작성자 | 변경 내용 |
|
||||||
|
|------|--------|--------|----------|
|
||||||
|
| 1.0 | 2025-01-23 | 길동 (아키텍트), 준호 (Backend Developer) | 초안 작성 (5개 마이크로서비스) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 부록
|
||||||
|
|
||||||
|
### A. 참조 문서
|
||||||
|
- 유저스토리: `design/userstory.md`
|
||||||
|
- 외부 시퀀스 설계서: `design/backend/sequence/outer/*.puml`
|
||||||
|
- 내부 시퀀스 설계서: `design/backend/sequence/inner/*.puml`
|
||||||
|
- 공통 설계 원칙: `claude/common-principles.md`
|
||||||
|
- API 설계 가이드: `claude/api-design.md`
|
||||||
|
|
||||||
|
### B. 파일 구조
|
||||||
|
```
|
||||||
|
design/backend/api/
|
||||||
|
├── user-service-api.yaml # User Service API 명세
|
||||||
|
├── meeting-service-api.yaml # Meeting Service API 명세
|
||||||
|
├── stt-service-api.yaml # STT Service API 명세
|
||||||
|
├── ai-service-api.yaml # AI Service API 명세
|
||||||
|
├── notification-service-api.yaml # Notification Service API 명세
|
||||||
|
└── API설계서.md # 본 문서
|
||||||
|
```
|
||||||
|
|
||||||
|
### C. OpenAPI 3.0 주요 섹션
|
||||||
|
- **openapi**: 버전 정보 (3.0.3)
|
||||||
|
- **info**: API 메타데이터
|
||||||
|
- **servers**: 서버 URL
|
||||||
|
- **paths**: API 엔드포인트
|
||||||
|
- **components**: 재사용 가능한 컴포넌트
|
||||||
|
- schemas: 데이터 모델
|
||||||
|
- parameters: 공통 파라미터
|
||||||
|
- responses: 공통 응답
|
||||||
|
- securitySchemes: 인증 방식
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**© 2025 회의록 작성 및 공유 개선 서비스. All rights reserved.**
|
||||||
1034
design/backend/api/ai-service-api.yaml
Normal file
1034
design/backend/api/ai-service-api.yaml
Normal file
File diff suppressed because it is too large
Load Diff
1811
design/backend/api/meeting-service-api.yaml
Normal file
1811
design/backend/api/meeting-service-api.yaml
Normal file
File diff suppressed because it is too large
Load Diff
932
design/backend/api/notification-service-api.yaml
Normal file
932
design/backend/api/notification-service-api.yaml
Normal file
@ -0,0 +1,932 @@
|
|||||||
|
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: []
|
||||||
458
design/backend/api/spec/ai-service-api-spec.md
Normal file
458
design/backend/api/spec/ai-service-api-spec.md
Normal file
@ -0,0 +1,458 @@
|
|||||||
|
# AI Service API 설계서
|
||||||
|
|
||||||
|
## 개요
|
||||||
|
|
||||||
|
AI Service는 회의록 작성 및 공유 개선 서비스의 핵심 차별화 기능을 제공하는 마이크로서비스입니다.
|
||||||
|
|
||||||
|
### 주요 기능
|
||||||
|
- **회의록 자동 작성**: LLM 기반 회의록 자동 생성
|
||||||
|
- **Todo 자동 추출**: 액션 아이템 자동 식별 및 담당자 추출
|
||||||
|
- **회의록 개선**: 프롬프팅 기반 다양한 형식 변환
|
||||||
|
- **관련 회의록 연결**: RAG 기반 벡터 유사도 검색
|
||||||
|
- **전문용어 감지**: 맥락 기반 용어 설명 제공
|
||||||
|
- **실시간 추천**: 논의사항/결정사항 자동 제안
|
||||||
|
|
||||||
|
## API 명세 파일
|
||||||
|
- **파일 위치**: `design/backend/api/ai-service-api.yaml`
|
||||||
|
- **OpenAPI 버전**: 3.0.3
|
||||||
|
- **검증 상태**: ✅ Valid
|
||||||
|
|
||||||
|
## API 엔드포인트 목록
|
||||||
|
|
||||||
|
### 1. 회의록 자동 작성 (Transcript)
|
||||||
|
|
||||||
|
#### POST /transcripts/process
|
||||||
|
회의록 자동 작성
|
||||||
|
|
||||||
|
**유저스토리**: UFR-AI-010
|
||||||
|
**Controller**: TranscriptController
|
||||||
|
|
||||||
|
**Request Body**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"meetingId": "550e8400-e29b-41d4-a716-446655440000",
|
||||||
|
"transcriptText": "안녕하세요. 오늘 회의는...",
|
||||||
|
"userId": "user123",
|
||||||
|
"userName": "김철수",
|
||||||
|
"context": {
|
||||||
|
"title": "신규 프로젝트 킥오프 미팅",
|
||||||
|
"participants": ["김철수", "이영희", "박민수"],
|
||||||
|
"agenda": ["프로젝트 개요", "일정 논의", "역할 분담"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response (200 OK)**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"transcriptId": "660e8400-e29b-41d4-a716-446655440001",
|
||||||
|
"meetingId": "550e8400-e29b-41d4-a716-446655440000",
|
||||||
|
"content": {
|
||||||
|
"summary": "프로젝트 킥오프 미팅에서 기술 스택과 일정을 확정했습니다.",
|
||||||
|
"discussions": [...],
|
||||||
|
"decisions": [...],
|
||||||
|
"pendingItems": [...]
|
||||||
|
},
|
||||||
|
"suggestions": {
|
||||||
|
"discussionTopics": [...],
|
||||||
|
"decisions": [...]
|
||||||
|
},
|
||||||
|
"createdAt": "2025-01-23T10:30:00Z",
|
||||||
|
"status": "DRAFT"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Todo 자동 추출 (Todo)
|
||||||
|
|
||||||
|
#### POST /todos/extract
|
||||||
|
Todo 자동 추출
|
||||||
|
|
||||||
|
**유저스토리**: UFR-AI-020
|
||||||
|
**Controller**: TodoController
|
||||||
|
|
||||||
|
**Request Body**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"meetingId": "550e8400-e29b-41d4-a716-446655440000",
|
||||||
|
"userId": "user123"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response (200 OK)**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"meetingId": "550e8400-e29b-41d4-a716-446655440000",
|
||||||
|
"todos": [
|
||||||
|
{
|
||||||
|
"content": "API 설계서 작성",
|
||||||
|
"assignee": "박민수",
|
||||||
|
"dueDate": "2025-01-30",
|
||||||
|
"priority": "HIGH",
|
||||||
|
"sectionReference": "결정사항 #3"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalCount": 5,
|
||||||
|
"extractedAt": "2025-01-23T11:00:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. 회의록 개선 (Improve)
|
||||||
|
|
||||||
|
#### POST /transcripts/{meetingId}/improve
|
||||||
|
회의록 개선
|
||||||
|
|
||||||
|
**유저스토리**: UFR-AI-030
|
||||||
|
**Controller**: ImproveController
|
||||||
|
|
||||||
|
**Path Parameters**:
|
||||||
|
- `meetingId` (uuid, required): 회의 ID
|
||||||
|
|
||||||
|
**Request Body**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"promptType": "1PAGE_SUMMARY",
|
||||||
|
"customPrompt": "경영진 보고용으로 3가지 핵심 결정사항만 요약해주세요",
|
||||||
|
"userId": "user123"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Prompt Types**:
|
||||||
|
- `1PAGE_SUMMARY`: A4 1장 분량 요약
|
||||||
|
- `CORE_SUMMARY`: 3-5개 핵심 포인트
|
||||||
|
- `DETAILED_REPORT`: 시간순 상세 기록
|
||||||
|
- `DECISION_FOCUSED`: 의사결정 중심
|
||||||
|
- `ACTION_FOCUSED`: 액션 아이템 중심
|
||||||
|
- `EXECUTIVE_REPORT`: 경영진 보고용
|
||||||
|
- `CUSTOM`: 사용자 정의
|
||||||
|
|
||||||
|
**Response (200 OK)**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"transcriptId": "770e8400-e29b-41d4-a716-446655440002",
|
||||||
|
"version": 2,
|
||||||
|
"baseVersion": 1,
|
||||||
|
"improvementType": "1PAGE_SUMMARY",
|
||||||
|
"content": "## 프로젝트 킥오프 미팅 요약\n\n### 핵심 결정사항...",
|
||||||
|
"originalLink": "/transcripts/660e8400-e29b-41d4-a716-446655440001",
|
||||||
|
"createdAt": "2025-01-23T11:30:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. 관련 회의록 연결 (Relation)
|
||||||
|
|
||||||
|
#### GET /transcripts/{meetingId}/related
|
||||||
|
관련 회의록 조회
|
||||||
|
|
||||||
|
**유저스토리**: UFR-AI-040
|
||||||
|
**Controller**: RelationController
|
||||||
|
|
||||||
|
**Path Parameters**:
|
||||||
|
- `meetingId` (uuid, required): 회의 ID
|
||||||
|
|
||||||
|
**Query Parameters**:
|
||||||
|
- `transcriptId` (uuid, required): 회의록 ID
|
||||||
|
- `limit` (integer, optional): 최대 개수 (default: 5, max: 10)
|
||||||
|
|
||||||
|
**Response (200 OK)**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"relatedTranscripts": [
|
||||||
|
{
|
||||||
|
"transcriptId": "aa0e8400-e29b-41d4-a716-446655440005",
|
||||||
|
"title": "프로젝트 X 주간 회의",
|
||||||
|
"date": "2025-01-15",
|
||||||
|
"participants": ["김철수", "이영희"],
|
||||||
|
"relevanceScore": 85.5,
|
||||||
|
"commonKeywords": ["MSA", "API Gateway", "Spring Boot"],
|
||||||
|
"link": "/transcripts/aa0e8400-e29b-41d4-a716-446655440005"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalCount": 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. 전문용어 감지 및 설명 (Term)
|
||||||
|
|
||||||
|
#### POST /terms/detect
|
||||||
|
전문용어 감지
|
||||||
|
|
||||||
|
**유저스토리**: UFR-RAG-010
|
||||||
|
**Controller**: TermController
|
||||||
|
|
||||||
|
**Request Body**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"meetingId": "550e8400-e29b-41d4-a716-446655440000",
|
||||||
|
"text": "MSA 아키텍처로 설계하고, API Gateway를 통해 라우팅합니다...",
|
||||||
|
"organizationId": "org123"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response (200 OK)**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"detectedTerms": [
|
||||||
|
{
|
||||||
|
"term": "MSA",
|
||||||
|
"position": {"line": 5, "offset": 42},
|
||||||
|
"confidence": 0.92,
|
||||||
|
"category": "기술",
|
||||||
|
"highlight": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalCount": 8,
|
||||||
|
"highlightInfo": [...]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### GET /terms/{term}/explain
|
||||||
|
맥락 기반 용어 설명
|
||||||
|
|
||||||
|
**유저스토리**: UFR-RAG-020
|
||||||
|
**Controller**: ExplanationController
|
||||||
|
|
||||||
|
**Path Parameters**:
|
||||||
|
- `term` (string, required): 용어명
|
||||||
|
|
||||||
|
**Query Parameters**:
|
||||||
|
- `meetingId` (uuid, required): 회의 ID
|
||||||
|
- `context` (string, optional): 현재 회의 맥락
|
||||||
|
|
||||||
|
**Response (200 OK)**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"term": "MSA",
|
||||||
|
"basicDefinition": "Microservices Architecture의 약자로, 애플리케이션을 작은 독립적인 서비스로 나누는 아키텍처 패턴",
|
||||||
|
"contextualMeaning": "이번 프로젝트에서는 확장성과 독립 배포를 위해 MSA를 적용하기로 결정",
|
||||||
|
"useCases": [
|
||||||
|
"2024년 프로젝트 X에서 주문/결제/배송 서비스를 독립적으로 구성",
|
||||||
|
"서비스별 독립 배포로 배포 시간 70% 단축"
|
||||||
|
],
|
||||||
|
"relatedProjects": [...],
|
||||||
|
"pastDiscussions": [...],
|
||||||
|
"references": [...]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. 실시간 추천 (Suggestion)
|
||||||
|
|
||||||
|
#### POST /suggestions/discussion
|
||||||
|
논의사항 제안
|
||||||
|
|
||||||
|
**유저스토리**: UFR-AI-010
|
||||||
|
**Controller**: SuggestionController
|
||||||
|
|
||||||
|
**Request Body**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"meetingId": "550e8400-e29b-41d4-a716-446655440000",
|
||||||
|
"transcriptText": "프로젝트 일정에 대해 논의했습니다..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response (200 OK)**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"suggestions": [
|
||||||
|
{
|
||||||
|
"id": "880e8400-e29b-41d4-a716-446655440003",
|
||||||
|
"topic": "보안 요구사항 검토",
|
||||||
|
"reason": "안건에 포함되어 있으나 아직 논의되지 않음",
|
||||||
|
"priority": "HIGH",
|
||||||
|
"relatedAgenda": "프로젝트 개요",
|
||||||
|
"estimatedTime": 15
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalCount": 3,
|
||||||
|
"timestamp": "2025-01-23T10:35:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### POST /suggestions/decision
|
||||||
|
결정사항 제안
|
||||||
|
|
||||||
|
**유저스토리**: UFR-AI-010
|
||||||
|
**Controller**: SuggestionController
|
||||||
|
|
||||||
|
**Request Body**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"meetingId": "550e8400-e29b-41d4-a716-446655440000",
|
||||||
|
"transcriptText": "React로 프론트엔드를 개발하기로 했습니다..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response (200 OK)**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"suggestions": [
|
||||||
|
{
|
||||||
|
"id": "990e8400-e29b-41d4-a716-446655440004",
|
||||||
|
"content": "React로 프론트엔드 개발",
|
||||||
|
"category": "기술",
|
||||||
|
"decisionMaker": "김철수",
|
||||||
|
"participants": ["김철수", "이영희"],
|
||||||
|
"confidence": 0.85,
|
||||||
|
"extractedFrom": "프론트엔드는 React로 개발하기로 했습니다",
|
||||||
|
"context": "팀원 대부분이 React 경험이 있어 개발 속도가 빠를 것으로 예상"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalCount": 4,
|
||||||
|
"timestamp": "2025-01-23T10:35:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 공통 응답
|
||||||
|
|
||||||
|
### 에러 응답
|
||||||
|
|
||||||
|
#### 400 Bad Request
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "BAD_REQUEST",
|
||||||
|
"message": "필수 파라미터가 누락되었습니다",
|
||||||
|
"timestamp": "2025-01-23T10:30:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 404 Not Found
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "NOT_FOUND",
|
||||||
|
"message": "해당 회의록을 찾을 수 없습니다",
|
||||||
|
"timestamp": "2025-01-23T10:30:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 500 Internal Server Error
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "INTERNAL_SERVER_ERROR",
|
||||||
|
"message": "서버 처리 중 오류가 발생했습니다",
|
||||||
|
"timestamp": "2025-01-23T10:30:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 인증 (Security)
|
||||||
|
|
||||||
|
모든 API는 JWT 토큰 기반 인증을 사용합니다.
|
||||||
|
|
||||||
|
**인증 방식**: Bearer Token
|
||||||
|
|
||||||
|
**요청 헤더**:
|
||||||
|
```
|
||||||
|
Authorization: Bearer <JWT_TOKEN>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API 확인 방법
|
||||||
|
|
||||||
|
### Swagger Editor 사용
|
||||||
|
|
||||||
|
1. https://editor.swagger.io/ 접근
|
||||||
|
2. 생성된 `ai-service-api.yaml` 파일 내용 복사
|
||||||
|
3. Swagger Editor에 붙여넣기
|
||||||
|
4. 우측 패널에서 API 문서 확인
|
||||||
|
5. "Try it out" 기능으로 테스트 가능
|
||||||
|
|
||||||
|
### Swagger UI 로컬 실행
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Swagger UI Docker 실행
|
||||||
|
docker run -p 8080:8080 \
|
||||||
|
-e SWAGGER_JSON=/api/ai-service-api.yaml \
|
||||||
|
-v C:\Users\KTDS\home\workspace\HGZero\design\backend\api:/api \
|
||||||
|
swaggerapi/swagger-ui
|
||||||
|
|
||||||
|
# 브라우저에서 접근
|
||||||
|
# http://localhost:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 설계 원칙 준수 사항
|
||||||
|
|
||||||
|
### ✅ API 설계 가이드 준수
|
||||||
|
- OpenAPI 3.0.3 스펙 사용
|
||||||
|
- 모든 엔드포인트에 x-user-story, x-controller 명시
|
||||||
|
- 완전한 Request/Response 스키마 정의
|
||||||
|
- Example 데이터 포함
|
||||||
|
|
||||||
|
### ✅ 유저스토리 매칭
|
||||||
|
- UFR-AI-010: 회의록 자동 작성 (실시간 추천 포함)
|
||||||
|
- UFR-AI-020: Todo 자동 추출
|
||||||
|
- UFR-AI-030: 회의록 개선
|
||||||
|
- UFR-AI-040: 관련 회의록 연결
|
||||||
|
- UFR-RAG-010: 전문용어 감지
|
||||||
|
- UFR-RAG-020: 맥락 기반 용어 설명
|
||||||
|
|
||||||
|
### ✅ 내부 시퀀스 일치
|
||||||
|
- 모든 API는 내부 시퀀스 설계와 일관성 유지
|
||||||
|
- LLM 프롬프트 파라미터 포함
|
||||||
|
- RAG 검색 결과 구조 반영
|
||||||
|
|
||||||
|
### ✅ 서버 URL 설정
|
||||||
|
- SwaggerHub Mock Server (첫 번째)
|
||||||
|
- Local/Dev/Production 서버 URL 포함
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 차별화 포인트 반영
|
||||||
|
|
||||||
|
### 1. 맥락 기반 용어 설명
|
||||||
|
- 단순 정의가 아닌 조직 내 실제 사용 맥락 제공
|
||||||
|
- 과거 회의록, 사내 문서, 업무 이력 통합 검색
|
||||||
|
- 실용적인 설명으로 업무 지식 부족 해소
|
||||||
|
|
||||||
|
### 2. 강화된 Todo 연결
|
||||||
|
- AI 자동 추출 + 담당자 자동 식별
|
||||||
|
- 회의록과 양방향 연결
|
||||||
|
- Meeting Service로 실시간 전달
|
||||||
|
|
||||||
|
### 3. 프롬프팅 기반 회의록 개선
|
||||||
|
- 7가지 프롬프트 유형 지원
|
||||||
|
- 원본 보존 + 버전 관리
|
||||||
|
- 사용자 정의 프롬프트 지원
|
||||||
|
|
||||||
|
### 4. 실시간 추천
|
||||||
|
- 논의사항 제안 (빠진 안건 자동 감지)
|
||||||
|
- 결정사항 제안 (패턴 기반 자동 추출)
|
||||||
|
- 회의 진행 중 실시간 제공
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 처리 시간 예상
|
||||||
|
|
||||||
|
| API | 평균 처리 시간 |
|
||||||
|
|-----|---------------|
|
||||||
|
| 회의록 자동 작성 | 8-13초 |
|
||||||
|
| Todo 자동 추출 | 4-7초 |
|
||||||
|
| 회의록 개선 | 5-9초 |
|
||||||
|
| 관련 회의록 연결 | 5-8초 |
|
||||||
|
| 전문용어 감지 | 3-5초 |
|
||||||
|
| 맥락 기반 용어 설명 | 5-8초 |
|
||||||
|
| 논의사항 제안 | 2.5-3.5초 |
|
||||||
|
| 결정사항 제안 | 2.5-3.5초 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 문서 이력
|
||||||
|
|
||||||
|
| 버전 | 작성일 | 작성자 | 변경 내용 |
|
||||||
|
|------|--------|--------|----------|
|
||||||
|
| 1.0 | 2025-01-23 | 준호 (Backend Developer) | AI Service API 설계 완료 |
|
||||||
1306
design/backend/api/stt-service-api.yaml
Normal file
1306
design/backend/api/stt-service-api.yaml
Normal file
File diff suppressed because it is too large
Load Diff
531
design/backend/api/user-service-api.yaml
Normal file
531
design/backend/api/user-service-api.yaml
Normal file
@ -0,0 +1,531 @@
|
|||||||
|
openapi: 3.0.3
|
||||||
|
info:
|
||||||
|
title: User Service API
|
||||||
|
description: |
|
||||||
|
회의록 작성 및 공유 개선 서비스의 사용자 인증 전용 서비스
|
||||||
|
|
||||||
|
**핵심 기능:**
|
||||||
|
- LDAP 기반 사용자 인증
|
||||||
|
- JWT 토큰 발급 및 검증
|
||||||
|
- 세션 관리 (Access Token + Refresh Token)
|
||||||
|
|
||||||
|
**보안:**
|
||||||
|
- LDAP 인증 (LDAPS, port 636)
|
||||||
|
- JWT Bearer 토큰
|
||||||
|
- 계정 잠금 (5회 실패 시 30분)
|
||||||
|
- Refresh Token (Redis 저장, 7일 TTL)
|
||||||
|
|
||||||
|
version: 1.0.0
|
||||||
|
contact:
|
||||||
|
name: Backend Team
|
||||||
|
email: backend@company.com
|
||||||
|
|
||||||
|
servers:
|
||||||
|
- url: https://api.meeting.company.com
|
||||||
|
description: Production Server
|
||||||
|
- url: https://dev-api.meeting.company.com
|
||||||
|
description: Development Server
|
||||||
|
- url: http://localhost:8081
|
||||||
|
description: Local Development
|
||||||
|
|
||||||
|
tags:
|
||||||
|
- name: Authentication
|
||||||
|
description: 사용자 인증 관리 API
|
||||||
|
|
||||||
|
paths:
|
||||||
|
/api/v1/auth/login:
|
||||||
|
post:
|
||||||
|
summary: 사용자 로그인
|
||||||
|
description: |
|
||||||
|
LDAP 인증을 통한 사용자 로그인 처리
|
||||||
|
|
||||||
|
**처리 흐름:**
|
||||||
|
1. LDAP 서버에 사용자 인증 요청
|
||||||
|
2. 인증 성공 시 사용자 정보 조회
|
||||||
|
3. 신규 사용자일 경우 자동 등록
|
||||||
|
4. JWT Access Token 및 Refresh Token 발급
|
||||||
|
5. Refresh Token을 Redis에 저장 (7일 TTL)
|
||||||
|
6. 최종 로그인 일시 업데이트
|
||||||
|
|
||||||
|
**인증 실패 처리:**
|
||||||
|
- 5회 실패 시 계정 30분 잠금
|
||||||
|
- 잠금 상태에서는 로그인 불가
|
||||||
|
operationId: login
|
||||||
|
x-user-story: AFR-USER-010
|
||||||
|
x-controller: UserController
|
||||||
|
tags:
|
||||||
|
- Authentication
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/LoginRequest'
|
||||||
|
examples:
|
||||||
|
normal:
|
||||||
|
summary: 정상 로그인 요청
|
||||||
|
value:
|
||||||
|
username: "user001"
|
||||||
|
password: "P@ssw0rd123!"
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: 로그인 성공
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/LoginResponse'
|
||||||
|
examples:
|
||||||
|
success:
|
||||||
|
summary: 로그인 성공 응답
|
||||||
|
value:
|
||||||
|
accessToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||||
|
refreshToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||||
|
tokenType: "Bearer"
|
||||||
|
expiresIn: 3600
|
||||||
|
user:
|
||||||
|
userId: "user001"
|
||||||
|
username: "user001"
|
||||||
|
name: "홍길동"
|
||||||
|
email: "hong@company.com"
|
||||||
|
department: "개발팀"
|
||||||
|
title: "선임"
|
||||||
|
roles:
|
||||||
|
- "USER"
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/UnauthorizedError'
|
||||||
|
'403':
|
||||||
|
description: 계정 잠금
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
|
examples:
|
||||||
|
accountLocked:
|
||||||
|
summary: 계정 잠금 응답
|
||||||
|
value:
|
||||||
|
error:
|
||||||
|
code: "ACCOUNT_LOCKED"
|
||||||
|
message: "계정이 잠겼습니다"
|
||||||
|
details: "비밀번호 5회 실패로 30분간 계정이 잠겼습니다. 잠금 해제 시간: 2025-10-23T13:30:00Z"
|
||||||
|
timestamp: "2025-10-23T13:00:00Z"
|
||||||
|
path: "/api/v1/auth/login"
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/InternalServerError'
|
||||||
|
|
||||||
|
/api/v1/auth/refresh:
|
||||||
|
post:
|
||||||
|
summary: Access Token 갱신
|
||||||
|
description: |
|
||||||
|
Refresh Token을 사용하여 새로운 Access Token 발급
|
||||||
|
|
||||||
|
**처리 흐름:**
|
||||||
|
1. Refresh Token 검증
|
||||||
|
2. Redis에서 Refresh Token 존재 확인
|
||||||
|
3. 새로운 Access Token 발급
|
||||||
|
4. Refresh Token 갱신 (옵션)
|
||||||
|
operationId: refreshToken
|
||||||
|
x-user-story: AFR-USER-010
|
||||||
|
x-controller: UserController
|
||||||
|
tags:
|
||||||
|
- Authentication
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/RefreshTokenRequest'
|
||||||
|
examples:
|
||||||
|
normal:
|
||||||
|
summary: 토큰 갱신 요청
|
||||||
|
value:
|
||||||
|
refreshToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: 토큰 갱신 성공
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/RefreshTokenResponse'
|
||||||
|
examples:
|
||||||
|
success:
|
||||||
|
summary: 토큰 갱신 성공 응답
|
||||||
|
value:
|
||||||
|
accessToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||||
|
refreshToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||||
|
tokenType: "Bearer"
|
||||||
|
expiresIn: 3600
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/UnauthorizedError'
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/InternalServerError'
|
||||||
|
|
||||||
|
/api/v1/auth/logout:
|
||||||
|
post:
|
||||||
|
summary: 로그아웃
|
||||||
|
description: |
|
||||||
|
사용자 로그아웃 처리
|
||||||
|
|
||||||
|
**처리 흐름:**
|
||||||
|
1. Access Token에서 사용자 정보 추출
|
||||||
|
2. Redis에서 Refresh Token 삭제
|
||||||
|
3. 로그아웃 완료
|
||||||
|
operationId: logout
|
||||||
|
x-user-story: AFR-USER-010
|
||||||
|
x-controller: UserController
|
||||||
|
tags:
|
||||||
|
- Authentication
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: 로그아웃 성공
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/LogoutResponse'
|
||||||
|
examples:
|
||||||
|
success:
|
||||||
|
summary: 로그아웃 성공 응답
|
||||||
|
value:
|
||||||
|
message: "로그아웃되었습니다"
|
||||||
|
timestamp: "2025-10-23T14:30:00Z"
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/UnauthorizedError'
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/InternalServerError'
|
||||||
|
|
||||||
|
/api/v1/auth/validate:
|
||||||
|
get:
|
||||||
|
summary: 토큰 검증
|
||||||
|
description: |
|
||||||
|
JWT Access Token 유효성 검증
|
||||||
|
|
||||||
|
**검증 항목:**
|
||||||
|
- 토큰 서명 검증
|
||||||
|
- 토큰 만료 시간 확인
|
||||||
|
- 사용자 정보 조회 (옵션)
|
||||||
|
|
||||||
|
**용도:**
|
||||||
|
- API Gateway에서 인증 검증
|
||||||
|
- 다른 서비스에서 사용자 정보 조회
|
||||||
|
operationId: validateToken
|
||||||
|
x-user-story: AFR-USER-010
|
||||||
|
x-controller: UserController
|
||||||
|
tags:
|
||||||
|
- Authentication
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
parameters:
|
||||||
|
- name: includeUserInfo
|
||||||
|
in: query
|
||||||
|
description: 사용자 정보 포함 여부
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: 토큰 유효
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ValidateTokenResponse'
|
||||||
|
examples:
|
||||||
|
valid:
|
||||||
|
summary: 토큰 유효 응답
|
||||||
|
value:
|
||||||
|
valid: true
|
||||||
|
userId: "user001"
|
||||||
|
username: "user001"
|
||||||
|
roles:
|
||||||
|
- "USER"
|
||||||
|
expiresAt: "2025-10-23T15:00:00Z"
|
||||||
|
validWithUserInfo:
|
||||||
|
summary: 사용자 정보 포함 응답
|
||||||
|
value:
|
||||||
|
valid: true
|
||||||
|
userId: "user001"
|
||||||
|
username: "user001"
|
||||||
|
roles:
|
||||||
|
- "USER"
|
||||||
|
expiresAt: "2025-10-23T15:00:00Z"
|
||||||
|
user:
|
||||||
|
userId: "user001"
|
||||||
|
username: "user001"
|
||||||
|
name: "홍길동"
|
||||||
|
email: "hong@company.com"
|
||||||
|
department: "개발팀"
|
||||||
|
title: "선임"
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/UnauthorizedError'
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/InternalServerError'
|
||||||
|
|
||||||
|
components:
|
||||||
|
securitySchemes:
|
||||||
|
BearerAuth:
|
||||||
|
type: http
|
||||||
|
scheme: bearer
|
||||||
|
bearerFormat: JWT
|
||||||
|
description: JWT Bearer Token
|
||||||
|
|
||||||
|
schemas:
|
||||||
|
LoginRequest:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- username
|
||||||
|
- password
|
||||||
|
properties:
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
description: 사용자명 (사번)
|
||||||
|
minLength: 3
|
||||||
|
maxLength: 50
|
||||||
|
example: "user001"
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
description: 비밀번호
|
||||||
|
format: password
|
||||||
|
minLength: 8
|
||||||
|
maxLength: 100
|
||||||
|
example: "P@ssw0rd123!"
|
||||||
|
|
||||||
|
LoginResponse:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- accessToken
|
||||||
|
- refreshToken
|
||||||
|
- tokenType
|
||||||
|
- expiresIn
|
||||||
|
- user
|
||||||
|
properties:
|
||||||
|
accessToken:
|
||||||
|
type: string
|
||||||
|
description: JWT Access Token
|
||||||
|
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMDAxIiwidXNlcm5hbWUiOiJ1c2VyMDAxIiwicm9sZXMiOlsiVVNFUiJdLCJleHAiOjE3MzAwMDAwMDB9.signature"
|
||||||
|
refreshToken:
|
||||||
|
type: string
|
||||||
|
description: Refresh Token (7일 유효)
|
||||||
|
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMDAxIiwidHlwZSI6InJlZnJlc2giLCJleHAiOjE3MzA2MDQ4MDB9.signature"
|
||||||
|
tokenType:
|
||||||
|
type: string
|
||||||
|
description: 토큰 타입
|
||||||
|
enum:
|
||||||
|
- Bearer
|
||||||
|
example: "Bearer"
|
||||||
|
expiresIn:
|
||||||
|
type: integer
|
||||||
|
description: Access Token 만료 시간 (초)
|
||||||
|
example: 3600
|
||||||
|
user:
|
||||||
|
$ref: '#/components/schemas/UserInfo'
|
||||||
|
|
||||||
|
RefreshTokenRequest:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- refreshToken
|
||||||
|
properties:
|
||||||
|
refreshToken:
|
||||||
|
type: string
|
||||||
|
description: Refresh Token
|
||||||
|
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||||
|
|
||||||
|
RefreshTokenResponse:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- accessToken
|
||||||
|
- refreshToken
|
||||||
|
- tokenType
|
||||||
|
- expiresIn
|
||||||
|
properties:
|
||||||
|
accessToken:
|
||||||
|
type: string
|
||||||
|
description: 새로운 JWT Access Token
|
||||||
|
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||||
|
refreshToken:
|
||||||
|
type: string
|
||||||
|
description: 새로운 Refresh Token (옵션)
|
||||||
|
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||||
|
tokenType:
|
||||||
|
type: string
|
||||||
|
description: 토큰 타입
|
||||||
|
enum:
|
||||||
|
- Bearer
|
||||||
|
example: "Bearer"
|
||||||
|
expiresIn:
|
||||||
|
type: integer
|
||||||
|
description: Access Token 만료 시간 (초)
|
||||||
|
example: 3600
|
||||||
|
|
||||||
|
LogoutResponse:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- message
|
||||||
|
- timestamp
|
||||||
|
properties:
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
description: 로그아웃 완료 메시지
|
||||||
|
example: "로그아웃되었습니다"
|
||||||
|
timestamp:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
description: 로그아웃 시간
|
||||||
|
example: "2025-10-23T14:30:00Z"
|
||||||
|
|
||||||
|
ValidateTokenResponse:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- valid
|
||||||
|
- userId
|
||||||
|
- username
|
||||||
|
- roles
|
||||||
|
- expiresAt
|
||||||
|
properties:
|
||||||
|
valid:
|
||||||
|
type: boolean
|
||||||
|
description: 토큰 유효 여부
|
||||||
|
example: true
|
||||||
|
userId:
|
||||||
|
type: string
|
||||||
|
description: 사용자 ID
|
||||||
|
example: "user001"
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
description: 사용자명
|
||||||
|
example: "user001"
|
||||||
|
roles:
|
||||||
|
type: array
|
||||||
|
description: 사용자 권한 목록
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
example:
|
||||||
|
- "USER"
|
||||||
|
expiresAt:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
description: 토큰 만료 시간
|
||||||
|
example: "2025-10-23T15:00:00Z"
|
||||||
|
user:
|
||||||
|
$ref: '#/components/schemas/UserInfo'
|
||||||
|
description: 사용자 정보 (includeUserInfo=true 시)
|
||||||
|
|
||||||
|
UserInfo:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- userId
|
||||||
|
- username
|
||||||
|
- name
|
||||||
|
- email
|
||||||
|
properties:
|
||||||
|
userId:
|
||||||
|
type: string
|
||||||
|
description: 사용자 ID
|
||||||
|
example: "user001"
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
description: 사용자명 (사번)
|
||||||
|
example: "user001"
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: 이름
|
||||||
|
example: "홍길동"
|
||||||
|
email:
|
||||||
|
type: string
|
||||||
|
format: email
|
||||||
|
description: 이메일
|
||||||
|
example: "hong@company.com"
|
||||||
|
department:
|
||||||
|
type: string
|
||||||
|
description: 부서
|
||||||
|
example: "개발팀"
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
description: 직급
|
||||||
|
example: "선임"
|
||||||
|
roles:
|
||||||
|
type: array
|
||||||
|
description: 권한 목록
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
example:
|
||||||
|
- "USER"
|
||||||
|
|
||||||
|
ErrorResponse:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- error
|
||||||
|
properties:
|
||||||
|
error:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- code
|
||||||
|
- message
|
||||||
|
- timestamp
|
||||||
|
- path
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
type: string
|
||||||
|
description: 에러 코드
|
||||||
|
example: "AUTHENTICATION_FAILED"
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
description: 에러 메시지
|
||||||
|
example: "인증에 실패했습니다"
|
||||||
|
details:
|
||||||
|
type: string
|
||||||
|
description: 상세 에러 정보
|
||||||
|
example: "사용자명 또는 비밀번호가 올바르지 않습니다"
|
||||||
|
timestamp:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
description: 에러 발생 시간
|
||||||
|
example: "2025-10-23T12:00:00Z"
|
||||||
|
path:
|
||||||
|
type: string
|
||||||
|
description: 요청 경로
|
||||||
|
example: "/api/v1/auth/login"
|
||||||
|
|
||||||
|
responses:
|
||||||
|
UnauthorizedError:
|
||||||
|
description: 인증 실패
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
|
examples:
|
||||||
|
authenticationFailed:
|
||||||
|
summary: 인증 실패
|
||||||
|
value:
|
||||||
|
error:
|
||||||
|
code: "AUTHENTICATION_FAILED"
|
||||||
|
message: "인증에 실패했습니다"
|
||||||
|
details: "사용자명 또는 비밀번호가 올바르지 않습니다"
|
||||||
|
timestamp: "2025-10-23T12:00:00Z"
|
||||||
|
path: "/api/v1/auth/login"
|
||||||
|
invalidToken:
|
||||||
|
summary: 유효하지 않은 토큰
|
||||||
|
value:
|
||||||
|
error:
|
||||||
|
code: "INVALID_TOKEN"
|
||||||
|
message: "유효하지 않은 토큰입니다"
|
||||||
|
details: "토큰이 만료되었거나 형식이 올바르지 않습니다"
|
||||||
|
timestamp: "2025-10-23T12:00:00Z"
|
||||||
|
path: "/api/v1/auth/validate"
|
||||||
|
|
||||||
|
InternalServerError:
|
||||||
|
description: 서버 오류
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
|
examples:
|
||||||
|
serverError:
|
||||||
|
summary: 서버 오류
|
||||||
|
value:
|
||||||
|
error:
|
||||||
|
code: "INTERNAL_SERVER_ERROR"
|
||||||
|
message: "서버 오류가 발생했습니다"
|
||||||
|
details: "일시적인 오류입니다. 잠시 후 다시 시도해주세요"
|
||||||
|
timestamp: "2025-10-23T12:00:00Z"
|
||||||
|
path: "/api/v1/auth/login"
|
||||||
Loading…
x
Reference in New Issue
Block a user