@@ -214,7 +214,11 @@ class BackupService {
214214 }
215215
216216 try await performRestore ( category: . activity) { dataBytes in
217- let payload = try JSONDecoder ( ) . decode ( ActivityBackupV1 . self, from: dataBytes)
217+ let migrated = try self . migrateCoreOwnedBackupFields ( dataBytes, fieldMigrations: [
218+ " activities " : migrateBackupActivitiesJson,
219+ " activityTags " : migrateBackupActivityTagsJson,
220+ ] )
221+ let payload = try JSONDecoder ( ) . decode ( ActivityBackupV1 . self, from: migrated)
218222
219223 try await CoreService . shared. activity. upsertList ( payload. activities)
220224 try await CoreService . shared. activity. upsertTags ( payload. activityTags)
@@ -227,7 +231,10 @@ class BackupService {
227231 }
228232
229233 try await performRestore ( category: . metadata) { dataBytes in
230- let payload = try JSONDecoder ( ) . decode ( MetadataBackupV1 . self, from: dataBytes)
234+ let migrated = try self . migrateCoreOwnedBackupFields ( dataBytes, fieldMigrations: [
235+ " tagMetadata " : migrateBackupPreActivityMetadataJson,
236+ ] )
237+ let payload = try JSONDecoder ( ) . decode ( MetadataBackupV1 . self, from: migrated)
231238
232239 try await CoreService . shared. activity. upsertPreActivityMetadata ( payload. tagMetadata)
233240
@@ -762,6 +769,28 @@ class BackupService {
762769 }
763770 }
764771
772+ /// Fills in wallet ids that predate wallet-scoped activity data before a
773+ /// backup envelope is decoded. Each Core-owned array field is handed to the
774+ /// matching Core migration helper as raw JSON, so the app never edits Core
775+ /// model JSON itself. Records that already carry a wallet id are left
776+ /// unchanged, so this is safe to run on current backups too.
777+ private func migrateCoreOwnedBackupFields(
778+ _ dataBytes: Data ,
779+ fieldMigrations: [ String : ( String ) throws -> String ]
780+ ) throws -> Data {
781+ guard var root = try JSONSerialization . jsonObject ( with: dataBytes) as? [ String : Any ] else {
782+ return dataBytes
783+ }
784+ for (field, migrate) in fieldMigrations {
785+ guard let array = root [ field] as? [ Any ] else { continue }
786+ let arrayData = try JSONSerialization . data ( withJSONObject: array)
787+ let migratedJson = try migrate ( String ( decoding: arrayData, as: UTF8 . self) )
788+ guard let migratedData = migratedJson. data ( using: . utf8) else { continue }
789+ root [ field] = try JSONSerialization . jsonObject ( with: migratedData)
790+ }
791+ return try JSONSerialization . data ( withJSONObject: root)
792+ }
793+
765794 private func performRestore( category: BackupCategory , restoreAction: ( Data ) async throws -> Void ) async throws {
766795 do {
767796 let item = try await vssBackupClient. getObject ( key: category. rawValue)
0 commit comments