資料庫
預設範本使用的兩個 D1 資料庫,以及各資料表的用途和關聯。
預設範本使用兩個獨立的 Cloudflare D1 資料庫。DB 儲存業務資料,ANALYTICS_DB 儲存第一方造訪統計資料。兩個資料庫之間沒有資料表關聯,也不會在同一條 SQL 中跨資料庫進行聯結查詢。
DB
| 項目 | 內容 | 說明 |
|---|---|---|
| Binding 名稱 | DB | Worker 透過這個 Binding 存取業務資料庫。 |
| 範本預設資料庫名稱 | saavo-template-db | 首次部署時,部署指令碼會根據 Worker 名稱重新產生。 |
| 初始化指令碼 | schema/db-init.sql | 僅用於初始化空白資料庫,或手動重設資料庫。 |
| 初始化標記資料表 | saas_user | db:migrate 透過這張資料表判斷業務資料庫是否已初始化。 |
資料表
| 範圍 | 資料表 | 用途 |
|---|---|---|
| 帳號與驗證 | saas_user、saas_session、two_factor_setup_session、email_verification_session、password_reset_session | 使用者帳號、登入工作階段、雙重驗證、電子郵件驗證和密碼重設 |
| OAuth 2.0 | oauth_auth_session、oauth_client、oauth_auth_code、oauth_token | 授權請求、用戶端、授權碼和 Token |
| 角色與權益 | user_role_capability、user_entitlement_capability、capability_quota_event | 角色能力、權益能力和額度變動紀錄 |
| Reaction | event_execution、command_execution | Event 和 Command 執行紀錄 |
| 付款 | webhook_events、payment_customers、checkout_sessions、purchase_items、subscriptions、subscription_items、transactions、transaction_items、refunds | Webhook、Customer、Checkout、購買、訂閱、交易和退款 |
| 聯盟行銷 | affiliate_payout_profiles、affiliate_commissions、affiliate_monthly_payouts、affiliate_monthly_payout_records | 收款資料、佣金、每月結算和付款紀錄 |
| 客服案件與內容 | ticket、newsletter_subscriber | 客服案件索引和電子郵件訂閱 |
| 站內通知 | notification、user_notification | 通知內容及使用者已讀狀態 |
實體關聯
以下依業務模組分別列出主要資料庫的 ER 圖。圖中的關聯來自欄位含義,以及 Repository 和 Service 中的實際查詢,不以 SQL 是否宣告 FOREIGN KEY 為準。為避免關聯線過於密集,saas_user 等共用實體會重複出現在不同圖中。
帳號、驗證與 OAuth 2.0
saas_user.invited_by_id 形成使用者之間的推薦關係。登入、驗證和 OAuth 2.0 相關紀錄,分別透過 user_id、client_id、oauth_code 等欄位關聯使用者、用戶端和授權碼。
角色、權益與 Reaction
角色能力、權益能力和額度變動紀錄都可以關聯使用者。能力授予紀錄中的 event_id 和 command_id 指向對應的 Reaction 執行紀錄。額度變動紀錄則透過 Subject、來源、權益和能力等欄位,關聯對應的權益能力紀錄。
付款
payment_customers 記錄使用者帳號與付款服務供應商 Customer 的對應關係。Checkout、訂閱和交易可以透過站內 ID 關聯,也可以搭配 provider、connection_id 和付款服務供應商提供的 ID,確認是否為同一筆業務資料。webhook_events 儲存收到的 Webhook,並據此觸發付款資料同步。一筆 Webhook 紀錄不一定只對應某張付款資料表中的一筆紀錄。
聯盟行銷
佣金紀錄同時關聯推廣者、受推薦的使用者、交易和交易明細。訂閱佣金透過付款服務供應商、付款連線和訂閱 ID 查找對應的訂閱。每月結算則依推廣者、結算月份和幣別彙總佣金,不需要另外儲存外部索引鍵欄位。
客服案件、通知與電子郵件訂閱
user_notification 是使用者與通知之間的關聯資料表。客服案件可關聯提交人和處理人,其中 requester_id 小於或等於 0 時表示匿名提交,不對應 saas_user。電子郵件訂閱僅儲存電子郵件地址,不與使用者帳號建立實體關聯。
ANALYTICS_DB
| 項目 | 內容 | 說明 |
|---|---|---|
| Binding 名稱 | ANALYTICS_DB | Worker 透過這個 Binding 存取造訪統計資料庫。 |
| 範本預設資料庫名稱 | saavo-template-analytics-db | 首次部署時,部署指令碼會根據 Worker 名稱重新產生。 |
| 初始化指令碼 | schema/analytics-init.sql | 僅用於初始化空白資料庫,或手動重設資料庫。 |
| 初始化標記資料表 | analytics_session | db:migrate 透過這張資料表判斷統計資料庫是否已初始化。 |
資料表
| 資料表 | 用途 |
|---|---|
analytics_session | 造訪工作階段的訪客識別碼、裝置資訊、首次活動時間和首次接收時間 |
analytics_event | 網頁瀏覽和自訂事件,以及來源、裝置、地區和效能指標 |
analytics_event_property | Event 的自訂屬性 |
analytics_session_trait | 工作階段層級的自訂特徵 |
實體關聯
analytics_event 和 analytics_session_trait 都透過 (site_id, session_id) 關聯 analytics_session,analytics_event_property.event_id 則關聯 analytics_event.event_id。統計資料庫中的這三組關聯也受到 SQL 外部索引鍵約束。其中 Event 屬性和 Session Trait 會隨所屬紀錄一併刪除。
欄位慣例
| 慣例 | 說明 |
|---|---|
| 時間 | 除非 SQL 另有明確說明,*_at、*_start、*_end 這類欄位均使用 Unix 毫秒 |
| 布林值 | D1 使用 INTEGER 儲存布林狀態,通常以 1 表示是、0 表示否 |
| 金額 | *_minor 使用貨幣最小單位,例如人民幣的分、美元的美分 |
| JSON | JSON 是 SQLite 的型別宣告,實際內容仍以文字形式儲存,並由應用程式或 CHECK 約束確保 JSON 有效 |
| 虛刪除 | deleted_at 通常以 0 表示未刪除,非零值表示刪除時間 |
| 主索引鍵 | WITHOUT ROWID 資料表使用宣告的主索引鍵儲存紀錄,不再額外提供隱含的 rowid |
初始化資料庫與更新資料表結構
schema/db-init.sql 和 schema/analytics-init.sql 都包含 DROP TABLE IF EXISTS,只能用於初始化空白資料庫,或手動重設資料庫,不能用來更新正式環境的資料表結構。
資料庫遷移檔案統一放在 schema/migrations。業務資料庫的檔名採用 NNNN-db-description.sql,統計資料庫的檔名採用 NNNN-analytics-description.sql。需要修改正式環境的資料表結構時,應新增遷移檔案,再執行 npm run db:migrate:remote。
請勿在正式環境的資料庫執行初始化指令碼
初始化指令碼會刪除既有資料表和資料。db:reset:local 與 db:reset:remote 也會清空資料庫,僅能在確定需要重建資料庫時使用。