# API λ¬Έμ„œ (API.md) ## πŸš€ API κ°œμš” Todo-Project REST APIλŠ” κ°„κ²°ν•˜κ³  직관적인 할일 관리 κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€. ### κΈ°λ³Έ 정보 - **Base URL**: `http://localhost:9000/api` - **인증 방식**: JWT Bearer Token - **응닡 ν˜•μ‹**: JSON - **API 버전**: v1 ### 포트 μ„€μ • - **Frontend**: http://localhost:4000 - **Backend API**: http://localhost:9000 - **Database**: localhost:5434 ## πŸ” 인증 ### 둜그인 ```http POST /api/auth/login Content-Type: application/json { "email": "user@example.com", "password": "password123", "remember_me": false } ``` **응닡:** ```json { "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...", "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...", "token_type": "bearer", "expires_in": 1800 } ``` ### κΈ°κΈ° 등둝 (개인용 μ΅œμ ν™”) ```http POST /api/auth/register-device Content-Type: application/json Authorization: Bearer {access_token} { "device_name": "λ‚΄ iPhone", "fingerprint": "abc123def456", "platform": "mobile" } ``` **응닡:** ```json { "device_token": "long-term-device-token-here", "expires_at": "2024-02-15T10:30:00Z", "device_id": "device-uuid" } ``` ### κΈ°κΈ° 토큰 둜그인 ```http POST /api/auth/device-login Content-Type: application/json { "device_token": "long-term-device-token-here" } ``` ## πŸ“‹ 할일 관리 ### 할일 λͺ©λ‘ 쑰회 ```http GET /api/todos?status=active&limit=50&offset=0 Authorization: Bearer {access_token} ``` **쿼리 νŒŒλΌλ―Έν„°:** - `status`: `draft`, `scheduled`, `active`, `completed`, `delayed` - `limit`: νŽ˜μ΄μ§€λ‹Ή ν•­λͺ© 수 (κΈ°λ³Έ: 50) - `offset`: μ‹œμž‘ μœ„μΉ˜ (κΈ°λ³Έ: 0) **응닡:** ```json { "todos": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "user_id": "550e8400-e29b-41d4-a716-446655440001", "content": "ν”„λ‘œμ νŠΈ κΈ°νšμ„œ μž‘μ„±", "status": "active", "created_at": "2024-01-15T09:00:00Z", "start_date": "2024-01-15T10:00:00Z", "estimated_minutes": 120, "completed_at": null, "delayed_until": null, "parent_id": null, "split_order": null, "comment_count": 2 } ], "total": 1, "has_more": false } ``` ### 할일 생성 ```http POST /api/todos Content-Type: application/json Authorization: Bearer {access_token} { "content": "μƒˆλ‘œμš΄ 할일 λ‚΄μš©" } ``` **응닡:** ```json { "id": "550e8400-e29b-41d4-a716-446655440002", "user_id": "550e8400-e29b-41d4-a716-446655440001", "content": "μƒˆλ‘œμš΄ 할일 λ‚΄μš©", "status": "draft", "created_at": "2024-01-15T09:30:00Z", "start_date": null, "estimated_minutes": null, "completed_at": null, "delayed_until": null, "parent_id": null, "split_order": null, "comment_count": 0 } ``` ### 할일 일정 μ„€μ • ```http POST /api/todos/{todo_id}/schedule Content-Type: application/json Authorization: Bearer {access_token} { "start_date": "2024-01-16T14:00:00Z", "estimated_minutes": 90 } ``` **응닡:** μ—…λ°μ΄νŠΈλœ 할일 객체 ### 할일 μ™„λ£Œ 처리 ```http PUT /api/todos/{todo_id}/complete Authorization: Bearer {access_token} ``` **응닡:** μ™„λ£Œλœ 할일 객체 (status: "completed", completed_at 섀정됨) ### 할일 μ§€μ—° 처리 ```http PUT /api/todos/{todo_id}/delay Content-Type: application/json Authorization: Bearer {access_token} { "delayed_until": "2024-01-17T10:00:00Z" } ``` ### 할일 λΆ„ν•  ```http POST /api/todos/{todo_id}/split Content-Type: application/json Authorization: Bearer {access_token} { "subtasks": [ "1단계: μš”κ΅¬μ‚¬ν•­ 뢄석", "2단계: 섀계 λ¬Έμ„œ μž‘μ„±", "3단계: κ²€ν†  및 μˆ˜μ •" ], "estimated_minutes_per_task": [30, 60, 30] } ``` **응닡:** μƒμ„±λœ ν•˜μœ„ ν• μΌλ“€μ˜ λ°°μ—΄ ### 할일 상세 쑰회 (λŒ“κΈ€ 포함) ```http GET /api/todos/{todo_id} Authorization: Bearer {access_token} ``` **응닡:** ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "user_id": "550e8400-e29b-41d4-a716-446655440001", "content": "ν”„λ‘œμ νŠΈ κΈ°νšμ„œ μž‘μ„±", "status": "active", "created_at": "2024-01-15T09:00:00Z", "start_date": "2024-01-15T10:00:00Z", "estimated_minutes": 120, "completed_at": null, "delayed_until": null, "parent_id": null, "split_order": null, "comment_count": 2, "comments": [ { "id": "550e8400-e29b-41d4-a716-446655440003", "todo_item_id": "550e8400-e29b-41d4-a716-446655440000", "user_id": "550e8400-e29b-41d4-a716-446655440001", "content": "μ§„ν–‰ 상황 λ©”λͺ¨", "created_at": "2024-01-15T11:00:00Z", "updated_at": "2024-01-15T11:00:00Z" } ] } ``` ## πŸ’¬ λŒ“κΈ€/λ©”λͺ¨ 관리 ### λŒ“κΈ€ μΆ”κ°€ ```http POST /api/todos/{todo_id}/comments Content-Type: application/json Authorization: Bearer {access_token} { "content": "μ§„ν–‰ 상황 μ—…λ°μ΄νŠΈ" } ``` ### λŒ“κΈ€ λͺ©λ‘ 쑰회 ```http GET /api/todos/{todo_id}/comments Authorization: Bearer {access_token} ``` ## πŸ“Š 톡계 및 λŒ€μ‹œλ³΄λ“œ ### 할일 톡계 ```http GET /api/todos/stats Authorization: Bearer {access_token} ``` **응닡:** ```json { "total_count": 25, "draft_count": 5, "scheduled_count": 8, "active_count": 7, "completed_count": 4, "delayed_count": 1, "completion_rate": 16.0 } ``` ### ν™œμ„± 할일 쑰회 (μ‹œκ°„ 기반 μžλ™ ν™œμ„±ν™”) ```http GET /api/todos/active Authorization: Bearer {access_token} ``` **κΈ°λŠ₯:** scheduled μƒνƒœμ˜ 할일 쀑 μ‹œμž‘ μ‹œκ°„μ΄ μ§€λ‚œ 것듀을 μžλ™μœΌλ‘œ active둜 λ³€κ²½ν•˜κ³  λ°˜ν™˜ ## πŸ‘€ μ‚¬μš©μž 관리 ### ν˜„μž¬ μ‚¬μš©μž 정보 ```http GET /api/users/me Authorization: Bearer {access_token} ``` **응닡:** ```json { "id": "550e8400-e29b-41d4-a716-446655440001", "email": "user@example.com", "full_name": "μ‚¬μš©μž 이름", "is_active": true, "is_admin": false, "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-15T09:00:00Z", "last_login_at": "2024-01-15T09:00:00Z", "timezone": "Asia/Seoul", "language": "ko" } ``` ### μ‚¬μš©μž 정보 μˆ˜μ • ```http PUT /api/users/me Content-Type: application/json Authorization: Bearer {access_token} { "full_name": "μƒˆλ‘œμš΄ 이름", "timezone": "Asia/Seoul", "language": "ko" } ``` ## πŸ”— μ‹œλ†€λ‘œμ§€ 연동 (1단계) ### μ‹œλ†€λ‘œμ§€ μ„€μ • ν…ŒμŠ€νŠΈ ```http POST /api/synology/test-connection Content-Type: application/json Authorization: Bearer {access_token} { "dsm_url": "https://your-nas.synology.me:5001", "username": "todo_user", "password": "password123" } ``` **응닡:** ```json { "dsm_connection": "success", "calendar_connection": "success", "mail_connection": "success", "available_services": ["Calendar", "MailPlus"] } ``` ### μΊ˜λ¦°λ” 동기화 μˆ˜λ™ μ‹€ν–‰ ```http POST /api/synology/sync-calendar/{todo_id} Authorization: Bearer {access_token} ``` ### 메일 μ•Œλ¦Ό λ°œμ†‘ ```http POST /api/synology/send-notification/{todo_id} Authorization: Bearer {access_token} ``` ## πŸ”§ μ‹œμŠ€ν…œ 관리 ### ν—¬μŠ€ 체크 ```http GET /api/health ``` **응닡:** ```json { "status": "healthy", "timestamp": "2024-01-15T12:00:00Z", "version": "0.1.0", "database": "connected", "synology_integration": "enabled" } ``` ### API 정보 ```http GET /api/info ``` **응닡:** ```json { "name": "Todo Project API", "version": "0.1.0", "description": "κ°„κ²°ν•˜κ³  μŠ€λ§ˆνŠΈν•œ 개인용 할일 관리 μ‹œμŠ€ν…œ", "docs_url": "/docs", "redoc_url": "/redoc" } ``` ## πŸ“ 였λ₯˜ 응닡 ### ν‘œμ€€ 였λ₯˜ ν˜•μ‹ ```json { "error": { "code": "VALIDATION_ERROR", "message": "μž…λ ₯ 데이터가 μœ νš¨ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.", "details": { "field": "content", "issue": "μ΅œμ†Œ 1자 이상 μž…λ ₯ν•΄μ•Ό ν•©λ‹ˆλ‹€." } }, "timestamp": "2024-01-15T12:00:00Z" } ``` ### μ£Όμš” 였λ₯˜ μ½”λ“œ - `AUTHENTICATION_ERROR`: 인증 μ‹€νŒ¨ - `AUTHORIZATION_ERROR`: κΆŒν•œ μ—†μŒ - `VALIDATION_ERROR`: μž…λ ₯ 데이터 검증 μ‹€νŒ¨ - `NOT_FOUND`: λ¦¬μ†ŒμŠ€λ₯Ό 찾을 수 μ—†μŒ - `CONFLICT`: 데이터 좩돌 - `RATE_LIMIT_EXCEEDED`: μš”μ²­ ν•œλ„ 초과 - `SYNOLOGY_CONNECTION_ERROR`: μ‹œλ†€λ‘œμ§€ 연동 였λ₯˜ ### HTTP μƒνƒœ μ½”λ“œ - `200`: 성곡 - `201`: 생성 성곡 - `400`: 잘λͺ»λœ μš”μ²­ - `401`: 인증 ν•„μš” - `403`: κΆŒν•œ μ—†μŒ - `404`: 찾을 수 μ—†μŒ - `409`: 좩돌 - `422`: 검증 μ‹€νŒ¨ - `429`: μš”μ²­ ν•œλ„ 초과 - `500`: μ„œλ²„ 였λ₯˜ ## πŸš€ SDK 및 ν΄λΌμ΄μ–ΈνŠΈ ### JavaScript ν΄λΌμ΄μ–ΈνŠΈ 예제 ```javascript class TodoAPI { constructor(baseURL = 'http://localhost:9000/api') { this.baseURL = baseURL; this.token = localStorage.getItem('access_token'); } async createTodo(content) { const response = await fetch(`${this.baseURL}/todos`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.token}` }, body: JSON.stringify({ content }) }); return await response.json(); } async getTodos(status = null) { const params = status ? `?status=${status}` : ''; const response = await fetch(`${this.baseURL}/todos${params}`, { headers: { 'Authorization': `Bearer ${this.token}` } }); return await response.json(); } async completeTodo(todoId) { const response = await fetch(`${this.baseURL}/todos/${todoId}/complete`, { method: 'PUT', headers: { 'Authorization': `Bearer ${this.token}` } }); return await response.json(); } } // μ‚¬μš© 예제 const api = new TodoAPI(); // 할일 생성 const newTodo = await api.createTodo('μƒˆλ‘œμš΄ 할일'); // 할일 λͺ©λ‘ 쑰회 const activeTodos = await api.getTodos('active'); // 할일 μ™„λ£Œ await api.completeTodo(newTodo.id); ``` ## πŸ“š μΆ”κ°€ λ¦¬μ†ŒμŠ€ - **Swagger UI**: http://localhost:9000/docs - **ReDoc**: http://localhost:9000/redoc - **OpenAPI Spec**: http://localhost:9000/openapi.json 이 API λ¬Έμ„œλ₯Ό 톡해 Todo-Project의 λͺ¨λ“  κΈ°λŠ₯을 ν™œμš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€!