# P2.1: Schema Versioning Strategy - Documentation Draft **Purpose:** Draft documentation for iOS schema versioning strategy (ready to integrate into `ios/Plugin/README.md`) **Status:** Draft for review **Date:** 2025-12-22 --- ## Section to Add to `ios/Plugin/README.md` ### Schema Versioning Strategy **Current Schema Version:** `1` (initial schema) The iOS implementation uses **explicit schema versioning** to achieve parity with Android's Room database versioning approach. This provides observability and migration tracking without interfering with CoreData's automatic migration capabilities. #### Versioning Approach **CoreData Auto-Migration Remains Authoritative** The schema version is a **logical contract**, not a forced migration trigger. CoreData auto-migration (`shouldMigrateStoreAutomatically = true`) remains the authoritative mechanism for schema changes. Version mismatches are **logged, not blocked**. **Version Tracking** Schema version is stored in CoreData persistent store metadata using `NSPersistentStore` metadata dictionary. This approach: - ✅ Non-intrusive (does not require schema changes) - ✅ Observable (version can be read at any time) - ✅ Compatible with CoreData auto-migration - ✅ Matches Android's explicit versioning pattern **Current Implementation** - **Schema Version:** `1` (initial schema, established 2025-09-22) - **Version Storage:** `NSPersistentStore` metadata key `"schema_version"` - **Version Check:** Performed during `PersistenceController` initialization - **Logging:** Version logged on store load; mismatches logged as warnings #### Migration Contract **When to Bump Schema Version** The schema version should be incremented when: 1. **Entity changes:** - Adding new entities - Removing entities (rare, requires data migration) - Renaming entities (requires explicit migration) 2. **Attribute changes:** - Adding new required attributes (requires default values or migration) - Removing attributes (requires data cleanup) - Changing attribute types (requires type conversion) - Renaming attributes (requires explicit migration) 3. **Relationship changes:** - Adding/removing relationships - Changing relationship cardinality - Renaming relationships **When NOT to Bump** - Adding optional attributes (CoreData handles automatically) - Adding optional relationships (CoreData handles automatically) - Changing default values (no schema change required) - Adding indexes (metadata change, not schema change) **Version Bump Process** 1. Update CoreData model in Xcode (add/remove/modify entities/attributes) 2. Increment schema version constant in `PersistenceController` 3. Update metadata on next store load 4. Document migration in changelog 5. Update parity matrix if versioning strategy changes #### Android Parity **Android:** Room database with explicit `version = 2` and `Migration` objects **iOS:** CoreData with explicit schema version `1` in metadata + auto-migration Both platforms now have: - ✅ Explicit version tracking - ✅ Migration documentation - ✅ Version observability - ✅ Migration contract defined **Parity Status:** ✅ **Explicit versioning** (P2.1 complete) --- ## Implementation Notes ### Version Check Utility A simple version check is performed during `PersistenceController` initialization: ```swift // In PersistenceController.init() private func checkSchemaVersion() { guard let store = container?.persistentStoreCoordinator.persistentStores.first else { return } let currentVersion = store.metadata["schema_version"] as? Int ?? 1 let expectedVersion = SCHEMA_VERSION if currentVersion != expectedVersion { print("DNP-PLUGIN: Schema version mismatch - current: \(currentVersion), expected: \(expectedVersion)") // Log warning, but do not block (CoreData auto-migration handles actual migration) } else { print("DNP-PLUGIN: Schema version verified: \(currentVersion)") } // Update metadata if needed if currentVersion != expectedVersion { var metadata = store.metadata metadata["schema_version"] = expectedVersion // Note: Metadata update happens on next store save } } ``` ### Constants ```swift // In PersistenceController private static let SCHEMA_VERSION = 1 // Current schema version ``` --- ## Testing Version handling is verified through: 1. **Unit tests:** Verify version metadata is set correctly 2. **Integration tests:** Verify version check runs on store load 3. **Migration tests:** Verify version tracking survives migrations **Test Coverage:** - ✅ Version metadata is set on initial store creation - ✅ Version check runs during initialization - ✅ Version mismatches are logged (not blocked) - ✅ Version metadata persists across app restarts --- ## Related Documentation - **Android Schema Versioning:** `android/src/main/java/com/timesafari/dailynotification/DatabaseSchema.kt` (Room `version = 2`) - **CoreData Model:** `ios/Plugin/DailyNotificationModel.xcdatamodeld` - **PersistenceController:** `ios/Plugin/DailyNotificationModel.swift` - **Parity Matrix:** `docs/progress/04-PARITY-MATRIX.md` --- **Last Updated:** 2025-12-22 **Status:** Draft for integration