6.1 KiB
6.1 KiB
Supabase 資料庫架構文檔
資料表結構
1. profiles 表
用戶基本資料表,與 auth.users 關聯
| 欄位 | 類型 | 說明 | 限制 |
|---|---|---|---|
| id | UUID | 用戶ID | PRIMARY KEY, 關聯 auth.users |
| TEXT | 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 表政策
-- 用戶只能查看自己的資料
SELECT: auth.uid() = id
-- 用戶只能更新自己的資料
UPDATE: auth.uid() = id
flashcards 表政策
-- 用戶只能查看自己的詞卡
SELECT: auth.uid() = user_id
-- 用戶只能建立屬於自己的詞卡
INSERT: auth.uid() = user_id
-- 用戶只能更新自己的詞卡
UPDATE: auth.uid() = user_id
-- 用戶只能刪除自己的詞卡
DELETE: auth.uid() = user_id
study_sessions 表政策
-- 用戶只能查看自己的學習記錄
SELECT: auth.uid() = user_id
-- 用戶只能建立自己的學習記錄
INSERT: auth.uid() = user_id
tags 表政策
-- 用戶只能查看自己的標籤
SELECT: auth.uid() = user_id
-- 用戶只能建立屬於自己的標籤
INSERT: auth.uid() = user_id
-- 用戶只能更新自己的標籤
UPDATE: auth.uid() = user_id
-- 用戶只能刪除自己的標籤
DELETE: auth.uid() = user_id
資料庫函數
handle_new_user()
自動為新註冊用戶建立 profile
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 欄位
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
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
CREATE TRIGGER update_flashcards_updated_at
BEFORE UPDATE ON flashcards
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
索引建議
為了優化查詢效能,建議建立以下索引:
-- 詞卡查詢優化
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);
常用查詢範例
取得今日需要複習的詞卡
SELECT * FROM flashcards
WHERE user_id = auth.uid()
AND next_review_date <= CURRENT_DATE
ORDER BY next_review_date ASC, difficulty DESC;
取得用戶學習統計
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;
取得詞卡及其標籤
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;
資料備份策略
- 自動備份: Supabase 提供每日自動備份(Pro 計劃)
- 手動備份: 定期匯出重要資料表
- 備份腳本:
# 匯出資料
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 功能監控資料庫狀態。