環境變數

預設範本使用的環境變數、範本預設值和填寫要求。

Saavo 使用 .env 儲存本機開發變數,使用 .env.production 儲存正式環境變數。example.vars 是這兩個檔案的範本。執行 npm run saavo:init 時,如果 .env 不存在,指令碼會依這份範本建立檔案,並自動產生缺少的 SAAS_SECRET。

不要提交環境檔案

.env 和 .env.production 都可能包含金鑰,預設已加入 .gitignore。不要將這兩個檔案提交到 Git,也不要在記錄、截圖或前端程式碼中輸出其中的敏感內容。

VITE_ 變數會公開給瀏覽器

以 VITE_ 開頭的變數會在建置時寫入前端檔案,任何訪客都可以透過瀏覽器查看。這類變數只能儲存公開資訊,不能存放 API 金鑰、存取權杖、密碼或私密金鑰。

環境檔案

.env

供本機開發、測試和本機預覽使用。npm run saavo:init 會保留既有檔案,只補上缺少的 SAAS_SECRET,不會覆寫已填入的變數。

.env.production

部署指令碼使用的正式環境檔案。npm run deploy:init 會建立或更新這個檔案,寫入目前 Worker 的 workers.dev 網址,並透過互動方式設定所需資訊,不能假設既有值都會保持不變。空字串不會寫入遠端 Worker,檔案中未出現的遠端 Secret 也不會被刪除。

單獨在本機執行正式環境建置時,如果沒有 .env.production,專案也支援讀取 .env 的本機建置流程。這不代表專案已具備正式部署設定。

部署正式環境時,公開變數透過 Wrangler --var 寫入,其餘非空白變數則透過暫存 Secrets 檔案寫入 Worker Secret。暫存檔案使用完畢後會立即刪除。

寫入方式變數
一般變數VITE_SITE_URL、VITE_SAAVO_COLLECT_API_HOST、VITE_SAAVO_COLLECT_API_ENDPOINT、CLOUDFLARE_TURNSTILE_SITE_KEY、STRIPE_CONNECTION_ID、PADDLE_CONNECTION_ID、PADDLE_ENVIRONMENT、PADDLE_CLIENT_TOKEN、GITHUB_CLIENT_ID、GOOGLE_CLIENT_ID、R2_ACCOUNT_ID
Secret其他所有非空白變數

不要將 Cloudflare 部署驗證資訊寫入 .env.production

CLOUDFLARE_API_TOKEN、CLOUDFLARE_API_KEY、CLOUDFLARE_ACCOUNT_ID、CLOUDFLARE_EMAIL、CF_API_TOKEN、CF_ACCOUNT_ID,以及所有以 WRANGLER_ 開頭的變數,只供部署工具使用。npm run deploy:init 和 npm run deploy:update 會拒絕包含這些變數的 .env.production。

網站與流量統計

VITE_SITE_URL

Prop

Type

example.vars 沒有預設這個變數。本機開發時會產生 http://127.0.0.1:<連接埠>,尚未建立 .env.production 的本機建置使用 http://127.0.0.1:4173,首次部署時,指令碼會寫入目前 Worker 的 workers.dev 網址。

VITE_SAAVO_COLLECT_API_HOST

Prop

Type

VITE_SAAVO_COLLECT_API_ENDPOINT

Prop

Type

這兩個變數只在建置 public/js/analytics.js 時使用。修改後,需要重新建置網站。

應用程式金鑰

SAAS_SECRET

Prop

Type

example.vars 中的預設值為空。npm run saavo:init 會在缺少這個值時自動產生,也可以執行 npm run secret:generate 產生新值。

SAAS_SECRET 必須長期保持不變

同一專案的 .env 和 .env.production 必須使用完全相同的 SAAS_SECRET。專案產生加密資料後再修改這個值,可能導致雙重驗證金鑰、聯盟行銷收款資料、OAuth 用戶端 Secret 等既有資料無法解密。

Cloudflare Turnstile

config/deploy.ts 中的 auth.useTurnstile 預設為 { threshold: 2, interval: '1h' },用來依門檻觸發驗證。啟用這項設定時,需要同時填入網站金鑰和 Secret Key。設為 false 後,這兩個變數可以留空,不能用 true 取代設定物件。

CLOUDFLARE_TURNSTILE_SITE_KEY

Prop

Type

CLOUDFLARE_TURNSTILE_SECRET_KEY

Prop

Type

example.vars 使用 Cloudflare 官方測試驗證資訊,適合本機開發。部署正式環境前,應為正式網域建立 Turnstile Widget,並替換成實際的驗證資訊。

Stripe

config/payment.ts 預設選擇 Stripe。Checkout 需要 STRIPE_CONNECTION_ID 和 STRIPE_SECRET_KEY,Webhook 還需要 STRIPE_WEBHOOK_SECRET。缺少前兩項時,無法建立 Checkout,缺少最後一項時,則無法接收 Stripe Webhook。

STRIPE_CONNECTION_ID

Prop

Type

同一環境上線後,不要任意修改這個值,否則已儲存的 Stripe 物件可能被辨識為另一組連線的資料。測試環境和正式環境應使用不同的連線 ID。

STRIPE_SECRET_KEY

Prop

Type

STRIPE_WEBHOOK_SECRET

Prop

Type

Paddle

下列變數已寫入環境範本和型別宣告,但專案尚未實作 Paddle Checkout、客戶入口和 Webhook。只填入這些變數,不會啟用 Paddle 付款。

PADDLE_CONNECTION_ID

Prop

Type

PADDLE_ENVIRONMENT

Prop

Type

PADDLE_API_KEY

Prop

Type

PADDLE_WEBHOOK_SECRET

Prop

Type

PADDLE_CLIENT_TOKEN

Prop

Type

電子郵件

RESEND_API_KEY

Prop

Type

範本預設使用 Resend,因此正式部署時必須填入這個變數。本機缺少這個值時,npm run doctor 會發出警告。正式環境缺少這個值時,郵件寄送無法使用,遠端檢查也無法通過。

如果將 emailProvider.type 改為 cloudflare,就不需要 RESEND_API_KEY,但必須在 wrangler.jsonc 中設定 EMAIL 資源繫結。資源繫結請見 Cloudflare 資源繫結。

OAuth 登入

GitHub 和 Google 登入都要求 Client ID 與 Client Secret 成對填寫。兩個值都為空,表示不啟用對應的登入方式。只填入一個值時,該登入方式仍然無法使用,npm run doctor 會發出警告。

GITHUB_CLIENT_ID

Prop

Type

GITHUB_CLIENT_SECRET

Prop

Type

GOOGLE_CLIENT_ID

Prop

Type

GOOGLE_CLIENT_SECRET

Prop

Type

R2 API 驗證資訊

example.vars 將這組變數標記為「簽署範本版本下載」所需的 R2 API 驗證資訊。一般檔案上傳與 /uploaded 代理讀取使用 MAIN_R2 繫結,不會讀取這三項變數。若要使用臨時上傳與下載連結,需由業務 API 讀取驗證資訊,再傳入對應的簽署函式。只填入變數,不會自動新增 HTTP 路由。npm run doctor 會檢查三項是否同時填入。

R2_ACCOUNT_ID

Prop

Type

R2_ACCESS_KEY_ID

Prop

Type

R2_SECRET_ACCESS_KEY

Prop

Type

三項都為空,表示不設定。只填入其中一部分時,npm run doctor 會發出警告。

外部通知變數

外部通知變數沒有固定名稱。config/notifications.ts 中的每個 *Binding 欄位,都填入一個環境變數名稱,程式再依這個名稱讀取 Webhook、權杖或簽章金鑰。變數名稱可以依專案需求自行決定,不必沿用 example.vars 中的示例。

設定檔只儲存變數名稱

config/notifications.ts 只能填入 Binding 名稱,不能直接填入 Webhook URL、Bot Token、Chat ID、簽章金鑰或自訂請求標頭。

範本預設設定

範本預設未啟用外部通知管道。example.vars 只列出與 notifications.ts 原始碼註解搭配的變數示例,預設值都是空字串。

通知服務示例變數名稱儲存內容
SlackSLACK_OPERATIONS_WEBHOOK_URLIncoming Webhook URL
DiscordDISCORD_SALES_WEBHOOK_URLIncoming Webhook URL
DiscordDISCORD_SALES_THREAD_IDThread ID
TelegramTELEGRAM_ALERTS_BOT_TOKENBot Token
TelegramTELEGRAM_ALERTS_CHAT_IDChat ID
TelegramTELEGRAM_ALERTS_THREAD_IDMessage Thread ID
Microsoft TeamsTEAMS_OPERATIONS_WEBHOOK_URLWorkflow Webhook URL
飛書或 LarkFEISHU_RELEASE_WEBHOOK_URL自訂機器人 Webhook URL
飛書或 LarkFEISHU_RELEASE_SIGNING_SECRET機器人簽章金鑰
釘釘DINGTALK_RELEASE_WEBHOOK_URL自訂機器人 Webhook URL
釘釘DINGTALK_RELEASE_SIGNING_SECRET機器人加簽金鑰
企業微信WECOM_RELEASE_WEBHOOK_URL群組機器人 Webhook URL
通用 WebhookINTERNAL_AUDIT_WEBHOOK_URLHTTPS 請求網址
通用 WebhookINTERNAL_AUDIT_WEBHOOK_HEADERSHTTP 請求標頭組成的 JSON 物件

INTERNAL_AUDIT_WEBHOOK_HEADERS 的值是 JSON 物件字串,例如:

INTERNAL_AUDIT_WEBHOOK_HEADERS='{"Authorization":"Bearer token"}'

wrangler.jsonc 中的一般變數

下表的預設名稱來自範本原始碼。CLI 建立專案時,會先將 saavo-template 前綴替換成專案名稱。

下列變數不在 example.vars 中,而是直接寫在 wrangler.jsonc 的 vars 物件中。npm run deploy:init 會依 Worker 名稱更新這些資源名稱,不要在 .env 中重複填寫。

ASYNC_POLICY_TASK_QUEUE_NAME

Prop

Type

ASYNC_LOGGER_QUEUE_NAME

Prop

Type

ANALYTICS_QUEUE_NAME

Prop

Type

R2_BUCKET_NAME

Prop

Type

型別宣告

worker-configuration.d.ts 由 Wrangler 產生,用來宣告環境變數和 Cloudflare 資源繫結的型別。修改 wrangler.jsonc、新增或刪除固定變數,或調整資源繫結後,應執行:

npm run cf-typegen

這是自動產生的檔案,不要直接編輯。外部通知使用的是使用者自訂的 Binding 名稱,不會作為固定欄位逐項寫入 CloudflareBindings。