資料與設定遷移
評估資料表結構、設定、資源和業務識別碼的變更,為既有專案設計可驗證的遷移路徑。
範本原始碼能夠編譯,不代表原專案的資料可以直接搭配新版程式碼使用。本篇說明日後更新涉及結構或設定變更時,需要檢查的內容。沒有這些變更時,不需要額外建立遷移檔案。
一、先列出實際發生的變更
| 變更 | 需要的處理 |
|---|---|
| 僅修改頁面文案或不影響介面的樣式 | 通常不需要資料庫遷移 |
| 新增選用設定項目 | 檢查預設行為、Schema 和呼叫端 |
| 設定欄位重新命名或型別變更 | 同步實際設定、Schema、讀取程式碼和診斷指令碼 |
| 新增欄位、約束、索引或狀態 | 設計增量 SQL,檢查舊資料是否符合要求 |
| 產品、角色、權益等 Key 重新命名 | 同時檢查設定、程式碼與已儲存的紀錄 |
| Queue、Event 或 Command 資料格式變更 | 檢查等待執行的訊息,以及資料庫中的舊執行紀錄 |
| API 或驗證規則變更 | 檢查呼叫端、既有工作階段、權杖和失敗回應 |
「新增欄位」也可能造成不相容。例如,新增必填欄位卻沒有預設值,既有設定或舊資料就可能無法通過驗證。是否不相容,應以既有使用方式能否繼續運作判斷。
二、資料庫基準與遷移各自負責什麼
目前範本有兩套基準:
| Binding | 基準檔案 | 遷移命名 |
|---|---|---|
DB | schema/db-init.sql | NNNN-db-description.sql |
ANALYTICS_DB | schema/analytics-init.sql | NNNN-analytics-description.sql |
遷移檔案位於 schema/migrations,四位編號依執行順序安排,描述使用小寫字母、數字和連字號。自己的專案已有遷移時,要先核對編號、檔名與執行歷史,不能直接使用上游檔案覆蓋同名位置。
目前遷移指令碼會對空白資料庫執行基準,再套用符合命名規則的遷移。既有資料庫存在對應基準資料表時,只套用尚未執行的遷移。非空白資料庫缺少 saas_user 或 analytics_session 時,會停止並要求先檢查資料庫來源。
基準檔案包含刪除舊資料表的陳述式,不能靠重新執行基準來升級既有資料庫。修改基準也不會自動變更已上線的資料表結構。
同時驗證舊資料庫與空白資料庫
如果將某個新增欄位直接寫入新基準,又保留一項無條件新增同名欄位的遷移,空白資料庫初始化時就可能重複新增。目前指令碼不會自動判斷某個基準已包含哪些歷史變更。
因此,涉及基準調整時,必須分別驗證:
- 從目前專案實際的舊結構升級,保留原有資料。
- 從空白資料庫初始化,再套用遷移,能夠得到可用結構。
不要刪除遷移紀錄,或任意標記為「已執行」,讓兩條路徑看似成功。需要調整基準策略時,應明確設計,並保留可重現的測試結果。
三、從業務規則設計遷移
撰寫 SQL 前,先回答:舊程式碼讀取和寫入什麼、新程式碼需要什麼,以及歷史資料缺少的值從哪裡取得。
例如,某張業務資料表需要新增可為空值的備註欄位,可以先新增該欄位,再讓新程式碼使用。如果要新增非空值約束或唯一約束,必須先確認既有紀錄符合條件,不能只在空白資料庫上驗證 SQL。
重建資料表時,也要保留主索引鍵、外部索引鍵、索引、預設值和狀態約束。不要只複製欄位名稱,遺漏的索引或約束,可能直到上線後才造成查詢緩慢或資料重複。
已在正式環境或其他共用環境執行過的遷移,應保留歷史,需要修正時新增後續遷移。遷移是否執行,由目標資料庫記錄,不能因為本機檔案存在,就推斷線上已完成。
查詢方式和故障處理請見資料庫與遷移疑難排解。D1 遷移機制請見 Cloudflare D1 migrations。
四、驗證遷移,避免影響實際業務
準備隔離的測試資料,結構應能代表升級前版本。資料需包含空值、歷史狀態、關聯紀錄和已使用過的業務資料,不應只有新建的空白資料表。
確認指令的操作目標是本機測試狀態後,執行:
npm run db:migrate:local檢查遷移紀錄、最終結構、關鍵紀錄數量和業務關聯,再透過應用程式讀寫這些資料。若涉及權限和付款變更,也要檢查重複執行是否造成重複授予,以及狀態是否錯誤地回到先前值。
這個指令會處理兩個本機資料庫。如果業務資料庫成功、統計資料庫失敗,不能認為前面的變更也一併復原。正式環境遷移也不能視為跨兩個資料庫的同一筆交易。
需要測試空白資料庫時,請另外建立隔離的本機環境,不要清空正在使用的開發資料庫,只為了完成驗證步驟。
五、維持發布前後的相容性
目前 deploy:update 會先執行遠端遷移,再發布新 Worker。這表示 SQL 執行後,舊程式碼仍可能繼續處理請求。
新增結構通常比立即刪除舊結構更容易安排。例如,確實需要替換既有欄位時,可以評估分階段發布:先準備新結構並調整程式碼,再完成資料轉換,確認沒有舊參照後,才清理舊結構。
這只是有實際遷移需求時的發布方案,不要求每次更新都新增相容層。每個階段都應有完成條件,暫時的讀取邏輯和舊欄位,也要有明確的清理安排。
如果舊 Worker 無法讀取新結構,就不能宣稱「發布失敗時,直接切回舊程式碼即可」。應重新設計遷移順序,或為這項變更制定獨立的受控切換方案。
六、同步設定,同時保留專案身分
請對照以下位置處理設定變更:
config/中的專案值,以及src/libs/config/schemas/中的驗證。- 伺服器端與用戶端設定匯出,以及頁面、API、Service 和指令碼呼叫端。
example.vars與實際的.env、.env.production。wrangler.jsonc中的繫結,以及scripts/doctor/中的檢查規則。
不要使用新版範本的品牌、管理員電子郵件地址、產品或資源名稱,覆寫專案值。新增設定欄位時,先了解其預設效果,再決定本專案是否啟用。
新增 Secret 應透過原有的安全方式設定。SAAS_SECRET 必須保留專案既有值,它不是升級時應重新產生的版本識別碼。
七、環境變數與 Cloudflare 資源
example.vars 只是變數範本,不會自動將新欄位合併至既有環境檔案。變數重新命名後,需要同步修改讀取程式碼、檢查指令碼、環境檔案和部署行為。
以 VITE_ 開頭的變數可能進入瀏覽器端建置檔案,只能儲存公開值。刪除 .env.production 中的某個項目,或將其留空,也不會自動刪除 Worker 既有的遠端 Secret。應先檢查線上實際使用情況,再另外處理。
Binding 變更後,執行:
npm run cf-typegen
npm run doctor準備正式環境發布時,再執行 npm run doctor:remote。這些檢查不負責自動建立所有缺少的資源,也不能取代實際資源核對。
| 資源變更 | 特別檢查 |
|---|---|
| D1、KV | 保留原專案資源 ID,確認資料是否需要移轉 |
| R2 | MAIN_R2.bucket_name 與 R2_BUCKET_NAME 一致,原有檔案仍可存取 |
| Queue | 產生者、取用者與 *_QUEUE_NAME 一致,仍可處理舊訊息格式 |
| Durable Object | 匯出類別名稱、Binding 和遷移宣告,不能覆寫既有遷移歷史 |
| Cron | Wrangler 運算式與 src/entry/index.ts 的字串分派條件一致 |
新增遠端資源是獨立的實作步驟。不能假設 cf-typegen 會建立資源,也不能對既有專案重新執行首次部署,取代遷移設計。
八、將業務 Key 視為資料識別碼檢查
產品 ID、方案 ID、角色、權益、能力和 Scope,都可能寫入資料庫或外部系統。修改 Key 不只是改變顯示文案。
重新命名前,請搜尋定義、參照、資料庫儲存值和事件承載資料。例如,刪除舊 Price 的方案對應關係,可能影響舊訂單回呼和歷史訂閱處理。更換 STRIPE_CONNECTION_ID 也會改變付款紀錄的辨識範圍。
Queue 格式變更時,也應檢查 event_execution、command_execution 中的舊版本和承載資料。只升級新請求的建立程式碼,不能保證升級前已排入佇列的工作仍能執行。
本次沒有明確需求時,請保留穩定識別碼。確實需要遷移時,將轉換範圍、舊紀錄如何繼續處理,以及重複執行的行為寫入變更計畫。
九、事先確認恢復所需資料
資料保護範圍應涵蓋本次實際會變更的內容。D1 備份不包含 R2 檔案、KV 內容、Queue 訊息、Secret,或 Stripe 中已發生的交易。
為日後正式環境遷移準備資料庫匯出檔或可用還原點,並驗證還原方法。D1 提供 Time Travel,但應在操作時確認帳戶可用的時間範圍與目標還原點,不能假設可還原至任意歷史時間。請參閱 Time Travel 與備份。
還原資料庫也可能遺失還原點之後的合法寫入,因此需要核對這段時間的新使用者、付款和後台操作。這不是一般程式碼版本回復時,自動附帶的步驟。
完成以上準備後,再進入驗證、發布與維護紀錄。