마음 일기 API 명세서
Auth 서버 및 연관 API 중심 - Enhanced
버전: v1.2 |
최종 업데이트: 2025년 1월 |
상태: 안정 버전
API 개요
| 항목 | 설명 |
|---|---|
| 기본 URL | https://your-api-domain.com |
| 현재 버전 | v1.2 |
| 인증 방식 | Bearer Token (JWT) |
| 응답 형식 | JSON |
| 문자 인코딩 | UTF-8 |
| 타임존 | UTC (ISO 8601 형식) |
버전 관리 전략
마음 일기 API는 의미론적 버전 관리(Semantic Versioning)를 따릅니다.
| 버전 형식 | 설명 | 하위 호환성 |
|---|---|---|
| Major (v2.0) | 호환되지 않는 API 변경 | ❌ 호환되지 않음 |
| Minor (v1.3) | 하위 호환되는 기능 추가 | ✅ 하위 호환 |
| Patch (v1.2.1) | 하위 호환되는 버그 수정 | ✅ 하위 호환 |
📋 버전 지원 정책
- 현재 Major 버전: 최소 2년간 지원
- 이전 Major 버전: 1년간 지원 (deprecated)
- 새로운 기능은 최신 버전에만 추가
- 중요한 보안 업데이트는 모든 지원 버전에 적용
인증 방식
API는 JWT(JSON Web Token) 기반의 Bearer Token 인증을 사용합니다.
토큰 구조
| 토큰 타입 | 유효 기간 | 용도 |
|---|---|---|
| Access Token | 30분 | API 요청 인증 |
| Refresh Token | 7일 | Access Token 갱신 |
인증 헤더 형식
Authorization: Bearer {access_token}
🔒 보안 고려사항
- Access Token은 메모리에만 저장 (localStorage 사용 금지)
- Refresh Token은 HttpOnly 쿠키로 관리
- HTTPS 연결에서만 토큰 전송
- 토큰 만료 시 자동 갱신 로직 구현 권장
인증 API
인증 상태 확인 🔐 인증 필요
GET
/auth_check
현재 요청이 유효한 인증 토큰을 가지고 있는지 확인합니다.
| 항목 | 설명 |
|---|---|
| 인증 | Bearer Token 필요 |
| 응답 코드 |
200: 인증됨
401: 인증되지 않음
|
⚠️ 오류 응답 예시
{
"timestamp": "2024-01-15T10:30:00Z",
"status": 401,
"error": "Unauthorized",
"message": "JWT token is expired",
"path": "/auth_check"
}
JWT 토큰 재발급 🔐 인증 필요
POST
/auth/api/protected/refresh
만료된 Access Token과 유효한 Refresh Token을 사용하여 새로운 Access Token을 발급받습니다.
요청 필드
| 필드명 | 타입 | 필수/선택 | 제약 조건 | 설명 |
|---|---|---|---|---|
| expiredToken | string | 필수 | JWT 형식 | 만료된 Access Token |
| provider | string | 필수 | "server", "google", "kakao", "naver" | 인증 제공자 |
요청 본문
{
"expiredToken": "eyJhbGciOiJIUzUxMiJ9...",
"provider": "server"
}
응답 본문
{
"access_token": "eyJhbGciOiJIUzUxMiJ9...",
"expires_in": 1800,
"token_type": "Bearer"
}
200: 토큰 재발급 성공
401: Refresh Token 무효
406: 요청 유효하지 않음
⚠️ 오류 응답 예시
{
"timestamp": "2024-01-15T10:30:00Z",
"status": 401,
"error": "Unauthorized",
"message": "Refresh token not found or expired",
"path": "/auth/api/protected/refresh"
}
사용자 관리 API
회원 가입 🌐 공개
POST
/api/public/join
새로운 사용자를 등록합니다. 이메일 인증 코드가 사전에 검증되어야 합니다.
요청 필드
| 필드명 | 타입 | 필수/선택 | 제약 조건 | 설명 |
|---|---|---|---|---|
| userId | string | 필수 | 4-20자, 영문+숫자 | 사용자 ID |
| userPw | string | 필수 | 8-50자, 영문+숫자+특수문자 | 비밀번호 |
| userName | string | 필수 | 2-20자 | 실명 |
| nickname | string | 필수 | 2-15자, 중복 불가 | 닉네임 |
| phone | string | 선택 | 010-XXXX-XXXX 형식 | 휴대폰 번호 |
| string | 필수 | 유효한 이메일 형식 | 이메일 주소 | |
| birthDate | string | 선택 | YYYY-MM-DD 형식 | 생년월일 |
| gender | string | 선택 | "male", "female", "other" | 성별 |
| isPrivate | boolean | 선택 | 기본값: false | 프로필 공개 여부 |
| profile | string | 선택 | 유효한 URL | 프로필 이미지 URL |
| code | string | 필수 | 8자리 영문+숫자 | 이메일 인증 코드 |
📋 비밀번호 정책
- 최소 8자, 최대 50자
- 영문 대소문자, 숫자, 특수문자 중 3종류 이상 포함
- 연속된 문자 3개 이상 사용 금지
- 사용자 ID와 동일하거나 포함 금지
요청 본문
{
"userId": "newUser123",
"userPw": "password123!",
"userName": "홍길동",
"nickname": "쾌활한다람쥐",
"phone": "010-1234-5678",
"email": "[email protected]",
"role": "USER",
"birthDate": "1990-01-01",
"gender": "male",
"isPrivate": false,
"profile": "https://example.com/profile.jpg",
"code": "A1B2C3D4"
}
응답 본문
{
"message": "join successfully",
"userId": "newUser123",
"createdAt": "2024-01-15T10:30:00Z"
}
200: 회원 가입 성공
400: 잘못된 요청
409: 이미 존재하는 아이디/닉네임
500: 서버 오류
⚠️ 유효성 검사 오류 예시
{
"timestamp": "2024-01-15T10:30:00Z",
"status": 400,
"error": "Bad Request",
"message": "Validation failed",
"path": "/api/public/join",
"validationErrors": [
{
"field": "userPw",
"message": "비밀번호는 8자 이상이어야 합니다"
},
{
"field": "email",
"message": "유효한 이메일 형식이 아닙니다"
}
]
}
로그인 🌐 공개
POST
/api/auth/login
사용자 ID와 비밀번호로 로그인하고 JWT 토큰을 발급받습니다.
요청 필드
| 필드명 | 타입 | 필수/선택 | 제약 조건 | 설명 |
|---|---|---|---|---|
| userId | string | 필수 | 4-20자 | 사용자 ID |
| password | string | 필수 | 8-50자 | 비밀번호 |
요청 본문
{
"userId": "newUser123",
"password": "password123!"
}
응답 본문
{
"access_token": "eyJhbGciOiJIUzUxMiJ9...",
"expires_in": 1800,
"token_type": "Bearer",
"user": {
"userId": "newUser123",
"nickname": "쾌활한다람쥐",
"role": "USER"
}
}
200: 로그인 성공
400: 잘못된 요청
401: 로그인 실패
🔒 로그인 보안 정책
- 5회 연속 실패 시 계정 잠금 (30분)
- 로그인 성공 시 이전 세션 무효화
- Refresh Token은 HttpOnly 쿠키로 설정
프로필 이미지 업로드 🌐 공개
POST
/api/public/profileUpload
사용자 프로필 이미지를 업로드하고 이미지 URL을 반환받습니다.
| 항목 | 설명 |
|---|---|
| 요청 형식 | multipart/form-data |
| 파일 필드명 | profile |
| 지원 형식 | JPG, PNG, GIF |
| 최대 크기 | 5MB |
| 권장 해상도 | 500x500px |
응답 본문
{
"fileName": "https://your-file-server.com/attach/profile/xxxx_profile.jpg",
"originalName": "profile.jpg",
"size": 1024000,
"uploadedAt": "2024-01-15T10:30:00Z"
}
200: 업로드 성공
400: 잘못된 파일
500: 서버 오류
사용자 ID 중복 체크 🌐 공개
POST
/api/public/check/userId/IsDuplicate
제공된 사용자 ID가 이미 사용 중인지 확인합니다.
요청 본문
{
"userId": "newUser123"
}
응답 본문
{
"isDuplicate": true,
"message": "이미 사용 중인 아이디입니다"
}
200: 중복 체크 완료
닉네임 중복 체크 🌐 공개
POST
/api/public/check/nickname/IsDuplicate
제공된 닉네임이 이미 사용 중인지 확인합니다.
요청 본문
{
"nickname": "쾌활한다람쥐"
}
응답 본문
{
"isDuplicate": false,
"message": "사용 가능한 닉네임입니다"
}
200: 중복 체크 완료
로그아웃 (토큰 정리) 🌐 공개
POST
/api/public/clean/userTokenCookie
클라이언트의 refreshToken 쿠키를 만료시켜 제거합니다.
응답 본문
{
"message": "refreshToken deleted",
"loggedOutAt": "2024-01-15T10:30:00Z"
}
200: 로그아웃 성공
일기 API
일기 작성 🔐 인증 필요
POST
/api/diaries
새로운 일기를 작성하고 저장합니다.
요청 필드
| 필드명 | 타입 | 필수/선택 | 제약 조건 | 설명 |
|---|---|---|---|---|
| title | string | 선택 | 1-100자 | 일기 제목 |
| content | string | 필수 | 10-5000자 | 일기 내용 |
요청 본문
{
"title": "오늘의 일기",
"content": "오늘은 정말 즐거운 하루였다. 친구들과 함께 카페에서 즐거운 시간을 보냈고, 새로운 책도 읽기 시작했다."
}
응답 본문
{
"id": 1,
"userId": 123,
"title": "오늘의 일기",
"content": "오늘은 정말 즐거운 하루였다...",
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z",
"wordCount": 45,
"isAnalyzed": false
}
201: 일기 작성 성공
400: 잘못된 요청
401: 인증 실패
📝 일기 작성 가이드
- 하루에 최대 5개의 일기 작성 가능
- 내용은 최소 10자 이상 작성 필요
- 제목이 없을 경우 자동으로 날짜로 설정
- 작성 후 감정 분석을 위해 별도 API 호출 필요
일기 목록 조회 🔐 인증 필요
GET
/api/diaries
사용자가 작성한 일기 목록을 페이지네이션하여 조회합니다.
쿼리 파라미터
| 파라미터명 | 타입 | 필수/선택 | 기본값 | 설명 |
|---|---|---|---|---|
| page | integer | 선택 | 0 | 페이지 번호 (0부터 시작) |
| size | integer | 선택 | 10 | 페이지 당 항목 수 (최대 50) |
| sort | string | 선택 | createdAt,desc | 정렬 기준 |
| startDate | string | 선택 | - | 시작 날짜 (YYYY-MM-DD) |
| endDate | string | 선택 | - | 종료 날짜 (YYYY-MM-DD) |
응답 본문
{
"diaries": [
{
"id": 1,
"title": "오늘의 일기",
"createdAt": "2024-01-15T10:30:00Z",
"emotionStatus": "POSITIVE",
"wordCount": 45,
"isAnalyzed": true
}
],
"pageInfo": {
"currentPage": 0,
"totalPages": 5,
"totalElements": 42,
"hasNext": true,
"hasPrevious": false
}
}
200: 일기 목록 조회 성공
401: 인증 실패
감정 분석 API
일기 감정 분석 요청 🔐 인증 필요
POST
/api/diaries/{diaryId}/analysis
특정 일기에 대한 AI 감정 분석을 비동기적으로 요청합니다.
경로 파라미터
| 파라미터명 | 타입 | 필수/선택 | 제약 조건 | 설명 |
|---|---|---|---|---|
| diaryId | integer | 필수 | 양의 정수 | 분석할 일기의 ID |
응답 본문
{
"message": "Emotion analysis request accepted. Processing in background.",
"diaryId": 1,
"trackingId": "kafka-message-id-12345",
"estimatedTime": "2-5분",
"requestedAt": "2024-01-15T10:30:00Z"
}
202: 분석 요청 성공
401: 인증 실패
403: 접근 권한 없음
404: 일기를 찾을 수 없음
409: 이미 분석 중이거나 완료됨
🤖 AI 분석 정보
- 분석 소요 시간: 평균 2-5분
- 일기 내용이 10자 미만일 경우 분석 불가
- 하루 최대 20회 분석 요청 가능
- 분석 결과는 SSE를 통해 실시간 알림
일기 감정 분석 결과 조회 🔐 인증 필요
GET
/api/diaries/{diaryId}/analysis
특정 일기의 AI 감정 분석 결과를 조회합니다.
응답 본문 (분석 완료)
{
"diaryId": 1,
"analysis": {
"id": 42,
"emotionDetection": {
"joy": 80,
"sadness": 10,
"surprise": 5,
"calm": 5
},
"emotionSummary": "기쁨 80%, 슬픔 10%, 놀람 5%, 평온 5%",
"automaticThought": "나는 항상 실패한다.",
"promptForChange": "정말 항상 실패했나요? 성공했던 경험을 떠올려볼까요?",
"alternativeThought": "과거에 몇 번 실패했지만, 그것이 항상 실패한다는 의미는 아니다. 이번에는 다른 방법을 시도해볼 수 있다.",
"status": "POSITIVE",
"confidence": 0.85,
"analyzedAt": "2024-01-15T10:35:00Z"
}
}
응답 본문 (분석 진행 중)
{
"message": "Analysis is still in progress.",
"diaryId": 1,
"progress": 65,
"estimatedRemaining": "1-2분"
}
200: 분석 결과 조회 성공
202: 분석 진행 중
401: 인증 실패
404: 분석 결과를 찾을 수 없음
오류 처리
표준 오류 응답 형식
모든 API 오류는 다음과 같은 표준 형식으로 응답됩니다.
{
"timestamp": "2024-01-15T10:30:00Z",
"status": 400,
"error": "Bad Request",
"message": "상세 오류 메시지",
"path": "/api/endpoint",
"traceId": "abc123def456",
"validationErrors": [
{
"field": "필드명",
"message": "필드별 오류 메시지",
"rejectedValue": "거부된 값"
}
]
}
주요 오류 코드
| 상태 코드 | 오류 타입 | 설명 | 해결 방법 |
|---|---|---|---|
| 400 | Bad Request | 잘못된 요청 형식 또는 유효성 검사 실패 | 요청 데이터 확인 및 수정 |
| 401 | Unauthorized | 인증 토큰이 없거나 유효하지 않음 | 로그인 후 유효한 토큰으로 재요청 |
| 403 | Forbidden | 접근 권한이 없음 | 권한 확인 또는 관리자 문의 |
| 404 | Not Found | 요청한 리소스를 찾을 수 없음 | URL 및 리소스 ID 확인 |
| 409 | Conflict | 리소스 충돌 (중복 등) | 중복 데이터 확인 및 수정 |
| 429 | Too Many Requests | 요청 한도 초과 | 잠시 후 재시도 |
| 500 | Internal Server Error | 서버 내부 오류 | 관리자 문의 |
오류 처리 권장사항
💡 클라이언트 오류 처리 가이드
- 401 오류: 자동으로 토큰 갱신 시도 후 재요청
- 429 오류: Exponential Backoff 알고리즘 사용
- 5xx 오류: 사용자에게 친화적인 메시지 표시
- 네트워크 오류: 재시도 로직 구현 (최대 3회)
- 타임아웃: 30초 이상 응답 없을 시 요청 취소
오류 코드별 상세 예시
유효성 검사 실패 (400)
{
"timestamp": "2024-01-15T10:30:00Z",
"status": 400,
"error": "Bad Request",
"message": "Validation failed for multiple fields",
"path": "/api/public/join",
"traceId": "abc123def456",
"validationErrors": [
{
"field": "userPw",
"message": "비밀번호는 8자 이상이어야 합니다",
"rejectedValue": "123"
},
{
"field": "email",
"message": "유효한 이메일 형식이 아닙니다",
"rejectedValue": "invalid-email"
}
]
}
인증 실패 (401)
{
"timestamp": "2024-01-15T10:30:00Z",
"status": 401,
"error": "Unauthorized",
"message": "JWT token is expired",
"path": "/api/diaries",
"traceId": "def456ghi789",
"details": {
"tokenExpiredAt": "2024-01-15T10:00:00Z",
"refreshTokenAvailable": true
}
}