diff options
| author | Christian Cleberg <[email protected]> | 2026-07-24 23:35:18 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-07-24 23:37:00 -0500 |
| commit | 99e4623af1b08f36120a01b67cbe60df99668651 (patch) | |
| tree | 07c8365f0c0054837f2b63611d71d1fd9c2f4e6c /DomainDig.xcodeproj/project.pbxproj | |
| parent | a52dee116d4066d1b59bd90b4ebc4def4e1597d6 (diff) | |
| download | domain-dig-99e4623af1b08f36120a01b67cbe60df99668651.tar.gz domain-dig-99e4623af1b08f36120a01b67cbe60df99668651.tar.bz2 domain-dig-99e4623af1b08f36120a01b67cbe60df99668651.zip | |
feat: versioned store-migration policy for persisted data (v5 step 2)
Third v5.0.0 roadmap item: define and implement a migration policy for the
on-device persisted store (tracked domains, history/snapshots, audits,
workflows, monitoring, settings), so data upgrades cleanly across app versions
instead of relying on a one-shot marker.
- DataMigrationService is reworked from a single boolean marker
(`data.migrations.v3_4_0`) into a versioned runner keyed by an integer store
schema version (`data.storeSchemaVersion`). It runs each step once in
ascending order up to `currentStoreSchemaVersion`, stamping the version as it
goes. Adding a future migration is now a `case N:` plus a version bump.
Policy guarantees, all covered by tests:
- Forward-only and idempotent; every step must be safe on an empty/older store.
- Never downgrades: a store written by a newer build (higher version) is left
byte-for-byte untouched.
- Pre-versioning installs are handled: a set legacy boolean marker reads as
"already at v1", so the v1 normalization never re-runs for them.
v1 is the existing normalization pass (dedup + drop the legacy `watchedDomains`
key + sanitize monitoring settings), now expressed as migration step 1.
- Docs/data-migration.md documents the persisted surface, the two independent
version lines (store vs. backup export), when to use lenient decoding vs. a
migration step, the runner contract, an "adding a migration" checklist, and
backup-import compatibility. Linked from the README.
- DataMigrationServiceTests: 6 tests over legacy fixtures — fresh-store stamping,
legacy `watchedDomains` migration + key drop, in-place dedup of the stored
blob, idempotence, legacy-marker-as-v1, and the no-downgrade guard. Full unit
suite: 58 passing.
Diffstat (limited to 'DomainDig.xcodeproj/project.pbxproj')
| -rw-r--r-- | DomainDig.xcodeproj/project.pbxproj | 4 |
1 files changed, 4 insertions, 0 deletions
diff --git a/DomainDig.xcodeproj/project.pbxproj b/DomainDig.xcodeproj/project.pbxproj index e65c63a..4bab46e 100644 --- a/DomainDig.xcodeproj/project.pbxproj +++ b/DomainDig.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 05F775C7E0743AF727B008EE /* LocalAPIContract.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7572DA0A838E0A044F045260 /* LocalAPIContract.swift */; }; 38316D90539394C2CC7C12BE /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE8B269A01CC5E593DA3DFC2 /* Foundation.framework */; }; 47CD3BB1AE143733A73E0E5B /* DomainReportExporterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D7C7D97A4006831572F468 /* DomainReportExporterTests.swift */; }; + 4F96CEB875EC3501E784CE39 /* DataMigrationServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435AFB3F99D579D3D7B58279 /* DataMigrationServiceTests.swift */; }; 81359F63C7A23454B8FA0141 /* DomainReportBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E82320955416797CFE59464A /* DomainReportBuilderTests.swift */; }; 8BBFEF092F9874AE00E8E144 /* DomainInspectionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BBFEF032F9874AE00E8E144 /* DomainInspectionService.swift */; }; 8BBFEF0A2F9874AE00E8E144 /* DomainReportBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BBFEF042F9874AE00E8E144 /* DomainReportBuilder.swift */; }; @@ -75,6 +76,7 @@ /* Begin PBXFileReference section */ 0D85A44C5F315A1644AC9073 /* LocalAPIContractTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LocalAPIContractTests.swift; sourceTree = "<group>"; }; 15A25DF2B8BB52589D49986B /* DiffServiceTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DiffServiceTests.swift; sourceTree = "<group>"; }; + 435AFB3F99D579D3D7B58279 /* DataMigrationServiceTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DataMigrationServiceTests.swift; sourceTree = "<group>"; }; 54D7C7D97A4006831572F468 /* DomainReportExporterTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DomainReportExporterTests.swift; sourceTree = "<group>"; }; 5CA789D3607B55E3612E6FFA /* SnapshotFixture.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SnapshotFixture.swift; sourceTree = "<group>"; }; 7572DA0A838E0A044F045260 /* LocalAPIContract.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LocalAPIContract.swift; sourceTree = "<group>"; }; @@ -229,6 +231,7 @@ 54D7C7D97A4006831572F468 /* DomainReportExporterTests.swift */, CC948A02EC0184228BC4630E /* DomainDataPortabilityServiceTests.swift */, 0D85A44C5F315A1644AC9073 /* LocalAPIContractTests.swift */, + 435AFB3F99D579D3D7B58279 /* DataMigrationServiceTests.swift */, ); name = DomainDigTests; path = DomainDigTests; @@ -487,6 +490,7 @@ C7CA9E02B0DC2708DE7A8563 /* DomainDataPortabilityServiceTests.swift in Sources */, A5AF921BC1C2E6E940CC05DC /* SnapshotFixture.swift in Sources */, EA12012CDB4C21ABB4217D86 /* LocalAPIContractTests.swift in Sources */, + 4F96CEB875EC3501E784CE39 /* DataMigrationServiceTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; |
