Customization
Make HeartCo your own: name, colors, emails, sidebar, legal pages.
Branding
File: src/lib/config/branding.ts
All brand configuration is centralized in the APP_CONFIG object. Every value is configurable via an environment variable:
Identity
| Property | Default | Environment variable |
|---|---|---|
| Name | HeartCo | NEXT_PUBLIC_APP_NAME |
| Short name | HC | NEXT_PUBLIC_APP_SHORT_NAME |
| Tagline | "Launch your SaaS in 1 week" | NEXT_PUBLIC_APP_TAGLINE |
| Description | "The production-ready SaaS boilerplate..." | NEXT_PUBLIC_APP_DESCRIPTION |
| URL | http://localhost:3000 | NEXT_PUBLIC_APP_URL |
| Domain | heartco.fr | NEXT_PUBLIC_APP_DOMAIN |
Emails
| Property | Default | Environment variable |
|---|---|---|
| Primary email | hello@heartco.fr | NEXT_PUBLIC_APP_EMAIL |
| Support | support@heartco.fr | NEXT_PUBLIC_SUPPORT_EMAIL |
| No-reply | noreply@heartco.fr | NEXT_PUBLIC_NOREPLY_EMAIL |
Colors
| Property | Value | Usage |
|---|---|---|
| Primary | #6366f1 (Indigo) | Buttons, links, accents |
| Secondary | #8b5cf6 (Violet) | Gradients, secondary elements |
Social networks
Configurable via APP_CONFIG.social: twitter, linkedin, github, discord, instagram, youtube (empty by default).
Legal information
| Property | Environment variable |
|---|---|
| Company name | NEXT_PUBLIC_COMPANY_NAME |
| Registration number | NEXT_PUBLIC_REGISTRATION_NUMBER |
| VAT number | NEXT_PUBLIC_VAT_NUMBER |
| Address | NEXT_PUBLIC_COMPANY_ADDRESS |
Customization example
To rebrand the app as "MySaaS":
NEXT_PUBLIC_APP_NAME="MySaaS"
NEXT_PUBLIC_APP_SHORT_NAME="MS"
NEXT_PUBLIC_APP_TAGLINE="The all-in-one solution for your business"
NEXT_PUBLIC_APP_DOMAIN="mysaas.com"
NEXT_PUBLIC_APP_EMAIL="contact@mysaas.com"
NEXT_PUBLIC_SUPPORT_EMAIL="support@mysaas.com"
NEXT_PUBLIC_NOREPLY_EMAIL="noreply@mysaas.com"
NEXT_PUBLIC_COMPANY_NAME="MySaaS Inc."Tailwind and theming
Main file
src/styles/globals.css contains the CSS tokens and the Tailwind v4 configuration.
Semantic CSS tokens
HeartCo uses CSS custom properties for the light and dark themes:
:root {
--background: ...;
--foreground: ...;
--primary: ...;
--primary-foreground: ...;
--secondary: ...;
--card: ...;
--border: ...;
--ring: ...;
/* ... */
}
.dark {
--background: ...;
--foreground: ...;
/* ... dark variants */
}Custom colors
:root {
--color-brand: #6366f1;
--color-deep-navy: #0d1b2a;
--color-ai-blue: ...;
--color-ai-cyan: ...;
}Dark mode
Dark mode is handled by next-themes. Always use the semantic CSS tokens, never hardcoded colors:
// ✅ Correct — uses the tokens
<div className="bg-background text-foreground border-border">
// ❌ FORBIDDEN — hardcoded colors
<div className="bg-white text-gray-900 border-gray-200">Class merging
Use cn() (clsx + tailwind-merge) to merge classes:
import { cn } from "~/lib/utils";
<button className={cn(
"px-4 py-2 rounded-md",
variant === "primary" && "bg-primary text-primary-foreground",
variant === "outline" && "border border-input",
className
)} />Navigation (Sidebar)
File: src/lib/navigation/nav-config.ts
Structure
The sidebar is organized into 8 sections with semantic colors:
| Section | Color | Icon |
|---|---|---|
| Dashboard | Indigo | LayoutDashboard |
| AI Copilot | Violet | Sparkles |
| Sales | Emerald | Users |
| Invoicing | Amber | Receipt |
| Finance | Sky | TrendingUp |
| Operations | Orange | Wrench |
| Team | Teal | UserCog |
Editing an item
To change the label, icon or path of a module:
// src/lib/navigation/nav-config.ts
{
id: "crm",
label: "My CRM", // ← Change the label
path: "/dashboard/crm",
icon: Target, // ← Change the icon (Lucide)
badge: "core",
moduleId: "MODULE_CRM",
}Footer items
3 fixed items at the bottom of the sidebar:
- Marketplace —
/dashboard/marketplace - Help —
/help - Settings —
/dashboard/parametres
Badges
| Badge | Display | Usage |
|---|---|---|
core | — | Module included in the plan |
addon | Paid badge | Optional paid add-on module |
vertical | Vertical badge | Vertical module (construction) |
tag: NEW | "NEW" pill | New module |
tag: BETA | "BETA" pill | Module in beta |
Legal pages
Important: the 5 legal pages provided are generic templates. You must replace their content with your own texts before going to production. A warning banner (
showBoilerplateDisclaimer) is displayed until you customize the content.
The legal pages live in the src/app/(legal)/ route group:
| Page | Path | File |
|---|---|---|
| Terms of Use | /cgu | src/app/(legal)/cgu/page.tsx |
| Terms of Sale | /cgv | src/app/(legal)/cgv/page.tsx |
| Legal notice | /mentions-legales | src/app/(legal)/mentions-legales/page.tsx |
| Cookie policy | /politique-cookies | src/app/(legal)/politique-cookies/page.tsx |
| Privacy policy | /politique-confidentialite | src/app/(legal)/politique-confidentialite/page.tsx |
Customization
- Open each file and replace the text content with your real legal terms
- Dynamic legal information (company name, address, registration number) is pulled from
APP_CONFIG.legal— configure it via theNEXT_PUBLIC_LEGAL_*environment variables - To remove the warning banner, drop the
showBoilerplateDisclaimerprop from the component - Have your texts reviewed by a lawyer before going to production
Email templates
Folder: src/lib/emails/templates/
6 ready-to-use lifecycle templates:
| Template | Trigger | Description |
|---|---|---|
email-verification.ts | Sign-up | Verification link (24h) |
trial-welcome.ts | Trial start | Welcome + 3 features to try |
trial-reminder-7days.ts | Trial D-7 | Reminder with an upgrade incentive |
trial-reminder-2days.ts | Trial D-2 | Urgent conversion reminder |
trial-expired.ts | Trial end | Usage stats + paid plans |
newsletter-onboarding.ts | Sign-up D+3 | Per-feature personalized tips |
Customizing a template
The templates use Resend with inline HTML. To edit one:
- Open the template file in
src/lib/emails/templates/ - Edit the HTML, the texts, the colors
- Dynamic variables (name, link, etc.) are passed as parameters
Reminder templates
Payment reminders (src/lib/emails/relances.ts) use substitution variables:
| Variable | Description |
|---|---|
{{clientName}} | Client name |
{{invoiceNumber}} | Invoice number |
{{amount}} | Amount due |
{{dueDate}} | Due date |
{{daysPastDue}} | Days overdue |
{{orgName}} | Organization name |
{{signature}} | Configured signature |
Recipes
Four classic customization operations, ready to paste.
1. Rename the "HeartCo" brand to "MySaaS"
The brand is centralized in apps/web/src/lib/config/branding.ts and exposed via the NEXT_PUBLIC_APP_* environment variables. Golden rule: always use APP_CONFIG.name in code, never a hardcoded "HeartCo".
- Update
.env(or the Vercel variables in prod):
NEXT_PUBLIC_APP_NAME="MySaaS"
NEXT_PUBLIC_APP_DOMAIN="mysaas.com"
NEXT_PUBLIC_APP_URL="https://app.mysaas.com"- Search for any residual hardcoded references (rare — fix if found):
# With ripgrep
rg -i "heartco" apps/web/src --type ts --type tsx- Files to inspect manually (may contain the name outside
APP_CONFIG):apps/web/src/lib/config/branding.ts(centralizes the brand)- Legal pages
apps/web/src/app/(legal)/*.tsx(to be customized anyway) - Email templates
apps/web/src/lib/emails/templates/(inline HTML, signature, footer)
2. Replace the logo
The logo is served from apps/web/public/ (3 SVG files: logo.svg, logo-dark.svg, logo-mark.svg).
- Replace the 3 SVG files with your own (same names, same target dimensions)
- If the format differs (PNG/JPG), edit
apps/web/src/components/layout/logo.tsxto point to the new path - On Vercel production, redeploy to invalidate the CDN cache
3. Change the primary color
The brand color is a CSS token in apps/web/src/styles/globals.css. Every component using bg-primary, text-primary, border-primary inherits it automatically.
/* apps/web/src/styles/globals.css */
:root {
--color-brand: #YOUR_COLOR; /* Replace #6366f1 */
}Instant hot reload in dev (pnpm dev), pnpm build required in prod.
4. Disable a sidebar module without removing it
See the full procedure in 05-modules.md — in short:
- Open
apps/web/src/lib/navigation/nav-config.ts - Comment out the item in the
childrenarray of the relevant section - The tRPC router can stay in place — it simply becomes unreachable from the sidebar