Implement storage architecture from ai_blueprint.md

Primary sync: replace PersistenceActor JSON file with SwiftData + CloudKit
- Add SavedCardModel (@Model class) and PersistenceController (ModelContainer
  with .automatic CloudKit, fallback to local). BackgroundPersistenceActor
  (@ModelActor) handles all DB I/O off the main thread.
- One-time migration imports user_collection.json into SwiftData and renames
  the original file to prevent re-import.
- Inject modelContainer into SwiftUI environment in IYmtgApp.

Image storage: Documents/UserContent/ subfolder (blueprint requirement)
- ImageManager.dir now targets iCloud Documents/UserContent/ (or local equiv).
- migrateImagesToUserContent() moves existing JPGs to the new subfolder on
  first launch; called during the SwiftData migration.

Firebase: demoted to optional manual backup (metadata only, no images)
- Remove all automatic CloudEngine.save/delete/batchUpdatePrices calls from
  CollectionViewModel mutations.
- Add backupAllToFirebase() for user-triggered metadata sync.
- Add isFirebaseBackupEnabled to AppConfig (default false).
- Add Cloud Backup section in Library settings with iCloud vs Firebase
  explanation and "Backup Metadata to Firebase Now" button.

Also: full modular refactor (Data/, Features/, Services/ directories) and
README updated with CloudKit setup steps and revised release checklist.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 12:13:17 -05:00
parent b993ef4020
commit 24dcb44af4
38 changed files with 2786 additions and 2105 deletions

View File

@@ -208,12 +208,34 @@ IYmtg_Training/
## 4. Backend & Security
### Firebase Configuration (Required for Cloud Sync)
### Cloud Storage Architecture
The app uses a two-tier cloud strategy:
| Tier | Technology | What it stores | Cost |
| :--- | :--- | :--- | :--- |
| **Primary** | iCloud + CloudKit (SwiftData) | All card metadata, synced automatically across devices | Free (user's iCloud) |
| **Secondary** | Firebase Firestore | Metadata only — no images — optional manual backup | Free (Firestore free tier) |
Card images are stored in the user's iCloud Drive under `Documents/UserContent/` and are **never** uploaded to Firebase.
### iCloud / CloudKit Setup (Required for Primary Sync)
1. In Xcode, open **Signing & Capabilities**.
2. Add the **iCloud** capability. Enable **CloudKit**.
3. Add a CloudKit container named `iCloud.<your-bundle-id>`.
4. Add the **Background Modes** capability. Enable **Remote notifications**.
5. Set the minimum deployment target to **iOS 17** (required by SwiftData).
Without this setup the app falls back to local-only storage automatically.
### Firebase Configuration (Optional Secondary Backup)
Firebase is no longer the primary sync mechanism. It serves as a user-triggered metadata backup.
1. **Create Project:** Go to the Firebase Console and create a new project.
2. **Authentication:** Enable "Anonymous" sign-in in the Authentication tab.
3. **Firestore Database:** Create a database and apply the rules from `IYmtg_App_iOS/Firebase/firestore.rules`.
4. **Storage:** Enable Storage and apply the rules from `IYmtg_App_iOS/Firebase/storage.rules`.
5. **Setup:** Download `GoogleService-Info.plist` from Project Settings and drag it into the `IYmtg_App_iOS` folder in Xcode (ensure "Copy items if needed" is checked).
4. **Setup:** Download `GoogleService-Info.plist` from Project Settings and drag it into the `IYmtg_App_iOS` folder in Xcode (ensure "Copy items if needed" is checked).
5. Users trigger backup manually via **Library → Cloud Backup → Backup Metadata to Firebase Now**.
The app runs fully without `GoogleService-Info.plist` (Local Mode — iCloud sync still works).
### Over-the-Air (OTA) Model Updates
To update ML models without an App Store release:
@@ -249,6 +271,7 @@ chmod +x IYmtg_Automation/weekly_update.sh
**CRITICAL:** Edit `IYmtg_App_iOS/AppConfig.swift` before building to ensure payments and support work correctly:
1. Set `contactEmail` to your real email address.
2. Set `tipJarProductIDs` to your actual In-App Purchase IDs.
3. `isFirebaseBackupEnabled` defaults to `false`. Users opt-in from Library settings.
## 7. Development Mode
@@ -279,12 +302,17 @@ Perform these steps before submitting to the App Store.
* [ ] Verify `contactEmail` is valid.
* [ ] Verify `tipJarProductIDs` match App Store Connect.
* [ ] Ensure `enableFoilDetection` and other flags are `true`.
2. **Assets:**
2. **iCloud / CloudKit:**
* [ ] Signing & Capabilities → iCloud → CloudKit enabled.
* [ ] CloudKit container added: `iCloud.<bundle-id>`.
* [ ] Background Modes → Remote notifications enabled.
* [ ] Minimum deployment target set to **iOS 17**.
3. **Assets:**
* [ ] Ensure `Assets.xcassets` has the AppIcon filled for all sizes.
3. **Testing:**
4. **Testing:**
* [ ] Run Unit Tests (`Cmd+U`) - All must pass.
* [ ] Run on Physical Device - Verify Camera permissions prompt appears.
4. **Build:**
5. **Build:**
* [ ] Select "Any iOS Device (arm64)".
* [ ] Product -> Archive.
* [ ] Validate App in Organizer.