Skip to main content

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 Overview

SwiftAI Boilerplate Pro uses modern iOS development patterns with clean separation of concerns.
Full technical details: See /docs/foundations/Architecture.md in your project for complete technical coverage.

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:
/// 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: HTTPClient
    
    /// Keychain storage
    public let keychainStore: KeychainStore
    
    /// Auth client (SessionManager or MockAuthClient)
    public let sessionManager: AuthClient
    .
    .
    .
    // MARK: - Factory Methods
    
    /// Create ChatViewModel with injected dependencies
    public func makeChatViewModel(conversationID: UUID) -> ChatViewModel {
        ChatViewModel(
            conversationID: conversationID,
            messageRepository: messageRepository,
            llmClient: llmClient
        )
    }
}
Benefits:
  • ✅ No global singletons
  • ✅ Easy to mock for testing
  • ✅ Clear dependency graph
  • ✅ Compile-time safety

3. Protocol-Oriented Design

All external dependencies use protocols:
/// 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:
// - SupabaseAuthClient (production)
// - MockAuthClient (testing)
Benefits:
  • ✅ Swappable implementations
  • ✅ Easy testing with mocks
  • ✅ No vendor lock-in
  • ✅ Clear contracts

Module Structure

11 Swift Packages

Core

Foundation utilities, errors, logging

Networking

HTTP client with interceptors

Storage

SwiftData models, repositories

Auth

Authentication clients

Payments

Subscription management

AI

LLM client protocol

FeatureChat

Chat UI and ViewModels

FeatureSettings

Settings and paywall

DesignSystem

UI tokens, components, and accessibility

Localization

Type-safe strings, pluralization, i18n

Accessibility

VoiceOver, Dynamic Type, Reduce Motion
Key principles:
  • ✅ No circular dependencies
  • ✅ Core has no dependencies
  • ✅ Features depend on services
  • ✅ Services depend on infrastructure

Data Flow

Chat Message Flow

1. User types message → ChatView
2. ChatView calls → ChatViewModel.sendMessage()
3. ChatViewModel:
   - Saves message → MessageRepository
   - Streams AI response → LLMClient
   - Updates @Published state
4. View automatically re-renders

Authentication Flow

1. User enters credentials → SignInView
2. View calls → AuthViewModel.signIn()
3. AuthViewModel calls → AuthClient.signInWithEmail()
4. AuthClient:
   - Calls Supabase API
   - Saves token → Keychain (via SessionStore)
   - Returns AuthUser
5. CompositionRoot observes auth state change
6. Navigation switches to authenticated content

iOS 26 Liquid Glass Layer

v2.0 introduces a dedicated Liquid Glass primitive inside the DesignSystem package. 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 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.
@MainActor
@Observable
public final class ChatViewModel {
    private let messageRepository: any MessageRepository
    private let llmClient: any LLMClient
    ...
}

Architecture Rule: ≤ 400 Lines Per File

v2.0 enforces a hard ceiling: no Swift file exceeds 400 lines. When a type grows past that, it moves into extension-split siblings in the same folder. Examples from the v2.0 refactor:
  • SessionManager.swift+SignIn, +Refresh, +Persistence
  • L10n.swiftL10n+<Namespace>.swift per nested enum
  • SettingsView.swift → ≤ 125-line composition root with sections in Views/Settings/*.swift
  • ChatViewModel.swiftChatViewModel+Memory.swift
Why: keeps files scannable, keeps diffs small, keeps agent context windows productive. See the refactor commit range in git log for the full rewrite.

Concurrency Primitives

Async/Await Throughout

/// Send current input text
    public func send() async {
        // 1. Validate input
        .
        .
        .
Benefits:
  • ✅ No completion handlers
  • ✅ Structured concurrency
  • ✅ MainActor for UI updates
  • ✅ Sendable for thread safety

Testing Strategy

Unit Tests

Test ViewModels and repositories in isolation:
func testSendMessage() async throws {
    let mockLLM = MockLLMClient()
    let viewModel = ChatViewModel(llmClient: mockLLM, ...)
    
    await viewModel.sendMessage("Hello")
    
    XCTAssertEqual(viewModel.messages.count, 2) // user + AI
}

Integration Tests

Test component interaction:
func testCompositionRoot() {
    let composition = CompositionRoot()
    
    // Verify all dependencies created
    XCTAssertNotNil(composition.httpClient)
    XCTAssertNotNil(composition.sessionManager)
    
    // Verify factories work
    let chatVM = composition.makeChatViewModel(conversationID: uuid)
    XCTAssertNotNil(chatVM)
}

UI Tests

Test end-to-end flows:
func testChatFlow() throws {
    let app = XCUIApplication()
    app.launch()
    
    // Navigate to chat
    app.buttons["Start Chat"].tap()
    
    // Send message
    let textField = app.textFields["messageInput"]
    textField.tap()
    textField.typeText("Hello AI")
    app.buttons["send"].tap()
    
    // Verify response appears
    XCTAssertTrue(app.staticTexts["Hello AI"].exists)
}
Coverage target: 85-90% overall

Customization Entry Points

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:
// Want to use Firebase instead of Supabase?
class FirebaseAuthClient: AuthClient {
    func signIn(email: String, password: String) async throws -> AuthUser {
        // Firebase implementation
    }
    // ... implement other methods
}

// Update CompositionRoot:
self.sessionManager = FirebaseAuthClient(...)

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

  • Files ≤ 400 lines (extension-split when larger)
  • One type per file
  • MARK comments for navigation
  • Grouped by responsibility
  • All errors mapped to AppError
  • User-friendly messages
  • Technical details logged
  • Never swallow errors silently
  • Clear, explicit names
  • No abbreviations in public API
  • Consistent conventions
  • Self-documenting code
  • Lazy loading (messages, images)
  • Cursor-based pagination
  • Image compression
  • Offline-first data access
  • Background sync
  • Tokens in Keychain (never UserDefaults)
  • API keys server-side only
  • PII redacted in logs
  • Row Level Security (Supabase)

Key Files

PurposeFile Location
Dependency InjectionSwiftAIBoilerplatePro/Composition/CompositionRoot.swift
Feature FlagsSwiftAIBoilerplatePro/Composition/FeatureFlags.swift
App EntrySwiftAIBoilerplatePro/SwiftAIBoilerplatePro.swift
NavigationSwiftAIBoilerplatePro/AppShell/MainTabView.swift
Auth RouterSwiftAIBoilerplatePro/AppShell/LaunchRouter.swift

Learn More

Core Module

Error handling, logging, utilities

Networking

HTTP client architecture

Storage

SwiftData and repositories

CLAUDE.md

Guidelines for AI-assisted development
Find full technical documentation in your project: architecture-overview.md