> ## Documentation Index
> Fetch the complete documentation index at: https://docs.swiftaiboilerplate.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Customization Recipes

> Common customization patterns and examples

<Note>
  For complete customization guide with LLM prompts, see [Building Your App](/pages/guides/building-your-app)
</Note>

<Warning>
  **Shipping a white-labeled version?** Customizing colors and onboarding isn't enough on its own. Before you submit, run the [App Store 4.3 hardening checklist](/pages/guides/app-store-4-3-hardening) to clear binary fingerprints, branding leftovers, and listing copy that still reads like a template.
</Warning>

## Branding

### Change App Colors

**What to customize:** The design tokens read their colors from the DesignSystem package's own asset catalog via `Bundle.module`:

```text theme={null}
Packages/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/
├── AccentPrimary.colorset      # DSColors.accentPrimary / .primary
├── AccentSecondary.colorset
├── Background.colorset
├── Surface.colorset
├── SurfaceElevated.colorset
├── TextPrimary.colorset
├── TextSecondary.colorset
├── ChipBackground.colorset
├── Danger.colorset / Success.colorset / Warning.colorset
└── ...
```

**Steps:**

1. Open the color set in Xcode
2. Change Light Appearance color
3. Change Dark Appearance color
4. Build → colors update everywhere

**All components use design tokens** - change once, applies everywhere. Note: the `system`/`light`/`dark` themes read these assets, while the `aurora` and `obsidian` themes use hard-coded values in `DSColors.swift`, so customizing those requires editing the matching `switch activeTheme` branches.

### Replace App Icon

**Steps:**

1. Create 1024×1024 PNG
2. Drag to `SwiftAIBoilerplatePro/Assets.xcassets/AppIcon.appiconset`
3. Xcode generates all required sizes
4. Build and verify

### Customize Onboarding

**File:** `SwiftAIBoilerplatePro/AppShell/OnboardingPage.swift`

**Change the `defaultPages` array:**

```swift theme={null}
static let defaultPages: [OnboardingPage] = [
    OnboardingPage(
        title: "Your Title",
        description: "Your description",
        systemImage: "sparkles",  // Any SF Symbol
        accentColor: "blue"        // Hex or system color name
    ),
    // Add more pages...
]
```

## UI Customization

### Add Home Screen Feature Card

**File:** `SwiftAIBoilerplatePro/AppShell/HomeContent.swift`

Add to `HomeContent.FeatureItem.defaults` (or pass your own `featuredItems` into `HomeContent`):

```swift theme={null}
public static let defaults: [HomeContent.FeatureItem] = [
    // ... existing cards
    HomeContent.FeatureItem(
        title: "Your Feature",
        description: "Feature description",
        systemImage: "bookmark.fill",
        accentColor: "blue"
    ),
]
```

### Change Chat Bubble Colors

Bubble colors are derived from design tokens, not from dedicated bubble color sets. In `DSColors.swift`:

* `bubbleUserOrFallback` → `accentPrimary` (the `AccentPrimary.colorset` for system/light/dark)
* `bubbleAssistantOrFallback` → `surface` (a system color, `Color(.secondarySystemBackground)`, for system/light/dark)

Change the user bubble by editing `AccentPrimary.colorset` in `Packages/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/`. The assistant bubble follows the system surface color, so adjust the `surface` token's `switch activeTheme` branch in `DSColors.swift` to override it.

### Add Custom Theme

<Steps>
  <Step title="Create Color Sets">
    In the DesignSystem package catalog (`Packages/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets`), create color sets for any semantic colors your theme needs.
  </Step>

  <Step title="Add Theme Case">
    In `SettingsDTO.swift`, add a case to the string-backed `Theme` enum (used by the settings UI):

    ```swift theme={null}
    public enum Theme: String, Sendable, Equatable, CaseIterable {
        case system, light, dark, aurora, obsidian
        case myTheme  // Add this
    }
    ```
  </Step>

  <Step title="Map Colors">
    In `DSColors.swift`, add a `case .myTheme` to the internal `ThemePalette` enum and to each token `switch activeTheme` block.
  </Step>

  <Step title="Add to Picker">
    The appearance picker in `SettingsAppearanceSection.swift` iterates `SettingsDTO.Theme.allCases`, so the new case appears automatically once the enum and mappings are in place.
  </Step>
</Steps>

## Feature Customization

### Add Custom AI Persona

**File:** `Packages/FeatureChat/Sources/FeatureChat/ViewModels/ChatViewModel.swift`

`LLMMessage` lives in `FeatureChat` and its `role` is a `String` (`"user" | "assistant" | "system"`):

```swift theme={null}
// Inside ChatViewModel.send() (the real entry point is `public func send() async`),
// build the prompt list with a persona system message:
let systemPrompt = LLMMessage(
    role: "system",
    content: """
    You are a professional Swift developer.
    Provide clear, concise answers with code examples.
    """
)

let messages = [systemPrompt] + history  // `history` mapped to [LLMMessage]
// Pass `messages` to llmClient when streaming
```

<Note>
  The server-side AI Edge Function (`supabase/functions/ai/index.ts`) injects its own fixed `SYSTEM_PROMPT` and clients may only send `user`/`assistant` roles, so a client-supplied system message is for local/echo flows. To change the deployed persona, edit `SYSTEM_PROMPT` in the function and redeploy.
</Note>

### Add New SwiftData Model

<Steps>
  <Step title="Create Model">
    ```swift theme={null}
    @Model
    class YourModel {
        @Attribute(.unique) var id: UUID
        var property: String
        var createdAt: Date
    }
    ```
  </Step>

  <Step title="Create DTO">
    ```swift theme={null}
    struct YourModelDTO: Identifiable, Sendable {
        let id: UUID
        let property: String
        
        init(_ model: YourModel) {
            self.id = model.id
            self.property = model.property
        }
    }
    ```
  </Step>

  <Step title="Create Repository">
    Protocol + implementation following existing patterns
  </Step>

  <Step title="Add to Schema">
    In `SwiftAIBoilerplatePro/Composition/CompositionRoot.swift`, add your model to the `Schema([Conversation.self, Message.self, Settings.self])` array.
  </Step>
</Steps>

### Add Custom Setting

<Steps>
  <Step title="Update Settings Model">
    In `Packages/Storage/Sources/Storage/Models/Settings.swift`:

    ```swift theme={null}
    @Model
    public final class Settings {
        public var theme: String  // "system" | "light" | "dark"
        public var yourSetting: Bool = false  // Add this
    }
    ```
  </Step>

  <Step title="Update ViewModel">
    ```swift theme={null}
    @Observable
    class SettingsViewModel {
        var yourSetting: Bool
        
        func toggleYourSetting(_ enabled: Bool) async {
            // Save to repository
        }
    }
    ```
  </Step>

  <Step title="Update UI">
    ```swift theme={null}
    Toggle("Your Setting", isOn: $viewModel.yourSetting)
        .onChange(of: viewModel.yourSetting) {
            Task { await viewModel.toggleYourSetting($0) }
        }
    ```
  </Step>
</Steps>

## Backend Customization

### Change AI Model

**File:** `supabase/functions/ai/index.ts`

For cost safety, the function validates the requested model against an allowlist (security rule BL-003). To allow a different OpenRouter model, add it to `ALLOWED_MODELS`:

```typescript theme={null}
// Only allow-listed models are accepted; everything else is rejected with 400.
const ALLOWED_MODELS = [
  'openai/gpt-3.5-turbo',
  'openai/gpt-4o-mini',
  'anthropic/claude-3-5-sonnet',  // Add the models you want to permit
]
```

The request body's `model` defaults to `openai/gpt-3.5-turbo` and must be in this list. The server-side `SYSTEM_PROMPT` and role allowlist (`user`/`assistant`) are also enforced here.

**Deploy:**

```bash theme={null}
supabase functions deploy ai
```

### Add Usage Limits

`PaymentsClient.currentState()` and `state.isSubscribed` are real APIs; the per-day count below is illustrative — back it with your own repository query.

```swift theme={null}
func canSendMessage() async -> Bool {
    let state = await paymentsClient.currentState()
    
    if state.isSubscribed {
        return true  // Unlimited for pro
    } else {
        let count = await messageRepository.todayCount()  // your own query
        return count < 20  // Free tier limit
    }
}
```

## Module Customization

Each module has detailed customization examples:

<CardGroup cols={3}>
  <Card title="Core" href="/pages/modules/core">
    Custom errors, log categories
  </Card>

  <Card title="Networking" href="/pages/modules/networking">
    Custom requests, interceptors
  </Card>

  <Card title="Storage" href="/pages/modules/storage">
    New models, repositories
  </Card>

  <Card title="Auth" href="/pages/modules/auth">
    Social providers, custom fields
  </Card>

  <Card title="Payments" href="/pages/modules/payments">
    New tiers, usage limits
  </Card>

  <Card title="AI" href="/pages/modules/ai">
    Models, personas, prompts
  </Card>

  <Card title="FeatureChat" href="/pages/modules/feature-chat">
    UI styles, actions, search
  </Card>

  <Card title="FeatureSettings" href="/pages/modules/feature-settings">
    New settings, paywall
  </Card>

  <Card title="DesignSystem" href="/pages/modules/design-system">
    Themes, components, tokens
  </Card>
</CardGroup>

## Pro Tips

<Tip>
  **Test after each change** - Don't stack multiple changes without testing
</Tip>

<Tip>
  **Use design tokens** - Never hardcode colors or spacing
</Tip>

<Tip>
  **Follow existing patterns** - Look for similar features first
</Tip>

<Tip>
  **Keep files ≤ 300 lines** - Extract components when needed
</Tip>

## Need More Help?

<CardGroup cols={2}>
  <Card title="Building Guide" icon="book" href="/pages/guides/building-your-app">
    Step-by-step guide with LLM prompts
  </Card>

  <Card title="Module Docs" icon="cube" href="/pages/modules/core">
    Detailed technical docs
  </Card>

  <Card title="CLAUDE.md" icon="robot" href="https://github.com/SwiftAIBoilerplatePro/SwiftAIBoilerplatePro-Distribution/blob/main/docs/CLAUDE.md">
    AI coding guidelines
  </Card>

  <Card title="Architecture" icon="diagram-project" href="/pages/architecture">
    System design
  </Card>
</CardGroup>
