Skip to main content
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:
Benefits:
  • ✅ No global singletons
  • ✅ Easy to mock for testing
  • ✅ Clear dependency graph
  • ✅ Compile-time safety

3. Protocol-Oriented Design

All external dependencies use protocols:
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, ViewModels; owns LLMClient/LLMMessage

FeatureRating

Sentiment-based rating prompts

FeatureSettings

Settings and paywall UI

DesignSystem

Tokens, components, Liquid Glass, accessibility

Localization

Type-safe strings, pluralization, i18n
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.
Dependency graph (from template.manifest.json):
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.
Key principles:
  • ✅ No circular dependencies
  • ✅ Core has no dependencies
  • ✅ Features depend on services
  • ✅ Services depend on infrastructure

Data Flow

Chat Message Flow

Authentication Flow

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

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.swiftSessionManager+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.swiftChatViewModel+Memory.swift
Why: keeps files scannable, keeps diffs small, keeps agent context windows productive.

Concurrency Primitives

Async/Await Throughout

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:
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:

Integration Tests

Test component interaction through the composition root:

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:

Customization Entry Points

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 for the pricing model (grandfathered buyers get access when it ships).

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

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

Learn More

Core Module

Error handling, logging, utilities

Networking

HTTP client architecture

Storage

SwiftData and repositories

docs/CLAUDE.md

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