# SwiftData to CloudKit Sync Requirements (Reusable) Primary source of truth lives in Bedrock: `/Users/mattbruce/Documents/Projects/iPhone/Andromida/Bedrock/Sources/Bedrock/Storage/SWIFTDATA_CLOUDKIT_SETUP_GUIDE.md` This Andromida copy is app-facing reference material and should stay aligned with the Bedrock guide. Use this checklist for any iOS app that uses SwiftData with CloudKit and requires near-real-time multi-device sync. ## 1) Capabilities and Entitlements - Enable `iCloud` with `CloudKit` for the app target. - Enable `Push Notifications` for the app target. - Enable `Background Modes > Remote notifications`. - Add App Group if app + widget share local SQLite. Required entitlement keys: - `com.apple.developer.icloud-container-identifiers` - `com.apple.developer.icloud-services` including `CloudKit` - `com.apple.developer.ubiquity-kvstore-identifier` (if KVS is used) - `aps-environment` (must resolve per config) - `com.apple.security.application-groups` (if widget/app group storage is used) ## 2) Build Configuration Use xcconfig variables so environments are explicit and portable: - Debug: `APS_ENVIRONMENT = development` - Release: `APS_ENVIRONMENT = production` Entitlements should reference variables, not hard-coded values, where possible. ## 3) Model and Schema Constraints (SwiftData + CloudKit) - Avoid `@Attribute(.unique)` in CloudKit-mirrored models. - Ensure all stored properties have defaults or are optional. - Keep relationships optional for CloudKit compatibility. - Use additive schema evolution only (add fields/models; do not remove/rename/change types in place). ## 4) Runtime Sync Behavior - Prefer Bedrock `SwiftDataCloudKitSyncManager` as the reusable remote observer/lifecycle component. - Observe `.NSPersistentStoreRemoteChange` to detect remote merges. - On remote change, refetch from SwiftData and invalidate derived caches. - For long-lived stores, recreate `ModelContext` on remote change before refetch when stale objects are observed. - Keep a foreground fallback refresh as a safety net, but do not rely on force-quit/relaunch behavior. - Emit structured logs for remote sync events (event count + timestamp) for debugging. ## 5) UI Freshness Requirements - UI must re-render on each remote merge, even for batched updates. - Keep an observable refresh version/counter and increment on each successful reload. - Ensure list/detail views do not rely on stale assumptions when models are updated remotely. - Make high-frequency interaction rows fully tappable to reduce missed user actions. ## 6) Verification Matrix Test all cases on two physical devices with the same Apple ID and same app flavor: 1. Single toggle on Device A appears on Device B while both apps are open. 2. Rapid batch toggles on Device A all appear on Device B without manual pull-to-refresh. 3. Device B in background receives updates after foregrounding (without force quit). 4. Airplane mode recovery syncs correctly after reconnection. 5. Simultaneous edits resolve predictably (CloudKit last-writer-wins). ## 7) Observability and Console Checks - Device logs: filter by sync logger category (for example `CloudKitSync`). - CloudKit Console: validate record updates in the app container private database. - If pushes are delivered but UI is stale, investigate context freshness and view invalidation, not transport. ## 8) Reuse Checklist for New Apps Before shipping any new SwiftData+CloudKit app: - [ ] Capabilities: iCloud/CloudKit + Push + Remote Notifications are enabled - [ ] Entitlements include `aps-environment` and correct container IDs - [ ] xcconfig defines `APS_ENVIRONMENT` per configuration - [ ] Remote change observer reloads data and invalidates caches - [ ] UI has deterministic invalidation on remote reload - [ ] Two-device batch-update test passes without manual refresh - [ ] CloudKit Console verification documented in README/PRD