# 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 功能監控資料庫狀態。