2026-01-18 18:54:27 +09:00
|
|
|
# API 명세
|
|
|
|
|
|
|
|
|
|
Base URL: `/api`
|
|
|
|
|
|
|
|
|
|
## 인증
|
|
|
|
|
|
|
|
|
|
### POST /auth/login
|
|
|
|
|
로그인 (JWT 토큰 발급)
|
|
|
|
|
|
|
|
|
|
### GET /auth/me
|
|
|
|
|
현재 사용자 정보 (인증 필요)
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 멤버
|
|
|
|
|
|
|
|
|
|
### GET /members
|
|
|
|
|
멤버 목록 조회
|
|
|
|
|
|
|
|
|
|
### GET /members/:id
|
|
|
|
|
멤버 상세 조회
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 앨범
|
|
|
|
|
|
|
|
|
|
### GET /albums
|
|
|
|
|
앨범 목록 조회
|
|
|
|
|
|
|
|
|
|
### GET /albums/:id
|
|
|
|
|
앨범 상세 조회
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 일정
|
|
|
|
|
|
|
|
|
|
### GET /schedules
|
|
|
|
|
일정 조회
|
|
|
|
|
|
|
|
|
|
**Query Parameters:**
|
|
|
|
|
- `year`, `month` - 월별 조회 (필수, search 없을 때)
|
|
|
|
|
- `search` - 검색어 (Meilisearch 사용)
|
|
|
|
|
- `offset`, `limit` - 페이징
|
|
|
|
|
|
|
|
|
|
**월별 조회 응답:**
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"2026-01-18": {
|
|
|
|
|
"categories": [
|
|
|
|
|
{ "id": 2, "name": "유튜브", "color": "#ff0033", "count": 3 }
|
|
|
|
|
],
|
|
|
|
|
"schedules": [
|
|
|
|
|
{
|
|
|
|
|
"id": 123,
|
|
|
|
|
"title": "...",
|
|
|
|
|
"time": "19:00:00",
|
|
|
|
|
"category": { "id": 2, "name": "유튜브", "color": "#ff0033" },
|
2026-01-18 21:50:04 +09:00
|
|
|
"source": {
|
|
|
|
|
"name": "fromis_9",
|
|
|
|
|
"url": "https://www.youtube.com/watch?v=VIDEO_ID"
|
|
|
|
|
}
|
2026-01-18 18:54:27 +09:00
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2026-01-18 21:50:04 +09:00
|
|
|
**source 객체 (카테고리별):**
|
|
|
|
|
- YouTube (category_id=2): `{ name: "채널명", url: "https://www.youtube.com/..." }`
|
2026-01-19 12:32:04 +09:00
|
|
|
- X (category_id=3): `{ name: "", url: "https://x.com/realfromis_9/status/..." }` (name 빈 문자열)
|
2026-01-18 21:50:04 +09:00
|
|
|
- 기타 카테고리: source 없음
|
|
|
|
|
|
2026-01-18 18:54:27 +09:00
|
|
|
**검색 응답:**
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"schedules": [
|
|
|
|
|
{
|
|
|
|
|
"id": 123,
|
|
|
|
|
"title": "...",
|
|
|
|
|
"datetime": "2026-01-18T19:00:00",
|
|
|
|
|
"category": { "id": 2, "name": "유튜브", "color": "#ff0033" },
|
2026-01-18 21:50:04 +09:00
|
|
|
"source": { "name": "fromis_9", "url": "https://..." },
|
2026-01-18 18:54:27 +09:00
|
|
|
"members": ["송하영"],
|
|
|
|
|
"_rankingScore": 0.95
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"total": 100,
|
|
|
|
|
"offset": 0,
|
|
|
|
|
"limit": 20,
|
|
|
|
|
"hasMore": true
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2026-01-19 12:49:29 +09:00
|
|
|
### GET /schedules/categories
|
|
|
|
|
카테고리 목록 조회
|
|
|
|
|
|
|
|
|
|
**응답:**
|
|
|
|
|
```json
|
|
|
|
|
[
|
|
|
|
|
{ "id": 1, "name": "기타", "color": "#gray", "sort_order": 0 },
|
|
|
|
|
{ "id": 2, "name": "유튜브", "color": "#ff0033", "sort_order": 1 }
|
|
|
|
|
]
|
|
|
|
|
```
|
|
|
|
|
|
2026-01-18 18:54:27 +09:00
|
|
|
### GET /schedules/:id
|
|
|
|
|
일정 상세 조회
|
|
|
|
|
|
2026-01-19 12:49:29 +09:00
|
|
|
### DELETE /schedules/:id
|
|
|
|
|
일정 삭제 (인증 필요)
|
|
|
|
|
|
2026-01-18 18:54:27 +09:00
|
|
|
### POST /schedules/sync-search
|
|
|
|
|
Meilisearch 전체 동기화 (인증 필요)
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 추천 검색어
|
|
|
|
|
|
|
|
|
|
### GET /schedules/suggestions
|
|
|
|
|
추천 검색어 조회
|
|
|
|
|
|
|
|
|
|
**Query Parameters:**
|
|
|
|
|
- `q` - 검색어 (2자 이상)
|
|
|
|
|
- `limit` - 결과 개수 (기본 10)
|
|
|
|
|
|
|
|
|
|
**응답:**
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"suggestions": ["송하영", "송하영 직캠", "하영"]
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
2026-01-18 23:48:21 +09:00
|
|
|
## 관리자 - 봇 관리 (인증 필요)
|
2026-01-18 18:54:27 +09:00
|
|
|
|
2026-01-18 23:48:21 +09:00
|
|
|
### GET /admin/bots
|
|
|
|
|
봇 목록 조회
|
|
|
|
|
|
|
|
|
|
**응답:**
|
|
|
|
|
```json
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
"id": "youtube-fromis9",
|
|
|
|
|
"name": "fromis_9",
|
|
|
|
|
"type": "youtube",
|
|
|
|
|
"status": "running",
|
|
|
|
|
"last_check_at": "2026-01-18T10:30:00Z",
|
|
|
|
|
"last_added_count": 2,
|
|
|
|
|
"schedules_added": 150,
|
|
|
|
|
"check_interval": 2,
|
|
|
|
|
"error_message": null,
|
|
|
|
|
"enabled": true
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### POST /admin/bots/:id/start
|
|
|
|
|
봇 시작
|
|
|
|
|
|
|
|
|
|
### POST /admin/bots/:id/stop
|
|
|
|
|
봇 정지
|
|
|
|
|
|
|
|
|
|
### POST /admin/bots/:id/sync-all
|
|
|
|
|
전체 동기화 (모든 영상/트윗 수집)
|
|
|
|
|
|
|
|
|
|
**응답:**
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"success": true,
|
|
|
|
|
"addedCount": 25,
|
|
|
|
|
"total": 100
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### GET /admin/bots/quota-warning
|
|
|
|
|
YouTube API 할당량 경고 조회
|
|
|
|
|
|
|
|
|
|
**응답:**
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"active": true,
|
|
|
|
|
"message": "YouTube API 할당량 초과",
|
|
|
|
|
"timestamp": "2026-01-18T10:00:00Z"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### DELETE /admin/bots/quota-warning
|
|
|
|
|
할당량 경고 해제
|
2026-01-18 18:54:27 +09:00
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
2026-01-19 12:49:29 +09:00
|
|
|
## 관리자 - YouTube (인증 필요)
|
|
|
|
|
|
|
|
|
|
### GET /admin/youtube/video-info
|
|
|
|
|
YouTube 영상 정보 조회
|
|
|
|
|
|
|
|
|
|
**Query Parameters:**
|
|
|
|
|
- `url` - YouTube URL (watch, shorts, youtu.be 모두 지원)
|
|
|
|
|
|
|
|
|
|
**응답:**
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"videoId": "abc123",
|
|
|
|
|
"title": "영상 제목",
|
|
|
|
|
"channelId": "UCxxx",
|
|
|
|
|
"channelName": "채널명",
|
|
|
|
|
"date": "2026-01-19",
|
|
|
|
|
"time": "15:00:00",
|
|
|
|
|
"videoType": "video",
|
|
|
|
|
"videoUrl": "https://www.youtube.com/watch?v=abc123"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### POST /admin/youtube/schedule
|
|
|
|
|
YouTube 일정 저장
|
|
|
|
|
|
|
|
|
|
**Request Body:**
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"videoId": "abc123",
|
|
|
|
|
"title": "영상 제목",
|
|
|
|
|
"channelId": "UCxxx",
|
|
|
|
|
"channelName": "채널명",
|
|
|
|
|
"date": "2026-01-19",
|
|
|
|
|
"time": "15:00:00",
|
|
|
|
|
"videoType": "video"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
2026-01-19 12:57:06 +09:00
|
|
|
## 관리자 - X (인증 필요)
|
|
|
|
|
|
|
|
|
|
### GET /admin/x/post-info
|
|
|
|
|
X 게시글 정보 조회 (Nitter 스크래핑)
|
|
|
|
|
|
|
|
|
|
**Query Parameters:**
|
|
|
|
|
- `postId` - 게시글 ID (필수)
|
|
|
|
|
- `username` - 사용자명 (기본: realfromis_9)
|
|
|
|
|
|
|
|
|
|
**응답:**
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"postId": "1234567890",
|
|
|
|
|
"username": "realfromis_9",
|
|
|
|
|
"text": "게시글 전체 내용",
|
|
|
|
|
"title": "첫 문단 (자동 추출)",
|
|
|
|
|
"imageUrls": ["https://pbs.twimg.com/media/..."],
|
|
|
|
|
"date": "2026-01-19",
|
|
|
|
|
"time": "15:00:00",
|
|
|
|
|
"postUrl": "https://x.com/realfromis_9/status/1234567890",
|
|
|
|
|
"profile": {
|
|
|
|
|
"displayName": "프로미스나인 (fromis_9)",
|
|
|
|
|
"avatarUrl": "https://..."
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### POST /admin/x/schedule
|
|
|
|
|
X 일정 저장
|
|
|
|
|
|
|
|
|
|
**Request Body:**
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"postId": "1234567890",
|
|
|
|
|
"title": "게시글 제목",
|
|
|
|
|
"content": "게시글 내용",
|
|
|
|
|
"imageUrls": ["https://..."],
|
|
|
|
|
"date": "2026-01-19",
|
|
|
|
|
"time": "15:00:00"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
2026-01-18 18:54:27 +09:00
|
|
|
## 헬스 체크
|
|
|
|
|
|
|
|
|
|
### GET /health
|
|
|
|
|
서버 상태 확인
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## API 문서
|
|
|
|
|
|
|
|
|
|
### GET /docs
|
|
|
|
|
Scalar API Reference UI
|
|
|
|
|
|
|
|
|
|
### GET /docs/json
|
|
|
|
|
OpenAPI JSON 스펙
|