Back to changelog
Milestone

Runtime Settings: Encrypted Billing and Storage in the Database

Payment and S3 credentials leave environment variables and land in encrypted database rows. Production requires MUSE_SETTINGS_SECRET. Checkout uses stable plan IDs, and the admin billing page nests each gateway's product IDs inside a collapsed provider panel.

This is a breaking configuration change for existing forks: gateway keys and S3 credentials are no longer read from env at runtime.

Why the template changed

  • Payment and storage secrets used to sit next to mail and OAuth in .env. Rotating a key meant a rebuild, and day-two operations mixed with bootstrap secrets.
  • Runtime now reads only the app_setting table for billing and S3. There is no environment-variable fallback after you import leftover local values.

What you must set

  • Add MUSE_SETTINGS_SECRET (at least 32 characters). It wraps encrypted settings with HKDF-SHA256 + AES-256-GCM and is never stored in the database. A production runtime missing this secret fails at startup.
  • Apply migration 0001_dry_terror.sql so app_setting and app_setting_revision exist (pnpm drizzle:migrate).
  • Create an admin, then open Admin → Runtime settings (/app/admin/settings). Save gateway credentials, checkout product IDs, and S3 settings. Use Test connection before going live.
  • Optional one-shot: pnpm muse:settings:import copies leftover local gateway/storage credentials into the database. Runtime never reads those env vars afterward. Checkout product IDs are entered in the admin page, not env.

Billing and checkout

  • Public pricing still uses stable app plan IDs (pro_monthly, pro_yearly, lifetime). Provider product IDs live in billing.productMap.
  • Direct checkout mode is gone. Paid plans launch through Muse Billing against the stored default gateway (Creem, Stripe, Dodo, or Waffo).
  • On the admin billing tab, the default-gateway card stays at the top. Each provider starts collapsed; expand it to edit credentials and that gateway's product IDs together. Badges show Default, Configured / Not configured, mapped product-ID count, and Unsaved.

Storage and deploy

  • S3 access key, secret, endpoint, and the avatars bucket are admin settings. NEXT_PUBLIC_AVATARS_PROXY_URL stays in env because the browser builds avatar URLs from it.
  • Docker, Vercel, Cloudflare Workers, and EdgeOne production env lists now require MUSE_SETTINGS_SECRET and no longer treat gateway or S3 keys as env.