Project

General

Profile

Actions

Feature #3269

open
BA BA

[oms-forgot-password-v2] web: Forgot password flow with mobile OTP verification

Feature #3269: [oms-forgot-password-v2] web: Forgot password flow with mobile OTP verification

Added by Bot AI about 2 months ago. Updated about 2 months ago.

Status:
Resolved
Priority:
Normal
Assignee:
Target version:
-
Start date:
09/04/2026
Due date:
% Done:

0%

Estimated time:
Source:

Description

Overview

Feature for the web side. 32 acceptance criteria identified. 32 test case(s) generated.

Requirement

"Forgot Password Flow Implementation"

Attached file (read it directly for the real content): /opt/drcarrot-deploy/cross-repo-orchestration/contracts/.attachments/dev-hub-spec-XYexMWf96oRNbF27P-requirement.md

Additional requirement update: Attached file (read it directly for the real content): /opt/drcarrot-deploy/cross-repo-orchestration/contracts/.attachments/dev-hub-spec-8rnRtKk6dsLtCuNv5-OMS_Screens__standalone___4_.html

Acceptance Criteria

  • The Sign In (Login) screen displays a "Forgot Password?" link. (AC-c863f09c)
  • Clicking "Forgot Password?" on the Sign In screen navigates the user to the Forgot Password screen. (AC-9f181d54)
  • The Forgot Password screen accepts a registered mobile number (with +91 country code) as input — not an email or username. (AC-8e7eb311)
  • Submitting the mobile number via the "Send Reset Code" action sends a verification code (OTP) to that mobile number. (AC-91e6f6e7)
  • After submitting the mobile number, the user is navigated to the Verify Code screen. (AC-55ae7aa2)
  • The Verify Code screen displays the destination mobile number the code was sent to (e.g. "Enter the 6-digit code sent to +91 98404 21770"). (AC-ee4f5a96)
  • The Verify Code screen provides six individual digit boxes for entering the 6-digit verification code. (AC-856f6630)
  • The Verify Code screen provides a "Resend Code" action labeled "Didn't get a code? Resend Code". (AC-53037bbd)
  • The Resend Code action shows a countdown/timer (e.g. "Resend available in 00:30") and is disabled until the timer elapses. (AC-5a6da803)
  • Submitting an invalid verification code shows a proper error message. (AC-d885146e)
  • Submitting an expired verification code shows a proper error message. (AC-49ea65d9)
  • Submitting an incorrect verification code shows a proper error message. (AC-df52fa62)
  • After successful code verification, the user is navigated to the Reset Password screen. (AC-533a94da)
  • The Reset Password screen for this flow does not display or require a "Current Password" field. (AC-8247aab9)
  • The Reset Password screen provides "New Password" and "Re-enter New Password" fields. (AC-6077c02c)
  • The password policy is enforced: minimum 8 characters, at least 1 uppercase letter, 1 lowercase letter, 1 numeral, 1 special character, and not one of the last 3 passwords. (AC-8139f2d0)
  • The Reset Password screen shows live password strength feedback (Weak/Medium/Strong) as the user types the new password. (AC-df2c8ace)
  • If "New Password" and "Re-enter New Password" do not match, an inline "Passwords do not match" error is shown. (AC-686c4f63)
  • The "Save New Password" action commits the password reset. (AC-a397e09e)
  • After a successful password reset, a proper success message/state (e.g. a Password Reset Success screen or equivalent success state) is shown, since no such screen exists in the current design. (AC-fe7ba705)
  • After a successful password reset, any temporary reset/verification state (the OTP session, the reset token) is cleared/invalidated. (AC-a5a00dcd)
  • After a successful password reset, the user is redirected to the Sign In screen. (AC-62626fa7)
  • The user can successfully log in using their mobile number and the newly reset password. (AC-fac93dc1)
  • Verification codes are securely generated, stored, validated, and expired on the backend. (AC-58b03fdf)
  • Verification codes and reset tokens are not exposed in logs or API responses. (AC-7f605c20)
  • An expired verification code cannot be reused to complete the reset flow. (AC-e10c3f18)
  • A previously used (already-consumed) verification code cannot be reused to complete the reset flow. (AC-fd02984c)
  • Rate limiting/security controls are applied to verification-code request and resend endpoints. (AC-fc35922f)
  • Existing login, logout, session, and authentication flows continue to work unchanged after implementation. (AC-48e7fa93)
  • Requesting a verification code for an unregistered mobile number is handled gracefully without breaking the flow. (AC-8a3a41d3)
  • The flow handles API/network failure scenarios (e.g. failed OTP send, failed verification, failed password save) without crashing or leaving the UI in a broken state. (AC-bf01758e)
  • The flow behaves correctly when the user refreshes the page or navigates back at any step (Forgot Password, Verify Code, Reset Password). (AC-174082ab)

Test Cases

☐ The Sign In screen displays a visible "Forgot Password?" link.
☐ Clicking "Forgot Password?" on the Sign In screen navigates to the Forgot Password screen.
☐ The Forgot Password screen accepts a +91 mobile number as input and offers no email/username field.
☐ Submitting a registered mobile number via "Send Reset Code" triggers an OTP to be sent to that number.
☐ After submitting the mobile number, the user is navigated to the Verify Code screen.
☐ The Verify Code screen displays the destination mobile number the code was sent to.
☐ The Verify Code screen provides six individual digit boxes for the 6-digit code.
☐ The Verify Code screen provides a "Didn't get a code? Resend Code" action.
☐ The Resend Code action shows a countdown timer and stays disabled until the timer elapses.
☐ Submitting an invalid (malformed) verification code shows a proper error message.
☐ Submitting an expired verification code shows a proper error message.
☐ Submitting an incorrect verification code shows a proper error message.
☐ After successful code verification, the user is navigated to the Reset Password screen.
☐ The Reset Password screen for the forgot-password flow does not display or require a Current Password field.
☐ The Reset Password screen provides "New Password" and "Re-enter New Password" fields.
☐ The password policy (length, character classes, and no reuse of the last 3 passwords) is enforced.
☐ The Reset Password screen shows live Weak/Medium/Strong password strength feedback as the user types.
☐ A mismatch between "New Password" and "Re-enter New Password" shows an inline "Passwords do not match" error.
☐ The "Save New Password" action commits the password reset.
☐ After a successful password reset, a proper success message/state is shown.
☐ After a successful password reset, the temporary OTP session and reset token are cleared/invalidated.
☐ After a successful password reset, the user is redirected to the Sign In screen.
☐ The user can successfully log in using their mobile number and the newly reset password.
☐ Verification codes are securely generated, stored, validated, and expired on the backend.
☐ Verification codes and reset tokens are never exposed in API responses or application logs.
☐ An expired verification code cannot be reused to complete the reset flow.
☐ A previously used (already-consumed) verification code cannot be reused to complete the reset flow.
☐ Rate limiting/security controls are applied to the verification-code request and resend endpoints.
☐ Existing login, logout, session, and authentication flows continue to work unchanged after implementation.
☐ Requesting a verification code for an unregistered mobile number is handled gracefully without breaking the flow.
☐ The flow handles API/network failures at each step without crashing or leaving the UI in a broken state.
☐ The flow behaves correctly when the user refreshes the page or navigates back at any step.

Implementation Details

Diagnosis & Fix

Ticket #3269 adds an unauthenticated three-step password-recovery flow: (1) user enters their registered mobile number, (2) enters a 6-digit OTP with a resend countdown, (3) sets a new password with live strength validation. The entire data layer (4 Server Actions, getResetFlowState query, barrel, Zod schemas, Prisma model and migration, unit tests) is already complete. The remaining work is the UI layer: three new page segments under app/(auth), three new client components for the forms, a middleware matcher update to un-gate the new unauthenticated routes, and a 'Forgot Password?' link added to the existing SignInForm.

Merge Request

Commits

  • ccbb1a7 Contract (oms-forgot-password-v2)
  • 64e7d83 4. Dead Code (oms-forgot-password-v2)
  • 9cdf8fc 1. Unit Tests (oms-forgot-password-v2)
  • 0712d47 Design (oms-forgot-password-v2)
  • a3f5446 UI Implementation (oms-forgot-password-v2)
  • f383a8c Data Layer (oms-forgot-password-v2)

Verification

Quality Gates

  • 1. Unit Tests: PASS — 120 passed / 0 failed, 93.33% coverage
    • ✅ ForgotPasswordPage — rendering renders the brand panel: PASS
    • ✅ ForgotPasswordPage — rendering renders the ForgotPasswordForm: PASS
    • ✅ ForgotPasswordPage — rendering renders both sections inside the same full-screen container: PASS
    • ✅ ResetPasswordPage — flow guard redirects to /forgot-password when there is no reset-flow cookie: PASS
    • ✅ ResetPasswordPage — flow guard redirects to /forgot-password when the flow resolves to null (expired/consumed/invalid): PASS
    • ✅ ResetPasswordPage — flow guard redirects to /verify-otp when the flow exists but OTP has not been verified: PASS
    • ✅ ResetPasswordPage — rendering renders the brand panel and CompleteResetForm for a verified flow: PASS
    • ✅ ResetPasswordPage — rendering renders the page heading 'Set New Password': PASS
    • ✅ ResetPasswordPage — rendering renders the descriptive subtitle: PASS
    • ✅ ResetPasswordPage — rendering calls getResetFlowState with the actual cookie value: PASS
    • ✅ VerifyOtpPage — flow guard redirects to /forgot-password when there is no reset-flow cookie: PASS
    • ✅ VerifyOtpPage — flow guard redirects to /forgot-password when the flow state resolves to null (expired/consumed/invalid): PASS
    • ✅ VerifyOtpPage — flow guard redirects to /reset-password when the flow is already verified (skip ahead): PASS
    • ✅ VerifyOtpPage — rendering renders the brand panel and VerifyOtpForm when the flow is valid and unverified: PASS
    • ✅ VerifyOtpPage — rendering passes maskedMobile from the flow state to VerifyOtpForm: PASS
    • ✅ VerifyOtpPage — rendering passes initialSecondsUntilResend from the flow state to VerifyOtpForm: PASS
    • ✅ VerifyOtpPage — rendering calls getResetFlowState with the cookie value (not a hardcoded string): PASS
    • ✅ VerifyOtpPage — rendering passes an empty string to getResetFlowState when the cookie is absent: PASS
    • ✅ CompleteResetForm — rendering renders the 'New Password' and 'Re-enter New Password' fields: PASS
    • ✅ CompleteResetForm — rendering renders the 'Set New Password' submit button: PASS
    • ✅ CompleteResetForm — rendering renders the password policy card with all five client-side rules: PASS
    • ✅ CompleteResetForm — rendering renders the 'Not last 3 passwords' rule (server-only, always neutral): PASS
    • ✅ CompleteResetForm — rendering binds the form to completeReset via useFormState: PASS
    • ✅ CompleteResetForm — submit button gating submit button is disabled when no password has been entered: PASS
    • ✅ CompleteResetForm — submit button gating submit button is disabled when the password meets policy but confirm is empty: PASS
    • ✅ CompleteResetForm — submit button gating submit button is disabled when passwords don't match even if both meet policy: PASS
    • ✅ CompleteResetForm — submit button gating submit button is enabled when a strong password is entered and both fields match: PASS
    • ✅ CompleteResetForm — password strength shows no strength label before any password is typed: PASS
    • ✅ CompleteResetForm — password strength shows a strength label once the user starts typing: PASS
    • ✅ CompleteResetForm — password strength shows 'Strong' for a password that satisfies all 5 policy rules: PASS
    • ✅ CompleteResetForm — confirm password mismatch shows 'Passwords do not match' when confirmPassword differs from newPassword: PASS
    • ✅ CompleteResetForm — confirm password mismatch does not show the mismatch error when confirmPassword is empty: PASS
    • ✅ CompleteResetForm — server error state shows a toast with the server error message when state.ok is false: PASS
    • ✅ CompleteResetForm — server error state renders no toast in the initial state (no submit yet): PASS
    • ✅ CompleteResetForm — server error state also shows the field error inline when state.fieldErrors.newPassword is set: PASS
    • ✅ CompleteResetForm — server error state dismisses the toast when the dismiss button is clicked: PASS
    • ✅ ForgotPasswordForm — rendering renders the heading and description: PASS
    • ✅ ForgotPasswordForm — rendering renders a mobile number input with the required asterisk: PASS
    • ✅ ForgotPasswordForm — rendering renders the 'Send Reset Code' submit button: PASS
    • ✅ ForgotPasswordForm — rendering renders a 'Sign in' link back to /login: PASS
    • ✅ ForgotPasswordForm — rendering binds the form to requestResetCode via useFormState: PASS
    • ✅ ForgotPasswordForm — field error state shows the mobile field error when state includes a fieldErrors.mobile: PASS
    • ✅ ForgotPasswordForm — message error state shows the message-level error when state.ok is false and state.message is set: PASS
    • ✅ ForgotPasswordForm — message error state does not show a message-level error when state.ok is true: PASS
    • ✅ ForgotPasswordForm — post-submit navigation navigates to /verify-otp when a post-submit state has ok:true (different reference from initialState): PASS
    • ✅ ForgotPasswordForm — post-submit navigation does NOT navigate when state is the component's own initialState (first render, no submit): PASS
    • ✅ ForgotPasswordForm — post-submit navigation does NOT navigate to /verify-otp when state.ok is false after a failed submit: PASS
    • ✅ requestResetCode — input validation returns a field error when mobile is empty: PASS
    • ✅ requestResetCode — input validation returns a field error for a mobile that is too short: PASS
    • ✅ requestResetCode — input validation returns a field error for a mobile with non-numeric characters beyond +/-/space: PASS
    • …(70 more — see 1. Unit Tests's evidence file for the full list)
    1. Unit Tests attached: unit-tests-gate-5.json
  • 2. TypeScript: PASS — 0 error(s)
    1. TypeScript attached: tsc-output-20260904-080004.txt
  • 3. Lint: PASS — 0 error(s), 0 warning(s)
    1. Lint attached: lint-2115.txt
  • 4. Dead Code: PASS
    1. Dead Code attached: dead-code-3269.txt
  • 5. Code & Style Quality Audit: PASS
    1. Code & Style Quality Audit attached: W14_gate_quality-audit-3269.txt
  • 5a. Bundle Analyze: WARN
  • 5a. Bundle Analyze attached: bundle-analyze-3269.txt
  • 5b. Performance: PASS
  • 5b. Performance attached: performance-3269.txt
  • 6. Design Consistency Audit: FAIL
    1. Design Consistency Audit attached: design-consistency-audit-3269.txt
  • 7. Responsive Audit: FAIL
    1. Responsive Audit attached: responsive-audit-3269.txt
  • Code Review: PASS
  • UI Verify: N/A

UI Verification

N/A

  • Screens verified: forgot-password, verify-otp, reset-password
    Business Logic Verification: FAILED
  • Live verification evidence attached: live-verify-3269.txt

Verification Coverage

  • Acceptance criteria on this ticket: 32
    • [AC-c863f09c] The Sign In (Login) screen displays a "Forgot Password?" link.
    • [AC-9f181d54] Clicking "Forgot Password?" on the Sign In screen navigates the user to the Forgot Password screen.
    • [AC-8e7eb311] The Forgot Password screen accepts a registered mobile number (with +91 country code) as input — not an email or username.
    • [AC-91e6f6e7] Submitting the mobile number via the "Send Reset Code" action sends a verification code (OTP) to that mobile number.
    • [AC-55ae7aa2] After submitting the mobile number, the user is navigated to the Verify Code screen.
    • [AC-ee4f5a96] The Verify Code screen displays the destination mobile number the code was sent to (e.g. "Enter the 6-digit code sent to +91 98404 21770").
    • [AC-856f6630] The Verify Code screen provides six individual digit boxes for entering the 6-digit verification code.
    • [AC-53037bbd] The Verify Code screen provides a "Resend Code" action labeled "Didn't get a code? Resend Code".
    • [AC-5a6da803] The Resend Code action shows a countdown/timer (e.g. "Resend available in 00:30") and is disabled until the timer elapses.
    • [AC-d885146e] Submitting an invalid verification code shows a proper error message.
    • [AC-49ea65d9] Submitting an expired verification code shows a proper error message.
    • [AC-df52fa62] Submitting an incorrect verification code shows a proper error message.
    • [AC-533a94da] After successful code verification, the user is navigated to the Reset Password screen.
    • [AC-8247aab9] The Reset Password screen for this flow does not display or require a "Current Password" field.
    • [AC-6077c02c] The Reset Password screen provides "New Password" and "Re-enter New Password" fields.
    • [AC-8139f2d0] The password policy is enforced: minimum 8 characters, at least 1 uppercase letter, 1 lowercase letter, 1 numeral, 1 special character, and not one of the last 3 passwords.
    • [AC-df2c8ace] The Reset Password screen shows live password strength feedback (Weak/Medium/Strong) as the user types the new password.
    • [AC-686c4f63] If "New Password" and "Re-enter New Password" do not match, an inline "Passwords do not match" error is shown.
    • [AC-a397e09e] The "Save New Password" action commits the password reset.
    • [AC-fe7ba705] After a successful password reset, a proper success message/state (e.g. a Password Reset Success screen or equivalent success state) is shown, since no such screen exists in the current design.
    • [AC-a5a00dcd] After a successful password reset, any temporary reset/verification state (the OTP session, the reset token) is cleared/invalidated.
    • [AC-62626fa7] After a successful password reset, the user is redirected to the Sign In screen.
    • [AC-fac93dc1] The user can successfully log in using their mobile number and the newly reset password.
    • [AC-58b03fdf] Verification codes are securely generated, stored, validated, and expired on the backend.
    • [AC-7f605c20] Verification codes and reset tokens are not exposed in logs or API responses.
    • [AC-e10c3f18] An expired verification code cannot be reused to complete the reset flow.
    • [AC-fd02984c] A previously used (already-consumed) verification code cannot be reused to complete the reset flow.
    • [AC-fc35922f] Rate limiting/security controls are applied to verification-code request and resend endpoints.
    • [AC-48e7fa93] Existing login, logout, session, and authentication flows continue to work unchanged after implementation.
    • [AC-8a3a41d3] Requesting a verification code for an unregistered mobile number is handled gracefully without breaking the flow.
    • [AC-bf01758e] The flow handles API/network failure scenarios (e.g. failed OTP send, failed verification, failed password save) without crashing or leaving the UI in a broken state.
    • [AC-174082ab] The flow behaves correctly when the user refreshes the page or navigates back at any step (Forgot Password, Verify Code, Reset Password).
  • UI Verify exercised 0 interactive behavior(s), 0 failed
  • Business Logic Verification verdict: FAILED
  • Cross-check each acceptance criterion above against the attached UI/Business Logic evidence by hand — this run does not claim a verified per-item match, only that these are the real results it produced.

Orchestration slug: oms-forgot-password-v2 (side: web)


Files

unit-tests-gate-5.json (20.6 KB) unit-tests-gate-5.json Bot AI, 09/04/2026 12:09 PM
tsc-output-20260904-080004.txt (4.91 KB) tsc-output-20260904-080004.txt Bot AI, 09/04/2026 12:09 PM
lint-2115.txt (811 Bytes) lint-2115.txt Bot AI, 09/04/2026 12:09 PM
dead-code-3269.txt (4.13 KB) dead-code-3269.txt Bot AI, 09/04/2026 12:09 PM
W14_gate_quality-audit-3269.txt (21.8 KB) W14_gate_quality-audit-3269.txt Bot AI, 09/04/2026 12:09 PM
bundle-analyze-3269.txt (2.19 KB) bundle-analyze-3269.txt Bot AI, 09/04/2026 12:09 PM
performance-3269.txt (11.6 KB) performance-3269.txt Bot AI, 09/04/2026 12:09 PM
design-consistency-audit-3269.txt (20.7 KB) design-consistency-audit-3269.txt Bot AI, 09/04/2026 12:09 PM
responsive-audit-3269.txt (16.7 KB) responsive-audit-3269.txt Bot AI, 09/04/2026 12:09 PM
live-verify-3269.txt (9.75 KB) live-verify-3269.txt Bot AI, 09/04/2026 12:09 PM
Actions

Also available in: PDF Atom