> ## 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.

# Architecture

> System design, patterns, and module structure of SwiftAI Boilerplate Pro

SwiftAI Boilerplate Pro uses modern iOS development patterns with clean separation of concerns.

<Info>
  **Full technical details:** See `docs/foundations/Architecture.md` in your project for complete technical coverage.
</Info>

## Core Principles

### 1. MVVM Architecture

Clean separation between UI, business logic, and data:

**Benefits:**

* ✅ Views are dumb (no business logic)
* ✅ ViewModels are testable (no UIKit dependencies)
* ✅ Business logic isolated and reusable
* ✅ Clear data flow

### 2. Dependency Injection

Centralized composition with `CompositionRoot`:

```swift theme={null}
/// Central dependency injection container
/// Builds and owns all app-wide singletons and factories
@MainActor
@available(iOS 17.0, *)
public final class CompositionRoot {
    
    // MARK: - Singletons
    
    /// SwiftData model container
    public let modelContainer: ModelContainer
    
    /// HTTP client with interceptors
    public let httpClient: any HTTPClient

    /// Keychain storage
    public let keychainStore: KeychainStore

    /// Auth client (SessionManager wrapper in production, MockAuthClient in DEBUG)
    public let sessionManager: any AuthClient

    /// LLM client (ProxyLLMClient when configured, EchoLLMClient otherwise)
    public let llmClient: any LLMClient
    // ...
}

// View-model factories live in CompositionRoot+Factories.swift:
extension CompositionRoot {
    /// Create ChatViewModel with injected dependencies
    public func makeChatViewModel(conversationID: UUID) -> ChatViewModel {
        ChatViewModel(
            conversationID: conversationID,
            messageRepository: messageRepository,
            llmClient: llmClient,
            paymentsStatusProvider: PaymentsStatusAdapter(paymentsClient: paymentsClient)
        )
    }
}
```

**Benefits:**

* ✅ No global singletons
* ✅ Easy to mock for testing
* ✅ Clear dependency graph
* ✅ Compile-time safety

### 3. Protocol-Oriented Design

All external dependencies use protocols:

```swift theme={null}
/// Main authentication client protocol
@available(iOS 17.0, *)
@preconcurrency
public protocol AuthClient: Sendable {
    /// Sign in with Apple ID
    func signInWithApple() async throws -> AuthUser
    
    /// Sign in with Google
    func signInWithGoogle() async throws -> AuthUser
    // ...
}

// Implementations:
// - SessionManager (production actor; wrapped to AuthClient via SessionManagerWrapper)
// - MockAuthClient (DEBUG-only fallback)
```

**Benefits:**

* ✅ Swappable implementations
* ✅ Easy testing with mocks
* ✅ No vendor lock-in
* ✅ Clear contracts

## Module Structure

### 11 Swift Packages

<CardGroup cols={3}>
  <Card title="Core" icon="cube" href="/pages/modules/core">
    Foundation utilities, errors, logging
  </Card>

  <Card title="Networking" icon="wifi" href="/pages/modules/networking">
    HTTP client with interceptors
  </Card>

  <Card title="Storage" icon="database" href="/pages/modules/storage">
    SwiftData models, repositories
  </Card>

  <Card title="Auth" icon="shield" href="/pages/modules/auth">
    Authentication clients
  </Card>

  <Card title="Payments" icon="dollar" href="/pages/modules/payments">
    Subscription management
  </Card>

  <Card title="AI" icon="brain" href="/pages/modules/ai">
    LLM client protocol
  </Card>

  <Card title="FeatureChat" icon="comments" href="/pages/modules/feature-chat">
    Chat UI, ViewModels; owns `LLMClient`/`LLMMessage`
  </Card>

  <Card title="FeatureRating" icon="star" href="/pages/reference/features">
    Sentiment-based rating prompts
  </Card>

  <Card title="FeatureSettings" icon="gear" href="/pages/modules/feature-settings">
    Settings and paywall UI
  </Card>

  <Card title="DesignSystem" icon="swatchbook" href="/pages/modules/design-system">
    Tokens, components, Liquid Glass, accessibility
  </Card>

  <Card title="Localization" icon="globe" href="/pages/modules/localization">
    Type-safe strings, pluralization, i18n
  </Card>
</CardGroup>

<Note>
  A 12th package, **TestSupport** (`Packages/TestSupport`), ships shared test
  infrastructure (e.g. `URLProtocolStub`). It is test-only — not a reusable product
  module — so the "11 Swift Packages cleanly separated for reuse" claim still stands.
</Note>

**Dependency graph (from `template.manifest.json`):**

```text theme={null}
Core            → (no dependencies)
TestSupport     → (no dependencies, test-only)
DesignSystem    → (no dependencies)
Networking      → Core
Storage         → Core, Networking
Localization    → Core
Payments        → Core
FeatureRating   → Core, DesignSystem
Auth            → Core, Networking, Storage
FeatureChat     → Core, Storage, DesignSystem, Localization
AI              → Core, Networking, FeatureChat   (re-exports FeatureChat)
FeatureSettings → Core, Storage, Auth, Payments, DesignSystem, Localization
```

<Warning>
  **Coupling gotcha:** `LLMClient` and `LLMMessage` live in **FeatureChat**, and the
  **AI** package re-exports FeatureChat. Removing chat without first relocating those two
  types breaks `Packages/AI`. The removal order and module map are documented in
  `docs/checklists/APP_STORE_4_3_HARDENING.md`.
</Warning>

**Key principles:**

* ✅ No circular dependencies
* ✅ Core has no dependencies
* ✅ Features depend on services
* ✅ Services depend on infrastructure

## Data Flow

### Chat Message Flow

```text theme={null}
1. User types message → ChatView
2. ChatView calls → ChatViewModel.send()
3. ChatViewModel:
   - Appends message → MessageRepository
   - Streams AI response → LLMClient.streamResponse(messages:)
   - Mutates @Observable state on the main actor
4. View automatically re-renders
```

### Authentication Flow

```text theme={null}
1. User enters credentials → SignInView
2. View calls → AuthViewModel.signIn()
3. AuthViewModel calls → AuthClient.signInWithEmail(email:password:)
4. SessionManager (the AuthClient):
   - Calls Supabase API
   - Persists tokens → Keychain (via SessionStore)
   - Returns AuthUser, emits via authStates()
5. LaunchRouter observes the auth state change
6. Navigation switches to authenticated content
```

## iOS 26 Liquid Glass Layer

The DesignSystem package ships a dedicated Liquid Glass primitive.

**Primitive:** `Packages/DesignSystem/Sources/DesignSystem/Materials/SAIGlass.swift`

* **`SAIGlassStyle`**: `.regular` (default surface) and `.clear` (edge-to-edge hero surfaces).
* **`.saiGlass(...)` modifier**: one-call glass treatment for any view.
* **`SAIGlassContainer`**: merges nearby glass surfaces so adjacent cards, toolbars, and sheets sample the same background instead of stacking visually.

**Availability strategy:**

* **iOS 26+**: uses the native `Glass` material, `glassEffect`, and `GlassEffectContainer`.
* **iOS 17–25**: falls back to SwiftUI `Material` automatically. Same call sites, progressive enhancement at runtime.

The same file also exports `saiScrollEdgeGlass(_:)`, `saiSidebarAdaptable()`, `saiTabBarMinimize(_:)`, and `SAITabBarMinimizeStyle` for shell-level polish.

See [Design System Module](/pages/modules/design-system#liquid-glass) for the full API.

## Swift 6 Concurrency Model

The entire codebase builds under **strict concurrency checking** on the Swift 6 toolchain.

* **`@MainActor`-pinned storage repositories**: `MessageRepositoryImpl`, `ConversationRepositoryImpl`, and `SettingsRepositoryImpl` are all main-actor-isolated.
* **`@Observable` throughout**: view models and observable stores use the `@Observable` macro. No `ObservableObject`, no `@Published`, no `.onReceive`.
* **No `DispatchQueue.main` in app code**: all main-thread work goes through `@MainActor` or `MainActor.run`.
* **Explicit `any`**: every protocol-typed property and parameter uses the `any` keyword, as Swift 6 requires.
* **Async/await throughout**: no completion handlers, structured concurrency for cancellation, `Sendable` where crossing actor boundaries.

```swift theme={null}
@MainActor
@Observable
public final class ChatViewModel {
    private let messageRepository: any MessageRepository
    private let llmClient: any LLMClient
    ...
}
```

## Architecture Rule: ≤ 400 Lines Per File

A workspace-wide ceiling keeps every production and test Swift file ≤ 400 lines (enforced by `.swiftlint.yml` `file_length: warning: 400`). When a type grows past that, it moves into extension-split siblings in the same folder.

Examples in the codebase:

* `SessionManager.swift` → `SessionManager+SignIn`, `+Refresh`, `+Persistence`
* `L10n` strings → `L10n+<Namespace>.swift` per nested enum (Auth, Chat, Settings, …)
* `SettingsView.swift` → a 125-line composition root with sections split out
* `ChatViewModel.swift` → `ChatViewModel+Memory.swift`

Why: keeps files scannable, keeps diffs small, keeps agent context windows productive.

## Concurrency Primitives

### Async/Await Throughout

```swift theme={null}
/// Send the current input text.
public func send() async {
    // 1. Validate input (skip empty/whitespace)
    // 2. Append the user message via MessageRepository
    // 3. Stream the AI reply: llmClient.streamResponse(messages:)
    // 4. Mutate @Observable state on the main actor as tokens arrive
}
```

**Benefits:**

* ✅ No completion handlers
* ✅ Structured concurrency (cancellable stream tasks)
* ✅ MainActor for UI updates
* ✅ Sendable for thread safety

## Testing Strategy

The whole workspace runs in **one pass** via `Boilerplate.xctestplan`: **\~598 tests across 12 package test targets + the app test suites** (`SwiftAIBoilerplateProTests` unit + `SwiftAIBoilerplateProUITests`). A single `xcodebuild test` covers everything:

```bash theme={null}
xcodebuild test \
  -project SwiftAIBoilerplatePro.xcodeproj \
  -scheme SwiftAIBoilerplatePro \
  -destination 'platform=iOS Simulator,name=iPhone 17 Pro,OS=26.2' \
  CODE_SIGNING_ALLOWED=NO
```

The 12 package test targets are: `CoreTests`, `TestSupportTests`, `NetworkingTests`, `StorageTests`, `AuthTests`, `DesignSystemTests`, `FeatureChatTests`, `FeatureRatingTests`, `FeatureSettingsTests`, `PaymentsTests`, `LocalizationTests`, `AITests`. (`TestSupportTests` exercises the shared test-infrastructure package.)

### Unit Tests

Test ViewModels and repositories in isolation, injecting fakes for external clients:

```swift theme={null}
func testSendStreamsReply() async throws {
    let viewModel = ChatViewModel(
        conversationID: UUID(),
        messageRepository: messageRepository,
        llmClient: EchoLLMClient() // dev fallback echoes the prompt
    )
    viewModel.inputText = "Hello"

    await viewModel.send()

    XCTAssertFalse(viewModel.messages.isEmpty)
}
```

### Integration Tests

Test component interaction through the composition root:

```swift theme={null}
@MainActor
func testCompositionRoot() throws {
    let authConfig = AuthConfig(
        supabaseURL: URL(string: "https://test.supabase.co")!,
        supabaseAnonKey: "test_anon_key"
    )
    let paymentsConfig = PaymentsConfig(
        apiKey: "test_api_key",
        entitlementID: "test_entitlement"
    )
    let composition = try CompositionRoot(
        authConfig: authConfig,
        paymentsConfig: paymentsConfig
    )

    // Dependencies are wired
    XCTAssertNotNil(composition.httpClient)
    XCTAssertNotNil(composition.sessionManager)

    // Factories produce view models
    let chatVM = composition.makeChatViewModel(conversationID: UUID())
    XCTAssertNotNil(chatVM)
}
```

### UI Tests

Test end-to-end flows. UI suites need the `UI_TESTING=1` launch hook so the first-launch onboarding/permission alert does not block them:

```swift theme={null}
func testChatFlow() throws {
    let app = XCUIApplication()
    app.launchEnvironment["UI_TESTING"] = "1"
    app.launch()

    app.buttons["Start Chat"].tap()

    let textField = app.textFields["messageInput"]
    textField.tap()
    textField.typeText("Hello AI")
    app.buttons["send"].tap()

    XCTAssertTrue(app.staticTexts["Hello AI"].waitForExistence(timeout: 5))
}
```

## Customization Entry Points

<Tip>
  **App Generator (coming soon, separate product).** A standalone macOS app that drives
  your own coding-agent CLI (Claude Code / Codex / Gemini / Cursor) to generate a
  differentiated, App Store Guideline 4.3(a)-safe app *from* this template — using the
  module graph and recipes documented above. It is a separate purchase, not bundled in the
  boilerplate, and ships no LLM. See [License & Updates](/pages/reference/license) for the
  pricing model (grandfathered buyers get access when it ships).
</Tip>

### Add New Feature

1. **Create package** (if needed): `Packages/FeatureX/`
2. **Create models**: Define SwiftData models in `Storage`
3. **Create repository**: Data access layer
4. **Create ViewModel**: Business logic
5. **Create View**: SwiftUI interface
6. **Wire in CompositionRoot**: Add factory method

### Replace Backend

Implement the protocol:

```swift theme={null}
// Want to use Firebase instead of Supabase? Conform to the AuthClient protocol.
final class FirebaseAuthClient: AuthClient {
    func signInWithEmail(email: String, password: String) async throws -> AuthUser {
        // Firebase implementation
    }
    // ... signInWithApple, signInWithGoogle, signOut, currentUser, authStates, etc.
}

// Then wire it in CompositionRoot:
self.sessionManager = FirebaseAuthClient(...)
```

<Note>
  This swap snippet is illustrative — there is no `FirebaseAuthClient` in the template.
  The production implementation is `SessionManager` (a Supabase-backed actor) adapted to
  `AuthClient` via `SessionManagerWrapper`.
</Note>

### Add UI Components

1. Create component in `DesignSystem/Components/`
2. Use design tokens (DSColors, DSSpacing, etc.)
3. Add preview
4. Add snapshot test
5. Use in features

## Best Practices Applied

<AccordionGroup>
  <Accordion title="Code Organization">
    * Files ≤ 400 lines (extension-split when larger)
    * One type per file
    * MARK comments for navigation
    * Grouped by responsibility
  </Accordion>

  <Accordion title="Error Handling">
    * All errors mapped to `AppError`
    * User-friendly messages
    * Technical details logged
    * Never swallow errors silently
  </Accordion>

  <Accordion title="Naming">
    * Clear, explicit names
    * No abbreviations in public API
    * Consistent conventions
    * Self-documenting code
  </Accordion>

  <Accordion title="Performance">
    * Lazy loading (messages, images)
    * Cursor-based pagination
    * Image compression
    * Offline-first data access
    * Background sync
  </Accordion>

  <Accordion title="Security">
    * Tokens in Keychain (never UserDefaults)
    * API keys server-side only
    * PII redacted in logs
    * Row Level Security (Supabase)
  </Accordion>
</AccordionGroup>

## Key Files

| Purpose                  | File Location                                             |
| ------------------------ | --------------------------------------------------------- |
| **Dependency Injection** | `SwiftAIBoilerplatePro/Composition/CompositionRoot.swift` |
| **Feature Flags**        | `SwiftAIBoilerplatePro/Composition/FeatureFlags.swift`    |
| **App Entry**            | `SwiftAIBoilerplatePro/SwiftAIBoilerplatePro.swift`       |
| **Navigation**           | `SwiftAIBoilerplatePro/AppShell/MainTabView.swift`        |
| **Auth Router**          | `SwiftAIBoilerplatePro/AppShell/LaunchRouter.swift`       |

## Learn More

<CardGroup cols={2}>
  <Card title="Core Module" icon="cube" href="/pages/modules/core">
    Error handling, logging, utilities
  </Card>

  <Card title="Networking" icon="wifi" href="/pages/modules/networking">
    HTTP client architecture
  </Card>

  <Card title="Storage" icon="database" href="/pages/modules/storage">
    SwiftData and repositories
  </Card>

  <Card title="docs/CLAUDE.md" icon="robot" href="https://github.com/SwiftAIBoilerplatePro/SwiftAIBoilerplatePro-Distribution/blob/main/docs/CLAUDE.md">
    Guidelines for AI-assisted development
  </Card>
</CardGroup>

<Info>
  **Find full technical documentation in your project:** [Architecture.md](https://github.com/SwiftAIBoilerplatePro/SwiftAIBoilerplatePro-Distribution/blob/main/docs/foundations/Architecture.md)
</Info>
