Configuration

Brand identity, tenancy mode, routing, and feature flags — every knob in one place.


This template is designed so that a buyer touches as few files as possible to ship a white-labelled product. This page covers every configuration surface.

Brand identity

File: src/config/brand.ts

This is the single source of truth for your product identity. Edit it once and everything propagates — marketing pages, auth screens, email templates, legal docs.

export const brand = {
  name: "My Product",
  legalEntity: "My Product, Inc.",
  tagline: "Do the thing, faster.",
  description: "One-line description for SEO and email footers.",
  supportEmail: "support@myproduct.com",
  url: "https://myproduct.com",
  // ...
};

Assets

Drop your logo files into public/brand/:

| Filename | Usage | |----------|-------| | logo-light.svg | Light mode header | | logo-dark.svg | Dark mode header | | icon.svg | Favicon (32×32) | | og.png | Open Graph image (1200×630) |

Theme

The theme block in brand.ts sets OKLCH color values injected into globals.css:

theme: {
  primary: "oklch(0.6 0.2 250)",   // brand primary
  accent:  "oklch(0.65 0.18 200)", // accent / highlight
  radius:  "0.5rem",               // border-radius base
  preset:  "default",              // "default" | "brutalist" | "soft-pop" | "tangerine"
  font:    "geist",                // "geist" | "inter" | "cal-sans" | ...
},

Tenancy mode

Env var: TENANCY_MODE

| Value | URL pattern | Notes | |-------|-------------|-------| | cookie (default) | app.com/dashboard | Active org stored in cookie; simplest to deploy | | path | app.com/acme/dashboard | Org slug is the first path segment | | subdomain | acme.app.com/dashboard | Requires wildcard DNS + Vercel wildcard domain |

The proxy (src/proxy.ts) and tenancy resolver (src/lib/tenancy/) handle all three modes behind the same interface. Business logic never branches on TENANCY_MODE.

Host routing

Env var: ROOT_DOMAIN

In subdomain tenancy mode, ROOT_DOMAIN separates the apex (marketing) host from the app host:

ROOT_DOMAIN=myproduct.com

Apex host:    myproduct.com     → marketing pages
App host:     app.myproduct.com → dashboard
Tenant hosts: acme.myproduct.com → tenant dashboard (subdomain mode)

In cookie and path modes ROOT_DOMAIN is still read by the proxy but the apex/app split collapses — both are served on the same domain.

How marketing rewrites work

The proxy rewrites requests on the apex host to the /marketing route group:

  • myproduct.com/src/app/marketing/page.tsx
  • myproduct.com/pricingsrc/app/marketing/pricing/page.tsx
  • myproduct.com/blogsrc/app/marketing/blog/page.tsx

/docs is a top-level route (not inside /marketing) so it is served directly without a rewrite. It is accessible on both hosts.

Important: /docs and /blog must be listed in PUBLIC_PREFIXES inside src/proxy.ts to bypass the auth gate. Without this, unauthenticated visitors on the app host will be redirected to /login. See the note at the bottom of this page.

Feature flags

Feature flags live in src/config/app-config.ts. They are plain TypeScript constants — no external service required.

export const appConfig = {
  billing: {
    enabled: true,        // show pricing page and billing portal
    trialDays: 14,
  },
  invites: {
    enabled: true,        // org invitation flow
    maxPerOrg: 50,
  },
  auditLog: {
    enabled: false,       // audit log UI (requires Pro schema)
  },
};

Internationalisation

File: src/i18n/request.ts

next-intl is pre-wired. Message files live in messages/. The locale is read from the NEXT_LOCALE cookie and defaults to en. Add a new locale by:

  1. Adding a message file: messages/fr.json
  2. Exporting the locale in src/i18n/routing.ts
  3. Translating keys — the type system will surface missing entries

Email configuration

All email is sent via Resend. Templates are React Email components in src/lib/email/templates/. The from address is read from EMAIL_FROM. To preview templates locally:

pnpm email:dev   # starts React Email devserver on :3001

Deployment

The starter is optimised for Vercel:

  1. Import the repo in the Vercel dashboard
  2. Set all environment variables from .env.local
  3. Add ROOT_DOMAIN to your production env
  4. Connect the Neon database integration for automatic DATABASE_URL injection

For self-hosting, build with pnpm build and start with pnpm start. Ensure NODE_ENV=production is set so removeConsole and other build-time optimisations activate.


Proxy note: If you add new public-facing routes (like /docs), remember to add their path prefixes to PUBLIC_PREFIXES in src/proxy.ts. Otherwise the edge auth gate will redirect unauthenticated users to /login before your page renders.