Production rules
Eleven hard rules pulled from real production bugs. Don't break them.
These are the rules every change to this codebase must satisfy. They come from real bugs that bit real users — violating one means you've reintroduced a known problem.
1. BetterAuth base URL
Use NEXT_PUBLIC_APP_URL (no /api). Never NEXT_PUBLIC_API_URL — Better Auth appends /api/auth itself, so the API URL would yield /api/api/auth/.
2. Semantic color tokens only
Forbidden in JSX: bg-white, text-slate-*, border-gray-*, hex / rgb in className. Use bg-background, text-foreground, text-muted-foreground, border-border, bg-muted, bg-card, text-primary. They map to CSS variables in packages/ui/src/styles/globals.css and respect both themes.
3. Dark mode
next-themes with defaultTheme="system". Never set className="light" or colorScheme on <html>/<body>. Both themes must work after every change.
4. One header per layout
Header lives in app/layout.tsx. Page components must not render a duplicate <header> with logo / nav. Toolbars and breadcrumbs are fine.
5. Brand color
--primary in globals.css must be set for both light and dark themes before shipping. Default carries a /* CHANGE THIS */ marker.
6. Canonical URLs
Each page sets its own metadata.alternates.canonical. Never hardcode a single canonical in the root layout — search engines will treat every page as a duplicate of the homepage.
7. Payment integration = 3 parts
Every Polar.sh integration needs all three to function: checkout endpoint, HMAC-verified webhook, frontend subscription check. Skip one and money is lost or users are confused.
8. .env URL conventions
NEXT_PUBLIC_APP_URL=https://myapp.com # no /api
NEXT_PUBLIC_API_URL=https://myapp.com/api # with /api
BETTER_AUTH_URL=https://myapp.com # same as APP_URL9. Turbo race conditions
Parallel turbo builds occasionally race on the filesystem. If you see intermittent failures, build apps individually:
cd apps/web && bun run build10. Public vs admin
Public-facing UI lives in apps/web. Internal dashboards / admin tooling live in apps/admin. Don't mix.
11. API build for native modules
bun build src/index.ts --outdir dist --target bun --external sharp