Skip to content

Restructure the backup IA around a single Backups hub - #574

Merged
bradleymackey merged 4 commits into
mainfrom
backup-ia-restructure
Sep 15, 2026
Merged

bradleymackey merged 4 commits into
mainfrom
backup-ia-restructure

Conversation

@bradleymackey

Copy link
Copy Markdown
Member

Summary

The backup surface was split across two sidebar peers ("Backup" and "Restore"), with the Backup screen stacking four unrelated jobs — password management, inline auto-backup settings, PDF export, and device transfer — into one form. The password screen's "Generate Key" action also read as password generation when it actually derives an encryption key from a typed password. This PR restructures the IA:

  • Single "Backups" sidebar item opening a hub: a last-backup status banner (revives the orphaned LastBackupSummaryView) plus rows for Auto-Backup, Export, Restore, and Backup Password. BackupCreateView becomes BackupExportView (PDF + device transfer only); its strings-only view model and nine orphaned xcstrings keys are deleted.
  • Backup password screen reframed: the action is "Set Backup Password" (revealed alongside the entry fields once a password is typed), key derivation is presented as a progress state with distinct cancelled/error copy, and the About text explains derivation without the "generate" framing. Keygen cancellation and plaintext clearing are untouched.
  • Auto-Backup gets its own screen backed by a new AutoBackupViewModel (the initial-state-injection refactor deferred in Snapshot the rebuilt backup and encryption-edit screens #573): state is seeded synchronously from the service, provider states are injectable for tests, the destination row shows provider name + folder with a "Change" affordance, folder-configure failures surface as an error row with a recovery suggestion (previously swallowed by an empty catch), and the active provider resolves from configuration instead of a hardcoded availableProviders.first.

Manifesto review

Reviewed against MANIFESTO.md, corollary by corollary, since backups are explicitly governed by it. This is a navigation and copy restructure: backup payloads, encryption, and every action's mechanics are untouched. C1 — no bulk operation added; nothing touches per-item safety fields. C2/C3 — no new logging, telemetry, or error channels near duress features; the one new error surface (auto-backup folder configuration failures, previously swallowed by an empty catch) reports storage-provider errors only. C4 — device authentication still gates every operation that loads or uses the backup key: export, password set/change, the auto-backup screen, and restore imports all authenticate exactly as before; the new un-gated hub adds navigation, not capability. C5 — the hub banner shows backup recency and kind, never contents; no enumeration of protected items. C6 — no undo, no audit surface. C7 — no protective default flipped; auto-backup remains opt-in and its configuration remains behind device auth. C8 — no sensitive operation lost a step: merging the sidebar items removes a hop between two navigation screens, while every export, restore, and password flow retains its full sequence including authentication; the password screen reframe changes verbs ("Generate Key" → "Set Backup Password"), not gates. C9 — backup surfaces never referenced duress features; unchanged. C10 — backup, export, and transfer payloads are byte-identical. One visibility change flagged deliberately: the last-backup banner (date + kind) is now visible without device auth, where the old Backup screen showed nothing pre-auth. Weighed against C4/C7: the same fact is already discoverable without auth (the Restore screen is un-gated today; auto-backup files are visible in the Files app), the banner reveals neither destination, contents, nor protected-item structure, and surfacing backup staleness is itself a data-loss protection.

Testing

  • Full iOSAllTests plan passes locally on iPhone 18 Pro Max / iOS 27.0.
  • New suites: AutoBackupViewModelTests (19 tests), AutoBackupViewSnapshotTests (7 scenarios — the coverage Snapshot the rebuilt backup and encryption-edit screens #573 deferred), LastBackupSummaryViewSnapshotTests (4, with an injectable now for deterministic staleness).
  • Re-recorded and visually reviewed: BackupKeyChangeViewSnapshotTests, BackupViewSnapshotTests (hub + export), VaultMainNavigationViewSnapshotTests.
  • Simulator walk-through of the full flow passed: single sidebar entry, hub layout, every push/back/sheet, and every auth gate failing closed.
  • Not automatable (per Rebuild the last two non-Form screens, and drop the folder picker wrapper #556): a real folder pick through .fileImporter — needs one manual run with iCloud Drive.

🤖 Generated with Claude Code

bradleymackey and others added 4 commits September 15, 2026 20:39
Users read "Generate Key" as password generation; the button
derives an encryption key from the typed password. Rename the
action to "Set Backup Password", show derivation as progress
with distinct cancelled/error copy, and re-copy the About
details to match.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
AutoBackupSettingsView vended a Section into the Backup form,
which made its enabled/error states unreachable from snapshot
tests and buried the destination behind the toggle. It becomes
AutoBackupView, a pushed screen backed by AutoBackupViewModel:

- state seeded synchronously (the service publishers do not
  replay), with injectable provider states for tests — the
  initial-state refactor deferred in #573
- destination row shows provider name and folder, not just the
  folder leaf, with an explicit Change affordance
- provider configure failures surface as an error row with a
  recovery suggestion; previously swallowed by an empty catch
- activeProvider resolves from configuration.providerID instead
  of hardcoding availableProviders.first

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two sidebar peers split one feature: "Backup" stacked password
management, auto-backup, PDF export, and device transfer in a
single form, while "Restore" lived elsewhere. Replace both with
a "Backups" sidebar item opening BackupHomeView: a last-backup
status banner (revives the orphaned LastBackupSummaryView) and
rows for Auto-Backup, Export, Restore, and Backup Password.

The hub is reachable without device auth — it exposes navigation
and backup recency only. Every key-touching surface (export,
auto-backup, password change, restore imports) authenticates on
entry exactly as before.

BackupCreateView becomes BackupExportView (PDF + transfer only);
its strings-only view model and the orphaned xcstrings keys are
deleted. LastBackupSummaryView takes an injectable "now" so the
staleness snapshots are deterministic.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Hide "Set Backup Password" until a password is entered and move
it into the entry section, mirroring how the confirm field
reveals. The status footer joins the section footer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@bradleymackey
bradleymackey merged commit 7f01364 into main Sep 15, 2026
2 of 5 checks passed
@bradleymackey
bradleymackey deleted the backup-ia-restructure branch September 15, 2026 18:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant