Sign-in: resend cooldown locks out a corrected email address #20

Closed
opened 2026-06-11 08:02:37 +00:00 by ben.stull · 0 comments
Owner

What happened

On the sign-in email step (SignIn.tsx, SD-0001 §5.2), the operator typed the wrong
email address and submitted. The 60s resend cooldown then disabled the primary button
("Resend in 31s") even after correcting the address in the field, locking them out
of sending a code to the right address for the remainder of the window.

Diagnosis

  • Backend is correct: accounts/service.py::request_code enforces the cooldown
    per email address (WHERE email = %s, INV-3 → PUC-2c). A request for a different
    address would succeed immediately.
  • Frontend bug: frontend/src/screens/SignIn.tsx keeps one screen-level
    useCooldown counter with no memory of which address it was set for, and the email-step
    button is disabled={cooldown > 0} unconditionally. The UI invents a guard the server
    doesn't have.

Fix

Key the client cooldown to the address it was set for (e.g. track cooldownEmail
alongside the timer). On the email step, disable the button + show "Resend in Ns" only
when the current input normalizes to the cooled-down address; any other address shows an
enabled "Send code". The code-step resend keeps the countdown (it always targets the
sent-to address). Server retry_after_s remains the source of truth on 429.

Source

  • frontend/src/screens/SignIn.tsxuseCooldown, sendCode, email-step PrimaryButton
  • backend/app/domains/accounts/service.py::request_code (per-address cooldown, for contrast)
  • SD-0001 §5.2 (sign-in flow), INV-3 (resend cooldown)
## What happened On the sign-in email step (`SignIn.tsx`, SD-0001 §5.2), the operator typed the wrong email address and submitted. The 60s resend cooldown then disabled the primary button ("Resend in 31s") **even after correcting the address in the field**, locking them out of sending a code to the right address for the remainder of the window. ## Diagnosis - **Backend is correct**: `accounts/service.py::request_code` enforces the cooldown **per email address** (`WHERE email = %s`, INV-3 → PUC-2c). A request for a different address would succeed immediately. - **Frontend bug**: `frontend/src/screens/SignIn.tsx` keeps one screen-level `useCooldown` counter with no memory of *which address* it was set for, and the email-step button is `disabled={cooldown > 0}` unconditionally. The UI invents a guard the server doesn't have. ## Fix Key the client cooldown to the address it was set for (e.g. track `cooldownEmail` alongside the timer). On the email step, disable the button + show "Resend in Ns" only when the current input normalizes to the cooled-down address; any other address shows an enabled "Send code". The code-step resend keeps the countdown (it always targets the sent-to address). Server `retry_after_s` remains the source of truth on 429. ## Source - `frontend/src/screens/SignIn.tsx` — `useCooldown`, `sendCode`, email-step `PrimaryButton` - `backend/app/domains/accounts/service.py::request_code` (per-address cooldown, for contrast) - SD-0001 §5.2 (sign-in flow), INV-3 (resend cooldown)
ben.stull added the priority/P1type/bug labels 2026-06-11 08:02:37 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: wiggleverse/wiggleverse-ecomm#20