MuseMVP Docs
Quick Build

Application Configuration

A deep dive into src/config/index.ts: what each config item does, where it takes effect, and suggested change patterns.

src/config/index.ts is MuseMVP's runtime configuration entry point. It centrally manages i18n, auth behavior, storage, payments, and analytics.
If you want to "change product behavior," this file is usually your first stop.

What This Page Covers

This page only covers code-level configuration in src/config/index.ts. For bootstrap secrets (database, OAuth, mail, MUSE_SETTINGS_SECRET), see /docs/quick-build/environment-variables. Payment gateway and S3 credentials are not env vars — configure them at Runtime Settings.


Configuration Guide

i18n: Internationalization

Key fields:

  • i18n.enabled
  • i18n.locales.en|zh (appName/summary/description/keywords/docsAlias)
  • i18n.defaultLocale
  • i18n.defaultCurrency
  • i18n.localePrefix
  • i18n.localeCookieName

Practical impact:

  • docsAlias is used as the docs page title suffix (for example, xxx | Docs).
  • Header and footer labels live in home.json, not in this locale bundle.
  • localePrefix affects next-intl routing behavior and the language-hiding strategy of docs sources.

Suggestion When Updating Copy

Update en and zh in sync to avoid mismatches between bilingual navigation and footer text.

users: New User Onboarding Redirect and Billing Master Switch

Key field:

  • users.enableSetup

Current behavior:

  • enableSetup=true: newly registered users (logged-in users who have not completed onboarding) are redirected to /setup.

auth: Registration Methods and Session Lifecycle

Key fields:

  • auth.gates.allowRegister
  • auth.gates.allowSocialSignIn
  • auth.gates.allowPasswordSignIn
  • auth.gates.allowTwoFactorAuth
  • auth.lifecycle.redirectAfterLogin
  • auth.lifecycle.redirectAfterSignOut
  • auth.lifecycle.redirectWhenSessionExpired
  • auth.lifecycle.sessionTtlSeconds

Behavior highlights:

  • When allowRegister=false, /auth/register redirects to /auth/login.
  • allowPasswordSignIn and allowSocialSignIn mainly control frontend entry visibility.
  • allowTwoFactorAuth mainly controls whether the 2FA block is shown on the settings page.
  • sessionTtlSeconds is written directly into Better-Auth session.expiresIn.

Easy-to-Misunderstand Point

allowTwoFactorAuth is not a backend plugin master switch. The 2FA plugin is still registered; this flag mainly controls whether the frontend exposes the entry point.

Key fields:

  • mails.from
  • mails.links.logo

Behavior highlights:

  • If mails.from is only an email address, it will be automatically assembled into the format "AppName" <email@...> at send time.
  • mails.links.logo is used for the logo in email templates. By default it uses public/icon.png under the project root, and you can also switch to a custom external image URL with faster access.

ui: Themes, SaaS Shell, and Contact Delivery

ui is the most frequently changed section, so it is best understood in blocks.

ui: {
  enabledThemes: ["light", "dark", "system"],
  defaultTheme: "light",
  saas: { enabled: true, cookieInfo: { showBox: false } },
  contactForm: {
    to: "[email protected]",
    subject: "MuseMVP contact form message",
  },
}

Behavior highlights:

  • ui.saas.enabled=false closes entries to both auth and saas areas (related layouts redirect directly to home).
  • The signed-in shell lives under src/modules/layout/. See App Layout Customization.
  • contactForm.to / subject are the contact form delivery address and subject. They do not hide /contact.
  • Header and footer links are not config flags. Edit SwitchHeader, SwitchFooter, site-links.ts, and home.json.
  • Docs, blog, legal, features, changelog, and contact stay reachable unless you remove the nav link and the route file.

No page-visibility matrix

There is no ui.docs.enabled, ui.blog.enabled, ui.legal.allowMap, headerConfig, or footerConfig. Hide a public page by deleting its link in the header/footer components.

storage: Cloudflare R2

S3 credentials and the avatars bucket live in Admin → Runtime settings, not in config/index.ts.

Key fields that remain in config:

  • storage.proxyUrls.avatarsFile (from NEXT_PUBLIC_AVATARS_PROXY_URL)

Behavior highlights:

  • The upload API checks stored S3 credentials; missing values return STORAGE_ENV_MISSING.
  • NEXT_PUBLIC_AVATARS_PROXY_URL stays in env because client components build avatar URLs in the browser. Trailing / is stripped before URL composition.

payments: Billing Master Switch and Product Catalog Mapping

Key fields:

  • payments.enableBilling
  • payments.enableFree
  • payments.enableEnterprise
  • payments.productCatalog

productCatalog uses stable app plan IDs (pro_monthly, pro_yearly, lifetime) for the public pricing UI and checkout requests. Provider product IDs come from Admin → Runtime settings (billing.productMap).

Behavior highlights:

  • Checkout uses the stored product map; missing mappings throw a readable error.
  • pricing-desc-usage.ts also supports an optional originalAmount field for compare-at pricing display. It affects only the pricing UI; checkout still uses amount.
  • enableBilling=false disables the pricing entry and related billing flow branches. The /pricing route redirects home. The homepage PricingSection returns null. Homepage section order is the JSX list in (home)/page.tsx, not a config flag object.

Important Boundary

The default gateway and gateway API keys live in Admin → Runtime settings, not in config/index.ts and not in env. See Runtime Settings.

analytics: Analytics Script Injection

Key fields:

  • analytics.googleAnalyticsId
  • analytics.baiduTongjiId

Behavior highlights:

  • Analytics scripts are injected only in non-development environments.
  • If an ID is empty, the corresponding script is not rendered.

Post-Change Verification Checklist

pnpm type-check
pnpm build

Confirm Header / Footer copy renders correctly in both en and zh.

Confirm login/register/sign-out redirects match auth.lifecycle config.

Confirm checkout product IDs for each gateway you use are saved in Admin → Runtime settings (billing.productMap).

If originalAmount is configured, confirm the pricing card shows the strikethrough original price while checkout still uses amount.

Confirm avatar upload matches stored S3 settings plus NEXT_PUBLIC_AVATARS_PROXY_URL.