# P2.1: Schema Versioning Strategy - Implementation Plan

**Purpose:** Step-by-step implementation plan for P2.1 schema versioning  
**Status:** Ready for execution  
**Date:** 2025-12-22  
**Estimated Effort:** 4-6 hours

---

## Overview

Add explicit schema versioning to iOS CoreData implementation to achieve parity with Android's Room database versioning. This is a **documentation-first, minimal-code** approach that provides observability without interfering with CoreData's automatic migration.

---

## Implementation Steps

### Step 1: Add Schema Version Constant (5 min)

**File:** `ios/Plugin/DailyNotificationModel.swift`

**Location:** Add near top of `PersistenceController` class

**Code:**
```swift
class PersistenceController {
    // MARK: - Schema Versioning
    
    /// Current schema version (incremented when schema changes)
    private static let SCHEMA_VERSION = 1
    
    // ... existing code ...
}
```

**Verification:**
- [ ] Constant added
- [ ] Compiles without errors

---

### Step 2: Add Version Check Method (15 min)

**File:** `ios/Plugin/DailyNotificationModel.swift`

**Location:** Add as private method in `PersistenceController` class

**Code:**
```swift
    /**
     * Check and log schema version
     * 
     * Schema version is a logical contract, not a forced migration trigger.
     * CoreData auto-migration remains authoritative; version mismatches are
     * logged, not blocked.
     */
    private func checkSchemaVersion() {
        guard let store = container?.persistentStoreCoordinator.persistentStores.first else {
            return
        }
        
        let currentVersion = store.metadata["schema_version"] as? Int ?? 1
        let expectedVersion = PersistenceController.SCHEMA_VERSION
        
        if currentVersion != expectedVersion {
            print("DNP-PLUGIN: Schema version mismatch - current: \(currentVersion), expected: \(expectedVersion)")
            print("DNP-PLUGIN: CoreData auto-migration will handle schema changes")
            
            // Update metadata for future reference (does not trigger migration)
            var metadata = store.metadata
            metadata["schema_version"] = expectedVersion
            // Note: Metadata persists on next store save
        } else {
            print("DNP-PLUGIN: Schema version verified: \(currentVersion)")
        }
    }
```

**Verification:**
- [ ] Method added
- [ ] Compiles without errors
- [ ] Follows existing code style

---

### Step 3: Call Version Check on Initialization (5 min)

**File:** `ios/Plugin/DailyNotificationModel.swift`

**Location:** In `init(inMemory:)` method, after container is successfully loaded

**Code:**
```swift
                // Configure view context
                if let context = tempContainer?.viewContext {
                    context.automaticallyMergesChangesFromParent = true
                    context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
                }
                self.container = tempContainer
                
                // Check schema version (after container is initialized)
                checkSchemaVersion()
                
                // Verify all entities are available (after container is initialized)
                if let context = tempContainer?.viewContext {
                    verifyEntities(in: context)
                }
```

**Verification:**
- [ ] Version check called after container initialization
- [ ] Compiles without errors
- [ ] Version logged on app launch

---

### Step 4: Set Initial Version Metadata (10 min)

**File:** `ios/Plugin/DailyNotificationModel.swift`

**Location:** In `init(inMemory:)` method, when creating new store

**Code:**
```swift
            // Configure persistent store options
            let description = tempContainer?.persistentStoreDescriptions.first
            description?.shouldMigrateStoreAutomatically = true
            description?.shouldInferMappingModelAutomatically = true
            
            // Set initial schema version metadata (for new stores)
            if !inMemory {
                var metadata = description?.metadata ?? [:]
                if metadata["schema_version"] == nil {
                    metadata["schema_version"] = PersistenceController.SCHEMA_VERSION
                    description?.metadata = metadata
                }
            }
```

**Verification:**
- [ ] Initial version metadata set for new stores
- [ ] Compiles without errors
- [ ] Version metadata persists across app restarts

---

### Step 5: Add Documentation to README (30 min)

**File:** `ios/Plugin/README.md`

**Location:** Add new section after "Implementation Details" section

**Content:** Use the draft from `docs/progress/P2.1-SCHEMA-VERSIONING-DRAFT.md`

**Steps:**
1. Copy the "Schema Versioning Strategy" section from the draft
2. Paste into `ios/Plugin/README.md` after "Implementation Details"
3. Update "Last Updated" date in README header
4. Verify markdown formatting

**Verification:**
- [ ] Documentation added
- [ ] Markdown renders correctly
- [ ] All links/references are valid
- [ ] "Last Updated" date updated

---

### Step 6: Update Parity Matrix (5 min)

**File:** `docs/progress/04-PARITY-MATRIX.md`

**Location:** Update "Storage & Persistence" section

**Change:**
```markdown
| Schema versioning | ✅ Room migrations | ✅ Explicit | iOS has explicit version tracking in CoreData metadata |
```

**Verification:**
- [ ] Parity matrix updated
- [ ] Status changed from "⚠️ Partial" to "✅ Explicit"
- [ ] Notes section updated

---

### Step 7: Update Progress Docs (10 min)

**Files:**
- `docs/progress/00-STATUS.md`
- `docs/progress/01-CHANGELOG-WORK.md`
- `docs/progress/03-TEST-RUNS.md`

**Updates:**
1. Mark P2.1 as complete in status
2. Add changelog entry
3. Add test run entry (manual verification)

**Verification:**
- [ ] All progress docs updated
- [ ] Dates are correct
- [ ] Status reflects completion

---

### Step 8: Run CI and Verify (10 min)

**Command:**
```bash
./ci/run.sh
```

**Verification:**
- [ ] CI passes
- [ ] No new errors introduced
- [ ] Version logging appears in console output (manual check)

---

## Testing Checklist

### Manual Testing

- [ ] **New Store:** Create new CoreData store, verify version metadata is set
- [ ] **Existing Store:** Load existing store, verify version check runs
- [ ] **Version Logging:** Verify version logged on app launch
- [ ] **Metadata Persistence:** Verify version metadata persists across app restarts

### Code Review

- [ ] Code follows existing style
- [ ] Comments are clear and accurate
- [ ] No breaking changes introduced
- [ ] CoreData auto-migration still works

---

## Acceptance Criteria Checklist

- [ ] iOS schema versioning strategy documented (with explicit "logical contract" clarification)
- [ ] Version tracking implemented in CoreData model (metadata)
- [ ] Migration contract defined (when to bump versions)
- [ ] Version check utility added (logs version on init, does not block)
- [ ] Parity matrix updated (schema versioning: ✅ Explicit)
- [ ] All CI checks pass
- [ ] Progress docs updated

---

## Rollback Plan

If issues arise:

1. **Revert code changes:** Remove version check method and calls
2. **Revert documentation:** Remove schema versioning section from README
3. **Revert parity matrix:** Change back to "⚠️ Partial"
4. **Update progress docs:** Mark P2.1 as incomplete

**Baseline tag available:** `v1.0.11-p0-p1.4-p1.5-p2.6-p2.7-complete`

---

## Next Steps After P2.1

1. **Checkpoint:** Run `./ci/run.sh`, update progress docs
2. **Proceed to P2.2:** Combined edge case tests
3. **Optional:** Create baseline tag `v1.0.11-p2.1-complete` if desired

---

**Last Updated:** 2025-12-22  
**Status:** Ready for execution

