2455 lines
62 KiB
Markdown
2455 lines
62 KiB
Markdown
# Drama Ling API 規格文檔 (已重構為模組化)
|
||
|
||
## 📋 重要通知
|
||
**此文檔已重構為模組化設計!**
|
||
|
||
新的API文檔結構位於 [`api/`](./api/) 目錄下,包含:
|
||
- **API總覽和導航**: [api/README.md](./api/README.md)
|
||
- **各功能模組文檔**: 按功能拆分為10個獨立模組
|
||
- **共通規範**: 統一的設計原則和錯誤處理
|
||
|
||
## 🚀 快速導航
|
||
請前往 **[API 文檔總覽](./api/README.md)** 查看完整的模組化API規格。
|
||
|
||
## 📚 模組化結構
|
||
```
|
||
api/
|
||
├── README.md # 總覽和導航
|
||
├── authentication.md # 認證與授權
|
||
├── user-management.md # 用戶管理
|
||
├── learning-content.md # 學習內容 (待建立)
|
||
├── dialogue-practice.md # 對話練習 (待建立)
|
||
├── vocabulary.md # 詞彙系統 (待建立)
|
||
├── gamification.md # 遊戲化系統 (待建立)
|
||
├── subscription.md # 訂閱系統 (待建立)
|
||
├── daily-missions.md # 特殊任務 (待建立)
|
||
├── language-levels.md # 語言程度 (待建立)
|
||
├── errors.md # 錯誤處理
|
||
└── common.md # 共通規範
|
||
```
|
||
|
||
## ✅ 已完成的模組
|
||
- ✅ [認證與授權 API](./api/authentication.md)
|
||
- ✅ [用戶管理 API](./api/user-management.md)
|
||
- ✅ [共通規範](./api/common.md)
|
||
- ✅ [錯誤處理](./api/errors.md)
|
||
|
||
## 📋 待建立的模組
|
||
剩餘的API模組將從此文檔的內容中提取並重新組織:
|
||
- ⏳ 學習內容API (第332-416行)
|
||
- ⏳ 對話練習API (第615-776行)
|
||
- ⏳ 詞彙系統API (第417-614行)
|
||
- ⏳ 遊戲化系統API (第98-252行,第777-930行,第1791-1867行)
|
||
- ⏳ 訂閱系統API (第1868-2188行)
|
||
- ⏳ 特殊任務API (第1142-1447行)
|
||
- ⏳ 語言程度API (第1448-1790行)
|
||
|
||
---
|
||
|
||
**⚠️ 重要提醒**: 請使用新的模組化文檔進行API開發,此檔案僅作為遷移參考。
|
||
|
||
## API 設計原則
|
||
|
||
### RESTful 設計標準
|
||
- [ ] **資源導向**: API端點基於資源設計而非動作
|
||
- [ ] **HTTP動詞**: 正確使用GET、POST、PUT、DELETE、PATCH
|
||
- [ ] **狀態碼**: 使用標準HTTP狀態碼表示結果
|
||
- [ ] **無狀態**: API設計為無狀態,不依賴server端session
|
||
- [ ] **版本控制**: API版本控制策略 (如 `/api/v1/`)
|
||
|
||
### API 安全原則
|
||
- [ ] **身份驗證**: JWT Token認證機制
|
||
- [ ] **授權控制**: Role-based權限控制
|
||
- [ ] **資料驗證**: 嚴格的輸入資料驗證
|
||
- [ ] **速率限制**: 防止API濫用的速率控制
|
||
- [ ] **HTTPS強制**: 所有API強制使用HTTPS
|
||
|
||
### 回應格式標準
|
||
```json
|
||
{
|
||
"success": boolean,
|
||
"data": object | array | null,
|
||
"message": string,
|
||
"error": {
|
||
"code": string,
|
||
"message": string,
|
||
"details": object
|
||
},
|
||
"meta": {
|
||
"timestamp": "ISO8601",
|
||
"request_id": "string",
|
||
"pagination": object
|
||
}
|
||
}
|
||
```
|
||
|
||
## 認證與授權 API
|
||
|
||
### 用戶認證
|
||
```http
|
||
POST /api/v1/auth/register
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"email": "user@example.com",
|
||
"password": "securePassword123",
|
||
"username": "dramatic_learner",
|
||
"preferredLanguage": "en",
|
||
"nativeLanguage": "zh-TW"
|
||
}
|
||
```
|
||
|
||
```http
|
||
Response 201 Created
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"userId": "550e8400-e29b-41d4-a716-446655440000",
|
||
"username": "dramatic_learner",
|
||
"email": "user@example.com",
|
||
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"refreshToken": "550e8400-e29b-41d4-a716-446655440001",
|
||
"expiresIn": 3600
|
||
},
|
||
"message": "User registered successfully",
|
||
"meta": {
|
||
"timestamp": "2024-09-05T15:30:00Z",
|
||
"requestId": "550e8400-e29b-41d4-a716-446655440002"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 登入驗證
|
||
```http
|
||
POST /api/v1/auth/login
|
||
{
|
||
"email": "user@example.com",
|
||
"password": "securePassword123"
|
||
}
|
||
```
|
||
|
||
### Token 更新
|
||
```http
|
||
POST /api/v1/auth/refresh
|
||
Authorization: Bearer <refresh_token>
|
||
```
|
||
|
||
### 登出
|
||
```http
|
||
POST /api/v1/auth/logout
|
||
Authorization: Bearer <access_token>
|
||
```
|
||
|
||
## 命條系統 API
|
||
|
||
### 命條狀態管理 (LifePoints)
|
||
|
||
#### 獲取命條狀態
|
||
```http
|
||
GET /api/v1/life-points/status
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"current_life_points": 3,
|
||
"max_life_points": 5,
|
||
"recovery_rate": "5_hours_per_point",
|
||
"next_recovery_at": "2024-09-05T20:00:00Z",
|
||
"time_until_next_recovery": 14400, // seconds
|
||
"auto_recovery_enabled": true,
|
||
"last_used_at": "2024-09-05T14:30:00Z",
|
||
"daily_usage_stats": {
|
||
"points_used_today": 2,
|
||
"scenarios_attempted": 5,
|
||
"scenarios_completed": 3
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 購買命條
|
||
```http
|
||
POST /api/v1/life-points/purchase
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"quantity": 5, // 購買數量
|
||
"payment_method": "diamonds", // diamonds, cash, ad_watch
|
||
"payment_details": {
|
||
"diamond_cost": 100 // 如果使用鑽石支付
|
||
}
|
||
}
|
||
|
||
Response 201 Created
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"transaction_id": "LP_PUR_20240905_001",
|
||
"life_points_added": 5,
|
||
"payment_method": "diamonds",
|
||
"cost": {
|
||
"diamonds": 100
|
||
},
|
||
"new_life_points_total": 5,
|
||
"previous_balance": 0,
|
||
"purchased_at": "2024-09-05T16:00:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 觀看廣告獲得命條
|
||
```http
|
||
POST /api/v1/life-points/ad-reward
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"ad_id": "AD_LIFE_001",
|
||
"watch_completion": true,
|
||
"watch_duration": 30 // 實際觀看秒數
|
||
}
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"life_points_gained": 1,
|
||
"current_life_points": 4,
|
||
"ad_cooldown_remaining": 3600, // 下次看廣告的冷卻時間(秒)
|
||
"daily_ad_limit_remaining": 2,
|
||
"reward_claimed_at": "2024-09-05T16:30:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 消耗命條 (系統內部調用)
|
||
```http
|
||
POST /api/v1/life-points/consume
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"reason": "dialogue_mistake", // dialogue_mistake, challenge_failure, retry_scenario
|
||
"context": {
|
||
"dialogue_id": "DLG_20240905_001",
|
||
"scenario_id": "SC_Restaurant_01",
|
||
"mistake_type": "grammar_error"
|
||
}
|
||
}
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"life_points_consumed": 1,
|
||
"remaining_life_points": 2,
|
||
"can_continue": true,
|
||
"context_message": "語法錯誤,命條-1,請再試一次!",
|
||
"recovery_info": {
|
||
"next_recovery_at": "2024-09-05T20:00:00Z",
|
||
"time_until_recovery": 13500
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 命條耗盡處理
|
||
```http
|
||
GET /api/v1/life-points/exhausted-options
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"current_life_points": 0,
|
||
"recovery_options": [
|
||
{
|
||
"method": "wait",
|
||
"description": "等待自動回復",
|
||
"time_required": 18000, // 5小時秒數
|
||
"next_recovery_at": "2024-09-05T21:30:00Z",
|
||
"cost": 0
|
||
},
|
||
{
|
||
"method": "purchase_diamonds",
|
||
"description": "使用鑽石購買",
|
||
"life_points": 5,
|
||
"cost": {
|
||
"currency": "diamonds",
|
||
"amount": 100
|
||
}
|
||
},
|
||
{
|
||
"method": "watch_ad",
|
||
"description": "觀看廣告獲得",
|
||
"life_points": 1,
|
||
"available": true,
|
||
"cooldown_remaining": 0,
|
||
"daily_limit_remaining": 3
|
||
}
|
||
],
|
||
"consolation_reward": {
|
||
"type": "time_scroll", // 時光卷作為安慰獎勵
|
||
"quantity": 1,
|
||
"description": "獲得1個時光卷,可用於時光挑戰"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 用戶資料管理 API
|
||
|
||
### 用戶資料 (UserProfile)
|
||
|
||
#### 獲取用戶資料
|
||
```http
|
||
GET /api/v1/users/profile
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"user_id": "USR_12345",
|
||
"username": "dramatic_learner",
|
||
"email": "user@example.com",
|
||
"avatar_url": "https://cdn.example.com/avatars/12345.jpg",
|
||
"level": "B1",
|
||
"total_score": 15680,
|
||
"streak_days": 15,
|
||
"joined_date": "2024-01-15T08:00:00Z",
|
||
"last_active": "2024-09-05T14:30:00Z",
|
||
"preferences": {
|
||
"target_language": "en",
|
||
"native_language": "zh-TW",
|
||
"difficulty_preference": "adaptive",
|
||
"daily_goal_minutes": 30,
|
||
"notifications_enabled": true,
|
||
"theme": "light"
|
||
},
|
||
"subscription": {
|
||
"plan": "premium",
|
||
"status": "active",
|
||
"expires_at": "2025-01-15T08:00:00Z"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 更新用戶資料
|
||
```http
|
||
PUT /api/v1/users/profile
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"username": "new_username",
|
||
"avatar_url": "https://cdn.example.com/avatars/new_avatar.jpg",
|
||
"preferences": {
|
||
"daily_goal_minutes": 45,
|
||
"notifications_enabled": false
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 用戶學習統計
|
||
```http
|
||
GET /api/v1/users/stats
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"total_dialogues": 245,
|
||
"total_study_time": 1280, // minutes
|
||
"vocabulary_learned": 890,
|
||
"vocabulary_mastered": 650,
|
||
"scenarios_completed": 35,
|
||
"achievements_unlocked": 18,
|
||
"current_streak": 15,
|
||
"longest_streak": 28,
|
||
"weekly_progress": {
|
||
"dialogues_this_week": 12,
|
||
"minutes_this_week": 180,
|
||
"goal_completion_rate": 0.85
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 學習內容 API
|
||
|
||
### 課程與場景 (Lesson)
|
||
|
||
#### 獲取場景列表
|
||
```http
|
||
GET /api/v1/lessons/scenarios
|
||
Authorization: Bearer <access_token>
|
||
Query Parameters:
|
||
- category: string (daily_life, social, emergency, professional)
|
||
- difficulty: string (A1, A2, B1, B2, C1, C2)
|
||
- limit: integer (default: 20)
|
||
- offset: integer (default: 0)
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"scenarios": [
|
||
{
|
||
"scenario_id": "SC_Restaurant_01",
|
||
"title": "餐廳訂位",
|
||
"description": "學習如何在餐廳預約座位和點餐",
|
||
"category": "daily_life",
|
||
"difficulty": "A2",
|
||
"estimated_duration": 8, // minutes
|
||
"thumbnail_url": "https://cdn.example.com/scenarios/restaurant.jpg",
|
||
"vocabulary_count": 25,
|
||
"completion_rate": 0.75,
|
||
"user_completed": true,
|
||
"user_score": 85,
|
||
"unlock_condition": null,
|
||
"is_premium": false
|
||
}
|
||
],
|
||
"pagination": {
|
||
"total": 65,
|
||
"page": 1,
|
||
"per_page": 20,
|
||
"total_pages": 4
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 獲取場景詳情
|
||
```http
|
||
GET /api/v1/lessons/scenarios/{scenario_id}
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"scenario_id": "SC_Restaurant_01",
|
||
"title": "餐廳訂位",
|
||
"description": "學習如何在餐廳預約座位和點餐",
|
||
"category": "daily_life",
|
||
"difficulty": "A2",
|
||
"learning_objectives": [
|
||
"學會預約餐廳座位",
|
||
"掌握點餐相關詞彙",
|
||
"練習詢問食材和偏好"
|
||
],
|
||
"target_vocabulary": [
|
||
{
|
||
"word": "reservation",
|
||
"phonetic": "/ˌrezəˈveɪʃən/",
|
||
"translation": "預約",
|
||
"definition": "an arrangement to have something kept for you"
|
||
}
|
||
],
|
||
"cultural_notes": "西式餐廳通常需要事先預約,特別是在熱門時段...",
|
||
"estimated_duration": 8,
|
||
"prerequisite_scenarios": ["SC_Greeting_01"],
|
||
"user_progress": {
|
||
"completed": true,
|
||
"best_score": 85,
|
||
"completion_count": 3,
|
||
"last_completed": "2024-09-03T19:20:00Z"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 詞彙管理 API
|
||
|
||
#### 獲取詞彙列表
|
||
```http
|
||
GET /api/v1/vocabulary
|
||
Authorization: Bearer <access_token>
|
||
Query Parameters:
|
||
- category: string (life, academic, business, etc.)
|
||
- difficulty: string (A1-C2)
|
||
- mastery_level: string (learning, practicing, mastered)
|
||
- limit: integer (default: 50)
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"vocabulary": [
|
||
{
|
||
"vocab_id": "VOC_0001",
|
||
"word": "restaurant",
|
||
"phonetic": "/ˈrestərɑːnt/",
|
||
"part_of_speech": "noun",
|
||
"definition": "A place where people pay to sit and eat meals",
|
||
"translation": "餐廳",
|
||
"difficulty": "A2",
|
||
"frequency_rank": 1250,
|
||
"user_mastery": {
|
||
"level": "practicing", // learning, practicing, mastered
|
||
"score": 75,
|
||
"review_count": 5,
|
||
"last_reviewed": "2024-09-03T10:15:00Z",
|
||
"next_review": "2024-09-07T10:15:00Z"
|
||
},
|
||
"example_sentences": [
|
||
{
|
||
"english": "We made a reservation at the new restaurant.",
|
||
"chinese": "我們在新餐廳訂了位。"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 詞彙複習API (間隔複習系統)
|
||
|
||
#### 獲取間隔複習任務
|
||
```http
|
||
GET /api/v1/vocabulary/review/spaced
|
||
Authorization: Bearer <access_token>
|
||
Query Parameters:
|
||
- max_words: integer (default: 20, 每次複習的最大詞彙數)
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"review_session_id": "REV_SPACED_20240905_USR12345",
|
||
"total_words": 15,
|
||
"estimated_time": 5, // minutes
|
||
"review_algorithm": "spaced_repetition",
|
||
"words": [
|
||
{
|
||
"vocab_id": "VOC_0001",
|
||
"word": "restaurant",
|
||
"review_count": 3, // 這是第幾次複習
|
||
"next_review_multiplier": 8, // 2^3 = 8天後複習
|
||
"last_reviewed": "2024-08-28T10:15:00Z",
|
||
"mastery_level": "practicing", // learning, practicing, mastered
|
||
"review_type": "recognition", // recognition, recall, spelling
|
||
"options": ["餐廳", "旅館", "商店", "學校"] // for recognition type
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 詞彙學習階段API
|
||
```http
|
||
GET /api/v1/vocabulary/learning-stages/{vocab_id}
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"vocab_id": "VOC_0001",
|
||
"word": "restaurant",
|
||
"current_stage": "recognition", // recognition, familiarity, dialogue_application
|
||
"stages_progress": {
|
||
"recognition": {
|
||
"completed": true,
|
||
"completion_date": "2024-09-01T14:30:00Z",
|
||
"attempts": 2,
|
||
"success_rate": 100
|
||
},
|
||
"familiarity": {
|
||
"completed": false,
|
||
"attempts": 1,
|
||
"success_rate": 75,
|
||
"next_exercise": "image_matching"
|
||
},
|
||
"dialogue_application": {
|
||
"completed": false,
|
||
"required_scenarios": ["SC_Restaurant_01"],
|
||
"usage_count": 0
|
||
}
|
||
},
|
||
"overall_mastery": {
|
||
"level": "practicing",
|
||
"confidence_score": 75,
|
||
"estimated_mastery_date": "2024-09-15T00:00:00Z"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 詞彙熟悉度練習API
|
||
```http
|
||
POST /api/v1/vocabulary/fluency-practice
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"practice_type": "image_matching", // image_matching, sentence_reorder, word_association
|
||
"vocab_ids": ["VOC_0001", "VOC_0002"],
|
||
"difficulty_level": "A2"
|
||
}
|
||
|
||
Response 201 Created
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"practice_session_id": "FLUENCY_20240905_001",
|
||
"practice_type": "image_matching",
|
||
"exercises": [
|
||
{
|
||
"exercise_id": "EX_001",
|
||
"vocab_id": "VOC_0001",
|
||
"word": "restaurant",
|
||
"image_url": "https://cdn.example.com/vocab/restaurant.jpg",
|
||
"options": [
|
||
{
|
||
"text": "restaurant",
|
||
"image_url": "https://cdn.example.com/vocab/restaurant.jpg"
|
||
},
|
||
{
|
||
"text": "hospital",
|
||
"image_url": "https://cdn.example.com/vocab/hospital.jpg"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 每日詞彙複習API
|
||
```http
|
||
GET /api/v1/vocabulary/review/daily
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"review_session_id": "REV_20240905_USR12345",
|
||
"total_words": 15,
|
||
"estimated_time": 5, // minutes
|
||
"words": [
|
||
{
|
||
"vocab_id": "VOC_0001",
|
||
"word": "restaurant",
|
||
"review_type": "recognition", // recognition, recall, spelling
|
||
"options": ["餐廳", "旅館", "商店", "學校"] // for recognition type
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 提交複習結果
|
||
```http
|
||
POST /api/v1/vocabulary/review/submit
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"review_session_id": "REV_20240905_USR12345",
|
||
"results": [
|
||
{
|
||
"vocab_id": "VOC_0001",
|
||
"user_answer": "餐廳",
|
||
"is_correct": true,
|
||
"response_time": 2.5, // seconds
|
||
"confidence": 4 // 1-5 scale
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
## 對話練習 API
|
||
|
||
### 對話系統 (Dialogue)
|
||
|
||
#### 開始對話練習
|
||
```http
|
||
POST /api/v1/dialogues/start
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"scenario_id": "SC_Restaurant_01",
|
||
"difficulty_override": "A2", // optional
|
||
"target_vocabulary": ["reservation", "menu", "order"] // optional
|
||
}
|
||
|
||
Response 201 Created
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"dialogue_id": "DLG_20240905_001",
|
||
"scenario_id": "SC_Restaurant_01",
|
||
"session_token": "session_token_here",
|
||
"initial_context": {
|
||
"setting": "高級餐廳內部,晚上8點",
|
||
"your_role": "客人",
|
||
"ai_role": "餐廳服務員",
|
||
"objective": "成功預約並點餐"
|
||
},
|
||
"ai_message": {
|
||
"message": "Good evening! Welcome to Milano Restaurant. Do you have a reservation?",
|
||
"audio_url": "https://cdn.example.com/audio/dlg001_001.mp3",
|
||
"suggestions": [
|
||
"Yes, I have a reservation under Smith.",
|
||
"No, but could we get a table for two?",
|
||
"I'd like to make a reservation for tonight."
|
||
]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 發送對話訊息
|
||
```http
|
||
POST /api/v1/dialogues/{dialogue_id}/message
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"message": "Yes, I have a reservation under Chen for 8 PM.",
|
||
"message_type": "text", // text, audio
|
||
"audio_url": "https://cdn.example.com/user_audio/msg001.mp3" // if audio
|
||
}
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"ai_response": {
|
||
"message": "Perfect! Mr. Chen, your table for two is ready. Right this way please.",
|
||
"audio_url": "https://cdn.example.com/audio/dlg001_002.mp3",
|
||
"analysis": {
|
||
"grammar_score": 90,
|
||
"semantic_score": 95,
|
||
"fluency_score": 85,
|
||
"overall_score": 90,
|
||
"feedback": "Excellent use of formal language for restaurant context!"
|
||
},
|
||
"suggestions": [
|
||
"Thank you. Could we see the menu please?",
|
||
"Great! What do you recommend today?",
|
||
"Thank you. We'd like to start with drinks."
|
||
]
|
||
},
|
||
"dialogue_progress": {
|
||
"turns_completed": 2,
|
||
"estimated_turns_remaining": 6,
|
||
"objectives_completed": ["greeting", "reservation_confirmation"],
|
||
"objectives_remaining": ["ordering", "payment"]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 獲取AI分析詳情
|
||
```http
|
||
GET /api/v1/dialogues/{dialogue_id}/analysis
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"dialogue_id": "DLG_20240905_001",
|
||
"overall_analysis": {
|
||
"grammar_score": 88,
|
||
"semantic_score": 92,
|
||
"fluency_score": 85,
|
||
"total_score": 88,
|
||
"completion_percentage": 100
|
||
},
|
||
"detailed_feedback": [
|
||
{
|
||
"turn_number": 1,
|
||
"user_message": "Yes, I have a reservation under Chen for 8 PM.",
|
||
"analysis": {
|
||
"grammar_issues": [],
|
||
"semantic_appropriateness": "Excellent - appropriate formality level",
|
||
"fluency_notes": "Natural and confident delivery",
|
||
"suggestions": [],
|
||
"vocabulary_used": [
|
||
{
|
||
"word": "reservation",
|
||
"usage_correctness": "perfect",
|
||
"context_appropriateness": "excellent"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
],
|
||
"improvement_suggestions": [
|
||
"Consider using more varied vocabulary for ordering",
|
||
"Practice pronunciation of 'th' sounds"
|
||
],
|
||
"vocabulary_progress": {
|
||
"words_practiced": 8,
|
||
"words_used_correctly": 7,
|
||
"new_words_encountered": 3
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 結束對話
|
||
```http
|
||
POST /api/v1/dialogues/{dialogue_id}/complete
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"dialogue_summary": {
|
||
"dialogue_id": "DLG_20240905_001",
|
||
"duration": 420, // seconds
|
||
"turns_completed": 8,
|
||
"final_score": 88,
|
||
"objectives_achieved": 4,
|
||
"objectives_total": 4,
|
||
"vocabulary_practiced": 12,
|
||
"experience_gained": 150,
|
||
"score_gained": 75
|
||
},
|
||
"rewards": {
|
||
"experience_points": 150,
|
||
"score_points": 75,
|
||
"achievements_unlocked": ["First Perfect Dialogue"],
|
||
"vocabulary_progress": {
|
||
"words_advanced": 3,
|
||
"words_mastered": 1
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 回覆卡關輔助 API
|
||
|
||
### 回覆引導系統
|
||
|
||
#### 獲取回覆輔助
|
||
```http
|
||
POST /api/v1/dialogues/{dialogue_id}/assistance
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"assistance_type": "reply_guidance", // reply_guidance, translation
|
||
"context": {
|
||
"partner_message": "Good morning! How is your day going?",
|
||
"scenario_context": "friendly morning greeting at office",
|
||
"user_language_level": "A2",
|
||
"dialogue_history": [
|
||
{
|
||
"speaker": "partner",
|
||
"message": "Hello! Nice to meet you."
|
||
},
|
||
{
|
||
"speaker": "user",
|
||
"message": "Nice to meet you too."
|
||
}
|
||
]
|
||
}
|
||
}
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"assistance_id": "AST_20240905_001",
|
||
"assistance_type": "reply_guidance",
|
||
"analysis": {
|
||
"partner_intent": {
|
||
"intent": "friendly_greeting_inquiry",
|
||
"emotion": "positive_friendly",
|
||
"expectation": "positive_response_about_day",
|
||
"cultural_context": "Western casual workplace greeting",
|
||
"explanation": "對方是在進行友好的早晨問候,期待你分享今天的狀況或心情"
|
||
},
|
||
"response_guidance": {
|
||
"thinking_process": [
|
||
"對方表現友好,我應該同樣友善回應",
|
||
"這是詢問我今天的狀況,我可以簡單分享",
|
||
"可以考慮反問對方相同的問題表示關心"
|
||
],
|
||
"response_strategies": [
|
||
{
|
||
"strategy": "positive_sharing",
|
||
"description": "積極分享今天的狀況",
|
||
"tone": "upbeat"
|
||
},
|
||
{
|
||
"strategy": "brief_polite",
|
||
"description": "簡潔禮貌的回應",
|
||
"tone": "neutral_friendly"
|
||
},
|
||
{
|
||
"strategy": "reciprocal_inquiry",
|
||
"description": "回應後反問對方",
|
||
"tone": "engaging"
|
||
}
|
||
]
|
||
},
|
||
"reply_examples": [
|
||
{
|
||
"example": "Great, thank you! I'm feeling energetic today. How about you?",
|
||
"level": "A2",
|
||
"style": "friendly_reciprocal",
|
||
"explanation": "表達積極心情並反問對方,展現對話技巧"
|
||
},
|
||
{
|
||
"example": "Pretty good, thanks for asking!",
|
||
"level": "A2",
|
||
"style": "casual_brief",
|
||
"explanation": "簡潔友善的回應,適合快節奏對話"
|
||
},
|
||
{
|
||
"example": "It's going well so far! Just got to the office. What about your day?",
|
||
"level": "B1",
|
||
"style": "detailed_engaging",
|
||
"explanation": "提供更多細節並主動延續對話"
|
||
}
|
||
]
|
||
},
|
||
"cost_deducted": {
|
||
"item_type": "reply_hint",
|
||
"quantity": 1,
|
||
"remaining_quantity": 4
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 中翻英翻譯輔助
|
||
```http
|
||
POST /api/v1/translation/assistance
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"source_text": "今天天氣真好,讓我心情很愉快",
|
||
"context": {
|
||
"dialogue_scenario": "casual_conversation",
|
||
"formality_level": "informal",
|
||
"target_language_level": "A2",
|
||
"cultural_adaptation": true
|
||
}
|
||
}
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"translation_result": {
|
||
"primary_translation": "The weather is really nice today, it makes me feel happy.",
|
||
"alternative_translations": [
|
||
{
|
||
"text": "It's such a beautiful day today, I'm in a great mood!",
|
||
"level": "B1",
|
||
"style": "enthusiastic"
|
||
},
|
||
{
|
||
"text": "Today's nice weather is making me cheerful.",
|
||
"level": "A2",
|
||
"style": "simple_clear"
|
||
}
|
||
],
|
||
"grammar_notes": [
|
||
{
|
||
"point": "weather_description",
|
||
"explanation": "英文描述天氣常用 'The weather is + adjective' 句型"
|
||
},
|
||
{
|
||
"point": "causative_structure",
|
||
"explanation": "'makes me feel + adjective' 表達某事讓你產生某種感受"
|
||
}
|
||
],
|
||
"vocabulary_highlights": [
|
||
{
|
||
"chinese": "心情愉快",
|
||
"english": "feel happy / in a good mood",
|
||
"note": "英文有多種表達好心情的方式"
|
||
}
|
||
],
|
||
"cultural_adaptation": {
|
||
"original_style": "direct_emotional_expression",
|
||
"adapted_style": "moderate_positive_expression",
|
||
"explanation": "調整為西方文化中更常見的表達方式"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 時光挑戰系統 API
|
||
|
||
### 時光挑戰 (TimeWarp)
|
||
|
||
#### 獲取可用時光挑戰
|
||
```http
|
||
GET /api/v1/time-warp/challenges
|
||
Authorization: Bearer <access_token>
|
||
Query Parameters:
|
||
- difficulty: string (easy, medium, hard)
|
||
- challenge_type: string (vocabulary, dialogue, mixed)
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"available_challenges": [
|
||
{
|
||
"challenge_id": "TW_VOCAB_EASY_001",
|
||
"type": "vocabulary",
|
||
"difficulty": "easy",
|
||
"title": "快速詞彙挑戰",
|
||
"description": "在300秒內完成20個詞彙測試",
|
||
"time_limit": 300, // seconds
|
||
"target_score": 20,
|
||
"estimated_difficulty": "A2",
|
||
"rewards": {
|
||
"time_scrolls": 2,
|
||
"experience": 200,
|
||
"diamonds": 50
|
||
},
|
||
"requirements": {
|
||
"min_vocabulary_mastered": 50,
|
||
"min_level": "A2"
|
||
},
|
||
"user_best_score": 18,
|
||
"user_attempts": 3,
|
||
"unlock_condition": "complete_vocabulary_stage_1"
|
||
}
|
||
],
|
||
"user_time_scrolls": {
|
||
"current": 5,
|
||
"earned_today": 2,
|
||
"used_today": 1,
|
||
"total_earned": 87
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 開始時光挑戰
|
||
```http
|
||
POST /api/v1/time-warp/start
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"challenge_id": "TW_VOCAB_EASY_001",
|
||
"use_time_scroll": true // 是否消耗時光卷
|
||
}
|
||
|
||
Response 201 Created
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"session_id": "TW_SESSION_20240905_001",
|
||
"challenge_id": "TW_VOCAB_EASY_001",
|
||
"time_limit": 300,
|
||
"started_at": "2024-09-05T16:00:00Z",
|
||
"expires_at": "2024-09-05T16:05:00Z",
|
||
"time_scrolls_used": 1,
|
||
"remaining_time_scrolls": 4,
|
||
"challenge_content": {
|
||
"total_questions": 20,
|
||
"current_question": 1,
|
||
"questions": [
|
||
{
|
||
"question_id": "Q_001",
|
||
"type": "vocabulary_recognition",
|
||
"word": "restaurant",
|
||
"question": "選擇正確的中文翻譯",
|
||
"options": ["餐廳", "醫院", "學校", "商店"],
|
||
"correct_answer": "餐廳"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 提交時光挑戰答案
|
||
```http
|
||
POST /api/v1/time-warp/submit-answer
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"session_id": "TW_SESSION_20240905_001",
|
||
"question_id": "Q_001",
|
||
"answer": "餐廳",
|
||
"response_time": 2.5, // seconds
|
||
"timestamp": "2024-09-05T16:00:03Z"
|
||
}
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"correct": true,
|
||
"score_gained": 1,
|
||
"current_score": 1,
|
||
"time_remaining": 297.5,
|
||
"next_question": {
|
||
"question_id": "Q_002",
|
||
"type": "vocabulary_recognition",
|
||
"word": "hospital",
|
||
"question": "選擇正確的中文翻譯",
|
||
"options": ["餐廳", "醫院", "學校", "商店"]
|
||
},
|
||
"progress": {
|
||
"completed_questions": 1,
|
||
"total_questions": 20,
|
||
"completion_percentage": 5
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 完成時光挑戰
|
||
```http
|
||
POST /api/v1/time-warp/complete
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"session_id": "TW_SESSION_20240905_001",
|
||
"completion_reason": "time_up" // time_up, all_completed, user_quit
|
||
}
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"challenge_result": {
|
||
"session_id": "TW_SESSION_20240905_001",
|
||
"final_score": 18,
|
||
"target_score": 20,
|
||
"completion_percentage": 90,
|
||
"time_used": 298, // seconds
|
||
"time_limit": 300,
|
||
"success": false, // 未達到目標分數
|
||
"performance_rating": "good" // excellent, good, fair, poor
|
||
},
|
||
"rewards_earned": {
|
||
"experience": 150, // 減少因為未完全完成
|
||
"diamonds": 30,
|
||
"time_scrolls": 1, // 安慰獎勵
|
||
"achievements": []
|
||
},
|
||
"statistics": {
|
||
"correct_answers": 18,
|
||
"wrong_answers": 2,
|
||
"average_response_time": 14.9,
|
||
"fastest_answer": 1.2,
|
||
"slowest_answer": 28.5
|
||
},
|
||
"new_personal_record": false,
|
||
"leaderboard_rank": 245
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 獲取時光卷狀態
|
||
```http
|
||
GET /api/v1/time-warp/scrolls
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"current_scrolls": 5,
|
||
"scroll_history": [
|
||
{
|
||
"earned_at": "2024-09-05T14:30:00Z",
|
||
"source": "dialogue_failure_consolation",
|
||
"quantity": 1,
|
||
"scenario_id": "SC_Restaurant_01"
|
||
},
|
||
{
|
||
"used_at": "2024-09-05T15:00:00Z",
|
||
"challenge_id": "TW_VOCAB_EASY_001",
|
||
"quantity": 1,
|
||
"result": "completed"
|
||
}
|
||
],
|
||
"earning_sources": [
|
||
{
|
||
"source": "dialogue_failure_consolation",
|
||
"description": "對話失敗安慰獎勵",
|
||
"frequency": "每次對話失敗"
|
||
},
|
||
{
|
||
"source": "time_challenge_reward",
|
||
"description": "完成時光挑戰獎勵",
|
||
"frequency": "挑戰成功時"
|
||
},
|
||
{
|
||
"source": "daily_login_bonus",
|
||
"description": "每日登入獎勵",
|
||
"frequency": "連續登入7天"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
## 特殊任務系統 API *(新增基於新需求)*
|
||
|
||
### 今日任務管理 (Daily Mission System)
|
||
|
||
#### 獲取今日任務 *(更新規格)*
|
||
```http
|
||
GET /api/v1/missions/daily
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"daily_missions": [
|
||
{
|
||
"mission_id": "MISSION_VOCAB_RECOGNITION",
|
||
"type": "daily",
|
||
"title": "詞彙認識挑戰",
|
||
"description": "成功闖關1次詞彙認識關卡",
|
||
"icon": "🎯",
|
||
"objectives": [
|
||
{
|
||
"objective_id": "OBJ_VOCAB_RECOGNITION",
|
||
"description": "完成詞彙認識關卡通關",
|
||
"target_value": 1,
|
||
"current_value": 0,
|
||
"unit": "次",
|
||
"completion_criteria": "three_star_completion"
|
||
}
|
||
],
|
||
"rewards": {
|
||
"experience": 50,
|
||
"reward_type": "experience_points",
|
||
"description": "獲得50經驗值"
|
||
},
|
||
"status": "available",
|
||
"deadline": "2024-09-05T23:59:59Z",
|
||
"reset_time": "2024-09-06T00:00:00Z",
|
||
"completion_tracking": {
|
||
"last_completed_date": null,
|
||
"completion_count_today": 0
|
||
}
|
||
},
|
||
{
|
||
"mission_id": "MISSION_VOCAB_FLUENCY",
|
||
"type": "daily",
|
||
"title": "詞彙熟悉挑戰",
|
||
"description": "成功闖關1次詞彙熟悉關卡",
|
||
"icon": "💪",
|
||
"objectives": [
|
||
{
|
||
"objective_id": "OBJ_VOCAB_FLUENCY",
|
||
"description": "完成詞彙熟悉關卡通關",
|
||
"target_value": 1,
|
||
"current_value": 0,
|
||
"unit": "次",
|
||
"completion_criteria": "three_star_completion"
|
||
}
|
||
],
|
||
"rewards": {
|
||
"experience": 50,
|
||
"reward_type": "experience_points",
|
||
"description": "獲得50經驗值"
|
||
},
|
||
"status": "available",
|
||
"deadline": "2024-09-05T23:59:59Z",
|
||
"reset_time": "2024-09-06T00:00:00Z"
|
||
},
|
||
{
|
||
"mission_id": "MISSION_DIALOGUE_TRAINING",
|
||
"type": "daily",
|
||
"title": "對話訓練挑戰",
|
||
"description": "成功闖關1次對話訓練關卡",
|
||
"icon": "💬",
|
||
"objectives": [
|
||
{
|
||
"objective_id": "OBJ_DIALOGUE_TRAINING",
|
||
"description": "完成對話訓練關卡通關",
|
||
"target_value": 1,
|
||
"current_value": 1,
|
||
"unit": "次",
|
||
"completion_criteria": "completion_only"
|
||
}
|
||
],
|
||
"rewards": {
|
||
"experience": 75,
|
||
"reward_type": "experience_points",
|
||
"description": "獲得75經驗值"
|
||
},
|
||
"status": "completed",
|
||
"deadline": "2024-09-05T23:59:59Z",
|
||
"completed_at": "2024-09-05T14:30:00Z"
|
||
},
|
||
{
|
||
"mission_id": "MISSION_PERFECT_DIALOGUE",
|
||
"type": "daily",
|
||
"title": "完美對話挑戰",
|
||
"description": "在對話訓練關卡拿到滿星分數1次",
|
||
"icon": "⭐",
|
||
"objectives": [
|
||
{
|
||
"objective_id": "OBJ_PERFECT_DIALOGUE",
|
||
"description": "對話訓練關卡獲得滿星評價",
|
||
"target_value": 1,
|
||
"current_value": 0,
|
||
"unit": "次",
|
||
"completion_criteria": "three_star_completion"
|
||
}
|
||
],
|
||
"rewards": {
|
||
"experience": 100,
|
||
"reward_type": "experience_points",
|
||
"description": "獲得100經驗值"
|
||
},
|
||
"status": "available",
|
||
"deadline": "2024-09-05T23:59:59Z",
|
||
"requirements": {
|
||
"subscription_required": true,
|
||
"feature_access": "dialogue_training"
|
||
}
|
||
}
|
||
],
|
||
"daily_summary": {
|
||
"total_missions": 4,
|
||
"completed_missions": 1,
|
||
"available_missions": 3,
|
||
"total_experience_available": 275,
|
||
"experience_earned_today": 75,
|
||
"next_reset_time": "2024-09-06T00:00:00Z"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 關卡完成任務檢查 *(新增 - 關卡結算時調用)*
|
||
```http
|
||
POST /api/v1/missions/check-completion
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"challenge_completed": {
|
||
"challenge_type": "vocabulary_recognition", // vocabulary_recognition, vocabulary_fluency, dialogue_training
|
||
"challenge_id": "VOCAB_INTRO_001",
|
||
"completion_result": {
|
||
"success": true,
|
||
"stars_earned": 3,
|
||
"score": 95,
|
||
"perfect_score": true,
|
||
"completion_time": 120 // seconds
|
||
},
|
||
"context": {
|
||
"scenario_id": "SC_Restaurant_01", // For dialogue training
|
||
"vocabulary_learned": ["reservation", "menu", "order"] // For vocab challenges
|
||
}
|
||
}
|
||
}
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"missions_updated": [
|
||
{
|
||
"mission_id": "MISSION_VOCAB_RECOGNITION",
|
||
"previous_progress": 0,
|
||
"new_progress": 1,
|
||
"completed": true,
|
||
"completion_time": "2024-09-05T16:45:00Z",
|
||
"reward_available": true
|
||
}
|
||
],
|
||
"missions_completed": [
|
||
{
|
||
"mission_id": "MISSION_VOCAB_RECOGNITION",
|
||
"reward": {
|
||
"experience": 50,
|
||
"reward_type": "experience_points",
|
||
"description": "完成詞彙認識挑戰!"
|
||
},
|
||
"show_completion_popup": true,
|
||
"completion_message": "恭喜!您完成了今日詞彙認識挑戰,獲得50經驗值!"
|
||
}
|
||
],
|
||
"should_show_reward_screen": true,
|
||
"total_experience_gained": 50
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 領取任務獎勵 *(更新規格)*
|
||
```http
|
||
POST /api/v1/missions/{mission_id}/claim_reward
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"mission_id": "MISSION_VOCAB_RECOGNITION",
|
||
"reward_claimed": {
|
||
"experience": 50,
|
||
"reward_type": "experience_points",
|
||
"description": "詞彙認識挑戰完成獎勵"
|
||
},
|
||
"updated_user_stats": {
|
||
"total_experience": 15730,
|
||
"experience_gained_today": 125,
|
||
"level_progress": {
|
||
"current_level": "B1",
|
||
"experience_to_next": 270,
|
||
"level_up": false
|
||
}
|
||
},
|
||
"reward_claimed_at": "2024-09-05T16:47:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 重置每日任務 *(系統內部調用)*
|
||
```http
|
||
POST /api/v1/missions/daily/reset
|
||
Authorization: Bearer <system_token>
|
||
{
|
||
"reset_time": "2024-09-06T00:00:00Z",
|
||
"reset_type": "daily_automatic"
|
||
}
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"missions_reset": 4,
|
||
"users_affected": 15420,
|
||
"reset_completed_at": "2024-09-06T00:00:15Z",
|
||
"next_reset_scheduled": "2024-09-07T00:00:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 獲取任務詳情
|
||
```http
|
||
GET /api/v1/tasks/{task_id}
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"task_id": "TASK_WEEKLY_001",
|
||
"type": "weekly",
|
||
"title": "週練習大師",
|
||
"description": "本週完成20次對話練習並達到平均85分",
|
||
"long_description": "挑戰自己在本週內完成20次高品質的對話練習...",
|
||
"objectives": [
|
||
{
|
||
"objective_id": "OBJ_001",
|
||
"description": "完成對話練習",
|
||
"target_value": 20,
|
||
"current_value": 8,
|
||
"unit": "次"
|
||
},
|
||
{
|
||
"objective_id": "OBJ_002",
|
||
"description": "平均分數達標",
|
||
"target_value": 85,
|
||
"current_value": 87.5,
|
||
"unit": "分"
|
||
}
|
||
],
|
||
"rewards": {
|
||
"experience": 500,
|
||
"score": 300,
|
||
"special_items": ["premium_scenario_unlock"],
|
||
"achievements": ["weekly_master"]
|
||
},
|
||
"progress_percentage": 40,
|
||
"deadline": "2024-09-08T23:59:59Z",
|
||
"difficulty": "medium"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 領取任務獎勵
|
||
```http
|
||
POST /api/v1/tasks/{task_id}/claim_reward
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"rewards_claimed": {
|
||
"experience": 500,
|
||
"score": 300,
|
||
"special_items": ["premium_scenario_unlock"],
|
||
"achievements": ["weekly_master"]
|
||
},
|
||
"updated_user_stats": {
|
||
"total_experience": 15680,
|
||
"total_score": 8950,
|
||
"level": "B1+",
|
||
"achievements_count": 19
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 語言程度晉階系統 API *(新增基於新需求)*
|
||
|
||
### 語言程度管理 (Language Level Advancement)
|
||
|
||
#### 獲取語言程度狀態
|
||
```http
|
||
GET /api/v1/language-level/status
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"current_level": {
|
||
"level_id": "LEVEL_A2_2",
|
||
"level_number": 3,
|
||
"cefr_level": "A2",
|
||
"level_name": "A2中級",
|
||
"description": "能夠理解和使用日常用語和基本短語",
|
||
"learning_focus": [
|
||
"基礎日常對話",
|
||
"簡單描述個人背景",
|
||
"表達基本需求"
|
||
]
|
||
},
|
||
"advancement_progress": {
|
||
"previous_level_requirements": {
|
||
"required_perfect_dialogues": 15,
|
||
"completed_perfect_dialogues": 15,
|
||
"completion_percentage": 100,
|
||
"completed_at": "2024-08-15T10:30:00Z"
|
||
},
|
||
"current_level_requirements": {
|
||
"required_perfect_dialogues": 10,
|
||
"completed_perfect_dialogues": 7,
|
||
"completion_percentage": 70,
|
||
"remaining_dialogues": 3
|
||
},
|
||
"total_progress": {
|
||
"total_required": 25, // 15 + 10
|
||
"total_completed": 22, // 15 + 7
|
||
"overall_percentage": 88
|
||
}
|
||
},
|
||
"next_level": {
|
||
"level_id": "LEVEL_B1_1",
|
||
"level_number": 4,
|
||
"cefr_level": "B1",
|
||
"level_name": "B1初級",
|
||
"unlock_requirements": {
|
||
"previous_level_dialogues": 15,
|
||
"current_level_dialogues": 10
|
||
},
|
||
"benefits": [
|
||
"解鎖更豐富的對話場景",
|
||
"更複雜的語言結構練習",
|
||
"進階語法訓練"
|
||
]
|
||
},
|
||
"level_statistics": {
|
||
"days_at_current_level": 21,
|
||
"estimated_days_to_next": 5,
|
||
"perfect_dialogues_this_week": 3,
|
||
"learning_streak": 12
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 滿星對話完成檢查 *(關卡結算時調用)*
|
||
```http
|
||
POST /api/v1/language-level/perfect-dialogue-completed
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"dialogue_result": {
|
||
"dialogue_id": "DLG_20240905_001",
|
||
"scenario_id": "SC_Restaurant_01",
|
||
"final_score": 95,
|
||
"stars_earned": 3,
|
||
"is_perfect_score": true,
|
||
"evaluation_scores": {
|
||
"grammar_score": 95,
|
||
"semantic_score": 96,
|
||
"fluency_score": 94,
|
||
"vocabulary_score": 97
|
||
},
|
||
"completion_time": "2024-09-05T16:45:00Z"
|
||
}
|
||
}
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"level_progress_updated": true,
|
||
"previous_progress": {
|
||
"current_level_dialogues": 6,
|
||
"total_completed": 21
|
||
},
|
||
"new_progress": {
|
||
"current_level_dialogues": 7,
|
||
"total_completed": 22
|
||
},
|
||
"advancement_check": {
|
||
"ready_for_advancement": false,
|
||
"requirements_met": {
|
||
"previous_level_complete": true,
|
||
"current_level_complete": false
|
||
},
|
||
"remaining_requirements": {
|
||
"perfect_dialogues_needed": 3
|
||
}
|
||
},
|
||
"level_up_triggered": false
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 語言程度晉階觸發 *(系統檢查完成條件)*
|
||
```http
|
||
POST /api/v1/language-level/advancement-check
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"advancement_eligible": true,
|
||
"current_level": {
|
||
"level_id": "LEVEL_A2_2",
|
||
"level_number": 3,
|
||
"cefr_level": "A2"
|
||
},
|
||
"advancement_to": {
|
||
"level_id": "LEVEL_B1_1",
|
||
"level_number": 4,
|
||
"cefr_level": "B1",
|
||
"level_name": "B1初級"
|
||
},
|
||
"requirements_satisfied": {
|
||
"previous_level_dialogues": {
|
||
"required": 15,
|
||
"completed": 15,
|
||
"satisfied": true
|
||
},
|
||
"current_level_dialogues": {
|
||
"required": 10,
|
||
"completed": 10,
|
||
"satisfied": true
|
||
}
|
||
},
|
||
"advancement_rewards": {
|
||
"experience_bonus": 500,
|
||
"achievement": "language_advancement_b1",
|
||
"content_unlocked": [
|
||
"SC_Business_Meeting_01",
|
||
"SC_Job_Interview_01",
|
||
"SC_Academic_Discussion_01"
|
||
]
|
||
},
|
||
"show_advancement_ceremony": true
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 執行語言程度晉階
|
||
```http
|
||
POST /api/v1/language-level/advance
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"advancement_completed": true,
|
||
"previous_level": {
|
||
"level_id": "LEVEL_A2_2",
|
||
"level_number": 3,
|
||
"cefr_level": "A2"
|
||
},
|
||
"new_level": {
|
||
"level_id": "LEVEL_B1_1",
|
||
"level_number": 4,
|
||
"cefr_level": "B1",
|
||
"level_name": "B1初級",
|
||
"description": "能夠處理日常生活中大部分語言需求",
|
||
"learning_focus": [
|
||
"工作和學習場景對話",
|
||
"表達觀點和意見",
|
||
"描述經驗和事件"
|
||
]
|
||
},
|
||
"rewards_granted": {
|
||
"experience_gained": 500,
|
||
"achievements_unlocked": ["language_advancement_b1"],
|
||
"content_unlocked": {
|
||
"scenarios": [
|
||
{
|
||
"scenario_id": "SC_Business_Meeting_01",
|
||
"title": "商務會議",
|
||
"difficulty": "B1"
|
||
},
|
||
{
|
||
"scenario_id": "SC_Job_Interview_01",
|
||
"title": "工作面試",
|
||
"difficulty": "B1"
|
||
}
|
||
],
|
||
"vocabulary_packs": ["VOCAB_PACK_B1_BUSINESS"]
|
||
}
|
||
},
|
||
"next_level_preview": {
|
||
"level_id": "LEVEL_B1_2",
|
||
"level_name": "B1中級",
|
||
"unlock_requirements": {
|
||
"previous_level_dialogues": 15,
|
||
"current_level_dialogues": 10
|
||
}
|
||
},
|
||
"advancement_date": "2024-09-05T17:00:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 獲取語言程度歷史
|
||
```http
|
||
GET /api/v1/language-level/history
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"advancement_history": [
|
||
{
|
||
"level_id": "LEVEL_A1_1",
|
||
"level_name": "A1初級",
|
||
"cefr_level": "A1",
|
||
"started_at": "2024-01-15T10:00:00Z",
|
||
"completed_at": "2024-02-28T16:30:00Z",
|
||
"duration_days": 44,
|
||
"perfect_dialogues_completed": 10,
|
||
"total_scenarios_completed": 25
|
||
},
|
||
{
|
||
"level_id": "LEVEL_A2_1",
|
||
"level_name": "A2初級",
|
||
"cefr_level": "A2",
|
||
"started_at": "2024-02-28T16:30:00Z",
|
||
"completed_at": "2024-06-15T14:20:00Z",
|
||
"duration_days": 107,
|
||
"perfect_dialogues_completed": 25,
|
||
"total_scenarios_completed": 45
|
||
}
|
||
],
|
||
"performance_analysis": {
|
||
"average_advancement_days": 75.5,
|
||
"total_perfect_dialogues": 67,
|
||
"strongest_areas": ["vocabulary_usage", "fluency"],
|
||
"improvement_areas": ["grammar_complexity", "cultural_awareness"],
|
||
"learning_velocity": "steady" // fast, steady, gradual
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 獲取各程度評估標準
|
||
```http
|
||
GET /api/v1/language-level/criteria
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"evaluation_criteria": {
|
||
"semantic_appropriateness": {
|
||
"description": "語意合適度",
|
||
"weight": 25,
|
||
"factors": [
|
||
"上下文理解準確性",
|
||
"回應內容相關性",
|
||
"情境適當性"
|
||
]
|
||
},
|
||
"grammar_accuracy": {
|
||
"description": "語法錯誤率",
|
||
"weight": 25,
|
||
"factors": [
|
||
"句法結構正確性",
|
||
"動詞時態使用",
|
||
"語序和搭配"
|
||
]
|
||
},
|
||
"fluency": {
|
||
"description": "表達流暢度",
|
||
"weight": 25,
|
||
"factors": [
|
||
"語言自然度",
|
||
"停頓和節奏",
|
||
"表達連貫性"
|
||
]
|
||
},
|
||
"vocabulary_score": {
|
||
"description": "詞彙分數",
|
||
"weight": 25,
|
||
"factors": [
|
||
"詞彙多樣性",
|
||
"詞彙準確性",
|
||
"適當詞彙選擇"
|
||
]
|
||
}
|
||
},
|
||
"level_standards": {
|
||
"A1": {
|
||
"minimum_score": 60,
|
||
"focus_areas": ["基礎詞彙", "簡單句型", "基本溝通"]
|
||
},
|
||
"A2": {
|
||
"minimum_score": 70,
|
||
"focus_areas": ["日常對話", "基本語法", "情境理解"]
|
||
},
|
||
"B1": {
|
||
"minimum_score": 75,
|
||
"focus_areas": ["工作學習", "意見表達", "經驗描述"]
|
||
},
|
||
"B2": {
|
||
"minimum_score": 80,
|
||
"focus_areas": ["複雜主題", "抽象概念", "論述技巧"]
|
||
},
|
||
"C1": {
|
||
"minimum_score": 85,
|
||
"focus_areas": ["專業溝通", "文化理解", "精確表達"]
|
||
},
|
||
"C2": {
|
||
"minimum_score": 90,
|
||
"focus_areas": ["母語水準", "微妙差異", "專精表達"]
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 排行榜與競爭 API
|
||
|
||
### 排行榜系統 (Leaderboard)
|
||
|
||
#### 獲取排行榜
|
||
```http
|
||
GET /api/v1/leaderboard
|
||
Authorization: Bearer <access_token>
|
||
Query Parameters:
|
||
- type: string (global, weekly, friends, regional)
|
||
- category: string (overall, dialogue_count, vocabulary_mastered)
|
||
- limit: integer (default: 50)
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"leaderboard_type": "global",
|
||
"category": "overall",
|
||
"period": "all_time",
|
||
"updated_at": "2024-09-05T15:30:00Z",
|
||
"user_rank": {
|
||
"rank": 1247,
|
||
"score": 15680,
|
||
"percentile": 78.5
|
||
},
|
||
"top_users": [
|
||
{
|
||
"rank": 1,
|
||
"user_id": "USR_VIP_001",
|
||
"username": "LanguageMaster",
|
||
"avatar_url": "https://cdn.example.com/avatars/vip001.jpg",
|
||
"score": 45680,
|
||
"level": "C2",
|
||
"country": "TW",
|
||
"streak_days": 365,
|
||
"badges": ["yearly_champion", "perfectionist"]
|
||
}
|
||
],
|
||
"nearby_users": [
|
||
// Users around current user's rank
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 好友排行榜
|
||
```http
|
||
GET /api/v1/leaderboard/friends
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"friends_ranking": [
|
||
{
|
||
"rank": 1,
|
||
"user_id": "USR_12346",
|
||
"username": "StudyBuddy",
|
||
"avatar_url": "https://cdn.example.com/avatars/12346.jpg",
|
||
"score": 18950,
|
||
"level": "B2",
|
||
"status": "online",
|
||
"recent_activity": "完成了商務會議場景 - 2小時前"
|
||
}
|
||
],
|
||
"current_user": {
|
||
"rank": 3,
|
||
"score": 15680,
|
||
"score_difference": -3270, // difference from rank 1
|
||
"rank_change": 1 // compared to last week
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 訂閱與購買 API
|
||
|
||
### 訂閱管理 (Subscription)
|
||
|
||
#### 獲取訂閱方案 *(更新基於新需求)*
|
||
```http
|
||
GET /api/v1/subscriptions/plans
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"plans": [
|
||
{
|
||
"plan_id": "PLAN_MONTHLY",
|
||
"name": "月費會員",
|
||
"description": "解鎖對話訓練功能,享受完整學習體驗",
|
||
"price": {
|
||
"monthly": {
|
||
"amount": 600,
|
||
"currency": "TWD",
|
||
"original_price": 600,
|
||
"test_discount": {
|
||
"percentage": 80,
|
||
"discounted_price": 120,
|
||
"description": "內部測試期間2折優惠"
|
||
}
|
||
}
|
||
},
|
||
"features": [
|
||
"解鎖所有對話訓練關卡",
|
||
"無限制對話練習次數",
|
||
"完整語言程度評估",
|
||
"詳細學習分析報告",
|
||
"優先客服支援"
|
||
],
|
||
"limitations": [
|
||
"訪客可透過設備ID訂閱",
|
||
"不含額外道具和內容包"
|
||
],
|
||
"access_control": {
|
||
"required_for": ["dialogue_training", "conversation_scenarios"],
|
||
"free_access": ["vocabulary_recognition", "vocabulary_fluency", "spaced_review"]
|
||
}
|
||
}
|
||
],
|
||
"current_subscription": {
|
||
"plan_id": "PLAN_MONTHLY",
|
||
"status": "active",
|
||
"expires_at": "2024-10-05T15:30:00Z",
|
||
"auto_renewal": true,
|
||
"payment_method": "credit_card",
|
||
"subscription_source": "device_id" // device_id, registered_account
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 訂閱方案 *(支援訪客訂閱)*
|
||
```http
|
||
POST /api/v1/subscriptions/subscribe
|
||
Authorization: Bearer <access_token> // Optional for guest users
|
||
|
||
{
|
||
"plan_id": "PLAN_MONTHLY",
|
||
"billing_cycle": "monthly",
|
||
"payment_method_id": "pm_1234567890",
|
||
"auto_renewal": true,
|
||
"subscription_context": {
|
||
"trigger_source": "first_vocabulary_completion", // first_vocabulary_completion, settings_page, dialogue_access_blocked
|
||
"device_id": "DEV_iOS_12345", // Required for guest subscription
|
||
"user_type": "guest" // guest, registered
|
||
}
|
||
}
|
||
|
||
Response 201 Created
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"subscription_id": "SUB_20240905_001",
|
||
"plan_id": "PLAN_MONTHLY",
|
||
"status": "active",
|
||
"started_at": "2024-09-05T15:30:00Z",
|
||
"expires_at": "2024-10-05T15:30:00Z",
|
||
"next_billing_date": "2024-10-05T15:30:00Z",
|
||
"amount_paid": 120, // With test discount
|
||
"original_amount": 600,
|
||
"discount_applied": 480,
|
||
"currency": "TWD",
|
||
"subscription_source": "device_id",
|
||
"access_unlocked": {
|
||
"dialogue_training": true,
|
||
"conversation_scenarios": true,
|
||
"premium_content": false
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 檢查訂閱狀態 *(新增 - 對話訓練權限檢查)*
|
||
```http
|
||
GET /api/v1/subscriptions/access-check
|
||
Authorization: Bearer <access_token> // Optional for guest users
|
||
Query Parameters:
|
||
- feature: string (dialogue_training, conversation_scenarios, premium_content)
|
||
- device_id: string (Required if no auth token)
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"has_access": false,
|
||
"subscription_status": "none", // active, expired, none
|
||
"required_plan": "PLAN_MONTHLY",
|
||
"blocking_reason": "subscription_required",
|
||
"subscription_prompt": {
|
||
"title": "解鎖對話訓練功能",
|
||
"message": "對話訓練需要訂閱月費會員才能使用",
|
||
"cta_text": "立即訂閱",
|
||
"special_offer": {
|
||
"discount_percentage": 80,
|
||
"original_price": 600,
|
||
"discounted_price": 120,
|
||
"offer_text": "內部測試期間限時2折優惠!"
|
||
}
|
||
},
|
||
"free_alternatives": [
|
||
{
|
||
"feature": "vocabulary_recognition",
|
||
"description": "免費的詞彙認識練習"
|
||
},
|
||
{
|
||
"feature": "vocabulary_fluency",
|
||
"description": "免費的詞彙熟悉練習"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 內購系統 (Purchase)
|
||
|
||
#### 獲取道具商店內容
|
||
```http
|
||
GET /api/v1/store/items
|
||
Authorization: Bearer <access_token>
|
||
Query Parameters:
|
||
- category: string (power_ups, scenario_pack, expert_course, premium_content)
|
||
- item_type: string (time_extension, life_restore, time_travel, reply_hint)
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"power_up_items": [
|
||
{
|
||
"item_id": "ITEM_TIME_EXT_001",
|
||
"type": "time_extension",
|
||
"name": "加時道具",
|
||
"icon": "🕰️",
|
||
"description": "為對話訓練加時1分3秒",
|
||
"single_price": {
|
||
"amount": 300,
|
||
"currency": "diamonds"
|
||
},
|
||
"bundle_price": {
|
||
"amount": 1200,
|
||
"currency": "diamonds",
|
||
"quantity": 5,
|
||
"discount_percentage": 20
|
||
},
|
||
"usage_limit": null,
|
||
"effects": ["adds_63_seconds"]
|
||
},
|
||
{
|
||
"item_id": "ITEM_REPLY_HINT_001",
|
||
"type": "reply_hint",
|
||
"name": "回覆提示道具",
|
||
"icon": "💡",
|
||
"description": "獲得AI智慧引導,突破對話卡關",
|
||
"single_price": {
|
||
"amount": 30,
|
||
"currency": "diamonds"
|
||
},
|
||
"bundle_price": {
|
||
"amount": 250,
|
||
"currency": "diamonds",
|
||
"quantity": 10,
|
||
"discount_percentage": 17
|
||
},
|
||
"usage_limit": "3_per_dialogue",
|
||
"effects": [
|
||
"partner_intent_analysis",
|
||
"response_thinking_guidance",
|
||
"reply_examples",
|
||
"chinese_to_english_translation"
|
||
]
|
||
},
|
||
{
|
||
"item_id": "ITEM_LIFE_RESTORE_001",
|
||
"type": "life_restore",
|
||
"name": "補命道具",
|
||
"icon": "❤️",
|
||
"description": "為對話學習的時間卡復活1次機會",
|
||
"single_price": {
|
||
"amount": 100,
|
||
"currency": "diamonds"
|
||
},
|
||
"bundle_price": {
|
||
"amount": 400,
|
||
"currency": "diamonds",
|
||
"quantity": 5,
|
||
"discount_percentage": 20
|
||
},
|
||
"usage_limit": null,
|
||
"effects": ["retry_failed_dialogue"]
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 獲取付費內容
|
||
```http
|
||
GET /api/v1/store/content
|
||
Authorization: Bearer <access_token>
|
||
Query Parameters:
|
||
- category: string (scenario_pack, expert_course, premium_content)
|
||
- price_range: string (0-100, 100-500, 500+)
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"content_packs": [
|
||
{
|
||
"content_id": "PACK_TRAVEL_001",
|
||
"type": "scenario_pack",
|
||
"title": "旅遊場景包",
|
||
"description": "包含機場、飯店、觀光等15個實用旅遊場景",
|
||
"price": {
|
||
"amount": 149,
|
||
"currency": "TWD",
|
||
"original_price": 199,
|
||
"discount_percentage": 25
|
||
},
|
||
"content_preview": {
|
||
"scenarios_count": 15,
|
||
"estimated_hours": 8,
|
||
"difficulty_range": "A2-B2",
|
||
"preview_scenario": "SC_AIRPORT_001"
|
||
},
|
||
"thumbnail_url": "https://cdn.example.com/packs/travel.jpg",
|
||
"user_owned": false,
|
||
"special_offer": {
|
||
"expires_at": "2024-09-10T23:59:59Z",
|
||
"offer_text": "限時75折優惠!"
|
||
}
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 購買道具
|
||
```http
|
||
POST /api/v1/store/purchase/item
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"item_id": "ITEM_REPLY_HINT_001",
|
||
"quantity": 1,
|
||
"purchase_type": "single" // single, bundle
|
||
}
|
||
|
||
Response 201 Created
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"purchase_id": "PUR_ITEM_20240905_001",
|
||
"item_id": "ITEM_REPLY_HINT_001",
|
||
"item_name": "回覆提示道具",
|
||
"quantity_purchased": 1,
|
||
"diamonds_spent": 30,
|
||
"transaction_details": {
|
||
"previous_diamond_balance": 1500,
|
||
"current_diamond_balance": 1470,
|
||
"previous_item_count": 0,
|
||
"current_item_count": 1
|
||
},
|
||
"purchased_at": "2024-09-05T16:30:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 購買內容
|
||
```http
|
||
POST /api/v1/store/purchase
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"content_id": "PACK_TRAVEL_001",
|
||
"payment_method_id": "pm_1234567890"
|
||
}
|
||
|
||
Response 201 Created
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"purchase_id": "PUR_20240905_001",
|
||
"content_id": "PACK_TRAVEL_001",
|
||
"amount_paid": 149,
|
||
"currency": "TWD",
|
||
"purchased_at": "2024-09-05T15:45:00Z",
|
||
"content_unlocked": {
|
||
"scenarios": ["SC_AIRPORT_001", "SC_HOTEL_001", "..."],
|
||
"access_expires": null // permanent access
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 廣告系統 (AdImpression)
|
||
|
||
#### 獲取廣告獎勵機會
|
||
```http
|
||
GET /api/v1/ads/opportunities
|
||
Authorization: Bearer <access_token>
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"available_ads": [
|
||
{
|
||
"ad_id": "AD_REWARD_001",
|
||
"type": "video",
|
||
"duration": 30, // seconds
|
||
"reward": {
|
||
"type": "extra_dialogue",
|
||
"quantity": 2,
|
||
"description": "額外2次對話練習機會"
|
||
},
|
||
"cooldown_remaining": 0, // seconds until next ad
|
||
"daily_limit_remaining": 3
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 觀看廣告獲得獎勵
|
||
```http
|
||
POST /api/v1/ads/watch
|
||
Authorization: Bearer <access_token>
|
||
{
|
||
"ad_id": "AD_REWARD_001",
|
||
"watch_duration": 30, // seconds actually watched
|
||
"completion_status": "completed" // completed, skipped, error
|
||
}
|
||
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"reward_granted": {
|
||
"type": "extra_dialogue",
|
||
"quantity": 2,
|
||
"expires_at": "2024-09-06T15:45:00Z"
|
||
},
|
||
"next_ad_available_at": "2024-09-05T16:15:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 錯誤處理
|
||
|
||
### 標準錯誤碼
|
||
```json
|
||
{
|
||
"success": false,
|
||
"error": {
|
||
"code": "VALIDATION_ERROR",
|
||
"message": "輸入資料驗證失敗",
|
||
"details": {
|
||
"field": "email",
|
||
"reason": "invalid_format"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 常見錯誤碼
|
||
- `UNAUTHORIZED` (401): 未授權存取
|
||
- `FORBIDDEN` (403): 權限不足
|
||
- `NOT_FOUND` (404): 資源不存在
|
||
- `VALIDATION_ERROR` (400): 資料驗證失敗
|
||
- `RATE_LIMIT_EXCEEDED` (429): 超過速率限制
|
||
- `INTERNAL_SERVER_ERROR` (500): 伺服器內部錯誤
|
||
- `SERVICE_UNAVAILABLE` (503): 服務暫時不可用
|
||
|
||
### 訂閱相關錯誤
|
||
- `SUBSCRIPTION_REQUIRED`: 需要訂閱才能存取
|
||
- `SUBSCRIPTION_EXPIRED`: 訂閱已過期
|
||
- `PAYMENT_FAILED`: 付款處理失敗
|
||
- `CONTENT_NOT_PURCHASED`: 內容未購買
|
||
|
||
### 回覆輔助相關錯誤
|
||
- `INSUFFICIENT_REPLY_HINTS`: 回覆提示道具不足
|
||
- `DAILY_HINT_LIMIT_EXCEEDED`: 超過每日提示使用限制
|
||
- `DIALOGUE_HINT_LIMIT_EXCEEDED`: 超過單次對話提示使用限制
|
||
- `TRANSLATION_SERVICE_ERROR`: 翻譯服務錯誤
|
||
- `AI_ASSISTANCE_UNAVAILABLE`: AI輔助服務暫時不可用
|
||
|
||
### 道具系統相關錯誤
|
||
- `INSUFFICIENT_DIAMONDS`: 鑽石不足
|
||
- `ITEM_NOT_AVAILABLE`: 道具不可購買
|
||
- `ITEM_USAGE_LIMIT_REACHED`: 道具使用次數已達上限
|
||
- `INVALID_ITEM_QUANTITY`: 無效的道具數量
|
||
|
||
### 命條系統相關錯誤
|
||
- `INSUFFICIENT_LIFE_POINTS`: 命條不足,無法開始關卡
|
||
- `LIFE_POINTS_AT_MAXIMUM`: 命條已滿,無法恢復更多
|
||
- `RECOVERY_COOLDOWN_ACTIVE`: 恢復冷卻時間未結束
|
||
- `AD_WATCH_LIMIT_EXCEEDED`: 超過每日觀看廣告次數限制
|
||
- `LIFE_POINTS_PURCHASE_FAILED`: 命條購買失敗
|
||
|
||
### 詞彙學習系統相關錯誤
|
||
- `VOCABULARY_STAGE_LOCKED`: 詞彙學習階段未解鎖
|
||
- `VOCABULARY_NOT_FOUND`: 詞彙不存在
|
||
- `INVALID_LEARNING_STAGE`: 無效的學習階段
|
||
- `SPACED_REPETITION_ALGORITHM_ERROR`: 間隔複習算法計算錯誤
|
||
- `VOCABULARY_PROGRESS_SYNC_FAILED`: 詞彙進度同步失敗
|
||
|
||
### 時光挑戰相關錯誤
|
||
- `INSUFFICIENT_TIME_SCROLLS`: 時光卷不足
|
||
- `TIME_CHALLENGE_NOT_AVAILABLE`: 時光挑戰不可用
|
||
- `CHALLENGE_ALREADY_IN_PROGRESS`: 已有進行中的挑戰
|
||
- `CHALLENGE_TIME_EXPIRED`: 挑戰時間已過期
|
||
- `CHALLENGE_SESSION_INVALID`: 無效的挑戰會話
|
||
- `CHALLENGE_REQUIREMENTS_NOT_MET`: 不滿足挑戰要求
|
||
|
||
### 特殊任務系統相關錯誤 *(新增)*
|
||
- `MISSION_NOT_AVAILABLE`: 任務不可用或已完成
|
||
- `MISSION_REQUIREMENTS_NOT_MET`: 不滿足任務要求
|
||
- `MISSION_ALREADY_COMPLETED`: 任務已經完成
|
||
- `MISSION_EXPIRED`: 任務已過期
|
||
- `MISSION_REWARD_ALREADY_CLAIMED`: 任務獎勵已領取
|
||
- `INVALID_MISSION_COMPLETION_DATA`: 無效的任務完成數據
|
||
- `MISSION_RESET_FAILED`: 任務重置失敗
|
||
|
||
### 語言程度晉階相關錯誤 *(新增)*
|
||
- `LANGUAGE_LEVEL_NOT_FOUND`: 語言程度不存在
|
||
- `ADVANCEMENT_REQUIREMENTS_NOT_MET`: 不滿足晉階條件
|
||
- `ADVANCEMENT_ALREADY_COMPLETED`: 晉階已經完成
|
||
- `INVALID_PERFECT_DIALOGUE_DATA`: 無效的滿星對話數據
|
||
- `LEVEL_CALCULATION_ERROR`: 程度計算錯誤
|
||
- `ADVANCEMENT_CEREMONY_FAILED`: 晉階儀式顯示失敗
|
||
- `LEVEL_PROGRESS_SYNC_FAILED`: 程度進度同步失敗
|
||
|
||
### 訂閱系統相關錯誤 *(新增)*
|
||
- `SUBSCRIPTION_ACCESS_DENIED`: 訂閱權限不足
|
||
- `GUEST_SUBSCRIPTION_FAILED`: 訪客訂閱失敗
|
||
- `DEVICE_ID_REQUIRED`: 需要設備ID進行訂閱
|
||
- `SUBSCRIPTION_DISCOUNT_EXPIRED`: 訂閱優惠已過期
|
||
- `SUBSCRIPTION_PLAN_NOT_FOUND`: 訂閱方案不存在
|
||
- `FEATURE_REQUIRES_SUBSCRIPTION`: 功能需要訂閱權限
|
||
|
||
---
|
||
|
||
## API 版本控制與部署
|
||
|
||
### 版本控制策略
|
||
- [ ] **URL版本控制**: `/api/v1/`, `/api/v2/`
|
||
- [ ] **向後相容**: 新版本保持向後相容性
|
||
- [ ] **廢棄通知**: 提前6個月通知API廢棄
|
||
- [ ] **多版本支援**: 同時支援2-3個版本
|
||
- [ ] **版本文檔**: 每個版本維護獨立文檔
|
||
|
||
### 環境配置
|
||
```bash
|
||
# 開發環境
|
||
API_BASE_URL=https://dev-api.dramaling.com
|
||
API_VERSION=v1
|
||
|
||
# 測試環境
|
||
API_BASE_URL=https://staging-api.dramaling.com
|
||
API_VERSION=v1
|
||
|
||
# 生產環境
|
||
API_BASE_URL=https://api.dramaling.com
|
||
API_VERSION=v1
|
||
```
|
||
|
||
### 效能考量
|
||
- [ ] **回應時間**: 95%的API請求在200ms內回應
|
||
- [ ] **快取策略**: 靜態內容使用CDN,動態內容使用Redis
|
||
- [ ] **資料庫優化**: 適當的索引和查詢優化
|
||
- [ ] **負載平衡**: 水平擴展API服務器
|
||
- [ ] **監控告警**: API效能和錯誤率監控
|
||
|
||
---
|
||
|
||
## 待完成任務
|
||
|
||
### 高優先級
|
||
1. [ ] 完善所有API端點的詳細規格和範例
|
||
2. [ ] 設計API的認證和授權機制
|
||
3. [ ] 實現訂閱系統的付款流程和權限控制 *(新增)*
|
||
4. [ ] 完善語言程度晉階算法的API實現 *(新增)*
|
||
5. [ ] 建立API文檔的自動生成和維護流程
|
||
6. [ ] 實現API的錯誤處理和驗證邏輯
|
||
|
||
### 中優先級
|
||
1. [ ] 設計特殊任務系統的績效追蹤和分析API *(新增)*
|
||
2. [ ] 實現訂閱系統與對話訓練的權限整合 *(新增)*
|
||
3. [ ] 建立語言程度評估標準的動態調整機制 *(新增)*
|
||
4. [ ] 設計API的快取和效能優化策略
|
||
5. [ ] 建立API的測試套件和自動化測試
|
||
6. [ ] 規劃API的版本控制和遷移策略
|
||
7. [ ] 設計API的監控和分析系統
|
||
|
||
### 低優先級
|
||
1. [ ] 研究GraphQL作為REST API的補充
|
||
2. [ ] 探索Real-time API (WebSocket) 的應用場景
|
||
3. [ ] 建立多語言程度並行學習的API架構 *(新增)*
|
||
4. [ ] 設計個人化任務推薦系統API *(新增)*
|
||
5. [ ] 建立API的開發者工具和SDK
|
||
6. [ ] 設計第三方整合的API授權機制
|
||
|
||
### 新功能整合相關 *(新增類別)*
|
||
1. [ ] 訂閱系統與現有付費功能的整合測試
|
||
2. [ ] 特殊任務系統與遊戲化元素的API整合
|
||
3. [ ] 語言程度系統與學習路徑規劃的API對接
|
||
4. [ ] 三大新系統間的數據一致性保證機制
|
||
5. [ ] 新功能的A/B測試API設計和實現
|
||
|
||
---
|
||
|
||
**最後更新**: 2024年9月5日
|
||
**負責人**: 待分配
|
||
**審查週期**: 每兩週檢討一次 |