Skip to content

Conversation

@torlando-proton
Copy link
Collaborator

Problem

After a fresh install + backup restore, no propagation node is selected. The user must manually go into Settings and pick a relay, even if they had one selected before the backup.

Root Cause

ContactExport doesn't include the isMyRelay field. During export, the relay designation is silently dropped. On import, all contacts are created with isMyRelay = false, and the manualPropagationNode DataStore preference isn't restored either. Auto-selection may not trigger because the import flow doesn't explicitly kick it off.

Fix

Export side:

  • Add isMyRelay: Boolean? to ContactExport (nullable for backward compatibility with older backups)
  • Export isMyRelay in MigrationExporter.exportContactsForIdentity()

Import side:

  • Restore isMyRelay during importContacts()
  • Track which contact was the relay and restore manualPropagationNode preference
  • Set autoSelectPropagationNode = false when restoring a manual relay
  • After full import, if auto-select is enabled but no relay was restored, trigger propagationNodeManager.enableAutoSelect()
  • Inject PropagationNodeManager into MigrationImporter via Hilt

Backward compatibility: Old backups without isMyRelay will have it default to null (treated as false), falling through to auto-selection — same behavior as before this fix.

Testing

  • Export a backup with a relay selected → verify isMyRelay: true appears in export JSON
  • Fresh install + restore → verify the relay is automatically selected
  • Fresh install + restore from OLD backup (no isMyRelay) → verify auto-selection triggers
  • Verify manual vs auto relay preference is correctly restored

Fix relay selection not working after backup restore by ensuring
relay information is properly exported and imported.

Changes:
- Add isMyRelay field to ContactExport (nullable for backward compatibility)
- Export isMyRelay field in MigrationExporter.exportContactsForIdentity()
- Restore isMyRelay field during import in MigrationImporter.importContacts()
- Restore manualPropagationNode setting when relay contact is imported
- Disable auto-select when manual relay is restored
- Trigger auto-selection after import if enabled but no relay was restored
- Inject PropagationNodeManager into MigrationImporter for auto-selection

This ensures that after restoring from backup:
1. The relay contact is properly marked with isMyRelay=true
2. The manual propagation node preference is restored
3. Auto-selection is triggered if enabled but no relay was restored

Fixes the issue where no propagation node would be selected after
backup restore, requiring manual re-configuration.
@sentry
Copy link

sentry bot commented Jan 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 27, 2026

Greptile Overview

Greptile Summary

This PR fixes relay (propagation node) selection restoration after backup import by:

  • Adding isMyRelay field to ContactExport (nullable for backward compatibility)
  • Exporting the relay flag in MigrationExporter
  • Tracking relay hash during contact import
  • Implementing a 3-phase restoration strategy in MigrationImporter:
    1. Track relay from contacts during DB transaction (without writing settings)
    2. Restore all DataStore preferences via importSettings() (may include relay settings)
    3. Call restoreRelaySettings() after settings import to handle fallback cases

The implementation correctly addresses the ordering issues from previous review comments. The new restoreRelaySettings() method runs after importSettings() completes, ensuring settings aren't overwritten. It prioritizes relay settings from the backup's DataStore, falls back to the contact's isMyRelay flag for older backups, and triggers auto-selection if no relay was found and auto-select is enabled.

Backward compatibility: Old backups without isMyRelay will have it default to null (treated as false), and relay restoration will rely on the backup's DataStore preferences or trigger auto-selection if those are missing.

Confidence Score: 4/5

  • This PR is safe to merge with proper testing of backup/restore scenarios
  • The implementation correctly fixes the relay restoration issue with proper sequencing and backward compatibility. Score reflects the complexity of the 3-phase restoration logic and the need for thorough testing of edge cases (old backups, multiple relays, auto-selection scenarios)
  • Pay attention to MigrationImporter.kt due to the complex relay restoration logic and multiple code paths

Important Files Changed

Filename Overview
app/src/main/java/com/lxmf/messenger/migration/MigrationData.kt Added isMyRelay field to ContactExport for backward-compatible relay restoration
app/src/main/java/com/lxmf/messenger/migration/MigrationExporter.kt Export isMyRelay flag from contact entities to support relay selection restoration
app/src/main/java/com/lxmf/messenger/migration/MigrationImporter.kt Restore relay settings after import; fixed ordering issue but implementation is overly complex

Sequence Diagram

sequenceDiagram
    participant User
    participant MigrationImporter
    participant Database
    participant SettingsRepository
    participant PropagationNodeManager
    
    User->>MigrationImporter: importData(backup.columba)
    
    Note over MigrationImporter: Phase 1: Database Transaction
    MigrationImporter->>MigrationImporter: importDatabaseData()
    MigrationImporter->>MigrationImporter: importContacts()
    
    loop For each contact
        alt contact.isMyRelay == true
            Note over MigrationImporter: Track relay hash<br/>(don't write to DataStore yet)
            MigrationImporter->>MigrationImporter: restoredRelayHash = contact.destinationHash
        end
        MigrationImporter->>Database: Insert ContactEntity with isMyRelay flag
    end
    
    Note over MigrationImporter: Phase 2: Settings Import
    MigrationImporter->>SettingsRepository: importSettings(bundle.settings)
    SettingsRepository->>SettingsRepository: importAllPreferences()
    Note over SettingsRepository: Restores all DataStore prefs<br/>including manualPropagationNode<br/>and autoSelectPropagationNode<br/>(if present in backup)
    
    Note over MigrationImporter: Phase 3: Relay Restoration
    MigrationImporter->>MigrationImporter: restoreRelaySettings(restoredRelayHash)
    MigrationImporter->>SettingsRepository: getManualPropagationNode()
    SettingsRepository-->>MigrationImporter: manualRelay
    
    alt manualRelay != null
        Note over MigrationImporter: Settings already restored relay<br/>from backup DataStore
    else restoredRelayHash != null
        Note over MigrationImporter: Fallback: use contact's isMyRelay<br/>(for old backup format)
        MigrationImporter->>SettingsRepository: saveManualPropagationNode(restoredRelayHash)
        MigrationImporter->>SettingsRepository: saveAutoSelectPropagationNode(false)
    else No relay from either source
        MigrationImporter->>SettingsRepository: getAutoSelectPropagationNode()
        SettingsRepository-->>MigrationImporter: isAutoSelect
        alt isAutoSelect == true
            Note over MigrationImporter: Trigger auto-selection<br/>to pick a relay
            MigrationImporter->>PropagationNodeManager: enableAutoSelect()
        end
    end
    
    MigrationImporter-->>User: Import complete
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

- Extract restoreRelaySettings() to run after both the DB transaction
  and importSettings(), ensuring DataStore writes are never inside a
  Room transaction scope (prevents inconsistent state on rollback)
- Return relay hash through ContactImportResult → TransactionResult
  instead of writing to DataStore inside importContacts()
- Check if importSettings already restored the relay before writing
  from the contact's isMyRelay flag, removing redundant overwrites
- Add warning log when multiple relay contacts found in backup

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@torlando-tech
Copy link
Owner

@greptileai

@torlando-tech torlando-tech merged commit 248f756 into main Jan 28, 2026
10 checks passed
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.

3 participants