dramaling-vocab-learning/docs/03_development/api/supabase-schema.md

242 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Supabase 資料庫架構文檔
## 資料表結構
### 1. profiles 表
用戶基本資料表,與 auth.users 關聯
| 欄位 | 類型 | 說明 | 限制 |
|-----|------|------|------|
| id | UUID | 用戶ID | PRIMARY KEY, 關聯 auth.users |
| email | TEXT | Email | UNIQUE |
| username | TEXT | 用戶名稱 | 可選 |
| created_at | TIMESTAMP | 建立時間 | 自動產生 |
| updated_at | TIMESTAMP | 更新時間 | 自動更新 |
### 2. flashcards 表
詞卡資料表,儲存所有詞卡內容
| 欄位 | 類型 | 說明 | 限制 |
|-----|------|------|------|
| id | UUID | 詞卡ID | PRIMARY KEY |
| user_id | UUID | 擁有者ID | FOREIGN KEY → profiles |
| word | VARCHAR(255) | 單字/片語 | NOT NULL |
| translation | TEXT | 中文翻譯 | |
| context | TEXT | 使用情境 | |
| example | TEXT | 例句 | |
| pronunciation | TEXT | 發音/音標 | |
| difficulty | INTEGER | 難度等級 | 1-5, DEFAULT 3 |
| next_review_date | DATE | 下次複習日期 | DEFAULT 今天 |
| review_count | INTEGER | 複習次數 | DEFAULT 0 |
| ease_factor | DECIMAL(3,2) | SM-2 難度係數 | DEFAULT 2.5 |
| interval | INTEGER | 複習間隔(天) | DEFAULT 1 |
| created_at | TIMESTAMP | 建立時間 | 自動產生 |
| updated_at | TIMESTAMP | 更新時間 | 自動更新 |
### 3. study_sessions 表
學習記錄表,追蹤每次複習
| 欄位 | 類型 | 說明 | 限制 |
|-----|------|------|------|
| id | UUID | 記錄ID | PRIMARY KEY |
| user_id | UUID | 用戶ID | FOREIGN KEY → profiles |
| flashcard_id | UUID | 詞卡ID | FOREIGN KEY → flashcards |
| rating | INTEGER | 評分 | 1-5 (1=完全忘記, 5=非常簡單) |
| studied_at | TIMESTAMP | 學習時間 | 自動產生 |
### 4. tags 表
標籤表,用於分類詞卡
| 欄位 | 類型 | 說明 | 限制 |
|-----|------|------|------|
| id | UUID | 標籤ID | PRIMARY KEY |
| name | VARCHAR(100) | 標籤名稱 | NOT NULL |
| user_id | UUID | 建立者ID | FOREIGN KEY → profiles |
| created_at | TIMESTAMP | 建立時間 | 自動產生 |
### 5. flashcard_tags 表
詞卡-標籤關聯表
| 欄位 | 類型 | 說明 | 限制 |
|-----|------|------|------|
| flashcard_id | UUID | 詞卡ID | FOREIGN KEY → flashcards |
| tag_id | UUID | 標籤ID | FOREIGN KEY → tags |
PRIMARY KEY: (flashcard_id, tag_id)
## Row Level Security (RLS) 政策
### profiles 表政策
```sql
-- 用戶只能查看自己的資料
SELECT: auth.uid() = id
-- 用戶只能更新自己的資料
UPDATE: auth.uid() = id
```
### flashcards 表政策
```sql
-- 用戶只能查看自己的詞卡
SELECT: auth.uid() = user_id
-- 用戶只能建立屬於自己的詞卡
INSERT: auth.uid() = user_id
-- 用戶只能更新自己的詞卡
UPDATE: auth.uid() = user_id
-- 用戶只能刪除自己的詞卡
DELETE: auth.uid() = user_id
```
### study_sessions 表政策
```sql
-- 用戶只能查看自己的學習記錄
SELECT: auth.uid() = user_id
-- 用戶只能建立自己的學習記錄
INSERT: auth.uid() = user_id
```
### tags 表政策
```sql
-- 用戶只能查看自己的標籤
SELECT: auth.uid() = user_id
-- 用戶只能建立屬於自己的標籤
INSERT: auth.uid() = user_id
-- 用戶只能更新自己的標籤
UPDATE: auth.uid() = user_id
-- 用戶只能刪除自己的標籤
DELETE: auth.uid() = user_id
```
## 資料庫函數
### handle_new_user()
自動為新註冊用戶建立 profile
```sql
CREATE OR REPLACE FUNCTION handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.profiles (id, email)
VALUES (new.id, new.email);
RETURN new;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
```
### update_updated_at()
自動更新 updated_at 欄位
```sql
CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = TIMEZONE('utc'::text, NOW());
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
```
## 觸發器
### on_auth_user_created
新用戶註冊時自動建立 profile
```sql
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW EXECUTE FUNCTION handle_new_user();
```
### update_flashcards_updated_at
更新詞卡時自動更新 updated_at
```sql
CREATE TRIGGER update_flashcards_updated_at
BEFORE UPDATE ON flashcards
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
```
## 索引建議
為了優化查詢效能,建議建立以下索引:
```sql
-- 詞卡查詢優化
CREATE INDEX idx_flashcards_user_id ON flashcards(user_id);
CREATE INDEX idx_flashcards_next_review ON flashcards(user_id, next_review_date);
-- 學習記錄查詢優化
CREATE INDEX idx_study_sessions_user_id ON study_sessions(user_id);
CREATE INDEX idx_study_sessions_flashcard_id ON study_sessions(flashcard_id);
CREATE INDEX idx_study_sessions_studied_at ON study_sessions(user_id, studied_at DESC);
-- 標籤查詢優化
CREATE INDEX idx_tags_user_id ON tags(user_id);
CREATE INDEX idx_flashcard_tags_flashcard ON flashcard_tags(flashcard_id);
CREATE INDEX idx_flashcard_tags_tag ON flashcard_tags(tag_id);
```
## 常用查詢範例
### 取得今日需要複習的詞卡
```sql
SELECT * FROM flashcards
WHERE user_id = auth.uid()
AND next_review_date <= CURRENT_DATE
ORDER BY next_review_date ASC, difficulty DESC;
```
### 取得用戶學習統計
```sql
SELECT
COUNT(DISTINCT flashcard_id) as total_reviewed,
COUNT(*) as total_reviews,
DATE(studied_at) as study_date
FROM study_sessions
WHERE user_id = auth.uid()
AND studied_at >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY DATE(studied_at)
ORDER BY study_date DESC;
```
### 取得詞卡及其標籤
```sql
SELECT
f.*,
ARRAY_AGG(t.name) as tags
FROM flashcards f
LEFT JOIN flashcard_tags ft ON f.id = ft.flashcard_id
LEFT JOIN tags t ON ft.tag_id = t.id
WHERE f.user_id = auth.uid()
GROUP BY f.id;
```
## 資料備份策略
1. **自動備份**: Supabase 提供每日自動備份Pro 計劃)
2. **手動備份**: 定期匯出重要資料表
3. **備份腳本**:
```bash
# 匯出資料
pg_dump -h [SUPABASE_HOST] -U postgres -d postgres > backup.sql
# 還原資料
psql -h [SUPABASE_HOST] -U postgres -d postgres < backup.sql
```
## 效能監控
定期檢查以下指標:
- 查詢執行時間
- 索引使用率
- 資料表大小
- 連線數量
使用 Supabase Dashboard 的 Database Health 功能監控資料庫狀態。