# News Engine Console - API 문서 ## 목차 1. [개요](#개요) 2. [인증](#인증) 3. [API 엔드포인트](#api-엔드포인트) - [Users API](#1-users-api) - [Keywords API](#2-keywords-api) - [Pipelines API](#3-pipelines-api) - [Applications API](#4-applications-api) - [Monitoring API](#5-monitoring-api) 4. [에러 코드](#에러-코드) 5. [예제 코드](#예제-코드) --- ## 개요 **Base URL**: `http://localhost:8101/api/v1` **Content-Type**: `application/json` **인증 방식**: JWT Bearer Token (OAuth2 Password Flow) **테스트 완료**: 37개 엔드포인트 모두 테스트 완료 (100% 성공률) --- ## 인증 ### OAuth2 Password Flow 모든 API 요청은 JWT 토큰을 통한 인증이 필요합니다. #### 로그인하여 토큰 받기 ```bash POST /api/v1/users/login Content-Type: application/x-www-form-urlencoded username=admin&password=admin123456 ``` **응답:** ```json { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer", "expires_in": 1800 } ``` #### 인증된 요청 보내기 모든 API 요청에 Authorization 헤더를 포함해야 합니다: ```bash Authorization: Bearer {access_token} ``` --- ## API 엔드포인트 ## 1. Users API 사용자 관리 및 인증을 위한 API입니다. ### 1.1 로그인 **Endpoint**: `POST /api/v1/users/login` **권한**: 공개 (인증 불필요) **Request Body** (application/x-www-form-urlencoded): ``` username=admin password=admin123456 ``` **Response** (200 OK): ```json { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer", "expires_in": 1800 } ``` **cURL 예제:** ```bash curl -X POST http://localhost:8101/api/v1/users/login \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'username=admin&password=admin123456' ``` --- ### 1.2 현재 사용자 정보 조회 **Endpoint**: `GET /api/v1/users/me` **권한**: 인증된 사용자 **Response** (200 OK): ```json { "_id": "507f1f77bcf86cd799439011", "username": "admin", "email": "admin@example.com", "full_name": "Administrator", "role": "admin", "disabled": false, "created_at": "2025-01-04T12:00:00Z", "last_login": "2025-01-04T14:30:00Z" } ``` **cURL 예제:** ```bash curl -X GET http://localhost:8101/api/v1/users/me \ -H 'Authorization: Bearer {token}' ``` --- ### 1.3 사용자 목록 조회 **Endpoint**: `GET /api/v1/users/` **권한**: 관리자(admin)만 가능 **Query Parameters**: - `role` (optional): 역할 필터 (admin/editor/viewer) - `disabled` (optional): 비활성화 상태 필터 (true/false) - `search` (optional): username, email, full_name에서 검색 **Response** (200 OK): ```json [ { "_id": "507f1f77bcf86cd799439011", "username": "admin", "email": "admin@example.com", "full_name": "Administrator", "role": "admin", "disabled": false, "created_at": "2025-01-04T12:00:00Z", "last_login": "2025-01-04T14:30:00Z" } ] ``` **cURL 예제:** ```bash # 모든 사용자 조회 curl -X GET http://localhost:8101/api/v1/users/ \ -H 'Authorization: Bearer {token}' # 관리자만 필터링 curl -X GET 'http://localhost:8101/api/v1/users/?role=admin' \ -H 'Authorization: Bearer {token}' # 검색 curl -X GET 'http://localhost:8101/api/v1/users/?search=john' \ -H 'Authorization: Bearer {token}' ``` --- ### 1.4 사용자 통계 **Endpoint**: `GET /api/v1/users/stats` **권한**: 관리자(admin)만 가능 **Response** (200 OK): ```json { "total": 10, "active": 8, "disabled": 2, "by_role": { "admin": 2, "editor": 5, "viewer": 3 } } ``` **cURL 예제:** ```bash curl -X GET http://localhost:8101/api/v1/users/stats \ -H 'Authorization: Bearer {token}' ``` --- ### 1.5 특정 사용자 조회 **Endpoint**: `GET /api/v1/users/{user_id}` **권한**: 관리자 또는 본인 **Response** (200 OK): ```json { "_id": "507f1f77bcf86cd799439011", "username": "john_doe", "email": "john@example.com", "full_name": "John Doe", "role": "editor", "disabled": false, "created_at": "2025-01-04T12:00:00Z", "last_login": "2025-01-04T14:30:00Z" } ``` **cURL 예제:** ```bash curl -X GET http://localhost:8101/api/v1/users/507f1f77bcf86cd799439011 \ -H 'Authorization: Bearer {token}' ``` --- ### 1.6 사용자 생성 **Endpoint**: `POST /api/v1/users/` **권한**: 관리자(admin)만 가능 **Request Body**: ```json { "username": "new_user", "email": "newuser@example.com", "password": "secure_password123", "full_name": "New User", "role": "editor" } ``` **Response** (201 Created): ```json { "_id": "507f1f77bcf86cd799439012", "username": "new_user", "email": "newuser@example.com", "full_name": "New User", "role": "editor", "disabled": false, "created_at": "2025-01-04T15:00:00Z", "last_login": null } ``` **cURL 예제:** ```bash curl -X POST http://localhost:8101/api/v1/users/ \ -H 'Authorization: Bearer {token}' \ -H 'Content-Type: application/json' \ -d '{ "username": "new_user", "email": "newuser@example.com", "password": "secure_password123", "full_name": "New User", "role": "editor" }' ``` --- ### 1.7 사용자 수정 **Endpoint**: `PUT /api/v1/users/{user_id}` **권한**: 관리자 또는 본인 (본인은 email, full_name만 수정 가능) **Request Body**: ```json { "email": "updated@example.com", "full_name": "Updated Name", "role": "admin", "disabled": false } ``` **Response** (200 OK): ```json { "_id": "507f1f77bcf86cd799439012", "username": "new_user", "email": "updated@example.com", "full_name": "Updated Name", "role": "admin", "disabled": false, "created_at": "2025-01-04T15:00:00Z", "last_login": null } ``` **cURL 예제:** ```bash curl -X PUT http://localhost:8101/api/v1/users/507f1f77bcf86cd799439012 \ -H 'Authorization: Bearer {token}' \ -H 'Content-Type: application/json' \ -d '{ "email": "updated@example.com", "full_name": "Updated Name" }' ``` --- ### 1.8 사용자 삭제 **Endpoint**: `DELETE /api/v1/users/{user_id}` **권한**: 관리자(admin)만 가능 (본인 삭제 불가) **Response** (204 No Content) **cURL 예제:** ```bash curl -X DELETE http://localhost:8101/api/v1/users/507f1f77bcf86cd799439012 \ -H 'Authorization: Bearer {token}' ``` --- ### 1.9 사용자 활성화/비활성화 토글 **Endpoint**: `POST /api/v1/users/{user_id}/toggle` **권한**: 관리자(admin)만 가능 (본인 토글 불가) **Response** (200 OK): ```json { "_id": "507f1f77bcf86cd799439012", "username": "new_user", "email": "updated@example.com", "full_name": "Updated Name", "role": "editor", "disabled": true, "created_at": "2025-01-04T15:00:00Z", "last_login": null } ``` **cURL 예제:** ```bash curl -X POST http://localhost:8101/api/v1/users/507f1f77bcf86cd799439012/toggle \ -H 'Authorization: Bearer {token}' ``` --- ### 1.10 비밀번호 변경 **Endpoint**: `POST /api/v1/users/change-password` **권한**: 인증된 사용자 (본인만) **Request Body**: ```json { "old_password": "current_password", "new_password": "new_secure_password123" } ``` **Response** (200 OK): ```json { "message": "Password changed successfully" } ``` **cURL 예제:** ```bash curl -X POST http://localhost:8101/api/v1/users/change-password \ -H 'Authorization: Bearer {token}' \ -H 'Content-Type: application/json' \ -d '{ "old_password": "current_password", "new_password": "new_secure_password123" }' ``` --- ## 2. Keywords API 키워드 관리를 위한 API입니다. ### 2.1 키워드 목록 조회 **Endpoint**: `GET /api/v1/keywords/` **권한**: 인증된 사용자 **Query Parameters**: - `category` (optional): 카테고리 필터 (people/topics/companies) - `status` (optional): 상태 필터 (active/inactive) - `search` (optional): 키워드 텍스트 검색 - `page` (default: 1): 페이지 번호 - `page_size` (default: 50, max: 100): 페이지 크기 - `sort_by` (default: "created_at"): 정렬 필드 - `sort_order` (default: -1): 정렬 순서 (1: 오름차순, -1: 내림차순) **Response** (200 OK): ```json { "keywords": [ { "_id": "507f1f77bcf86cd799439013", "keyword": "도널드 트럼프", "category": "people", "status": "active", "pipeline_type": "all", "priority": 8, "metadata": { "description": "Former US President", "aliases": ["Donald Trump", "Trump"] }, "created_at": "2025-01-04T12:00:00Z", "updated_at": "2025-01-04T12:00:00Z", "created_by": "admin" } ], "total": 100, "page": 1, "page_size": 50 } ``` **cURL 예제:** ```bash # 모든 키워드 조회 curl -X GET http://localhost:8101/api/v1/keywords/ \ -H 'Authorization: Bearer {token}' # 카테고리 필터링 curl -X GET 'http://localhost:8101/api/v1/keywords/?category=people&status=active' \ -H 'Authorization: Bearer {token}' # 페이지네이션 curl -X GET 'http://localhost:8101/api/v1/keywords/?page=2&page_size=20' \ -H 'Authorization: Bearer {token}' ``` --- ### 2.2 특정 키워드 조회 **Endpoint**: `GET /api/v1/keywords/{keyword_id}` **권한**: 인증된 사용자 **Response** (200 OK): ```json { "_id": "507f1f77bcf86cd799439013", "keyword": "도널드 트럼프", "category": "people", "status": "active", "pipeline_type": "all", "priority": 8, "metadata": { "description": "Former US President", "aliases": ["Donald Trump", "Trump"] }, "created_at": "2025-01-04T12:00:00Z", "updated_at": "2025-01-04T12:00:00Z", "created_by": "admin" } ``` **cURL 예제:** ```bash curl -X GET http://localhost:8101/api/v1/keywords/507f1f77bcf86cd799439013 \ -H 'Authorization: Bearer {token}' ``` --- ### 2.3 키워드 생성 **Endpoint**: `POST /api/v1/keywords/` **권한**: 인증된 사용자 **Request Body**: ```json { "keyword": "일론 머스크", "category": "people", "status": "active", "pipeline_type": "all", "priority": 9, "metadata": { "description": "CEO of Tesla and SpaceX", "aliases": ["Elon Musk"] } } ``` **Response** (201 Created): ```json { "_id": "507f1f77bcf86cd799439014", "keyword": "일론 머스크", "category": "people", "status": "active", "pipeline_type": "all", "priority": 9, "metadata": { "description": "CEO of Tesla and SpaceX", "aliases": ["Elon Musk"] }, "created_at": "2025-01-04T15:00:00Z", "updated_at": "2025-01-04T15:00:00Z", "created_by": "admin" } ``` **cURL 예제:** ```bash curl -X POST http://localhost:8101/api/v1/keywords/ \ -H 'Authorization: Bearer {token}' \ -H 'Content-Type: application/json' \ -d '{ "keyword": "일론 머스크", "category": "people", "status": "active", "pipeline_type": "all", "priority": 9, "metadata": { "description": "CEO of Tesla and SpaceX", "aliases": ["Elon Musk"] } }' ``` --- ### 2.4 키워드 수정 **Endpoint**: `PUT /api/v1/keywords/{keyword_id}` **권한**: 인증된 사용자 **Request Body**: ```json { "priority": 10, "status": "inactive", "metadata": { "description": "Updated description" } } ``` **Response** (200 OK): ```json { "_id": "507f1f77bcf86cd799439014", "keyword": "일론 머스크", "category": "people", "status": "inactive", "pipeline_type": "all", "priority": 10, "metadata": { "description": "Updated description" }, "created_at": "2025-01-04T15:00:00Z", "updated_at": "2025-01-04T15:30:00Z", "created_by": "admin" } ``` **cURL 예제:** ```bash curl -X PUT http://localhost:8101/api/v1/keywords/507f1f77bcf86cd799439014 \ -H 'Authorization: Bearer {token}' \ -H 'Content-Type: application/json' \ -d '{ "priority": 10, "status": "inactive" }' ``` --- ### 2.5 키워드 삭제 **Endpoint**: `DELETE /api/v1/keywords/{keyword_id}` **권한**: 인증된 사용자 **Response** (204 No Content) **cURL 예제:** ```bash curl -X DELETE http://localhost:8101/api/v1/keywords/507f1f77bcf86cd799439014 \ -H 'Authorization: Bearer {token}' ``` --- ### 2.6 키워드 상태 토글 **Endpoint**: `POST /api/v1/keywords/{keyword_id}/toggle` **권한**: 인증된 사용자 **설명**: 키워드 상태를 active ↔ inactive로 전환합니다. **Response** (200 OK): ```json { "_id": "507f1f77bcf86cd799439014", "keyword": "일론 머스크", "category": "people", "status": "active", "pipeline_type": "all", "priority": 10, "metadata": {}, "created_at": "2025-01-04T15:00:00Z", "updated_at": "2025-01-04T15:45:00Z", "created_by": "admin" } ``` **cURL 예제:** ```bash curl -X POST http://localhost:8101/api/v1/keywords/507f1f77bcf86cd799439014/toggle \ -H 'Authorization: Bearer {token}' ``` --- ### 2.7 키워드 통계 **Endpoint**: `GET /api/v1/keywords/{keyword_id}/stats` **권한**: 인증된 사용자 **Response** (200 OK): ```json { "keyword_id": "507f1f77bcf86cd799439014", "total_articles": 1523, "recent_articles": 45, "avg_daily_articles": 12.5, "last_collected": "2025-01-04T14:30:00Z", "trends": { "last_7_days": [10, 12, 15, 8, 14, 11, 13], "last_30_days_avg": 11.2 } } ``` **cURL 예제:** ```bash curl -X GET http://localhost:8101/api/v1/keywords/507f1f77bcf86cd799439014/stats \ -H 'Authorization: Bearer {token}' ``` --- ## 3. Pipelines API 파이프라인 관리 및 제어를 위한 API입니다. ### 3.1 파이프라인 목록 조회 **Endpoint**: `GET /api/v1/pipelines/` **권한**: 인증된 사용자 **Query Parameters**: - `type` (optional): 파이프라인 타입 필터 (rss_collector/translator/image_generator) - `status` (optional): 상태 필터 (running/stopped/error) **Response** (200 OK): ```json { "pipelines": [ { "_id": "507f1f77bcf86cd799439015", "name": "RSS Collector - Politics", "type": "rss_collector", "status": "running", "config": { "interval_minutes": 30, "max_articles": 100, "categories": ["politics"] }, "schedule": "*/30 * * * *", "stats": { "total_processed": 1523, "success_count": 1500, "error_count": 23, "last_run": "2025-01-04T14:30:00Z", "average_duration_seconds": 45.2 }, "last_run": "2025-01-04T14:30:00Z", "next_run": "2025-01-04T15:00:00Z", "created_at": "2025-01-01T00:00:00Z", "updated_at": "2025-01-04T14:30:00Z" } ], "total": 5 } ``` **cURL 예제:** ```bash # 모든 파이프라인 조회 curl -X GET http://localhost:8101/api/v1/pipelines/ \ -H 'Authorization: Bearer {token}' # 실행 중인 파이프라인만 조회 curl -X GET 'http://localhost:8101/api/v1/pipelines/?status=running' \ -H 'Authorization: Bearer {token}' ``` --- ### 3.2 특정 파이프라인 조회 **Endpoint**: `GET /api/v1/pipelines/{pipeline_id}` **권한**: 인증된 사용자 **Response** (200 OK): ```json { "_id": "507f1f77bcf86cd799439015", "name": "RSS Collector - Politics", "type": "rss_collector", "status": "running", "config": { "interval_minutes": 30, "max_articles": 100, "categories": ["politics"] }, "schedule": "*/30 * * * *", "stats": { "total_processed": 1523, "success_count": 1500, "error_count": 23, "last_run": "2025-01-04T14:30:00Z", "average_duration_seconds": 45.2 }, "last_run": "2025-01-04T14:30:00Z", "next_run": "2025-01-04T15:00:00Z", "created_at": "2025-01-01T00:00:00Z", "updated_at": "2025-01-04T14:30:00Z" } ``` **cURL 예제:** ```bash curl -X GET http://localhost:8101/api/v1/pipelines/507f1f77bcf86cd799439015 \ -H 'Authorization: Bearer {token}' ``` --- ### 3.3 파이프라인 생성 **Endpoint**: `POST /api/v1/pipelines/` **권한**: 인증된 사용자 **Request Body**: ```json { "name": "Translation Pipeline - Korean", "type": "translator", "status": "stopped", "config": { "source_language": "en", "target_language": "ko", "batch_size": 10 }, "schedule": "0 */2 * * *" } ``` **Response** (201 Created): ```json { "_id": "507f1f77bcf86cd799439016", "name": "Translation Pipeline - Korean", "type": "translator", "status": "stopped", "config": { "source_language": "en", "target_language": "ko", "batch_size": 10 }, "schedule": "0 */2 * * *", "stats": { "total_processed": 0, "success_count": 0, "error_count": 0, "last_run": null, "average_duration_seconds": null }, "last_run": null, "next_run": null, "created_at": "2025-01-04T15:00:00Z", "updated_at": "2025-01-04T15:00:00Z" } ``` **cURL 예제:** ```bash curl -X POST http://localhost:8101/api/v1/pipelines/ \ -H 'Authorization: Bearer {token}' \ -H 'Content-Type: application/json' \ -d '{ "name": "Translation Pipeline - Korean", "type": "translator", "status": "stopped", "config": { "source_language": "en", "target_language": "ko", "batch_size": 10 }, "schedule": "0 */2 * * *" }' ``` --- ### 3.4 파이프라인 수정 **Endpoint**: `PUT /api/v1/pipelines/{pipeline_id}` **권한**: 인증된 사용자 **Request Body**: ```json { "name": "Updated Pipeline Name", "config": { "source_language": "en", "target_language": "ko", "batch_size": 20 } } ``` **Response** (200 OK): ```json { "_id": "507f1f77bcf86cd799439016", "name": "Updated Pipeline Name", "type": "translator", "status": "stopped", "config": { "source_language": "en", "target_language": "ko", "batch_size": 20 }, "schedule": "0 */2 * * *", "stats": { "total_processed": 0, "success_count": 0, "error_count": 0, "last_run": null, "average_duration_seconds": null }, "last_run": null, "next_run": null, "created_at": "2025-01-04T15:00:00Z", "updated_at": "2025-01-04T15:30:00Z" } ``` **cURL 예제:** ```bash curl -X PUT http://localhost:8101/api/v1/pipelines/507f1f77bcf86cd799439016 \ -H 'Authorization: Bearer {token}' \ -H 'Content-Type: application/json' \ -d '{ "name": "Updated Pipeline Name", "config": { "batch_size": 20 } }' ``` --- ### 3.5 파이프라인 삭제 **Endpoint**: `DELETE /api/v1/pipelines/{pipeline_id}` **권한**: 인증된 사용자 **Response** (204 No Content) **cURL 예제:** ```bash curl -X DELETE http://localhost:8101/api/v1/pipelines/507f1f77bcf86cd799439016 \ -H 'Authorization: Bearer {token}' ``` --- ### 3.6 파이프라인 통계 조회 **Endpoint**: `GET /api/v1/pipelines/{pipeline_id}/stats` **권한**: 인증된 사용자 **Response** (200 OK): ```json { "total_processed": 1523, "success_count": 1500, "error_count": 23, "last_run": "2025-01-04T14:30:00Z", "average_duration_seconds": 45.2 } ``` **cURL 예제:** ```bash curl -X GET http://localhost:8101/api/v1/pipelines/507f1f77bcf86cd799439015/stats \ -H 'Authorization: Bearer {token}' ``` --- ### 3.7 파이프라인 시작 **Endpoint**: `POST /api/v1/pipelines/{pipeline_id}/start` **권한**: 인증된 사용자 **설명**: 중지된 파이프라인을 시작합니다. **Response** (200 OK): ```json { "_id": "507f1f77bcf86cd799439015", "name": "RSS Collector - Politics", "type": "rss_collector", "status": "running", "config": {...}, "schedule": "*/30 * * * *", "stats": {...}, "last_run": "2025-01-04T14:30:00Z", "next_run": "2025-01-04T15:00:00Z", "created_at": "2025-01-01T00:00:00Z", "updated_at": "2025-01-04T15:00:00Z" } ``` **cURL 예제:** ```bash curl -X POST http://localhost:8101/api/v1/pipelines/507f1f77bcf86cd799439015/start \ -H 'Authorization: Bearer {token}' ``` --- ### 3.8 파이프라인 중지 **Endpoint**: `POST /api/v1/pipelines/{pipeline_id}/stop` **권한**: 인증된 사용자 **설명**: 실행 중인 파이프라인을 중지합니다. **Response** (200 OK): ```json { "_id": "507f1f77bcf86cd799439015", "name": "RSS Collector - Politics", "type": "rss_collector", "status": "stopped", "config": {...}, "schedule": "*/30 * * * *", "stats": {...}, "last_run": "2025-01-04T14:30:00Z", "next_run": null, "created_at": "2025-01-01T00:00:00Z", "updated_at": "2025-01-04T15:30:00Z" } ``` **cURL 예제:** ```bash curl -X POST http://localhost:8101/api/v1/pipelines/507f1f77bcf86cd799439015/stop \ -H 'Authorization: Bearer {token}' ``` --- ### 3.9 파이프라인 재시작 **Endpoint**: `POST /api/v1/pipelines/{pipeline_id}/restart` **권한**: 인증된 사용자 **설명**: 파이프라인을 중지 후 다시 시작합니다. **Response** (200 OK): ```json { "_id": "507f1f77bcf86cd799439015", "name": "RSS Collector - Politics", "type": "rss_collector", "status": "running", "config": {...}, "schedule": "*/30 * * * *", "stats": {...}, "last_run": "2025-01-04T15:30:00Z", "next_run": "2025-01-04T16:00:00Z", "created_at": "2025-01-01T00:00:00Z", "updated_at": "2025-01-04T15:30:00Z" } ``` **cURL 예제:** ```bash curl -X POST http://localhost:8101/api/v1/pipelines/507f1f77bcf86cd799439015/restart \ -H 'Authorization: Bearer {token}' ``` --- ### 3.10 파이프라인 로그 조회 **Endpoint**: `GET /api/v1/pipelines/{pipeline_id}/logs` **권한**: 인증된 사용자 **Query Parameters**: - `limit` (default: 100, max: 1000): 최대 로그 수 - `level` (optional): 로그 레벨 필터 (INFO/WARNING/ERROR) **Response** (200 OK): ```json [ { "timestamp": "2025-01-04T15:30:00Z", "level": "INFO", "message": "Pipeline started successfully", "pipeline_id": "507f1f77bcf86cd799439015" }, { "timestamp": "2025-01-04T15:30:15Z", "level": "INFO", "message": "Processed 50 articles", "pipeline_id": "507f1f77bcf86cd799439015" }, { "timestamp": "2025-01-04T15:30:20Z", "level": "ERROR", "message": "Failed to fetch article: Connection timeout", "pipeline_id": "507f1f77bcf86cd799439015" } ] ``` **cURL 예제:** ```bash # 최근 100개 로그 curl -X GET http://localhost:8101/api/v1/pipelines/507f1f77bcf86cd799439015/logs \ -H 'Authorization: Bearer {token}' # 에러 로그만 조회 curl -X GET 'http://localhost:8101/api/v1/pipelines/507f1f77bcf86cd799439015/logs?level=ERROR&limit=50' \ -H 'Authorization: Bearer {token}' ``` --- ### 3.11 파이프라인 설정 수정 **Endpoint**: `PUT /api/v1/pipelines/{pipeline_id}/config` **권한**: 인증된 사용자 **Request Body**: ```json { "interval_minutes": 15, "max_articles": 200 } ``` **Response** (200 OK): ```json { "_id": "507f1f77bcf86cd799439015", "name": "RSS Collector - Politics", "type": "rss_collector", "status": "running", "config": { "interval_minutes": 15, "max_articles": 200, "categories": ["politics"] }, "schedule": "*/30 * * * *", "stats": {...}, "last_run": "2025-01-04T15:30:00Z", "next_run": "2025-01-04T16:00:00Z", "created_at": "2025-01-01T00:00:00Z", "updated_at": "2025-01-04T15:45:00Z" } ``` **cURL 예제:** ```bash curl -X PUT http://localhost:8101/api/v1/pipelines/507f1f77bcf86cd799439015/config \ -H 'Authorization: Bearer {token}' \ -H 'Content-Type: application/json' \ -d '{ "interval_minutes": 15, "max_articles": 200 }' ``` --- ## 4. Applications API OAuth2 애플리케이션 관리를 위한 API입니다. ### 4.1 애플리케이션 목록 조회 **Endpoint**: `GET /api/v1/applications/` **권한**: 인증된 사용자 (관리자는 모든 앱, 일반 사용자는 자신의 앱만) **Response** (200 OK): ```json [ { "_id": "507f1f77bcf86cd799439017", "name": "News Frontend App", "client_id": "app_RssjY8eNbTYv5SBHoHhlbQ", "redirect_uris": [ "http://localhost:3000/auth/callback", "https://news.example.com/auth/callback" ], "grant_types": ["authorization_code", "refresh_token"], "scopes": ["read", "write"], "owner_id": "507f1f77bcf86cd799439011", "created_at": "2025-01-04T10:00:00Z", "updated_at": "2025-01-04T10:00:00Z" } ] ``` **cURL 예제:** ```bash curl -X GET http://localhost:8101/api/v1/applications/ \ -H 'Authorization: Bearer {token}' ``` --- ### 4.2 애플리케이션 통계 **Endpoint**: `GET /api/v1/applications/stats` **권한**: 관리자(admin)만 가능 **Response** (200 OK): ```json { "total": 15, "by_owner": { "507f1f77bcf86cd799439011": 5, "507f1f77bcf86cd799439012": 3, "507f1f77bcf86cd799439013": 7 }, "by_grant_type": { "authorization_code": 10, "client_credentials": 5 } } ``` **cURL 예제:** ```bash curl -X GET http://localhost:8101/api/v1/applications/stats \ -H 'Authorization: Bearer {token}' ``` --- ### 4.3 특정 애플리케이션 조회 **Endpoint**: `GET /api/v1/applications/{app_id}` **권한**: 관리자 또는 앱 소유자 **Response** (200 OK): ```json { "_id": "507f1f77bcf86cd799439017", "name": "News Frontend App", "client_id": "app_RssjY8eNbTYv5SBHoHhlbQ", "redirect_uris": [ "http://localhost:3000/auth/callback" ], "grant_types": ["authorization_code", "refresh_token"], "scopes": ["read", "write"], "owner_id": "507f1f77bcf86cd799439011", "created_at": "2025-01-04T10:00:00Z", "updated_at": "2025-01-04T10:00:00Z" } ``` **cURL 예제:** ```bash curl -X GET http://localhost:8101/api/v1/applications/507f1f77bcf86cd799439017 \ -H 'Authorization: Bearer {token}' ``` --- ### 4.4 애플리케이션 생성 **Endpoint**: `POST /api/v1/applications/` **권한**: 인증된 사용자 **중요**: client_secret은 생성 시에만 반환되므로 반드시 저장하세요! **Request Body**: ```json { "name": "Mobile App", "redirect_uris": [ "myapp://auth/callback" ], "grant_types": ["authorization_code", "refresh_token"], "scopes": ["read", "write"] } ``` **Response** (201 Created): ```json { "_id": "507f1f77bcf86cd799439018", "name": "Mobile App", "client_id": "app_AbC123XyZ456", "client_secret": "secret_DEF789uvw012", "redirect_uris": [ "myapp://auth/callback" ], "grant_types": ["authorization_code", "refresh_token"], "scopes": ["read", "write"], "owner_id": "507f1f77bcf86cd799439011", "created_at": "2025-01-04T16:00:00Z", "updated_at": "2025-01-04T16:00:00Z" } ``` **cURL 예제:** ```bash curl -X POST http://localhost:8101/api/v1/applications/ \ -H 'Authorization: Bearer {token}' \ -H 'Content-Type: application/json' \ -d '{ "name": "Mobile App", "redirect_uris": ["myapp://auth/callback"], "grant_types": ["authorization_code", "refresh_token"], "scopes": ["read", "write"] }' ``` --- ### 4.5 애플리케이션 수정 **Endpoint**: `PUT /api/v1/applications/{app_id}` **권한**: 관리자 또는 앱 소유자 **Request Body**: ```json { "name": "Updated Mobile App", "redirect_uris": [ "myapp://auth/callback", "myapp://oauth/callback" ] } ``` **Response** (200 OK): ```json { "_id": "507f1f77bcf86cd799439018", "name": "Updated Mobile App", "client_id": "app_AbC123XyZ456", "redirect_uris": [ "myapp://auth/callback", "myapp://oauth/callback" ], "grant_types": ["authorization_code", "refresh_token"], "scopes": ["read", "write"], "owner_id": "507f1f77bcf86cd799439011", "created_at": "2025-01-04T16:00:00Z", "updated_at": "2025-01-04T16:30:00Z" } ``` **cURL 예제:** ```bash curl -X PUT http://localhost:8101/api/v1/applications/507f1f77bcf86cd799439018 \ -H 'Authorization: Bearer {token}' \ -H 'Content-Type: application/json' \ -d '{ "name": "Updated Mobile App", "redirect_uris": ["myapp://auth/callback", "myapp://oauth/callback"] }' ``` --- ### 4.6 애플리케이션 삭제 **Endpoint**: `DELETE /api/v1/applications/{app_id}` **권한**: 관리자 또는 앱 소유자 **Response** (204 No Content) **cURL 예제:** ```bash curl -X DELETE http://localhost:8101/api/v1/applications/507f1f77bcf86cd799439018 \ -H 'Authorization: Bearer {token}' ``` --- ### 4.7 클라이언트 시크릿 재생성 **Endpoint**: `POST /api/v1/applications/{app_id}/regenerate-secret` **권한**: 관리자 또는 앱 소유자 **중요**: 새 client_secret은 재생성 시에만 반환되므로 반드시 저장하세요! **Response** (200 OK): ```json { "_id": "507f1f77bcf86cd799439018", "name": "Mobile App", "client_id": "app_AbC123XyZ456", "client_secret": "secret_NEW789xyz012", "redirect_uris": [ "myapp://auth/callback" ], "grant_types": ["authorization_code", "refresh_token"], "scopes": ["read", "write"], "owner_id": "507f1f77bcf86cd799439011", "created_at": "2025-01-04T16:00:00Z", "updated_at": "2025-01-04T17:00:00Z" } ``` **cURL 예제:** ```bash curl -X POST http://localhost:8101/api/v1/applications/507f1f77bcf86cd799439018/regenerate-secret \ -H 'Authorization: Bearer {token}' ``` --- ## 5. Monitoring API 시스템 모니터링 및 통계를 위한 API입니다. ### 5.1 시스템 상태 조회 **Endpoint**: `GET /api/v1/monitoring/health` **권한**: 인증된 사용자 **Response** (200 OK): ```json { "status": "healthy", "timestamp": "2025-01-04T17:00:00Z", "components": { "mongodb": { "status": "up", "response_time_ms": 5 }, "redis": { "status": "up", "response_time_ms": 2 }, "pipelines": { "status": "healthy", "running": 3, "stopped": 2, "error": 0 } } } ``` **cURL 예제:** ```bash curl -X GET http://localhost:8101/api/v1/monitoring/health \ -H 'Authorization: Bearer {token}' ``` --- ### 5.2 시스템 메트릭 조회 **Endpoint**: `GET /api/v1/monitoring/metrics` **권한**: 인증된 사용자 **Response** (200 OK): ```json { "timestamp": "2025-01-04T17:00:00Z", "keywords": { "total": 150, "active": 120, "inactive": 30, "by_category": { "people": 60, "topics": 50, "companies": 40 } }, "pipelines": { "total": 5, "running": 3, "stopped": 2, "error": 0 }, "users": { "total": 25, "active": 20, "disabled": 5, "by_role": { "admin": 3, "editor": 12, "viewer": 10 } }, "applications": { "total": 15 } } ``` **cURL 예제:** ```bash curl -X GET http://localhost:8101/api/v1/monitoring/metrics \ -H 'Authorization: Bearer {token}' ``` --- ### 5.3 활동 로그 조회 **Endpoint**: `GET /api/v1/monitoring/logs` **권한**: 인증된 사용자 **Query Parameters**: - `limit` (default: 100, max: 1000): 최대 로그 수 - `level` (optional): 로그 레벨 필터 (INFO/WARNING/ERROR) - `start_date` (optional): 시작 날짜 (ISO 8601 형식) - `end_date` (optional): 종료 날짜 (ISO 8601 형식) **Response** (200 OK): ```json { "logs": [ { "timestamp": "2025-01-04T17:00:00Z", "level": "INFO", "message": "User admin logged in", "source": "auth", "user_id": "507f1f77bcf86cd799439011" }, { "timestamp": "2025-01-04T16:55:00Z", "level": "WARNING", "message": "Pipeline RSS Collector - Politics slowing down", "source": "pipeline", "pipeline_id": "507f1f77bcf86cd799439015" } ], "total": 2 } ``` **cURL 예제:** ```bash # 최근 100개 로그 curl -X GET http://localhost:8101/api/v1/monitoring/logs \ -H 'Authorization: Bearer {token}' # 에러 로그만 조회 curl -X GET 'http://localhost:8101/api/v1/monitoring/logs?level=ERROR&limit=50' \ -H 'Authorization: Bearer {token}' # 날짜 범위로 필터링 curl -X GET 'http://localhost:8101/api/v1/monitoring/logs?start_date=2025-01-04T00:00:00Z&end_date=2025-01-04T23:59:59Z' \ -H 'Authorization: Bearer {token}' ``` --- ### 5.4 데이터베이스 통계 **Endpoint**: `GET /api/v1/monitoring/database/stats` **권한**: 관리자(admin)만 가능 **Response** (200 OK): ```json { "database": "news_engine_console_db", "collections": 5, "data_size": 15728640, "storage_size": 20971520, "indexes": 12, "index_size": 262144, "avg_obj_size": 512, "objects": 30720 } ``` **cURL 예제:** ```bash curl -X GET http://localhost:8101/api/v1/monitoring/database/stats \ -H 'Authorization: Bearer {token}' ``` --- ### 5.5 컬렉션 통계 **Endpoint**: `GET /api/v1/monitoring/database/collections` **권한**: 관리자(admin)만 가능 **Response** (200 OK): ```json { "collections": [ { "name": "users", "count": 25, "size": 51200, "avg_obj_size": 2048, "storage_size": 102400, "indexes": 3, "index_size": 32768 }, { "name": "keywords", "count": 150, "size": 307200, "avg_obj_size": 2048, "storage_size": 409600, "indexes": 4, "index_size": 65536 } ], "total": 5 } ``` **cURL 예제:** ```bash curl -X GET http://localhost:8101/api/v1/monitoring/database/collections \ -H 'Authorization: Bearer {token}' ``` --- ### 5.6 파이프라인 성능 조회 **Endpoint**: `GET /api/v1/monitoring/pipelines/performance` **권한**: 인증된 사용자 **Query Parameters**: - `hours` (default: 24, min: 1, max: 168): 조회할 시간 범위 **Response** (200 OK): ```json { "period": "24 hours", "pipelines": [ { "pipeline_id": "507f1f77bcf86cd799439015", "name": "RSS Collector - Politics", "total_runs": 48, "successful_runs": 47, "failed_runs": 1, "success_rate": 97.9, "avg_duration_seconds": 45.2, "total_processed": 2400, "errors": [ { "timestamp": "2025-01-04T15:30:20Z", "message": "Connection timeout" } ] } ], "total_pipelines": 5 } ``` **cURL 예제:** ```bash # 최근 24시간 curl -X GET http://localhost:8101/api/v1/monitoring/pipelines/performance \ -H 'Authorization: Bearer {token}' # 최근 7일 curl -X GET 'http://localhost:8101/api/v1/monitoring/pipelines/performance?hours=168' \ -H 'Authorization: Bearer {token}' ``` --- ### 5.7 에러 요약 **Endpoint**: `GET /api/v1/monitoring/errors/summary` **권한**: 인증된 사용자 **Query Parameters**: - `hours` (default: 24, min: 1, max: 168): 조회할 시간 범위 **Response** (200 OK): ```json { "period": "24 hours", "total_errors": 15, "by_source": { "pipeline": 10, "auth": 3, "database": 2 }, "by_level": { "ERROR": 12, "CRITICAL": 3 }, "recent_errors": [ { "timestamp": "2025-01-04T17:00:00Z", "level": "ERROR", "message": "Failed to fetch RSS feed: Connection timeout", "source": "pipeline", "pipeline_id": "507f1f77bcf86cd799439015" }, { "timestamp": "2025-01-04T16:45:00Z", "level": "CRITICAL", "message": "MongoDB connection lost", "source": "database" } ] } ``` **cURL 예제:** ```bash # 최근 24시간 에러 curl -X GET http://localhost:8101/api/v1/monitoring/errors/summary \ -H 'Authorization: Bearer {token}' # 최근 48시간 에러 curl -X GET 'http://localhost:8101/api/v1/monitoring/errors/summary?hours=48' \ -H 'Authorization: Bearer {token}' ``` --- ## 에러 코드 ### HTTP 상태 코드 | 코드 | 의미 | 설명 | |------|------|------| | 200 | OK | 요청 성공 | | 201 | Created | 리소스 생성 성공 | | 204 | No Content | 요청 성공, 응답 본문 없음 (주로 DELETE) | | 400 | Bad Request | 잘못된 요청 (유효성 검증 실패) | | 401 | Unauthorized | 인증 실패 (토큰 없음/만료/잘못됨) | | 403 | Forbidden | 권한 없음 (인증은 되었으나 권한 부족) | | 404 | Not Found | 리소스를 찾을 수 없음 | | 500 | Internal Server Error | 서버 내부 오류 | ### 에러 응답 형식 모든 에러는 다음 형식으로 반환됩니다: ```json { "detail": "Error message describing what went wrong" } ``` ### 일반적인 에러 예제 #### 1. 인증 실패 (401) ```json { "detail": "Incorrect username or password" } ``` #### 2. 권한 부족 (403) ```json { "detail": "Only admins can list users" } ``` #### 3. 리소스 없음 (404) ```json { "detail": "User with ID 507f1f77bcf86cd799439011 not found" } ``` #### 4. 유효성 검증 실패 (400) ```json { "detail": "Username already exists" } ``` #### 5. 토큰 만료 (401) ```json { "detail": "Could not validate credentials" } ``` --- ## 예제 코드 ### Python 예제 ```python import requests import json # Base URL BASE_URL = "http://localhost:8101/api/v1" # 1. 로그인하여 토큰 받기 def login(username, password): response = requests.post( f"{BASE_URL}/users/login", data={"username": username, "password": password}, headers={"Content-Type": "application/x-www-form-urlencoded"} ) response.raise_for_status() return response.json()["access_token"] # 2. 헤더에 토큰 추가 def get_headers(token): return { "Authorization": f"Bearer {token}", "Content-Type": "application/json" } # 3. 사용 예제 def main(): # 로그인 token = login("admin", "admin123456") headers = get_headers(token) # 현재 사용자 정보 조회 response = requests.get(f"{BASE_URL}/users/me", headers=headers) print("Current user:", response.json()) # 키워드 목록 조회 response = requests.get( f"{BASE_URL}/keywords/", headers=headers, params={"category": "people", "page_size": 10} ) print("Keywords:", response.json()) # 키워드 생성 new_keyword = { "keyword": "테스트 키워드", "category": "topics", "status": "active", "priority": 7 } response = requests.post( f"{BASE_URL}/keywords/", headers=headers, json=new_keyword ) print("Created keyword:", response.json()) # 파이프라인 시작 pipeline_id = "507f1f77bcf86cd799439015" response = requests.post( f"{BASE_URL}/pipelines/{pipeline_id}/start", headers=headers ) print("Pipeline started:", response.json()) if __name__ == "__main__": main() ``` ### JavaScript (Node.js) 예제 ```javascript const axios = require('axios'); const BASE_URL = 'http://localhost:8101/api/v1'; // 1. 로그인하여 토큰 받기 async function login(username, password) { const response = await axios.post(`${BASE_URL}/users/login`, new URLSearchParams({ username, password }), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } ); return response.data.access_token; } // 2. API 클라이언트 생성 function createClient(token) { return axios.create({ baseURL: BASE_URL, headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }); } // 3. 사용 예제 async function main() { try { // 로그인 const token = await login('admin', 'admin123456'); const client = createClient(token); // 현재 사용자 정보 조회 const userResponse = await client.get('/users/me'); console.log('Current user:', userResponse.data); // 키워드 목록 조회 const keywordsResponse = await client.get('/keywords/', { params: { category: 'people', page_size: 10 } }); console.log('Keywords:', keywordsResponse.data); // 키워드 생성 const newKeyword = { keyword: '테스트 키워드', category: 'topics', status: 'active', priority: 7 }; const createResponse = await client.post('/keywords/', newKeyword); console.log('Created keyword:', createResponse.data); // 파이프라인 시작 const pipelineId = '507f1f77bcf86cd799439015'; const startResponse = await client.post(`/pipelines/${pipelineId}/start`); console.log('Pipeline started:', startResponse.data); } catch (error) { console.error('Error:', error.response?.data || error.message); } } main(); ``` ### JavaScript (Browser/Fetch) 예제 ```javascript const BASE_URL = 'http://localhost:8101/api/v1'; // 1. 로그인하여 토큰 받기 async function login(username, password) { const response = await fetch(`${BASE_URL}/users/login`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ username, password }) }); if (!response.ok) { throw new Error(`Login failed: ${response.statusText}`); } const data = await response.json(); return data.access_token; } // 2. 인증된 요청 함수 async function authenticatedRequest(url, options = {}, token) { const response = await fetch(url, { ...options, headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', ...options.headers, } }); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || response.statusText); } // 204 No Content인 경우 빈 응답 if (response.status === 204) { return null; } return response.json(); } // 3. 사용 예제 async function main() { try { // 로그인 const token = await login('admin', 'admin123456'); console.log('Logged in successfully'); // 현재 사용자 정보 조회 const user = await authenticatedRequest( `${BASE_URL}/users/me`, { method: 'GET' }, token ); console.log('Current user:', user); // 키워드 목록 조회 const keywords = await authenticatedRequest( `${BASE_URL}/keywords/?category=people&page_size=10`, { method: 'GET' }, token ); console.log('Keywords:', keywords); // 키워드 생성 const newKeyword = { keyword: '테스트 키워드', category: 'topics', status: 'active', priority: 7 }; const created = await authenticatedRequest( `${BASE_URL}/keywords/`, { method: 'POST', body: JSON.stringify(newKeyword) }, token ); console.log('Created keyword:', created); } catch (error) { console.error('Error:', error.message); } } // 브라우저에서 실행 main(); ``` --- ## 부록: 권한 요약표 | 엔드포인트 | 필요 권한 | 비고 | |-----------|---------|------| | POST /users/login | 공개 | 인증 불필요 | | GET /users/me | 인증됨 | 본인 정보만 | | GET /users/ | 관리자 | 전체 사용자 목록 | | GET /users/stats | 관리자 | 통계 조회 | | GET /users/{id} | 관리자 또는 본인 | | | POST /users/ | 관리자 | 사용자 생성 | | PUT /users/{id} | 관리자 또는 본인 | 본인은 제한적 수정 | | DELETE /users/{id} | 관리자 | 본인 삭제 불가 | | POST /users/{id}/toggle | 관리자 | 본인 토글 불가 | | POST /users/change-password | 인증됨 | 본인만 | | GET /keywords/* | 인증됨 | | | POST /keywords/ | 인증됨 | | | PUT /keywords/{id} | 인증됨 | | | DELETE /keywords/{id} | 인증됨 | | | GET /pipelines/* | 인증됨 | | | POST /pipelines/ | 인증됨 | | | PUT /pipelines/{id} | 인증됨 | | | DELETE /pipelines/{id} | 인증됨 | | | POST /pipelines/{id}/start | 인증됨 | | | POST /pipelines/{id}/stop | 인증됨 | | | POST /pipelines/{id}/restart | 인증됨 | | | GET /applications/ | 인증됨 | 관리자는 모두, 일반은 본인만 | | GET /applications/stats | 관리자 | | | GET /applications/{id} | 관리자 또는 소유자 | | | POST /applications/ | 인증됨 | | | PUT /applications/{id} | 관리자 또는 소유자 | | | DELETE /applications/{id} | 관리자 또는 소유자 | | | POST /applications/{id}/regenerate-secret | 관리자 또는 소유자 | | | GET /monitoring/health | 인증됨 | | | GET /monitoring/metrics | 인증됨 | | | GET /monitoring/logs | 인증됨 | | | GET /monitoring/database/stats | 관리자 | | | GET /monitoring/database/collections | 관리자 | | | GET /monitoring/pipelines/performance | 인증됨 | | | GET /monitoring/errors/summary | 인증됨 | | --- ## 변경 이력 | 버전 | 날짜 | 변경 내용 | |------|------|---------| | 1.0.0 | 2025-01-04 | 초기 버전 (37개 엔드포인트) | --- **문서 생성일**: 2025-01-04 **API 버전**: v1 **테스트 상태**: 100% 완료 (37/37 엔드포인트) **서버 포트**: 8101