1. Branding
The init wizard wrote application configuration into config/app.ts and environment values into .env.local. Review both, replacing placeholder branding, URLs and legal details. Init does not recolor the design tokens or replace image assets.
- Logo — replace
public/logo.svg,public/logo-dark.svg,public/icon.svgandpublic/favicon.svg; review the matching paths and dimensions inappConfig.logo. - OG image — provide a 1200×630 image and update
appConfig.seo.openGraph.images. The default points to/og-image.png; supply that asset underpublic/or configure your own existing URL. - Brand color — follow
DESIGN.mdand theoklch()tokens inapp/globals.css. The current raspberry palette derives from--brand-h: 350; review hue, chroma and contrast in both themes rather than replacing isolated component colors. Tailwind and shadcn consume the tokens through@theme inline.
2. Business model: B2C or B2B?
Edit config/app.ts:
export const appConfig = {
// ...
businessModel: 'b2c', // or 'b2b'
}
| B2C | B2B | |
|---|---|---|
| Account model | 1 user = 1 personal account | N users = 1 workspace |
| Onboarding | Single signup | Signup + workspace setup + invitations |
| Pricing | Per user | Per workspace (with seats) |
| Sidebar | Personal dashboard only | Personal + org dashboards |
Changing the business-model flag does not migrate existing Accounts or subscriptions. Choose the intended model before admitting users and review any later transition separately.
3. Billing model
Also in config/app.ts:
billingModel: 'subscription' // or 'one_time' or 'hybrid'
- subscription — recurring payments through the provider selected during initialization. Default for SaaS.
- one_time — license purchases; access duration comes from the configured license product and is not necessarily lifetime.
- hybrid — both. Useful if you sell both a subscription tier and one-off add-ons.
The pricing page automatically shows only the purchase types your model enables.
4. Finalize your prices
Open config/pricing.ts and shape your plans / credit packs / licenses. Each plan has:
- an
id(kept as-is forever — it is whatsubscriptions.plan_idstores) - a
name - an amount in whole currency units (e.g.
29for €29) - provider catalogue bindings for every sold currency, billing interval, and dev/prod environment
The same config/pricing.ts file is used in dev and prod. Its providerCatalogIds map is keyed by internal offer, optional interval, and currency, then by Stripe/Lemon Squeezy/Paddle and { dev, prod }. Fill only the providers and commercial combinations you actually sell: Stripe and Paddle use Price IDs, while Lemon Squeezy uses Variant IDs. NEXT_PUBLIC_INSTANCE_MODE selects the environment slot; PAYMENTS_PROVIDER selects the provider server-side.
5. Languages (i18n)
The boilerplate ships with French (fr-FR), Swiss French (fr-CH), US English (en-US), and Canadian English (en-CA), URL-based: /fr-FR/..., /fr-CH/..., /en-US/..., and /en-CA/.... To remove one or add one:
- Edit
i18n/config.ts: update thelocalesarray,localeNames,localeFlags. - Copy
i18n/messages/en-US.jsonto your new locale (e.g.es-ES.json) and translate the values. - Restart the dev server.
Full reference: Internationalization.
6. Email provider
If you picked noop earlier, switch to Brevo or Mailjet now:
- Open the provider dashboard → API keys → copy your key.
- Paste it in
.env.localasBREVO_API_KEYorMAILJET_API_KEY_PUBLIC+MAILJET_API_KEY_PRIVATE. - Set
EMAIL_FROM_NAMEandEMAIL_FROM_ADDRESS. - Verify your sender domain inside the provider (SPF + DKIM). Magic links land in spam without this.
- Test by requesting a magic link from
/en-US/loginwith a real email address.
7. Replace the placeholder content
- Hero, features, testimonials, FAQ — landing components live in
components/landing-*.tsx. Most read content from i18n message files, so editi18n/messages/{locale}.json. - Logo cloud — drop SVGs in
public/logos/and reference them incomponents/logo-cloud.tsx. - Legal pages —
/terms,/privacy,/legalare CMS pages. Edit them in/admin-dashboard/cmsonce logged in as admin.
- The landing page shows your real branding, real prices, no placeholders
- Your locales array matches what you actually want to sell in
- A magic link sent to a real inbox arrives within ~30 seconds, not in spam
- Legal pages render with your company info, not Lorem Ipsum