742 lines
12 KiB
Markdown
742 lines
12 KiB
Markdown
# DramaLing API 端點詳細規格
|
|
|
|
## 🌐 API 基礎設定
|
|
|
|
### Base URL
|
|
```
|
|
Development: http://localhost:3000/api
|
|
Production: https://api.dramaling.com
|
|
```
|
|
|
|
### 認證方式
|
|
```http
|
|
Authorization: Bearer <JWT_TOKEN>
|
|
```
|
|
|
|
### 響應格式
|
|
```typescript
|
|
interface ApiResponse<T> {
|
|
success: boolean
|
|
data?: T
|
|
error?: {
|
|
code: string
|
|
message: string
|
|
details?: any
|
|
}
|
|
meta?: {
|
|
pagination?: {
|
|
page: number
|
|
limit: number
|
|
total: number
|
|
totalPages: number
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## 🔐 認證 API
|
|
|
|
### POST /api/auth/register
|
|
**註冊新用戶**
|
|
|
|
```typescript
|
|
// Request
|
|
interface RegisterRequest {
|
|
email: string
|
|
username: string
|
|
password: string
|
|
confirmPassword: string
|
|
}
|
|
|
|
// Response
|
|
interface RegisterResponse {
|
|
user: {
|
|
id: string
|
|
email: string
|
|
username: string
|
|
}
|
|
message: string
|
|
}
|
|
|
|
// Validation
|
|
- email: valid email format
|
|
- username: 3-20 characters, alphanumeric and underscore
|
|
- password: min 8 chars, must contain uppercase, lowercase, number
|
|
- confirmPassword: must match password
|
|
```
|
|
|
|
### POST /api/auth/login
|
|
**用戶登入**
|
|
|
|
```typescript
|
|
// Request
|
|
interface LoginRequest {
|
|
email: string
|
|
password: string
|
|
rememberMe?: boolean
|
|
}
|
|
|
|
// Response
|
|
interface LoginResponse {
|
|
user: User
|
|
accessToken: string
|
|
refreshToken: string
|
|
expiresIn: number
|
|
}
|
|
|
|
// Error codes
|
|
- INVALID_CREDENTIALS: 帳號或密碼錯誤
|
|
- ACCOUNT_LOCKED: 帳號被鎖定
|
|
- EMAIL_NOT_VERIFIED: Email 未驗證
|
|
```
|
|
|
|
### POST /api/auth/logout
|
|
**登出**
|
|
|
|
```typescript
|
|
// Request
|
|
interface LogoutRequest {
|
|
refreshToken?: string
|
|
allDevices?: boolean
|
|
}
|
|
|
|
// Response
|
|
interface LogoutResponse {
|
|
message: string
|
|
}
|
|
```
|
|
|
|
### POST /api/auth/refresh
|
|
**更新 Token**
|
|
|
|
```typescript
|
|
// Request
|
|
interface RefreshRequest {
|
|
refreshToken: string
|
|
}
|
|
|
|
// Response
|
|
interface RefreshResponse {
|
|
accessToken: string
|
|
refreshToken: string
|
|
expiresIn: number
|
|
}
|
|
```
|
|
|
|
### POST /api/auth/verify-email
|
|
**驗證 Email**
|
|
|
|
```typescript
|
|
// Request
|
|
interface VerifyEmailRequest {
|
|
token: string
|
|
}
|
|
|
|
// Response
|
|
interface VerifyEmailResponse {
|
|
message: string
|
|
user: User
|
|
}
|
|
```
|
|
|
|
### POST /api/auth/forgot-password
|
|
**忘記密碼**
|
|
|
|
```typescript
|
|
// Request
|
|
interface ForgotPasswordRequest {
|
|
email: string
|
|
}
|
|
|
|
// Response
|
|
interface ForgotPasswordResponse {
|
|
message: string
|
|
}
|
|
```
|
|
|
|
### POST /api/auth/reset-password
|
|
**重設密碼**
|
|
|
|
```typescript
|
|
// Request
|
|
interface ResetPasswordRequest {
|
|
token: string
|
|
newPassword: string
|
|
confirmPassword: string
|
|
}
|
|
|
|
// Response
|
|
interface ResetPasswordResponse {
|
|
message: string
|
|
}
|
|
```
|
|
|
|
### POST /api/auth/google
|
|
**Google OAuth**
|
|
|
|
```typescript
|
|
// Request
|
|
interface GoogleAuthRequest {
|
|
idToken: string
|
|
}
|
|
|
|
// Response
|
|
interface GoogleAuthResponse {
|
|
user: User
|
|
accessToken: string
|
|
refreshToken: string
|
|
isNewUser: boolean
|
|
}
|
|
```
|
|
|
|
## 🎃 用戶 API
|
|
|
|
### GET /api/users/profile
|
|
**獲取用戶資料**
|
|
|
|
```typescript
|
|
// Response
|
|
interface ProfileResponse {
|
|
user: User
|
|
profile: UserProfile
|
|
stats: UserStats
|
|
}
|
|
```
|
|
|
|
### PUT /api/users/profile
|
|
**更新用戶資料**
|
|
|
|
```typescript
|
|
// Request
|
|
interface UpdateProfileRequest {
|
|
username?: string
|
|
displayName?: string
|
|
bio?: string
|
|
avatar?: File
|
|
preferredLanguage?: string
|
|
timezone?: string
|
|
}
|
|
|
|
// Response
|
|
interface UpdateProfileResponse {
|
|
user: User
|
|
message: string
|
|
}
|
|
```
|
|
|
|
### PUT /api/users/settings
|
|
**更新用戶設定**
|
|
|
|
```typescript
|
|
// Request
|
|
interface UpdateSettingsRequest {
|
|
dailyGoal?: number
|
|
reminderEnabled?: boolean
|
|
reminderTime?: string
|
|
emailNotifications?: boolean
|
|
pushNotifications?: boolean
|
|
theme?: 'light' | 'dark' | 'auto'
|
|
studyMode?: 'flip' | 'quiz' | 'typing'
|
|
}
|
|
```
|
|
|
|
### DELETE /api/users/account
|
|
**刪除帳號**
|
|
|
|
```typescript
|
|
// Request
|
|
interface DeleteAccountRequest {
|
|
password: string
|
|
reason?: string
|
|
}
|
|
|
|
// Response
|
|
interface DeleteAccountResponse {
|
|
message: string
|
|
}
|
|
```
|
|
|
|
## 🎓 詞卡 API
|
|
|
|
### GET /api/flashcard-sets
|
|
**獲取卡組列表**
|
|
|
|
```typescript
|
|
// Query parameters
|
|
interface GetSetsQuery {
|
|
page?: number
|
|
limit?: number
|
|
search?: string
|
|
tags?: string[]
|
|
orderBy?: 'created' | 'updated' | 'name' | 'progress'
|
|
order?: 'asc' | 'desc'
|
|
}
|
|
|
|
// Response
|
|
interface GetSetsResponse {
|
|
sets: FlashcardSet[]
|
|
pagination: Pagination
|
|
}
|
|
```
|
|
|
|
### POST /api/flashcard-sets
|
|
**創建卡組**
|
|
|
|
```typescript
|
|
// Request
|
|
interface CreateSetRequest {
|
|
name: string
|
|
description?: string
|
|
color?: string
|
|
tags?: string[]
|
|
isPublic?: boolean
|
|
}
|
|
|
|
// Response
|
|
interface CreateSetResponse {
|
|
set: FlashcardSet
|
|
}
|
|
```
|
|
|
|
### GET /api/flashcard-sets/:setId
|
|
**獲取卡組詳情**
|
|
|
|
```typescript
|
|
// Response
|
|
interface GetSetDetailResponse {
|
|
set: FlashcardSet
|
|
cards: Flashcard[]
|
|
stats: SetStats
|
|
}
|
|
```
|
|
|
|
### PUT /api/flashcard-sets/:setId
|
|
**更新卡組**
|
|
|
|
```typescript
|
|
// Request
|
|
interface UpdateSetRequest {
|
|
name?: string
|
|
description?: string
|
|
color?: string
|
|
tags?: string[]
|
|
isPublic?: boolean
|
|
}
|
|
```
|
|
|
|
### DELETE /api/flashcard-sets/:setId
|
|
**刪除卡組**
|
|
|
|
```typescript
|
|
// Response
|
|
interface DeleteSetResponse {
|
|
message: string
|
|
deletedCount: number
|
|
}
|
|
```
|
|
|
|
### GET /api/flashcards
|
|
**獲取詞卡列表**
|
|
|
|
```typescript
|
|
// Query parameters
|
|
interface GetCardsQuery {
|
|
setId?: string
|
|
search?: string
|
|
tags?: string[]
|
|
difficulty?: 'beginner' | 'intermediate' | 'advanced'
|
|
mastered?: boolean
|
|
favorite?: boolean
|
|
dueForReview?: boolean
|
|
page?: number
|
|
limit?: number
|
|
}
|
|
|
|
// Response
|
|
interface GetCardsResponse {
|
|
cards: Flashcard[]
|
|
pagination: Pagination
|
|
}
|
|
```
|
|
|
|
### POST /api/flashcards
|
|
**創建詞卡**
|
|
|
|
```typescript
|
|
// Request
|
|
interface CreateCardRequest {
|
|
setId: string
|
|
word: string
|
|
translation: string
|
|
partOfSpeech?: string
|
|
pronunciation?: string
|
|
definition?: string
|
|
exampleSentence?: string
|
|
exampleTranslation?: string
|
|
synonyms?: string[]
|
|
tags?: string[]
|
|
difficulty?: 'beginner' | 'intermediate' | 'advanced'
|
|
}
|
|
|
|
// Response
|
|
interface CreateCardResponse {
|
|
card: Flashcard
|
|
}
|
|
```
|
|
|
|
### PUT /api/flashcards/:cardId
|
|
**更新詞卡**
|
|
|
|
```typescript
|
|
// Request - same as CreateCardRequest but all fields optional
|
|
```
|
|
|
|
### DELETE /api/flashcards/:cardId
|
|
**刪除詞卡**
|
|
|
|
### POST /api/flashcards/batch
|
|
**批量操作**
|
|
|
|
```typescript
|
|
// Request
|
|
interface BatchOperationRequest {
|
|
operation: 'create' | 'update' | 'delete' | 'move'
|
|
cardIds?: string[]
|
|
data?: any
|
|
targetSetId?: string
|
|
}
|
|
|
|
// Response
|
|
interface BatchOperationResponse {
|
|
success: number
|
|
failed: number
|
|
errors?: any[]
|
|
}
|
|
```
|
|
|
|
## 🤖 AI 生成 API
|
|
|
|
### POST /api/ai/generate
|
|
**AI 生成詞卡**
|
|
|
|
```typescript
|
|
// Request
|
|
interface GenerateRequest {
|
|
mode: 'text' | 'theme'
|
|
input: string // text content or theme name
|
|
difficulty: 'beginner' | 'intermediate' | 'advanced'
|
|
count: number // 5-20
|
|
includeExamples?: boolean
|
|
includeSynonyms?: boolean
|
|
}
|
|
|
|
// Response
|
|
interface GenerateResponse {
|
|
cards: GeneratedCard[]
|
|
usage: {
|
|
promptTokens: number
|
|
completionTokens: number
|
|
totalTokens: number
|
|
}
|
|
}
|
|
|
|
interface GeneratedCard {
|
|
word: string
|
|
translation: string
|
|
partOfSpeech: string
|
|
pronunciation: string
|
|
definition: string
|
|
example: string
|
|
exampleTranslation: string
|
|
synonyms: string[]
|
|
difficulty: string
|
|
confidence: number // 0-1
|
|
}
|
|
```
|
|
|
|
### POST /api/ai/analyze-text
|
|
**分析文本難度**
|
|
|
|
```typescript
|
|
// Request
|
|
interface AnalyzeTextRequest {
|
|
text: string
|
|
}
|
|
|
|
// Response
|
|
interface AnalyzeTextResponse {
|
|
difficulty: 'beginner' | 'intermediate' | 'advanced'
|
|
wordCount: number
|
|
uniqueWords: number
|
|
averageSentenceLength: number
|
|
readabilityScore: number
|
|
suggestedWords: string[]
|
|
}
|
|
```
|
|
|
|
### GET /api/ai/quota
|
|
**查詢 AI 使用額度**
|
|
|
|
```typescript
|
|
// Response
|
|
interface QuotaResponse {
|
|
used: number
|
|
limit: number
|
|
resetAt: string
|
|
isPremium: boolean
|
|
}
|
|
```
|
|
|
|
## 📚 學習 API
|
|
|
|
### GET /api/learning/due
|
|
**獲取待複習詞卡**
|
|
|
|
```typescript
|
|
// Query parameters
|
|
interface GetDueCardsQuery {
|
|
setId?: string
|
|
limit?: number
|
|
}
|
|
|
|
// Response
|
|
interface GetDueCardsResponse {
|
|
cards: StudyCard[]
|
|
totalDue: number
|
|
}
|
|
|
|
interface StudyCard extends Flashcard {
|
|
learningRecord: LearningRecord
|
|
}
|
|
```
|
|
|
|
### POST /api/learning/review
|
|
**提交評分**
|
|
|
|
```typescript
|
|
// Request
|
|
interface ReviewRequest {
|
|
cardId: string
|
|
rating: 1 | 2 | 3 | 4 | 5
|
|
responseTime: number // milliseconds
|
|
mode: 'flip' | 'quiz' | 'typing'
|
|
}
|
|
|
|
// Response
|
|
interface ReviewResponse {
|
|
nextReviewDate: string
|
|
interval: number
|
|
easeFactor: number
|
|
masteryLevel: number
|
|
}
|
|
```
|
|
|
|
### GET /api/learning/stats
|
|
**獲取學習統計**
|
|
|
|
```typescript
|
|
// Query parameters
|
|
interface GetStatsQuery {
|
|
period: 'today' | 'week' | 'month' | 'year' | 'all'
|
|
setId?: string
|
|
}
|
|
|
|
// Response
|
|
interface StatsResponse {
|
|
cardsReviewed: number
|
|
cardsLearned: number
|
|
cardsMastered: number
|
|
studyTime: number // minutes
|
|
accuracy: number // percentage
|
|
streak: number
|
|
dailyGoalProgress: number
|
|
chart: {
|
|
dates: string[]
|
|
values: number[]
|
|
}
|
|
}
|
|
```
|
|
|
|
### POST /api/learning/session/start
|
|
**開始學習會話**
|
|
|
|
```typescript
|
|
// Request
|
|
interface StartSessionRequest {
|
|
mode: 'review' | 'learn' | 'cram'
|
|
setId?: string
|
|
}
|
|
|
|
// Response
|
|
interface StartSessionResponse {
|
|
sessionId: string
|
|
cards: StudyCard[]
|
|
}
|
|
```
|
|
|
|
### POST /api/learning/session/end
|
|
**結束學習會話**
|
|
|
|
```typescript
|
|
// Request
|
|
interface EndSessionRequest {
|
|
sessionId: string
|
|
}
|
|
|
|
// Response
|
|
interface EndSessionResponse {
|
|
duration: number
|
|
cardsStudied: number
|
|
accuracy: number
|
|
xpEarned: number
|
|
achievements: Achievement[]
|
|
}
|
|
```
|
|
|
|
## 🏆 成就 API
|
|
|
|
### GET /api/achievements
|
|
**獲取成就列表**
|
|
|
|
```typescript
|
|
// Response
|
|
interface GetAchievementsResponse {
|
|
unlocked: Achievement[]
|
|
locked: Achievement[]
|
|
recent: Achievement[]
|
|
}
|
|
```
|
|
|
|
### POST /api/achievements/:achievementId/claim
|
|
**領取成就獎勵**
|
|
|
|
```typescript
|
|
// Response
|
|
interface ClaimAchievementResponse {
|
|
xpEarned: number
|
|
totalXp: number
|
|
newLevel?: number
|
|
}
|
|
```
|
|
|
|
## 🔔 通知 API
|
|
|
|
### GET /api/notifications
|
|
**獲取通知**
|
|
|
|
```typescript
|
|
// Query parameters
|
|
interface GetNotificationsQuery {
|
|
unreadOnly?: boolean
|
|
type?: string
|
|
page?: number
|
|
limit?: number
|
|
}
|
|
|
|
// Response
|
|
interface GetNotificationsResponse {
|
|
notifications: Notification[]
|
|
unreadCount: number
|
|
pagination: Pagination
|
|
}
|
|
```
|
|
|
|
### PUT /api/notifications/:notificationId/read
|
|
**標記已讀**
|
|
|
|
### PUT /api/notifications/read-all
|
|
**全部標記已讀**
|
|
|
|
### DELETE /api/notifications/:notificationId
|
|
**刪除通知**
|
|
|
|
## 📁 匯出/匯入 API
|
|
|
|
### GET /api/export/cards
|
|
**匯出詞卡**
|
|
|
|
```typescript
|
|
// Query parameters
|
|
interface ExportQuery {
|
|
format: 'csv' | 'json' | 'anki'
|
|
setId?: string
|
|
cardIds?: string[]
|
|
}
|
|
|
|
// Response: File download
|
|
```
|
|
|
|
### POST /api/import/cards
|
|
**匯入詞卡**
|
|
|
|
```typescript
|
|
// Request: FormData with file
|
|
interface ImportRequest {
|
|
file: File
|
|
setId: string
|
|
format: 'csv' | 'json' | 'anki'
|
|
duplicateStrategy: 'skip' | 'replace' | 'create'
|
|
}
|
|
|
|
// Response
|
|
interface ImportResponse {
|
|
imported: number
|
|
skipped: number
|
|
errors: any[]
|
|
}
|
|
```
|
|
|
|
## 🔒 錯誤碼規範
|
|
|
|
```typescript
|
|
enum ErrorCode {
|
|
// Authentication
|
|
AUTH_INVALID_TOKEN = 'AUTH001',
|
|
AUTH_TOKEN_EXPIRED = 'AUTH002',
|
|
AUTH_UNAUTHORIZED = 'AUTH003',
|
|
|
|
// Validation
|
|
VALIDATION_ERROR = 'VAL001',
|
|
INVALID_INPUT = 'VAL002',
|
|
|
|
// Resource
|
|
NOT_FOUND = 'RES001',
|
|
ALREADY_EXISTS = 'RES002',
|
|
|
|
// Rate Limit
|
|
RATE_LIMIT_EXCEEDED = 'RATE001',
|
|
QUOTA_EXCEEDED = 'RATE002',
|
|
|
|
// Server
|
|
INTERNAL_ERROR = 'SRV001',
|
|
SERVICE_UNAVAILABLE = 'SRV002',
|
|
}
|
|
```
|
|
|
|
## 📊 Rate Limiting
|
|
|
|
| Endpoint | Free User | Premium User |
|
|
|----------|-----------|-------------|
|
|
| AI Generate | 50/day | Unlimited |
|
|
| API Calls | 1000/hour | 10000/hour |
|
|
| File Upload | 10MB | 50MB |
|
|
| Export | 5/day | Unlimited |
|
|
|
|
## 🔧 Webhooks
|
|
|
|
### 可用 Webhooks
|
|
1. `user.created` - 新用戶註冊
|
|
2. `user.deleted` - 用戶刪除
|
|
3. `subscription.created` - 訂閱創建
|
|
4. `subscription.updated` - 訂閱更新
|
|
5. `achievement.unlocked` - 成就解鎖
|
|
|
|
### Webhook Payload
|
|
```typescript
|
|
interface WebhookPayload {
|
|
event: string
|
|
timestamp: string
|
|
data: any
|
|
signature: string
|
|
}
|
|
``` |