Skip to main content
v2.3.0 is available. Read the upgrade guide for the current capability contracts, AI quota migration, and validation results.

Typed records in v2.3.0

CodableRecordStore<Record> accepts Identifiable, Codable, and Sendable records. Use init(fileURL:) for persistence or init(inMemory:) for tests. Its list, get, upsert, delete, and replaceAll methods run through the actor. Writes encode the full collection and atomically replace the file before changing in-memory state. Invalid files and unknown schema versions return typed errors; they do not silently become empty stores. Inject one instance per file through CompositionRoot. This store suits small record sets; use the database repositories for relational queries or larger collections. Actor isolation does not coordinate separate instances or processes. The release fixes reloads from paths with spaces, Unicode, and percent sequences.
Full technical details in your project at /docs/modules/Storage.md

Concurrency notes (v2.2.0)

  • MessageRepositoryImpl, ConversationRepositoryImpl, and SettingsRepositoryImpl are @MainActor-pinned. If downstream code constructs these from a non-main actor, you need an await at the construction site. The public protocol API is unchanged.
  • Swift 6 strict concurrency across the package.
If you hit MainActor-isolated errors on ModelContext after upgrading, it’s this change. Build the repository on the main thread or await it from a background context.

What You Get

  • ✅ Repository pattern - Never expose @Model types to Views
  • ✅ DTO pattern - Lightweight, Sendable data transfer objects
  • ✅ Keychain wrapper - Secure, tested token storage
  • ✅ Cursor pagination - Efficient infinite scroll
  • ✅ Batch operations - Optimized bulk updates/deletes
  • ✅ Migration framework - Safe schema evolution
  • ✅ Optional cloud sync - Supabase integration (feature-flagged)
Time saved: 16-24 hours of implementing and testing repositories, pagination, Keychain, and migrations.

Production Setup (From Real Code)

Here’s how the boilerplate actually sets up storage in CompositionRoot.swift:

Key Architecture Decisions

  • ✅ @Model types stay in the data layer - Views consume DTOs, never @Model objects
  • ✅ DTOs are public - lightweight, Sendable structs
  • ✅ Repositories on @MainActor - SwiftData requirement
  • ✅ Protocol-based - easy to test with mocks
  • ✅ Single ModelContext - thread-safe, no conflicts

Repository Pattern (Production Implementation)

The boilerplate uses protocol-based repositories that return lightweight DTOs:
Why This Pattern:
  • Views never see @Model types (maintains MVVM boundaries)
  • DTOs are Sendable (thread-safe)
  • Easy to mock for testing
  • Can swap implementations (local, cloud, hybrid)

Optional Cloud Sync

Sync conversations and messages across devices:Setup Guide: Chat Sync Setup
  1. Run SQL migration
  2. Enable feature flag
  3. Wire up hybrid repositories
  4. Test cross-device sync

Keychain Storage (Real Implementation)

The boilerplate includes a production-ready Keychain wrapper used for all secure storage:
Production Features:
  • ✅ iOS Security framework (kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)
  • ✅ Automatic PII redaction in logs
  • ✅ Thread-safe operations
  • ✅ Comprehensive error handling
  • ✅ Works with AuthInterceptor via KeychainTokenProvider

Customization Examples

Add New SwiftData Model

Key Files

Dependencies

  • Core - Error handling, logging
  • Networking - For cloud sync (optional)

Used By

  • FeatureChat - Conversation and message storage
  • FeatureSettings - Settings persistence
  • Auth - Keychain for tokens
  • App target (profile) - ProfilePhotoStorageClient for profile photos (optional)

Best Practices

  • Use DTOs for passing data
  • @MainActor for ModelContext
  • Sendable for repositories
  • Unique IDs with @Attribute(.unique)
  • Protocol-based design
  • Return DTOs (not @Model objects)
  • Async/await throughout
  • Comprehensive error handling
  • Offline-first (local writes fast)
  • Background sync (non-blocking)
  • Graceful degradation
  • Optional (feature flag)

Learn More

Full Documentation

Complete Storage guide

Chat Sync

Enable cross-device sync

Photo Storage

Enable cloud photos

Building Guide

Add custom models

Test Coverage

StorageTests runs as part of the workspace suite — 646 tests across 12 package test targets + the app test suites in one App.xctestplan pass. Storage tests cover:
  • CRUD operations
  • Pagination
  • Error scenarios
  • Concurrent access
  • Keychain operations