3.2 KiB
title, created, tags, status, chosen-approach, asana
| title | created | tags | status | chosen-approach | asana | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Tech Design: Code-defined Core Data models | 2026-09-25 |
|
draft | Schemas defined in Swift with full version history; explicit lightweight migration | TODO |
Author: Alexey Martemyanov
Reviewer: Sam Symons
Stakeholders: Bartek, Dominik, Federico Cappelli, Michal Smaga
Project: Build the apps and packages outside Xcode (VS Code / swift build)
Background & Requirements
We're moving development and CI to VS Code and SwiftPM builds that don't go through Xcode.
Core Data schemas live in .xcdatamodeld files. Only Xcode compiles them into the .momd the app loads, so SwiftPM builds and tests outside Xcode have no model. BSK tests work around this by running momc at runtime.
Requirements:
- existing user stores open unchanged
- upgrades from any older version keep data
- minimum OS stays at iOS 15 / macOS 12.3.
Problem Statement
Core Data models can't be built outside Xcode.
Recommended Approach
Define each model in Swift instead of .xcdatamodeld, one file per model, containing every shipped schema version. A small Persistence helper builds the model at runtime and migrates stores created by older versions.[1]
Existing stores are unaffected: Core Data matches a store to a model by schema hashes, and the code-defined versions produce the same hashes as the compiled .momd. The hashes are pinned in tests.
Steps (one PR each):
Persistencesupport + PrivacyStats and BrowsingHistory.- Bookmarks + SyncMetadata.
- Stores combining several models: HTTPSUpgrade, RemoteMessaging, AppRatingPrompt.[2]
- macOS app models: History, Downloads, legacy Bookmark.
- Remove the
momcworkaround.
Each step is revertible: the on-disk format doesn't change.
Notes
[1] Old versions are needed because migration looks for the old schema in the compiled models, which will no longer exist. NSStagedMigrationManager handles code-defined versions but requires iOS 17 / macOS 14.
[2] A combined store needs the old versions of all its models, so they're converted together.
Alternatives:
- Remove only the generated dynamic CoreData property accessors:
momcis still needed and compiled as a separate Swift Build System Plugin step. - Commit precompiled
.momdfiles: binary artifacts that can drift from the source.
Trade-off: we lose Xcode's visual model editor (but we get standardized, structured, great&shiny code definitions!)
Testing
- Unit tests pin the schema hashes of every shipped version.
- Migration tests upgrade old-version stores and check the data.
- Package tests run with plain
swift test. - Manual check on iOS and macOS: upgrade from the App Store build and confirm the data is intact.
Additional Considerations
- Privacy — No change.
- Security — No change.
- Site Breakage — N/A.
- Experimentation — N/A. The schema can't be feature-flagged; rollback is a revert.
- Operational — Package builds no longer need Xcode‘s momd compiler. Migration failures are reported through the existing store-loading errors.
- Localization / Internationalization — N/A.