# Customization

Customize the Account UI to match your brand and messaging. Branding is driven by the `account` block in `quickback.config.ts` and the environment variables the compiler bakes in at build time.

## Branding

### App Identity

Set your application's name and description:

```bash
VITE_APP_NAME=Acme SaaS
VITE_APP_TAGLINE=Build faster, ship sooner
VITE_APP_DESCRIPTION=The complete platform for modern web applications
```

These values appear in:
- Page titles (`<title>Acme SaaS | Login</title>`)
- Meta descriptions
- UI headers and footers
- Email templates

### Visual Identity

```bash
# Primary theme color (used for buttons, links, accents)
VITE_THEME_COLOR=#3b82f6

# Company name (shown in footer, legal pages)
VITE_COMPANY_NAME=Acme Corporation

# Company address (shown in footer, receipts)
VITE_COMPANY_ADDRESS=123 Main St, Suite 100, San Francisco, CA 94105
```

### Logo and Favicon

Place your branding assets in the `public/` directory:

```
public/
├── logo.png          # Main logo (shown in header)
├── favicon.ico       # Browser favicon
└── og-image.png      # Social media preview image
```

Then update the paths in `src/config/app.ts`:

```ts title="src/config/app.ts"
branding: {
  primaryColor: "#1e293b",
  logoUrl: "/logo.png",
  faviconUrl: "/favicon.ico"
},
```

Or set them at runtime in `src/main.tsx`:

```ts
import { setAppConfig } from '@/config/app';

setAppConfig({
  branding: {
    logoUrl: '/logo.png',
    faviconUrl: '/favicon.ico',
  },
});
```

## Custom Labels

Override default UI labels using runtime configuration:

```ts
import { setAppConfig } from '@/config/app';

setAppConfig({
  labels: {
    terms: 'Terms and Conditions',
    privacy: 'Privacy Notice',
    support: 'Help Center',
    company: 'My Company',
    organizations: 'Workspaces',  // Rename "Organizations" to "Workspaces"
  },
});
```

### Available Labels

| Label | Default | Usage |
|-------|---------|-------|
| `terms` | "Terms of Service" | Footer link text |
| `privacy` | "Privacy Policy" | Footer link text |
| `support` | "Contact Support" | Footer link text |
| `company` | (from `VITE_COMPANY_NAME`) | Footer company name |
| `organizations` | "Organizations" | Navigation and page titles. Profile and the user menu prefix this as **Manage …** (`Manage Organizations`). |

## Custom Messages

Customize user-facing messages:

```ts
import { setAppConfig } from '@/config/app';

setAppConfig({
  messages: {
    noOrganizations: "You haven't joined any workspaces yet.",
    contactAdminForInvite: "Contact your team lead to get access.",
    noPendingInvitations: "No pending invites at this time",
    createOrganization: "Create Workspace",
    // ... more messages
  },
});
```

### Available Messages

| Message | Default | Usage |
|---------|---------|-------|
| `noOrganizations` | "You're not a member of any organizations yet." | Empty organizations list |
| `contactAdminForInvite` | "Contact an admin to be invited to an organization." | Organizations page help text |
| `noPendingInvitations` | "You have no pending invitations" | Empty invitations list |
| `createOrganization` | "Create Organization" | Button text |
| `accountInformation` | "Account Information" | Profile section header |
| `timezone` | "Timezone" | Label for timezone field |
| `serverLocation` | "Server Location" | Label for server location |
| `memberSince` | "Member since" | Account age label |
| `pendingInvitations` | "Pending Invitations" | Section header |
| `invitedAs` | "Invited as" | Invitation role label |
| `accept` | "Accept" | Accept invitation button |
| `decline` | "Decline" | Decline invitation button |
| `userFallback` | "User" | Fallback for missing name |
| `noEmailProvided` | "No email provided" | Fallback for missing email |
| `more` | "More" | Pagination/load more text |
| `total` | "total" | Total count label |
| `active` | "Active" | Active status label |
| `new` | "New" | New item label |

## Route Customization

Customize route paths using runtime configuration:

```ts
import { setAppConfig } from '@/config/app';

setAppConfig({
  routes: {
    public: {
      home: '/',
      login: '/sign-in',        // Change from /login
      signup: '/sign-up',       // Change from /signup
      forgotPassword: '/reset-password',
      welcome: '/getting-started',
    },
    authenticated: {
      dashboard: '/dashboard',
      profile: '/my-account',
      settings: '/preferences',
    },
    organizations: {
      list: '/workspaces',                    // Rename route
      create: '/workspaces/new',
      detail: (slug) => `/workspaces/${slug}`,
    },
  },
});
```

> **Route Configuration Limitations**
>
> Route changes via runtime config only affect client-side routing and internal links. External links to your Account UI should use the actual deployed routes (default paths).


## Password Requirements

Customize password validation rules:

```ts
import { setAppConfig } from '@/config/app';

setAppConfig({
  auth: {
    passwordRequirements: {
      minLength: 12,              // Minimum password length
      maxLength: 128,             // Maximum password length
      requireUppercase: true,     // Must have uppercase letter
      requireLowercase: true,     // Must have lowercase letter
      requireNumbers: true,       // Must have number
      requireSymbols: true,       // Must have special character
    },
  },
});
```

Password requirements are displayed to users during signup and password changes.

## Session Duration

Control how long users stay logged in:

```ts
import { setAppConfig } from '@/config/app';

setAppConfig({
  auth: {
    sessionDuration: 7 * 24 * 60 * 60,  // 7 days in seconds
  },
});
```

## Email Customization

Configure email sender information:

```bash
VITE_EMAIL_FROM=noreply@acme.com
VITE_EMAIL_REPLY_TO=support@acme.com
VITE_SUPPORT_EMAIL=help@acme.com
```

The `fromName` is automatically set to `VITE_APP_NAME`:

```ts
// Emails will show:
// From: "Acme SaaS <noreply@acme.com>"
```

## URL Configuration

Configure URLs for external links:

```bash
# Main application (redirected to after login)
VITE_QUICKBACK_APP_URL=https://app.acme.com

# Organization/tenant URL pattern
VITE_TENANT_URL_PATTERN=/workspace/{slug}

# Support pages
VITE_SUPPORT_URL=https://help.acme.com
VITE_PRIVACY_URL=https://acme.com/legal/privacy
VITE_TERMS_URL=https://acme.com/legal/terms
```

### Tenant URL Patterns

The tenant URL pattern supports flexible organization routing:

```bash
# Path-based routing
VITE_TENANT_URL_PATTERN=/organizations/{slug}
# Result: https://app.acme.com/organizations/acme-corp

# Subdomain routing
VITE_TENANT_URL_PATTERN=https://{slug}.acme.com
# Result: https://acme-corp.acme.com

# Custom pattern
VITE_TENANT_URL_PATTERN=/workspace/{slug}/dashboard
# Result: https://app.acme.com/workspace/acme-corp/dashboard
```

## Complete Customization Example

Here's a complete example showing all customization options:

```ts title="src/main.tsx"
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { setAppConfig } from '@/config/app';
import './app/globals.css';
import './custom-styles.css';  // Your custom CSS overrides

// Apply customizations before rendering
setAppConfig({
  name: 'Acme SaaS',
  tagline: 'Build faster, ship sooner',
  description: 'The complete platform for modern web applications',

  branding: {
    primaryColor: '#3b82f6',
    logoUrl: '/acme-logo.png',
    faviconUrl: '/favicon.ico',
  },

  labels: {
    organizations: 'Workspaces',
    terms: 'Terms and Conditions',
    privacy: 'Privacy Notice',
    support: 'Help Center',
  },

  messages: {
    noOrganizations: "You haven't joined any workspaces yet.",
    createOrganization: 'Create Workspace',
    contactAdminForInvite: 'Contact your team lead for access.',
  },

  routes: {
    public: {
      login: '/sign-in',
      signup: '/sign-up',
    },
    organizations: {
      list: '/workspaces',
      create: '/workspaces/new',
      detail: (slug) => `/workspaces/${slug}`,
    },
  },

  auth: {
    passwordRequirements: {
      minLength: 12,
      requireSymbols: true,
    },
    sessionDuration: 7 * 24 * 60 * 60,  // 7 days
  },
});

// Render app
import App from './App';
const root = document.getElementById('root')!;
createRoot(root).render(
  <StrictMode>
    <App />
  </StrictMode>
);
```

## Custom Styles

Override default styles with custom CSS:

```css title="custom-styles.css"
/* Override primary color */
:root {
  --primary: 59 130 246;  /* Tailwind blue-500 */
  --primary-foreground: 255 255 255;
}

/* Custom logo size */
.logo {
  width: 180px;
  height: auto;
}

/* Custom button styles */
.btn-primary {
  background-color: var(--primary);
  border-radius: 8px;
  font-weight: 600;
}
```

Import your custom CSS after the Account UI styles:

```ts
import './app/globals.css';
import './custom-styles.css';  // Your overrides
```

## Next Steps

- **[With Quickback](/ui/account/with-quickback)** - How the compiler builds and bundles your customized UI
- **[Environment Variables](/ui/account/environment-variables)** - Complete configuration reference
- **[Feature Flags](/ui/account/features)** - Enable/disable features
