Files
zapstore/spec/work/WORK-026-new-device-key-reminder.md
2026-07-17 16:24:40 -03:00

4.4 KiB

WORK-026 - New Device Key Reminder

Feature: FEAT-006-device-key.md Status: In Progress

Tasks

  • 1. Detect a missing device key before generating the fresh key
    • Files: lib/main.dart, lib/services/device_key_service.dart
    • Keep the result in memory for the current app session only.
  • 2. Replace the startup restore dialog with an inline reminder
    • Files: lib/screens/search_screen.dart, lib/services/device_backup_service.dart
    • Render the reminder between search and stacks only for a newly generated key.
  • 3. Support restoring a pasted nsec from Device key management
    • Files: lib/screens/profile_screen.dart, lib/widgets/device_restore_dialog.dart lib/services/device_backup_service.dart
    • Validate, replace, and sync a pasted-nsec or Amber-restored key without blocking the UI.
  • 4. Verify analysis and targeted tests
    • fvm flutter test test/services/device_key_service_test.dart test/services/device_backup_service_test.dart test/services/settings_service_test.dart
    • HOME=/tmp fvm flutter analyze
  • 5. Protect Amber recovery records
    • Files: lib/services/device_backup_service.dart, lib/widgets/device_restore_dialog.dart
    • Normal Amber sign-in preserves an existing verified Amber recovery record; explicit Device key management offers Amber recovery without scheduling a replacement backup.

Verification

  • The startup flow captures device_key presence before generating the key; only an absent key enables the session-only reminder.
  • Pasting an invalid nsec surfaces an error without replacing the current key.
  • A successful restore replaces the device key before the one-shot private-data synchronization begins.

Decisions

2026-07-15 - New-key reminder is session-only

Context: A first-run restore dialog blocks discovery and requires users to choose a recovery method before using the store.

Decision: Capture whether device_key was absent before creating it, then show a non-interactive reminder for the current app session. The key's presence suppresses it on later launches; no onboarding state is written.

Rationale: Device-key recovery remains accessible from Data Management at any time without treating Amber as a prerequisite or gating the UI.

The obsolete persisted restoreOnboardingComplete value is removed. Amber recovery is now explicitly initiated from Device key management, which prevents normal Amber sign-in backup from overwriting a recovery record first.

2026-07-17 - Existing Amber recovery records are immutable on sign-in

Context: A fresh install creates a new device key before the user can sign in with Amber. Automatically backing up that key could replace the only record that points to the prior device's private state.

Decision: On a normal Amber sign-in, decrypt any existing Amber backup. If it holds a different device key, offer restore (never overwrite). If it matches the current key, do nothing. Only create a new Amber backup when none exists.

Rationale: Sign-in is the path users expect for recovery. Preserving the remote backup alone left them with an empty fresh key and no prompt.

2026-07-17 - Emulator verification

Verified on emulator-5554 with a fresh Amber account:

  1. Signed in, enabled background auto-updates, confirmed device-state publish.
  2. Cleared Zapstore data (new device key generated).
  3. Normal Amber sign-in logged preserving existing Amber device-key backup and left the new key in place.
  4. Profile → Restore → Restore with Amber restored npub15adrzvs….
  5. After relaunch, background auto-updates was on again.
  6. Restored portable settings now also invalidate localSettingsProvider so the toggle refreshes without requiring an app restart.

2026-07-17 - Private stack hydration after restore

Context: syncRestoredKey did query kinds 30267/30078, but discarded the result and relied on isolate QueryResultNotification to refresh LocalSource stack watchers. After a pubkey swap those watchers can miss the update, and bookmarks/unmanaged notifiers kept empty in-memory state from the fresh key.

Decision: Sync with LocalAndRemoteSource, re-save fetched models so LocalSource consumers refresh with req:null, and reset bookmarks/unmanaged notifiers whenever devicePubkeyProvider changes.

Rationale: Private stacks must decrypt and appear under the restored device key without requiring an app restart.