- 개발 환경 Base URL:
https://dev.taba.asia/api/v1 - 프로덕션 Base URL:
https://www.taba.asia/api/v1 - 인증 방식: JWT Bearer Token
- Content-Type:
application/json - API 버전: v1
참고: 이 문서는 개발/프로덕션 환경 공통 API 명세입니다.
예시 URL은 개발 환경(dev.taba.asia)을 기준으로 작성되었으며, 프로덕션 환경에서는www.taba.asia로 변경하여 사용하세요.
모든 API는 다음 형식으로 응답합니다:
{
"success": true,
"data": { ... },
"message": "성공 메시지 (선택사항)"
}에러 응답:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "에러 메시지"
}
}대부분의 API는 JWT 토큰 인증이 필요합니다. 요청 헤더에 다음을 포함하세요:
Authorization: Bearer {token}
POST /auth/signup
인증: 불필요
Content-Type: multipart/form-data
Request:
email: 이메일 (필수)password: 비밀번호 (필수, 최소 8자)nickname: 닉네임 (필수, 2-50자)agreeTerms: 이용약관 동의 (필수, boolean)agreePrivacy: 개인정보처리방침 동의 (필수, boolean)profileImage: 프로필 이미지 파일 (선택사항)
Request Body 예시 (multipart/form-data):
email: user@example.com
password: password123
nickname: 사용자
agreeTerms: true
agreePrivacy: true
profileImage: [파일]
Response (201 Created):
{
"success": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "uuid",
"email": "user@example.com",
"nickname": "사용자"
}
},
"message": "회원가입이 완료되었습니다."
}POST /auth/login
인증: 불필요
Request Body:
{
"email": "user@example.com",
"password": "password123"
}Response (200 OK):
{
"success": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "uuid",
"email": "user@example.com",
"nickname": "사용자"
}
},
"message": "로그인에 성공했습니다."
}GET /users/{userId}
인증: 필요
Response (200 OK):
{
"success": true,
"data": {
"id": "uuid",
"email": "user@example.com",
"nickname": "사용자",
"profileImageUrl": "https://dev.taba.asia/api/v1/files/{fileId}",
"createdAt": "2024-01-01T00:00:00"
}
}PUT /users/{userId}
인증: 필요
Content-Type: multipart/form-data
Request:
nickname: 닉네임 (선택사항, 2-50자)avatarUrl: 아바타 URL (선택사항)profileImage: 프로필 이미지 파일 (선택사항)
참고사항:
- 프로필 수정 후, 다른 API에서 유저 정보를 조회할 때 변경된 닉네임과 프로필 이미지가 즉시 반영됩니다.
- 예: 편지 목록, 친구 목록, 알림 등에서 표시되는 유저 정보는 항상 최신 데이터를 반영합니다.
Response (200 OK):
{
"success": true,
"data": {
"id": "uuid",
"email": "user@example.com",
"nickname": "수정된 닉네임",
"profileImageUrl": "https://dev.taba.asia/api/v1/files/{fileId}"
},
"message": "프로필이 수정되었습니다."
}PUT /users/{userId}/fcm-token
인증: 필요
Request Body:
{
"fcmToken": "fcm_token_string"
}Response (200 OK):
{
"success": true,
"data": null,
"message": "FCM 토큰이 등록되었습니다."
}DELETE /users/{userId}
인증: 필요
참고사항:
- 본인만 탈퇴할 수 있습니다.
- 회원탈퇴 시 사용자 정보는 소프트 삭제됩니다.
- 탈퇴 후 해당 계정으로 로그인할 수 없습니다.
Response (200 OK):
{
"success": true,
"data": null,
"message": "회원탈퇴가 완료되었습니다."
}GET /friends
인증: 필요
Response (200 OK):
{
"success": true,
"data": {
"friends": [
{
"id": "uuid",
"email": "friend@example.com",
"nickname": "친구1",
"avatarUrl": "https://dev.taba.asia/api/v1/files/{fileId}",
"joinedAt": "2024-01-01T00:00:00",
"friendCount": 5,
"sentLetters": 10,
"unreadLetterCount": 3
}
]
}
}참고사항:
unreadLetterCount: 해당 친구로부터 받은 안 읽은 개인편지(DIRECT) 개수- 공개편지는 안 읽은 개수에 포함되지 않습니다.
POST /friends/invite
인증: 필요
Request Body:
{
"inviteCode": "ABC123"
}참고사항:
- 올바르지 않은 초대 코드인 경우:
INVALID_INVITE_CODE에러 반환 - 만료된 초대 코드인 경우:
INVITE_CODE_EXPIRED에러 반환 - 이미 사용된 초대 코드인 경우:
INVITE_CODE_ALREADY_USED에러 반환 - 자신의 초대 코드를 사용한 경우: 본인 정보와 함께 "본인은 친구 추가할 수 없습니다." 메시지 반환 (201 Created)
- 이미 친구인 경우: 친구 정보와 함께 "이미 친구입니다." 메시지 반환 (201 Created)
- 새로운 친구인 경우: 친구 정보와 함께 "친구가 추가되었습니다." 메시지 반환 (201 Created)
Response (201 Created) - 새로운 친구 추가 성공:
{
"success": true,
"data": {
"friend": {
"id": "uuid",
"email": "friend@example.com",
"nickname": "친구1",
"avatarUrl": "https://dev.taba.asia/api/v1/files/{fileId}",
"joinedAt": "2024-01-01T00:00:00",
"friendCount": 5,
"sentLetters": 10
},
"alreadyFriends": false,
"isOwnCode": false
},
"message": "친구가 추가되었습니다."
}Response (201 Created) - 자신의 초대 코드를 사용한 경우:
{
"success": true,
"data": {
"friend": {
"id": "uuid",
"email": "user@example.com",
"nickname": "본인",
"avatarUrl": "https://dev.taba.asia/api/v1/files/{fileId}",
"joinedAt": "2024-01-01T00:00:00",
"friendCount": 5,
"sentLetters": 10
},
"alreadyFriends": false,
"isOwnCode": true
},
"message": "본인은 친구 추가할 수 없습니다."
}Response (201 Created) - 이미 친구인 경우:
{
"success": true,
"data": {
"friend": {
"id": "uuid",
"email": "friend@example.com",
"nickname": "친구1",
"avatarUrl": "https://dev.taba.asia/api/v1/files/{fileId}",
"joinedAt": "2024-01-01T00:00:00",
"friendCount": 5,
"sentLetters": 10
},
"alreadyFriends": true,
"isOwnCode": false
},
"message": "이미 친구입니다."
}DELETE /friends/{friendId}
인증: 필요
참고사항:
- 친구 관계가 존재하지 않는 경우
FRIENDSHIP_NOT_FOUND에러를 반환합니다. - 친구 ID가 유효하지 않은 경우
USER_NOT_FOUND에러를 반환합니다. - 자기 자신을 친구 삭제 대상으로 지정할 수 없습니다.
- 양방향 친구 관계가 모두 소프트 삭제됩니다.
Response (200 OK):
{
"success": true,
"data": null,
"message": "친구가 삭제되었습니다."
}에러 응답 (404 Not Found) - 친구 관계가 없는 경우:
{
"success": false,
"error": {
"code": "FRIENDSHIP_NOT_FOUND",
"message": "친구 관계를 찾을 수 없습니다."
}
}GET /friends/{friendId}/letters
인증: 필요
Response (200 OK):
{
"success": true,
"data": {
"content": [
{
"id": "uuid",
"letter": {
"id": "uuid",
"title": "편지 제목",
"preview": "편지 미리보기",
"fontFamily": "Jua"
},
"sentAt": "2024-01-01T00:00:00",
"sentByMe": false,
"isRead": true,
"fontFamily": "Jua"
}
],
"pageable": { ... },
"totalElements": 10,
"totalPages": 1
}
}참고사항:
- 친구 간 주고받은 편지 목록을 반환합니다 (양방향).
- 공개편지 포함: 친구가 작성한 공개편지 중 내가 답장을 보낸 공개편지만 목록에 포함됩니다.
- 공개편지에 답장한 경우, 공개편지의
sentAt이 답장 시간 바로 전(1초 전)으로 조정되어 표시됩니다. - 이를 통해 공개편지가 답장보다 시간상 앞서 표시되어 대화 흐름이 자연스럽게 유지됩니다.
- 공개편지에 답장한 경우, 공개편지의
- 예약전송 편지 포함: 예약전송 편지도 목록에 포함됩니다.
- 예약전송 편지의 경우
sentAt이scheduledAt으로 표시됩니다 - 받는 사람은 예약 시간 전까지 편지를 열람할 수 없지만, 목록에는 표시됩니다
- 예약전송 편지의 경우
sentByMe: 내가 보낸 편지인지 여부 (true: 내가 보낸 편지, false: 친구가 보낸 편지 또는 공개편지)isRead:- DIRECT 편지: 내가 받은 편지인 경우 읽음 상태 (내가 보낸 편지인 경우 null)
- PUBLIC 편지: 공개편지에 답장을 보내면 자동으로 읽음 처리되며, 이후 읽음 상태가 표시됩니다 (아직 읽지 않은 경우 false)
letter: 편지 요약 정보 (id, title, preview, fontFamily)- 시간순 정렬:
sentAt(또는scheduledAt) 기준 오름차순 정렬 (오래된 편지부터 최신 편지 순서) - 페이지네이션 정보가 포함됩니다.
POST /letters
인증: 필요
Content-Type: application/json
Request Body:
{
"title": "편지 제목",
"content": "편지 내용",
"preview": "편지 미리보기",
"visibility": "PUBLIC",
"template": {
"background": "#1D1433",
"textColor": "#FFFFFF",
"fontFamily": "Jua",
"fontSize": 16.0
},
"attachedImages": ["https://dev.taba.asia/api/v1/files/{fileId}"],
"scheduledAt": "2024-01-01T12:00:00",
"recipientId": "uuid",
"language": "ko"
}참고사항:
visibility:PUBLIC,DIRECT중 하나 (필수)- 익명 기능은 제거되었습니다. 모든 편지는 작성자 정보가 표시됩니다.
recipientId: 직접 전송(DIRECT) 편지인 경우 필수, 공개 편지인 경우 선택사항scheduledAt: 예약전송 시간 (선택사항). 미래 시간을 지정하면 해당 시간에 자동으로 발송됩니다.- 예약전송 제한사항:
- 예약전송은 친구에게만 보낼 수 있습니다 (
DIRECT타입만 가능,PUBLIC불가) - 수신자(
recipientId)가 필수입니다 - 친구 관계가 있어야 합니다
- 예약전송은 친구에게만 보낼 수 있습니다 (
- 예약전송 시간이 현재 시간보다 이전이거나 같으면 즉시 발송됩니다
- 예약전송 제한사항:
language: 편지 언어 (선택사항).ko(한국어),en(영어),ja(일본어) 중 하나attachedImages: 첨부 이미지 URL 배열 (선택사항). 여러 이미지를 첨부할 수 있으며, 순서대로 저장됩니다.- 이미지 업로드는
/filesAPI를 통해 먼저 수행하고, 반환된 URL을 사용합니다. - 예:
["https://dev.taba.asia/api/v1/files/{fileId1}", "https://dev.taba.asia/api/v1/files/{fileId2}"]
- 이미지 업로드는
Response (201 Created):
{
"success": true,
"data": {
"letter": {
"id": "uuid",
"title": "편지 제목",
"content": "편지 내용",
"preview": "편지 미리보기",
"sender": {
"id": "uuid",
"nickname": "작성자",
"avatarUrl": "https://dev.taba.asia/api/v1/files/{fileId}"
},
"visibility": "PUBLIC",
"sentAt": "2024-01-01T00:00:00",
"views": 0,
"attachedImages": ["https://dev.taba.asia/api/v1/files/{fileId}"],
"template": {
"background": "#1D1433",
"textColor": "#FFFFFF",
"fontFamily": "Jua",
"fontSize": 16.0
},
"language": "ko"
}
},
"message": "편지가 작성되었습니다."
}GET /letters/{letterId}
인증: 필요
참고사항:
- 편지의 접근 권한을 확인합니다 (PUBLIC, DIRECT)
- 예약전송 편지 접근 제한:
- 예약전송 편지(
scheduledAt이 있고sentAt이 null인 경우)는 받는 사람이 예약 시간 전까지 열람할 수 없습니다 - 보낸 사람은 언제든지 열람 가능합니다
- 예약 시간이 지나면 자동으로 발송되며, 이후 받는 사람도 열람할 수 있습니다
- 예약전송 편지(
- 읽음 처리 (작성자가 아닌 경우에만 자동 처리):
- 공개 편지(PUBLIC):
LetterRecipient테이블을 통해 읽음 상태가 자동으로 기록됩니다. 여러 사용자가 읽을 수 있으므로 사용자별로 읽음 상태를 관리합니다. - 직접 전송 편지(DIRECT): 수신자가 조회하면
Letter엔티티의isRead필드가 자동으로 업데이트됩니다. 1:1 편지이므로 편지 자체의 읽음 상태로 관리합니다.
- 공개 편지(PUBLIC):
- 편지를 조회하면 조회수(
views)가 증가합니다. isRead: 읽음 상태 (작성자가 아닌 경우에만 표시)true: 읽음false: 읽지 않음null: 작성자인 경우
Response (200 OK):
{
"success": true,
"data": {
"letter": {
"id": "uuid",
"title": "편지 제목",
"content": "편지 내용",
"preview": "편지 미리보기",
"sender": {
"id": "uuid",
"nickname": "작성자",
"profileImageUrl": "https://dev.taba.asia/api/v1/files/{fileId}"
},
"visibility": "PUBLIC",
"sentAt": "2024-01-01T00:00:00",
"views": 10,
"attachedImages": [
"https://dev.taba.asia/api/v1/files/{fileId1}",
"https://dev.taba.asia/api/v1/files/{fileId2}"
],
"template": {
"background": "#1D1433",
"textColor": "#FFFFFF",
"fontFamily": "Jua",
"fontSize": 16.0
},
"language": "ko",
"isRead": true
}
}
}GET /letters/public
인증: 선택사항
Query Parameters:
languages(선택사항): 언어 필터링. 여러 언어를 선택하려면 같은 파라미터를 여러 번 사용하세요.- 예:
?languages=ko&languages=en(한국어와 영어) - 가능한 값:
ko(한국어),en(영어),ja(일본어) - 생략 시 모든 언어의 편지를 조회합니다.
- 예:
참고사항:
- 모든 편지는 작성자 정보가 표시됩니다 (익명 기능 제거)
- 로그인한 사용자의 경우 자신이 작성한 편지는 목록에서 제외됩니다
- 언어 필터링은 여러 언어를 동시에 선택할 수 있습니다 (예: 한국어와 영어)
- 읽음 처리: 목록 조회 시에는 읽음 처리가 되지 않습니다. 실제 편지 상세 조회(
GET /letters/{letterId}) 시에만 읽음 처리가 됩니다. - 조회수: 목록 조회 시에는 조회수가 증가하지 않습니다. 실제 편지 상세 조회 시에만 조회수가 증가합니다.
isRead: 읽음 상태 (로그인한 사용자이고 작성자가 아닌 경우에만 표시)true: 읽음false: 읽지 않음null: 작성자인 경우 또는 비로그인 사용자
Request 예시:
GET /letters/public?languages=ko&languages=en&page=0&size=20
Response (200 OK):
{
"success": true,
"data": {
"content": [
{
"id": "uuid",
"title": "편지 제목",
"content": "편지 내용",
"preview": "편지 미리보기",
"sender": {
"id": "uuid",
"nickname": "작성자",
"profileImageUrl": "https://dev.taba.asia/api/v1/files/{fileId}"
},
"visibility": "PUBLIC",
"sentAt": "2024-01-01T00:00:00",
"views": 10,
"attachedImages": ["https://dev.taba.asia/api/v1/files/{fileId}"],
"template": {
"background": "#1D1433",
"textColor": "#FFFFFF",
"fontFamily": "Jua",
"fontSize": 16.0
},
"language": "ko",
"isRead": true
}
],
"pageable": { ... },
"totalElements": 100,
"totalPages": 5
}
}GET /letters/my
인증: 필요
Query Parameters:
page: 페이지 번호 (기본값: 0)size: 페이지 크기 (기본값: 20)sort: 정렬 기준 (기본값: createdAt,desc)
참고사항:
- 현재 로그인한 사용자가 작성한 모든 편지를 조회합니다.
- 삭제되지 않은 편지만 조회됩니다 (소프트 삭제).
- 작성일 기준 내림차순으로 정렬됩니다 (최신 편지부터).
- 본인이 작성한 편지이므로 읽음 처리는 수행되지 않습니다.
Response (200 OK):
{
"success": true,
"data": {
"content": [
{
"id": "uuid",
"title": "편지 제목",
"content": "편지 내용",
"preview": "편지 미리보기",
"sender": {
"id": "uuid",
"nickname": "작성자",
"avatarUrl": "https://dev.taba.asia/api/v1/files/{fileId}"
},
"visibility": "PUBLIC",
"sentAt": "2024-01-01T00:00:00",
"views": 10,
"attachedImages": ["https://dev.taba.asia/api/v1/files/{fileId}"],
"template": {
"background": "#1D1433",
"textColor": "#FFFFFF",
"fontFamily": "Jua",
"fontSize": 16.0
},
"language": "ko"
}
],
"pageable": {
"pageNumber": 0,
"pageSize": 20
},
"totalElements": 1,
"totalPages": 1
}
}POST /letters/{letterId}/reply
인증: 필요
Request Body:
{
"title": "답장 제목",
"content": "답장 내용",
"preview": "답장 미리보기",
"template": {
"background": "#1D1433",
"textColor": "#FFFFFF",
"fontFamily": "Jua",
"fontSize": 16.0
},
"attachedImages": ["https://dev.taba.asia/api/v1/files/{fileId}"],
"scheduledAt": "2024-01-01T12:00:00"
}참고사항:
recipientId는 필요하지 않습니다. 원본 편지의 작성자가 자동으로 수신자가 됩니다.- 공개 편지, 직접 전송 편지 모두에 답장 가능합니다.
- 답장은 항상
DIRECT타입으로 생성됩니다. - 친구가 아닌 사용자에게 답장을 보내면 자동으로 양방향 친구 관계가 생성됩니다.
- 자기 자신에게 답장할 수 없습니다.
scheduledAt: 예약전송 시간 (선택사항). 답장도 예약전송 가능하며, 예약전송인 경우 친구 관계가 있어야 합니다.- 공개 편지(PUBLIC)에 답장하는 경우:
- 원본 편지 ID(
originalLetterId)가 답장 편지에 저장되어, 친구와의 편지 목록에서 해당 공개편지만 표시됩니다. - 공개 편지에 답장을 보내면 자동으로 해당 공개 편지가 읽음 처리됩니다 (
LetterRecipient를 통해).
- 원본 편지 ID(
attachedImages: 첨부 이미지 URL 배열 (선택사항). 여러 이미지를 첨부할 수 있으며, 순서대로 저장됩니다.- 이미지 업로드는
/filesAPI를 통해 먼저 수행하고, 반환된 URL을 사용합니다.
- 이미지 업로드는
Response (201 Created):
{
"success": true,
"data": {
"letter": {
"id": "uuid",
"title": "답장 제목",
"content": "답장 내용",
"preview": "답장 미리보기",
"sender": {
"id": "uuid",
"nickname": "작성자",
"profileImageUrl": "https://dev.taba.asia/api/v1/files/{fileId}"
},
"visibility": "DIRECT",
"sentAt": "2024-01-01T00:00:00",
"views": 0,
"attachedImages": [
"https://dev.taba.asia/api/v1/files/{fileId1}",
"https://dev.taba.asia/api/v1/files/{fileId2}"
],
"template": {
"background": "#1D1433",
"textColor": "#FFFFFF",
"fontFamily": "Jua",
"fontSize": 16.0
},
"language": "ko"
}
},
"message": "답장이 전송되었습니다. 친구가 자동으로 추가되었습니다."
}DELETE /letters/{letterId}
인증: 필요
참고사항:
- 자신이 작성한 편지만 삭제할 수 있습니다.
- 편지는 소프트 삭제됩니다 (실제로 삭제되지 않고
deletedAt필드에 타임스탬프가 기록됩니다). - 삭제된 편지는 조회되지 않습니다.
Response (200 OK):
{
"success": true,
"message": "편지가 삭제되었습니다."
}에러 응답:
403 Forbidden: 자신이 작성한 편지가 아닌 경우404 Not Found: 편지를 찾을 수 없는 경우
POST /invite-codes/generate
인증: 필요
참고사항:
- 기존에 유효한 초대 코드가 있으면 새로 생성하지 않고 기존 코드를 반환합니다.
- 초대 코드는 생성 후 3분간 유효합니다.
Response (201 Created):
{
"success": true,
"data": {
"code": "ABC123",
"expiresAt": "2024-01-01T00:03:00",
"remainingMinutes": 3
},
"message": "초대 코드가 생성되었습니다."
}GET /invite-codes/current
인증: 필요
참고사항:
- 현재 유효한 초대 코드가 없거나 만료된 경우
null을 반환합니다.
Response (200 OK) - 유효한 코드가 있는 경우:
{
"success": true,
"data": {
"code": "ABC123",
"expiresAt": "2024-01-01T00:03:00",
"remainingMinutes": 2
}
}Response (200 OK) - 유효한 코드가 없는 경우:
{
"success": true,
"data": null
}GET /notifications
인증: 필요
Query Parameters:
category(선택사항): 알림 카테고리 필터링- 가능한 값:
LETTER,REACTION,FRIEND,SYSTEM - 생략 시 모든 카테고리의 알림을 조회합니다.
- 가능한 값:
page(선택사항): 페이지 번호 (기본값: 0)size(선택사항): 페이지 크기 (기본값: 20)
참고사항:
- 알림 목록은 생성일시(
time) 기준 내림차순으로 정렬됩니다 (최신 알림부터). isUnread: 읽지 않은 알림 여부true: 읽지 않은 알림false: 읽은 알림
- 페이지네이션 정보가 포함됩니다.
Response (200 OK):
{
"success": true,
"data": {
"content": [
{
"id": "uuid",
"title": "새 편지를 받았습니다",
"subtitle": "친구가 편지를 보냈습니다",
"time": "2024-01-01T00:00:00",
"category": "LETTER",
"isUnread": true,
"relatedId": "letter-uuid"
}
],
"pageable": { ... },
"totalElements": 10,
"totalPages": 1
}
}PUT /notifications/{notificationId}/read
인증: 필요
참고사항:
- 특정 알림을 읽음 처리합니다.
- 읽음 처리된 알림의
isUnread값이false로 변경됩니다. - 읽지 않은 알림을 읽음 처리한 경우, 업데이트된 뱃지 숫자가 FCM 푸시 알림으로 자동 전송됩니다 (iOS/Android 모두 지원).
Response (200 OK):
{
"success": true,
"data": {
"id": "uuid",
"title": "새 편지를 받았습니다",
"subtitle": "친구가 편지를 보냈습니다",
"time": "2024-01-01T00:00:00",
"category": "LETTER",
"isUnread": false,
"relatedId": "letter-uuid"
}
}PUT /notifications/read-all
인증: 필요
참고사항:
- 현재 사용자의 모든 읽지 않은 알림을 일괄 읽음 처리합니다.
- 읽음 처리된 알림 개수를 반환합니다.
- 읽음 처리한 알림이 있는 경우, 업데이트된 뱃지 숫자가 FCM 푸시 알림으로 자동 전송됩니다 (iOS/Android 모두 지원).
Response (200 OK):
{
"success": true,
"data": {
"readCount": 5,
"message": "모든 알림이 읽음 처리되었습니다."
}
}DELETE /notifications/{notificationId}
인증: 필요
참고사항:
- 본인의 알림만 삭제할 수 있습니다.
- 알림 삭제 시 읽지 않은 알림 개수(
/notifications/unread-count)에 즉시 반영됩니다. - 읽지 않은 알림을 삭제한 경우, 업데이트된 뱃지 숫자가 FCM 푸시 알림으로 자동 전송됩니다 (iOS/Android 모두 지원).
Response (200 OK):
{
"success": true,
"data": "알림이 삭제되었습니다.",
"message": "알림이 삭제되었습니다."
}GET /notifications/unread-count
인증: 필요
참고사항:
- 현재 사용자의 읽지 않은 편지 개수를 반환합니다.
- 앱 뱃지 숫자 표시용으로 사용됩니다.
- FCM 푸시 알림 발송 시에도 이 개수가 뱃지 숫자로 전송됩니다.
- 편지 읽음 처리 시 즉시 반영됩니다.
- 뱃지 계산 기준: 내가 받은 읽지 않은 DIRECT 편지만 카운트됩니다.
- 내가 보낸 편지는 카운트되지 않습니다.
- 공개편지(PUBLIC)는 카운트되지 않습니다.
- 친구 추가 알림이나 답장 알림 등은 뱃지에 포함되지 않습니다.
FCM 푸시 알림 뱃지 지원:
- iOS: APNs의
badge필드를 통해 읽지 않은 알림 개수가 자동으로 설정됩니다. - Android: FCM data payload의
badge필드에 읽지 않은 알림 개수가 포함됩니다. 앱에서 이 값을 받아 뱃지를 업데이트할 수 있습니다.
뱃지 업데이트 시점:
- 편지 수신 시: 새 편지를 받으면 읽지 않은 편지 개수를 계산하여 뱃지 숫자로 전송합니다.
- 편지 읽음 처리 시: 편지를 읽으면 업데이트된 뱃지 숫자가 silent push로 전송됩니다.
- 뱃지 동기화 시: 앱이 포그라운드로 올라오거나 알림 목록 화면 진입 시 현재 읽지 않은 편지 개수로 뱃지를 동기화합니다.
뱃지 계산 기준:
- 뱃지 숫자는 내가 받은 읽지 않은 DIRECT 편지 개수를 기준으로 합니다.
- 카운트되는 편지:
- DIRECT 편지 중 수신자가 현재 사용자이고 읽지 않은 편지
- 카운트되지 않는 항목:
- 내가 보낸 편지 (수신자가 나인 경우에도 내가 보낸 편지는 카운트되지 않음)
- 공개편지(PUBLIC) - 공개편지는 뱃지에 포함되지 않습니다
- 친구 추가 알림, 답장 알림 등 - 내가 한 액션에 대한 알림은 뱃지에 포함되지 않습니다
FCM Data Payload 구조 (알림 생성 시):
{
"notificationId": "uuid",
"category": "LETTER",
"relatedId": "letter-uuid",
"deepLink": "/letter/letter-uuid",
"badge": "3"
}FCM Data Payload 구조 (뱃지 업데이트만):
{
"type": "badge_update",
"badge": "2"
}Response (200 OK):
{
"success": true,
"data": {
"unreadCount": 3
}
}POST /notifications/badge/sync
인증: 필요
참고사항:
- 현재 읽지 않은 편지 개수를 계산하여 뱃지 숫자를 동기화합니다.
- 앱이 포그라운드로 올라오거나 알림 목록 화면 진입 시 호출하는 것을 권장합니다.
- 읽지 않은 편지 개수를 반환하며, 동시에 FCM 푸시 알림으로 뱃지 숫자를 업데이트합니다.
- iOS와 Android 모두 지원합니다.
- 뱃지 계산 기준: 내가 받은 읽지 않은 DIRECT 편지만 카운트됩니다.
- 내가 보낸 편지나 내가 한 액션(친구 추가, 답장 등)은 뱃지에 포함되지 않습니다.
Response (200 OK):
{
"success": true,
"data": {
"unreadCount": 3
}
}POST /files
인증: 필요
Content-Type: multipart/form-data
Request:
file: 파일 (필수, 이미지 파일만 가능)
Response (201 Created):
{
"success": true,
"data": {
"fileId": "uuid",
"url": "https://dev.taba.asia/api/v1/files/{fileId}"
}
}GET /files/{fileId}
인증: 필요
Response: 이미지 파일 반환
POST /blocks/{userId}
인증: 필요
참고사항:
- 차단하면 친구 관계가 자동으로 삭제됩니다 (양방향).
- 차단한 사용자의 공개 편지는 목록에서 제외됩니다.
- 자기 자신은 차단할 수 없습니다.
- 이미 차단한 사용자는 다시 차단할 수 없습니다.
Response (201 Created):
{
"success": true,
"data": "사용자를 차단했습니다.",
"message": "사용자를 차단했습니다."
}에러 응답:
400 Bad Request: 자기 자신을 차단하려는 경우 또는 이미 차단한 사용자인 경우404 Not Found: 차단할 사용자를 찾을 수 없는 경우
DELETE /blocks/{userId}
인증: 필요
참고사항:
- 차단 해제 후에도 친구 관계는 자동으로 복구되지 않습니다.
- 친구가 되려면 다시 초대 코드를 사용하거나 편지 답장을 통해 친구가 되어야 합니다.
Response (200 OK):
{
"success": true,
"data": "차단이 해제되었습니다.",
"message": "차단이 해제되었습니다."
}에러 응답:
400 Bad Request: 차단하지 않은 사용자를 해제하려는 경우
GET /blocks
인증: 필요
Response (200 OK):
{
"success": true,
"data": [
{
"id": "uuid",
"nickname": "차단한사용자",
"avatarUrl": "https://dev.taba.asia/api/v1/files/{fileId}",
"blockedAt": "2024-01-01T00:00:00"
}
]
}참고사항:
- 차단한 사용자 목록을 반환합니다.
- 차단한 사용자가 없으면 빈 배열을 반환합니다.
blockedAt: 차단한 시간
다음 URL에서 인터랙티브 API 문서를 확인할 수 있습니다:
- 개발 환경: https://dev.taba.asia/api/v1/swagger-ui/index.html
- 프로덕션 환경: https://www.taba.asia/api/v1/swagger-ui/index.html
- 모든 API에서 반환되는 유저 정보(닉네임, 프로필 이미지 등)는 항상 최신 데이터를 반영합니다.
- 프로필을 수정하면, 편지 목록, 친구 목록, 알림 등 다른 API에서 조회되는 유저 정보에도 즉시 반영됩니다.
- 캐싱으로 인한 오래된 데이터가 표시되지 않도록 보장됩니다.
- 유효 시간: 3분
- 형식: 정확히 6자리 숫자+영문 조합 (예:
A1B2C3,9X7Y2Z,ABC123) - 대문자 영문(A-Z)과 숫자(0-9) 조합만 사용
- 친구가 아닌 사용자에게 답장을 보내면 자동으로 양방향 친구 관계가 생성됩니다
- 뱃지 숫자는 내가 받은 읽지 않은 DIRECT 편지 개수로 표시됩니다.
- iOS와 Android 모두 지원합니다.
- 편지 수신, 읽음 처리 시 뱃지 숫자가 자동으로 업데이트됩니다.
- FCM 푸시 알림을 통해 뱃지 숫자가 실시간으로 동기화됩니다.
- 중요: 내가 보낸 편지나 내가 한 액션(친구 추가, 답장 등)은 뱃지에 포함되지 않습니다.
- 예: 내가 친구를 추가하거나 공개편지에 답장을 보낼 때, 상대방에게는 알림과 뱃지가 추가되지만 나 자신에게는 뱃지가 카운트되지 않습니다.
- 사용자를 차단하면 친구 관계가 자동으로 삭제됩니다 (양방향).
- 차단한 사용자의 공개 편지는 목록에서 제외됩니다.
- 차단 해제 후에도 친구 관계는 자동으로 복구되지 않습니다.
- 친구가 되려면 다시 초대 코드를 사용하거나 편지 답장을 통해 친구가 되어야 합니다.
- 편지가 5건 이상 신고되면 자동으로 삭제됩니다 (soft delete).
- 삭제된 편지는 목록에서 제외되며 조회할 수 없습니다.