feat: rejoin study#782
Conversation
…boarding screens, core utilities, and localization.
…g logic and UI to support 13 words.
…th a new service and backend migration.
… field and comprehensive help instructions.
|
Visit the preview URL for this PR (updated for commit b9e0027):
(expires Fri, 17 Jul 2026 15:09:56 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: 2149dad49ed83535217e50d5c18c0c8c90da629b |
…m the core package.
…anning, sharing, and downloading options.
…etup and color opacity, and streamline menu positioning.
…I theming in QR code scanner and settings screens
…icipation options, and recovery actions in English and German
…et for better readability
…h and German localizations
…mance optimization
…and refactor phrase display into a new widget.
|
#781 waiting for this |
There was a problem hiding this comment.
Pull request overview
This pull request implements a secure recovery code system by decoupling recovery phrases from user IDs. The changes introduce a new database table for recovery ID mapping, implement recovery phrase encoding/decoding using BIP39 wordlists, and create comprehensive UI flows for both generating and using recovery phrases.
Key Changes:
- Introduced
user_recoverytable withrecovery_id(PK) →user_id(FK) mapping for enhanced security - Implemented recovery phrase encoding/decoding using 13-word mnemonic phrases with checksum validation
- Created complete onboarding and rejoin flows with QR code support and multiple sharing options
Reviewed changes
Copilot reviewed 21 out of 23 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
supabase/migrations/20251208_user_recovery.sql |
Adds user_recovery table, RLS policies, and database functions for recovery ID management |
core/lib/src/util/recovery.dart |
Implements UUID encoding/decoding to recovery phrases with checksum validation |
core/lib/src/util/wordlists.dart |
Provides BIP39 English and German wordlists for recovery phrase generation |
app/lib/services/rejoin_study_service.dart |
Service layer for recovery phrase generation and account recovery logic |
app/lib/widgets/recovery_phrase_content.dart |
Reusable widget displaying recovery phrases with share/copy/download functionality |
app/lib/screens/app_onboarding/recovery_phrase_screen.dart |
Onboarding screen showing recovery phrase with confirmation checkbox |
app/lib/screens/app_onboarding/rejoin_study_screen.dart |
Screen for entering recovery phrase to rejoin study with validation |
app/lib/screens/app_onboarding/qr_code_scanner_screen.dart |
QR code scanner for recovery phrase input |
app/lib/util/recovery_qr_utils.dart |
Utilities for QR code generation, deep linking, and file operations |
app/lib/screens/study/dashboard/settings.dart |
Updated settings screen with recovery phrase management in ExpansionTile |
app/lib/routes.dart |
Added routes for recovery phrase, rejoin study, and QR scanner screens |
app/lib/l10n/* |
Comprehensive localization for English and German |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- RejoinStudyScreen → RestoreAccountScreen - RejoinStudyService → RestoreAccountService - l10n keys: rejoin_study* → restore_account* - File renames: rejoin_study_* → restore_account_* - Updated all imports and references
|
Deep link QA checklistPlease test these edge cases one by one:
|
Release deep-link QA notesPlease add release/live-device verification before merging or releasing:
Context: I removed iOS deferred deep linking because the previous fallback copied the invite link to the clipboard before App Store handoff. On iOS 16+, paste permission prompts/banners can scare users or fail. If deferred invite restore after install is required on iOS later, we should implement a real provider/backend deferred-link token flow instead of clipboard handoff. |
|
@mohiuddinshahrukh can you review? |




Secure Recovery Code Implementation
Summary
Decouples recovery phrases from user IDs to enhance security. Previously, recovery phrases were derived directly from user UUIDs, which posed a session hijacking risk if user IDs were ever leaked.
Solution
A new
user_recoverytable was introduced to map independentrecovery_idvalues touser_id.Recovery phrases are now derived from
recovery_idinstead ofuser_id.Changes
Database
user_recoverytable withrecovery_id(PK) →user_id(FK) mappingget_or_create_recovery()function for on-the-fly entry creationrecover_account()to acceptrecovery_idinstead ofuser_idApp
RejoinStudyService.getRecoveryPhrase()with cachingRejoinStudyService.getOrCreateRecoveryId()RecoveryPhraseContentwidget to consolidate duplicate UI codeRecoveryPhraseScreenandRecoveryPhraseWidgetTesting