Skip to content

CCCT-2407 Wire Email Entry Into PersonalID Signup And Recovery Flow#3735

Open
Jignesh-dimagi wants to merge 2 commits into
ccct-2377-email-entry-fragmentfrom
ccct-2407-email-navigation-flow
Open

CCCT-2407 Wire Email Entry Into PersonalID Signup And Recovery Flow#3735
Jignesh-dimagi wants to merge 2 commits into
ccct-2377-email-entry-fragmentfrom
ccct-2407-email-navigation-flow

Conversation

@Jignesh-dimagi
Copy link
Copy Markdown
Contributor

@Jignesh-dimagi Jignesh-dimagi commented May 22, 2026

CCCT-2407

Product Description

Connects the Email entry screen into the live PersonalID flow. After this PR the email step is actually reachable from a running app:

  • During signup, the Backup Code step routes into the Email entry screen when the server's email_otp_verification toggle is active; otherwise the flow continues straight to Photo Capture as before.
  • During recovery, the Backup Code step routes into the Email entry screen only when the server hasn't already returned a verified email for the user AND the toggle is active; otherwise the recovery is finalised immediately and the existing "Account Recovered" success screen is shown.
  • A verified email is persisted onto ConnectUserRecord.email at signup completion (Photo Capture) and at recovery completion (PersonalIdRecoveryCompleter), so it's visible on the HQ admin view of the PersonalID user.

Technical Summary

  • PersonalIdBackupCodeFragment.handleBackupCodeSubmission() (signup branch) and handleConfirmBackupCodeSuccess() (recovery branch) now read ReleaseToggleHelper.isEmailOtpVerificationActive(personalIdSessionData) against the in-flight session's featureReleaseToggles list and branch accordingly. Recovery additionally short-circuits to the success screen when personalIdSessionData.getEmail() != null (the server already has a verified address).
  • New navigateToEmail() helper stamps PersonalIDPreferences.setLastEmailOfferDate(now) whenever the screen is shown (anchor for the future 30-day re-prompt gate), selects EmailWorkFlow.RECOVERY or EmailWorkFlow.REGISTRATION based on isRecovery, and navigates via the new Safe Args action actionPersonalidBackupcodeToPersonalidEmail(workflow).
  • New nav action action_personalid_backupcode_to_personalid_email in nav_graph_personalid.xml (no arg overrides — destination's required workflow: EmailWorkFlow arg is passed by the caller).
  • PersonalIdPhotoCaptureFragment.createAndSaveConnectUser() now writes user.setEmail(personalIdSessionData.getEmail()) before storing the record. Mirrors the symmetric write inside PersonalIdRecoveryCompleter.finalizeAccountRecovery. The constructor signature for ConnectUserRecord is unchanged; the email is set via the setter post-construction.
  • PersonalIdRecoveryCompleter KDoc updated to remove the CCCT-2407 / CCCT-2378 TODOs that are now satisfied and restate which callsites invoke it.

Safety Assurance

Safety story

What gives confidence:

  • I walked four routing scenarios on a device: signup with the email_otp_verification toggle ON (Email screen appears after Backup Code), signup with the toggle OFF (skips straight to Photo Capture), recovery with a server-returned email (skips Email and goes straight to Recovery Success), and recovery with no server email and the toggle ON (Email screen appears so the user can add one).
  • The diff is small and pivots cleanly on ReleaseToggleHelper.isEmailOtpVerificationActive(...) — the toggle-off branches are byte-equivalent to the pre-PR behavior (signup → Photo, recovery → finalize + success).
  • The PhotoCapture and PersonalIdRecoveryCompleter email-persistence writes are symmetric: same user.email = sessionData.email shape on both paths, with sessionData.email populated only by the OTP-verify success callback (sessionData.email != null remains a strict synonym for "verified").
  • The new routing depends on EmailWorkFlow and actionPersonalidBackupcodeToPersonalidEmail, both introduced in CCCT-2377 Add Email Entry Fragment To PersonalID Flow #3729 (the base of this PR) — Safe Args compiles cleanly against that.

Risks to review:

  • I did not exercise the recovery + toggle OFF branch on a device. The existing navigateToSuccess() path is unchanged so the regression risk is limited to "did the toggle check evaluate correctly when off in recovery", but the codepath itself was not run.
  • I did not verify on a device that the verified email appears on the HQ admin view of the PersonalID user. The DB write logic mirrors PersonalIdRecoveryCompleter (which is server-tested in earlier flows), but the end-to-end "HQ shows the email" verification was not performed.
  • PersonalIDPreferences.setLastEmailOfferDate(now) is written eagerly the moment navigateToEmail() is invoked, before the user has interacted with the screen. If the user backs out without skipping or completing, the offer-date is still consumed. Acceptable given the 30-day cadence, but worth confirming with product.
  • The toggle check uses the session-data overload (isEmailOtpVerificationActive(personalIdSessionData)), which reads the toggle list that came back from /users/start_configuration for the current in-flight session — fresh and authoritative for signup/recovery, but does not cover legacy users who land here via a different entry point (none exist today; this is only relevant once the legacy add-email path lands).
  • This PR's base is CCCT-2377 Add Email Entry Fragment To PersonalID Flow #3729, not master. Any change to EmailWorkFlow, the email-entry destination args, or PersonalIdRecoveryCompleter.finalizeAccountRecovery's signature on that branch will rebase into here.

Automated test coverage

  • Existing PersonalIdEmailFragmentTest (8 cases) and PersonalIdPhoneFragmentTest (12 cases) continue to pass — the shared BasePersonalIdConfigurationTest is unchanged on this branch.
  • Not covered by automation: the PersonalIdBackupCodeFragment routing branches themselves (signup/recovery × toggle on/off × email present/null), the PersonalIDPreferences.setLastEmailOfferDate(now) side effect in navigateToEmail, and the PhotoCapture.createAndSaveConnectUser email-persistence write. Coverage is left to the manual QA steps in RELEASES.md for this release.

Jignesh-dimagi and others added 2 commits May 22, 2026 19:12
Routes the Backup Code step into the Email entry screen so the email feature
is actually reachable end-to-end:

  - Signup with email_otp_verification toggle ON → navigate to Email entry.
  - Signup with toggle OFF → continue straight to Photo Capture (unchanged).
  - Recovery with toggle ON and no server-returned email → Email entry.
  - Recovery with toggle ON and a server-returned email, or toggle OFF →
    finalize recovery via PersonalIdRecoveryCompleter and navigate to the
    success message screen.

navigateToEmail() stamps PersonalIDPreferences.setLastEmailOfferDate(now) so
the future 30-day re-prompt gate starts from when the offer is presented,
and selects EmailWorkFlow.RECOVERY or .REGISTRATION based on flow.

PhotoCapture.createAndSaveConnectUser now writes
user.setEmail(personalIdSessionData.getEmail()) so the verified address
persists on the new ConnectUserRecord. Mirrors the symmetric write inside
PersonalIdRecoveryCompleter for the recovery path.

PersonalIdRecoveryCompleter KDoc updated to reflect that the CCCT-2407 /
CCCT-2378 TODOs are now satisfied.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Jignesh-dimagi Jignesh-dimagi self-assigned this May 22, 2026
@Jignesh-dimagi
Copy link
Copy Markdown
Contributor Author

Suggested Review Order

  • app/res/navigation/nav_graph_personalid.xml — single new action action_personalid_backupcode_to_personalid_email; sets up the rest of the wiring.
  • app/src/org/commcare/fragments/personalId/PersonalIdBackupCodeFragment.java — main change: signup + recovery routing rules + navigateToEmail helper.
  • app/src/org/commcare/fragments/personalId/PersonalIdPhotoCaptureFragment.java — one-line user.setEmail(sessionData.getEmail()) for signup persistence.
  • app/src/org/commcare/personalId/PersonalIdRecoveryCompleter.kt — KDoc-only cleanup: removed the CCCT-2407 / CCCT-2378 TODOs now satisfied.
  • RELEASES.md — adds the routing scenarios under the existing WIP QA section for CommCare 2.64.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 22, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 23.30%. Comparing base (ae87985) to head (623b75c).

Additional details and impacted files
@@                        Coverage Diff                        @@
##             ccct-2377-email-entry-fragment    #3735   +/-   ##
=================================================================
  Coverage                             23.29%   23.30%           
- Complexity                             3938     3942    +4     
=================================================================
  Files                                   929      929           
  Lines                                 56456    56486   +30     
  Branches                               6707     6719   +12     
=================================================================
+ Hits                                  13152    13164   +12     
- Misses                                41601    41618   +17     
- Partials                               1703     1704    +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Jignesh-dimagi Jignesh-dimagi added the skip-integration-tests Skip android tests. label May 22, 2026
@Jignesh-dimagi Jignesh-dimagi marked this pull request as ready for review May 22, 2026 13:57
Copy link
Copy Markdown
Contributor

@conroy-ricketts conroy-ricketts left a comment

Choose a reason for hiding this comment

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

LGTM! Just had one minor comment

Comment thread RELEASES.md
- **Recovery with the server already returning a verified email for the user:** Walk PersonalID account recovery (validate backup code on a new device). Verify the flow skips the Email screen entirely and goes directly to the "Account Recovered" success screen.
- **Recovery with no server email, `email_otp_verification` toggle ON:** Recover an account that has no email on file. After backup code validation, verify the Email entry screen appears (so the user can add an email during recovery).
- **Recovery with `email_otp_verification` toggle OFF:** Recover any account with the toggle disabled. Verify the flow goes directly from backup code to the "Account Recovered" success screen without the Email screen.
- **Email persisted on the user record:** After completing a signup that included entering and verifying an email, verify the HQ admin view of the PersonalID user shows the email address that was entered. Repeat the same check after a recovery that included the Email screen.
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.

QA won't have access to the admin tool right?

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.

right, think QA can verify this by just checking if they don't get asked the email again while recovering the account.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I have thought about this line while committing but ultimately kept it so that QA is aware to verify the email address, either by viewing it on the dashboard (if possible, like the phone number) or, as @shubham1g5 suggested, to verify it by application flow, by recovering the same account.

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

Labels

skip-integration-tests Skip android tests.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants