运行时设置
把支付与存储凭证保存在数据库中,由管理员在 /app/admin/settings 维护。
支付网关凭证和 S3 存储凭证存放在 app_setting 表里,由管理员在 /app/admin/settings 维护。这两域运行时只读数据库,没有环境变量回退。
邮件、认证、Turnstile 和 NEXT_PUBLIC_AVATARS_PROXY_URL 仍使用环境变量。
首位管理员
注册仍走环境变量里的邮件(OTP)。用 pnpm muse:user:create 创建用户,再用 pnpm muse:user:role 提权,然后打开 /app/admin/settings。
哪些留在 env,哪些进后台
| 表面 | 来源 | 原因 |
|---|---|---|
| 站点 URL、数据库、Better Auth、OAuth、Turnstile | 环境变量 | 在任何管理员会话之前就必须可用 |
邮件(MAIL_PROVIDER、Resend / Cloudflare) | 环境变量 | 设置表为空时注册 OTP 仍需工作 |
MUSE_SETTINGS_SECRET | 环境变量 | 设置加密的包装密钥,绝不入库 |
NEXT_PUBLIC_AVATARS_PROXY_URL | 环境变量 | 客户端组件在浏览器里拼接头像 URL |
| 支付网关、webhook secret、默认网关 | 后台设置 | 仅服务端密钥,落库加密 |
| 结账产品 ID | 后台设置(billing.productMap) | 结账真源 |
| S3 access key、secret、endpoint、头像 bucket | 后台设置 | 仅服务端密钥,落库加密 |
首次部署顺序
配置 BETTER_AUTH_SECRET、MUSE_SETTINGS_SECRET、数据库和邮件环境变量。MUSE_SETTINGS_SECRET 至少 32 个字符。
执行迁移(pnpm drizzle:migrate),确保存在 app_setting 与 app_setting_revision。
创建并提权管理员(pnpm muse:user:create,然后 pnpm muse:user:role)。
打开 /app/admin/settings,保存网关凭证、结账产品 ID 和 S3 设置。上线前先点 测试连接。
计费页顶部是 默认网关 卡片。每个支付商(Creem、Stripe、Dodo、Waffo)默认 收起。展开后在同一面板里填写该网关凭证,以及对应的结账产品 ID(Pro 月付 / 年付 / Lifetime)。标题右侧会显示「默认」「已配置 / 未配置」、已映射产品 ID 数量,以及未保存时的「未保存」。
可选:pnpm muse:settings:import 把本地残留的网关/存储凭证一次性写入数据库。之后运行时不再读取这些 env。结账产品 ID 在后台设置里填写,不走环境变量。
加密
密钥字段以无前缀的 base64url 密文存储。每一行用 HKDF-SHA256(info 绑定 scope:key)派生 AES-256-GCM 密钥,附加数据同样绑定该字段身份。把密文挪到别的字段会解密失败。算法版本记在 cipher_version;非密钥字段为 0(明文)。
能力降级
没有网关时,登录后的定价 CTA 不可点,发起结账会返回可读错误。没有 S3 时,头像/文件接口返回 STORAGE_ENV_MISSING(503),存储页显示空态。公开首页保持静态,不查询这些设置。
缓存
设置按进程缓存,并以 app_setting_revision 为键。其他实例最长 30 秒后刷新。