Skip to content

feat: rejoin study#782

Open
ibrahimozkn wants to merge 53 commits into
devfrom
feat/rejoin-study
Open

feat: rejoin study#782
ibrahimozkn wants to merge 53 commits into
devfrom
feat/rejoin-study

Conversation

@ibrahimozkn

@ibrahimozkn ibrahimozkn commented Dec 1, 2025

Copy link
Copy Markdown
Contributor

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_recovery table was introduced to map independent recovery_id values to user_id.
Recovery phrases are now derived from recovery_id instead of user_id.

Changes

Database

  • Added user_recovery table with recovery_id (PK) → user_id (FK) mapping
  • Added get_or_create_recovery() function for on-the-fly entry creation
  • Updated recover_account() to accept recovery_id instead of user_id
  • Added RLS policies for the new table

App

  • Added RejoinStudyService.getRecoveryPhrase() with caching
  • Added RejoinStudyService.getOrCreateRecoveryId()
  • Created shared RecoveryPhraseContent widget to consolidate duplicate UI code
  • Simplified RecoveryPhraseScreen and RecoveryPhraseWidget
  • Added localization keys for error messages

Testing

  • Test new user onboarding flow
  • Test existing user settings → recovery phrase generation
  • Test full recovery flow with the new phrase

@github-actions github-actions Bot added dependencies Pull requests that update a dependency file app core labels Dec 1, 2025
@github-actions

github-actions Bot commented Dec 1, 2025

Copy link
Copy Markdown

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

@ibrahimozkn ibrahimozkn marked this pull request as ready for review December 11, 2025 14:33
Copilot AI review requested due to automatic review settings December 11, 2025 14:33
@ibrahimozkn

Copy link
Copy Markdown
Contributor Author

#781 waiting for this

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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_recovery table with recovery_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.

Comment thread app/lib/util/recovery_qr_utils.dart Outdated
Comment thread app/lib/widgets/recovery_phrase_content.dart Outdated
Comment thread supabase/migrations/20260709120000_user_recovery.sql
johannesvedder and others added 4 commits July 9, 2026 14:44
- RejoinStudyScreen → RestoreAccountScreen
- RejoinStudyService → RestoreAccountService
- l10n keys: rejoin_study* → restore_account*
- File renames: rejoin_study_* → restore_account_*
- Updated all imports and references
@johannesvedder

Copy link
Copy Markdown
Contributor
Screenshot 2026-07-09 at 15 28 42 Screenshot 2026-07-09 at 15 28 53 Screenshot 2026-07-09 at 15 29 23

@johannesvedder

johannesvedder commented Jul 9, 2026

Copy link
Copy Markdown
Contributor
  • Show recovery phrase as popup on first opening of dashboard and not directly the beginning
  • add to the recovery phrase description that the user can always see their recovery phrase again in the study settings
  • don't add verification step after showing recovery phrase ("insert the 5th word") because it gets too complex

@johannesvedder

johannesvedder commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Deep link QA checklist

Please test these edge cases one by one:

  • Web desktop opens https://app.dev.studyu.health/invite/test12345 and sees mobile-only message.
  • Mobile web with app installed opens https://app.dev.studyu.health/invite/test12345, app opens, same flow works.
  • Mobile app installed opens studyu-app://invite/test12345, onboarding starts if needed, welcome invite popup appears, accepting shows terms, accepting terms opens study overview.
  • Direct custom-scheme invite persists across app kill before onboarding finishes: open studyu-app://invite/test12345, kill app immediately, reopen app, invite popup still appears after onboarding/welcome.
  • Deferred Android invite persists across app kill before onboarding finishes: open mobile web invite without app, install/open app, kill before finishing onboarding, reopen app, invite popup still appears.
  • Declining invite popup clears persistence: open invite, decline popup, kill/reopen app, app starts normally without invite popup.
  • Accepting invite popup always shows Terms before study overview, even when user was already onboarded.
  • Study overview reached from invite has normal back button behavior: back from study overview returns to Terms. Forward should go to study overview again
  • Invalid invite shows error and does not persist stale invite on next restart.
  • Existing active-study user opens invite and sees warning that only one study can be active because interventions can interfere and alter results.
  • Existing active-study warning primary action keeps user in current study/dashboard and does not persist invite.
  • Existing active-study warning secondary action opens Settings, with current study loaded, so user can leave current study.
  • Existing active-study user kills/reopens app after warning; invite popup does not reappear.
  • If user opens invite A, then opens invite B before accepting, invite B replaces invite A.
  • Eligibility failure during invited join clears pending invite; restart does not show invite popup again.
  • Consent decline during invited join clears pending invite; restart does not show invite popup again.
  • Successful join through kickoff clears pending invite; restart opens dashboard/current study normally.
  • Android Play Store download button includes referrer for invite links.
  • iOS App Store download button opens App Store without copying invite to clipboard and no paste permission popup appears on first app launch.
  • iOS installed-app universal link still opens app when already installed (https://app.studyu.health/invite/test12345).
  • iOS not-installed flow does not promise deferred invite restore after install.

@johannesvedder

Copy link
Copy Markdown
Contributor

Release deep-link QA notes

Please add release/live-device verification before merging or releasing:

  • After dev release/deploy, test https://app.dev.studyu.health/invite/test12345 on a real Android device with the installed dev app, not only on an emulator.
  • After production release/deploy, test https://app.studyu.health/invite/test12345 on a real Android device with the installed production app.
  • Verify Android App Links with the release-signed APK fingerprint in assetlinks.json; debug/emulator builds use a different signing fingerprint and can fail verification even when studyu-app://... works through ADB.
  • Test iOS universal links on a live iPhone after release, both app-installed and not-installed flows.

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.

johannesvedder
johannesvedder previously approved these changes Jul 10, 2026
@johannesvedder

Copy link
Copy Markdown
Contributor

@mohiuddinshahrukh can you review?

@mohiuddinshahrukh

Copy link
Copy Markdown
Collaborator

praise: UI and UX is good - everything works as it should until: See issue
issue: I try to do a deeplink into the app using the following from terminal: adb -s <my_device_id> shell am start -a android.intent.action.VIEW -d "studyu-app://study/22222222-2222-4222-8222-222222222222"
This gets stuck into an infinte loading screen.
question:
image

If this is the way studies will be shared - then we don't need invite codes - yes? or how does it work with invite codes and sharable links/ qr codes

@mohiuddinshahrukh

Copy link
Copy Markdown
Collaborator

@johannesvedder

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app core dependencies Pull requests that update a dependency file flutter_common

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants