环境变量

默认模板使用的环境变量、模板默认值和填写要求。

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 凭据。模板保留了变量和类型声明,npm run doctor 也会检查三项是否同时填写;现有业务代码尚未读取它们。这组 API 凭据与 Worker 直接访问 MAIN_R2 的资源绑定无关。

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。