242 lines
6.1 KiB
Markdown
242 lines
6.1 KiB
Markdown
# 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 功能監控資料庫狀態。 |