Customization
Make the boilerplate your product while preserving its architecture and safety boundaries.
Customization contract
Customize the generated product in layers. Preserve the architecture and verification boundaries that make later agent work predictable; replace the product decisions that are intentionally neutral.
Start from a generated repository
Use create-app once to establish the product name, npm scope, display brand, unique Better Auth
secret, and independent Git history. Do not build a product inside the delivered foundation checkout
and do not run the scaffolder over an existing repository.
The initial brand replacement is deliberately narrow. It does not choose a commercial name, domain, logo, customer promise, sender, legal entity, support channel, or accessible palette. The optional Customize branding and design tokens playbook provides a maintained route for those changes. No domain, provider account, package registry, or permanent organization may be reserved without an explicit product decision.
Customization map
| Product decision | Primary surfaces | Preserve |
|---|---|---|
| Name and runtime identity | BRAND_NAME in apps/web/src/configs/config.ts and apps/docs/lib/shared.ts, static metadata, PWA manifest, email source | counted brand manifest, context-safe replacement, text-free mark |
| Customer outcome and copy | web metadata, auth/settings states, empty/error states, email copy | accurate capability claims, actionable failures, no inherited example behavior |
| Visual system | apps/web/src/styles/_variables.css, CSS Modules, local font/image assets | semantic token names, focus-visible, contrast, reduced motion, responsive states |
| Durable product capability | migration, shared Zod contract, server repository/service/routes, web service/module | ownership in SQL, layer boundaries, Hono RPC types, negative-path tests |
| Authentication options | typed server environment, apps/server/src/lib/auth.ts, login UI | Better Auth as sole session authority, atomic provider configuration, cookie/origin rules |
| Legal policy links | VITE_TERMS_URL, VITE_PRIVACY_URL, login acknowledgment | real public URLs, no placeholder legal claims |
| Plans and paid access | packages/contracts/src/billing.ts, selected provider adapter, entitlement service, settings UI | provider normalization, server-side gates, webhook idempotency/order |
| Transactional communication | packages/email/src, rendered server templates, mailer/event handlers | typed template inventory, escaping, local fallback, generated-artifact workflow |
| Public upload types | shared upload contract, upload domain, storage adapters, web upload service/UI | owner-scoped claims, metadata confirmation, expiry, size/type enforcement |
| Optional integration removal | full inventory in Removing subsystems | no dead keys/routes/packages/claims; fresh-buyer proof |
| Production topology | Railway or Dokploy API/Postgres, Vercel SPA, provider environment, health/readiness | supported target only after equivalent build, proxy, backup, rollback, and smoke evidence |
For product behavior, Add a domain end to end is an optional tested playbook. A different implementation is valid when it preserves the architecture and passes verification. A nearby component or route is an example of shape, not permission to skip ownership, validation, loading, error, migration, or security decisions.
Generated and source-owned files
Do not edit generated files manually:
apps/server/email-templates/*.htmlcomes frompackages/email/src;pnpm-lock.yamlcomes from the package manager;- database migration history comes from dbmate migration files, not direct production edits;
- production bundles, PWA service workers, source maps, and the compiled server come from builds;
- favicon raster variants come from a reviewed source asset and image-generation workflow.
Source ownership means a buyer may fork any code. It does not make every fork part of the supported foundation contract. Record deliberate architecture departures in a local decision file so a later agent knows which upstream assumptions no longer apply.
Product-specific files
Keep product behavior easy to distinguish from the foundation:
- create a domain rather than adding business SQL to a generic route;
- keep product-specific constants, copy, events, and policies in the owning domain/module;
- add a migration instead of editing the released baseline;
- add local documentation for non-obvious invariants and external resources;
- keep provider-specific types inside the provider adapter;
- add tests that describe the product's owner, lifecycle, limits, and failure behavior.
Do not rename every architecture term to match a brand. Stable names such as service,
repository, contracts, sessionAuth, and semantic design tokens are navigation aids for people
and agents.
Verification
For every material customization:
vp check
vp run -r test
vp run -r build
pnpm audit --audit-level high
git diff --checkAdd real Postgres integration tests for persistence/auth/billing/upload changes. Regenerate and inspect email HTML after email changes. Inspect the production PWA and browser states after identity or design changes. Exercise the selected supported Railway/Vercel or Dokploy/Vercel path after topology, origin, cookie, or environment changes.
Before release, generate a second custom-scope/custom-brand reference app from the exact foundation version. A foundation defect reproduces there; a product-only defect does not. Preserve that distinction when requesting support.
Completion criteria
- The application has one accurate identity and no neutral placeholder or source-product behavior.
- Product domains preserve contract, route, service, repository, ownership, and migration boundaries.
- Generated artifacts match their source and the lockfile is frozen.
- Optional integrations are either configured atomically, visibly unavailable, or removed as a complete vertical slice.
- Checks, tests, builds, dependency audit, relevant provider flows, and rendered states pass.
- Local decision records explain intentional departures that will affect future upgrades.