環境變數
預設範本使用的環境變數、範本預設值和填寫要求。
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 原始碼註解搭配的變數示例,預設值都是空字串。
| 通知服務 | 示例變數名稱 | 儲存內容 |
|---|---|---|
| Slack | SLACK_OPERATIONS_WEBHOOK_URL | Incoming Webhook URL |
| Discord | DISCORD_SALES_WEBHOOK_URL | Incoming Webhook URL |
| Discord | DISCORD_SALES_THREAD_ID | Thread ID |
| Telegram | TELEGRAM_ALERTS_BOT_TOKEN | Bot Token |
| Telegram | TELEGRAM_ALERTS_CHAT_ID | Chat ID |
| Telegram | TELEGRAM_ALERTS_THREAD_ID | Message Thread ID |
| Microsoft Teams | TEAMS_OPERATIONS_WEBHOOK_URL | Workflow Webhook URL |
| 飛書或 Lark | FEISHU_RELEASE_WEBHOOK_URL | 自訂機器人 Webhook URL |
| 飛書或 Lark | FEISHU_RELEASE_SIGNING_SECRET | 機器人簽章金鑰 |
| 釘釘 | DINGTALK_RELEASE_WEBHOOK_URL | 自訂機器人 Webhook URL |
| 釘釘 | DINGTALK_RELEASE_SIGNING_SECRET | 機器人加簽金鑰 |
| 企業微信 | WECOM_RELEASE_WEBHOOK_URL | 群組機器人 Webhook URL |
| 通用 Webhook | INTERNAL_AUDIT_WEBHOOK_URL | HTTPS 請求網址 |
| 通用 Webhook | INTERNAL_AUDIT_WEBHOOK_HEADERS | HTTP 請求標頭組成的 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。