# LocalData Migration Guide ## Overview `LocalData` provides protocol-based migration support to move data from legacy storage locations to modern `StorageKey` definitions. ## Automatic Migration When calling `get(_:)` on a key, the `StorageRouter` automatically: 1. Checks the primary location. 2. If not found, evaluates `migration` defined on the key. 3. If data is found in a source: - Unsecures it using the source's old policy. - Re-secures it using the destination key's policy. - Stores it in the new location. - Deletes the legacy data. - Returns the value. ## Proactive Migration (Sweep) You can trigger a sweep of all registered keys at app launch: ```swift try await StorageRouter.shared.registerCatalog(MyCatalog(), migrateImmediately: true) ``` This iterates through all keys in the catalog and calls `forceMigration(for:)` on each, ensuring all legacy data is consolidated. ## Defining Migration Sources ### Simple Legacy Migration For 1:1 migrations, attach a `SimpleLegacyMigration`: ```swift struct MyNewKey: StorageKey { // ... var migration: AnyStorageMigration? { AnyStorageMigration( SimpleLegacyMigration( destinationKey: self, sourceKey: .key(LegacyKey(name: "old_key_name", domain: .userDefaults(suite: nil))) ) ) } } ``` ### Protocol-Based Migration For complex scenarios, attach an explicit migration: ```swift struct MyMigration: StorageMigration { typealias DestinationKey = MyNewKey let destinationKey = MyNewKey() func shouldMigrate(using router: StorageRouter, context: MigrationContext) async throws -> Bool { try await router.exists(destinationKey) } func migrate(using router: StorageRouter, context: MigrationContext) async throws -> MigrationResult { // Custom migration logic MigrationResult(success: true) } } extension MyNewKey { var migration: AnyStorageMigration? { AnyStorageMigration(MyMigration()) } } ```