Skip to content

feat(v2): sign-up and account recovery follow their frames - #3297

Merged
lilyshen0722 merged 4 commits into
mainfrom
launch/signup-lift
Nov 2, 2026
Merged

lilyshen0722 merged 4 commits into
mainfrom
launch/signup-lift

Conversation

@lilyshen0722

Copy link
Copy Markdown
Contributor

Sign-up and account recovery now match their d215 frames, the same way sign-in did in #3292. Five screens: sign-up (with its sent-mail state), invite-required, verify-email, forgot-password and reset-password.

Screens

  • One card. Each screen is one stacked card with the error or status notice at the top. A new V2AuthNotice is shared with sign-in: an alert for errors, a status for confirmations.
  • Fields are marked, not just the notice. A bad invite code marks the code field. Any other sign-up error marks email and password. Reset marks both password fields when they're too short or don't match, and offers "Request a new link" only on a server failure.
  • Optional fields carry a small mono "optional" tag in the label row instead of "(optional)" in the label text.
  • Verify-email is rebuilt as a v2 card. It sends each token once, fails at once with no token, and offers one key to sign in.
  • Reset-password with no token says so and links to the forgot-password page instead of showing a form that can't work.

Phone scroll (CodeRabbit's point on #3292). A card taller than the window couldn't scroll: the sign-up card is 655px in a 600px window. .v2-login is now the scroller (flex: 1; min-height: 0; overflow-y: auto) with the card centred by margin: auto. Checked in a browser at 390×600 and 1440×640: the card scrolls and its last control is reachable.

Legacy routes. /register, /register/invite-required and /verify-email redirect to their v2 pages and keep the query string, using the LegacyAuthRedirect from #3292. The old Register and VerifyEmail components and their tests are deleted.

Artboard. The phone auth frames draw the 44px touch floor on their fields and keys, as live has it. The recovery screens get their own data-surface tags so each can be scored.

Strings. In English, "optional" is split out of the field labels. The verify page has a title, a verified line and "Go to sign in". The zh-CN changes:

key before after
auth.fields.optional (new) 选填
auth.register.invitationCode 邀请码(选填) 邀请码
auth.inviteRequired.name / useCase 姓名(选填) / 使用场景(选填) 姓名 / 使用场景
auth.verify.title 邮箱验证 验证邮箱
auth.verify.verified (new) 邮箱已验证。
auth.verify.goToSignIn (was goToLogin) 前往登录

Checked

  • Frontend suite: 218 suites and 2,563 tests pass; tsc clean. The new V2AuthPagesLayout.test.tsx has 25 tests covering order, marking, notices, the once-only verify call, legacy redirects and the scroll rule. The verify once-guard and the reset link rule were mutation-checked (each broken, test seen failing, restored).
  • Frame-diff of this branch served locally, signed out, against its own artboard: sign-in, sign-up, invite-required, forgot-password and reset-password all pass at 1440 and 390, light and dark (20 of 20). Sign-up scores 0.08/0.10 at 1440 and 0.297/0.407 at 390; reset-password is scored with a token in the link, as the email sends it.

🤖 Generated with Claude Code

https://claude.ai/code/session_015AKgpMD6Qh13f7fj6mbGT3

lilyshen0722 and others added 2 commits November 1, 2026 18:15
Sign-up, invitation required, verify email, forgot password and reset password
now match the d215 sign-up frames, on the same stacked card as sign-in:
- one notice row (V2AuthNotice) for errors and confirmations, which marks
  only the fields it is about (an invitation error marks the code)
- sign-up: providers first, "optional" in the code label, terms under the
  key, the sign-in line keeps the deep link; no subtitle
- invitation required: the waitlist sits on the "or" rule, its result is a
  status row above a plain key, and the address stays for a second send
- verify email: the last navy MUI card becomes the v2 card; a token is sent
  once (not again on a language change or StrictMode's double effect), and a
  missing token fails at once instead of "verifying" forever
- reset: a check the page makes rings both fields; a server failure carries
  its recovery link and leaves the fields alone; no token is one line and a key

The legacy /register, /register/invite-required and /verify-email routes
redirect with their query, and the legacy MUI Register page is retired.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015AKgpMD6Qh13f7fj6mbGT3
…rtboard draws 44px phone controls and tags each recovery screen

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015AKgpMD6Qh13f7fj6mbGT3
@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 41c2d8d and 6173b37.

Files selected for processing: 17
  • docs/design/artboards/d215/index.html
  • frontend/src/App.tsx
  • frontend/src/components/Pages.smoke.test.tsx
  • frontend/src/components/Register.test.tsx
  • frontend/src/components/Register.tsx
  • frontend/src/components/RegistrationInviteRequired.tsx
  • frontend/src/components/VerifyEmail.test.tsx
  • frontend/src/components/VerifyEmail.tsx
  • frontend/src/i18n/locales/en.json
  • frontend/src/i18n/locales/zh-CN.json
  • frontend/src/v2/__tests__/V2AuthPagesLayout.test.tsx
  • frontend/src/v2/components/V2AuthNotice.tsx
  • frontend/src/v2/components/V2ForgotPassword.tsx
  • frontend/src/v2/components/V2Login.tsx
  • frontend/src/v2/components/V2Register.tsx
  • frontend/src/v2/components/V2ResetPassword.tsx
  • frontend/src/v2/v2.css
Files with no reviewable changes: 4
  • frontend/src/components/Register.tsx
  • frontend/src/components/VerifyEmail.test.tsx
  • frontend/src/components/Pages.smoke.test.tsx
  • frontend/src/components/Register.test.tsx

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review.

Walkthrough

Legacy registration and email-verification routes now redirect to V2 pages. V2 authentication pages update registration, invitation-required, verification, and password-recovery presentation and feedback. Tests and translations cover these changes.

Changes: Authentication pages

Layer / File(s) Summary
Shared auth notices and layout
frontend/src/v2/components/V2AuthNotice.tsx, frontend/src/v2/components/V2Login.tsx, frontend/src/v2/v2.css, frontend/src/v2/__tests__/V2AuthPagesLayout.test.tsx, docs/design/artboards/d215/index.html
Adds shared alert and status notices. Updates login error presentation, authentication-page layout and styles, and related tests and design states.
Registration routes and forms
frontend/src/v2/components/V2Register.tsx, frontend/src/components/RegistrationInviteRequired.tsx, frontend/src/App.tsx, frontend/src/components/Register.tsx, frontend/src/components/Register.test.tsx, frontend/src/components/Pages.smoke.test.tsx, frontend/src/i18n/locales/en.json, frontend/src/i18n/locales/zh-CN.json, frontend/src/v2/__tests__/V2AuthPagesLayout.test.tsx
Updates registration field errors, invitation labels, success presentation, and deep-link navigation. Updates the invitation-required screen and its notices. Legacy registration routes redirect to V2, and the legacy registration component and related tests are removed.
Verification and password recovery
frontend/src/components/VerifyEmail.tsx, frontend/src/components/VerifyEmail.test.tsx, frontend/src/v2/components/V2ForgotPassword.tsx, frontend/src/v2/components/V2ResetPassword.tsx, frontend/src/i18n/locales/en.json, frontend/src/i18n/locales/zh-CN.json, frontend/src/v2/__tests__/V2AuthPagesLayout.test.tsx
Updates verification request handling and result notices, including a single request per token. Updates forgot- and reset-password notices, field states, and navigation. Removes the legacy verification tests and adds V2 authentication-page tests.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant VerifyEmail
  participant Axios
  participant VerificationAPI
  User->>VerifyEmail: Open verification page with token
  VerifyEmail->>Axios: Send encoded token once
  Axios->>VerificationAPI: Request email verification
  VerificationAPI-->>Axios: Return verification result
  Axios-->>VerifyEmail: Provide result or error
  VerifyEmail-->>User: Show notice and sign-in navigation
Loading

Possibly related issues

  • Team-Commonly/commonly#709: The issue asks for Chinese translations for registration, login, and verification flows; this PR updates authentication translations in zh-CN.json.

Possibly related PRs

  • Team-Commonly/commonly#3275: Adds design frames for the same authentication states implemented and updated here.
  • Team-Commonly/commonly#3292: Establishes legacy-to-V2 authentication redirects that this PR extends to registration and email verification.
  • Team-Commonly/commonly#3260: Changes invite-only registration fields and invitation error handling, which overlap with this PR’s invitation form updates.
Merge Risk: Minimal · up to 6173b

The authentication-page changes appear mergeable after normal checks. No concrete issue requiring a pre-merge fix is established by the supplied evidence.

Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title "feat(v2): sign-up and account recovery follow their frames" matches the main change: sign-up, invite-required, verify-email, forgot-password and reset-password are rebuilt as v2 stacked car…
Description check Passed The description is closely related to the changeset. It lists the five redesigned screens, the V2AuthNotice component, field-marking rules, the once-only verify-email request, the legacy route redirec…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title "feat(v2): sign-up and account recovery follow their frames" matches the main change: sign-up, invite-required, verify-email, forgot-password and reset-password are rebuilt as v2 stacked cards to match the d215 design frames. It also fits the shared V2AuthNotice component and the legacy redirects, though it does not mention the deleted Register/VerifyEmail components or the scroll fix.

Full details: Description check

Explanation

The description is closely related to the changeset. It lists the five redesigned screens, the V2AuthNotice component, field-marking rules, the once-only verify-email request, the legacy route redirects, deletion of the old Register and VerifyEmail components, the 44px artboard changes, and the English and zh-CN string updates. It also reports test and frame-diff results.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

…announced

- Forgot password: the backend answers generically, so a failure there is
  never about the address. The email field is no longer marked.
- Sign-up: a network or server failure marks no field; only a 4xx marks
  email and password.
- A status row mounts empty and takes its text a frame later. A live region
  is announced when its content changes, not for content it mounts with.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015AKgpMD6Qh13f7fj6mbGT3

@lilyshen0722 lilyshen0722 left a comment

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.

Code review (fresh reviewer, Opus at medium) at 9c943a3, including the zh-CN terminology and voice passes.

I found no blocking defects. There are three minor ones, listed below. I didn't run the tests, so the PR's "218 suites pass" claim is unchecked.

1. Behaviour kept

  • V2Register's POST body hasn't changed: email, password, the trimmed invitation code, signupRef/Source and locale. The invite-only redirect, the verify-pending path and the team-verification path are all still there.
  • The old Register.tsx also sent username, which the v2 path already dropped in TASK-290 A, so nothing is lost. Its invite-only redirect is matched by V2Register's check against the code held at mount.
  • LegacyAuthRedirect keeps the query, so /register?invite= and /verify-email?token= still work.
  • No references remain to invitationCodeRequired, nameOptional, useCaseOptional, goToLogin, register.subtitle or components/Register. VerifyEmail was rewritten in place rather than deleted, and V2App.tsx:8 imports it.

2. VerifyEmail and Reset

  • The sent ref guard holds under StrictMode, because the ref survives the double effect, and there's a test for it.
  • The token now goes through encodeURIComponent; main sent it raw. A missing token fails without a request.
  • Reset shows "request a new link" only when !fieldsBad, which means only after a server or network failure. Client-side validation returns before any POST.

3. Accessibility (minor defects)

  • V2ForgotPassword.tsx:64: aria-invalid is set on the email field for any error. The backend answers generically, so an error there is a 5xx or rate limit, never a bad email. The field shouldn't be marked.
  • V2Register.tsx:151: the credentials branch catches every non-invite error, network and 5xx included, and marks email and password for faults that aren't theirs. Mark the fields only for 4xx field errors.
  • V2AuthNotice.tsx:10: role="status" goes on with its text already inside. Screen readers often skip a live region that appears with content, so confirmations may not be announced. Alerts are fine.
  • Labels still wrap their inputs, and focus isn't moved.

4. Scroll change

  • Outside these screens, only V2OAuthComplete uses .v2-login. It's a short, non-stack card, and the auto margins still centre it.
  • The 480px block comes later in the file at equal specificity, so its margin: 0 wins.
  • .v2-login__hint is still restyled inside stack cards because .v2-login__card--stack .v2-login__hint has higher specificity, not because of order.
  • The removed classes __error, __success and __divider have no consumers left.

5. Security

  • LegacyAuthRedirect targets a fixed path. Server error messages are rendered as React text. Nothing reflects a parameter unescaped.

6. zh-CN

  • Terminology pass: 选填, 邀请码, 姓名, 使用场景, 验证邮箱, 邮箱已验证。 and 前往登录 all pass. 登录 is used correctly, there's no 您, and there's no Latin text needing spaces.
  • Voice pass: 验证邮箱 and 前往登录 lead with the verb, and 邮箱已验证。 reads naturally. Every string passes.

GATE: PASS

…empty

A 429 is a 4xx but not about what was typed, so it no longer marks email
and password. A status row that becomes an alert before its first frame
now fills at once instead of staying empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015AKgpMD6Qh13f7fj6mbGT3

@lilyshen0722 lilyshen0722 left a comment

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.

Re-stamp (same reviewer) at 3f79c2d, covering the three accessibility fixes.

I found no blocking defects at 3f79c2df, and the delayed fill can't leave a row empty in any way the current pages use it. I reviewed the source diff and only skimmed the test changes; I didn't run the suite.

  • Unmount and StrictMode: the cleanup cancels the pending frame. Under StrictMode the effect runs again and schedules a new one, so the row still fills.
  • Changing kind (latent defect), V2AuthNotice.tsx:12-16: if a status row turns into an alert before its frame fires, the cleanup cancels the frame and the effect stops at kind !== 'status'. filled stays false and the alert row stays empty for good. No caller does this today: VerifyEmail's kind is fixed when the row first appears, and every other page renders a separate notice for each kind. The fix is one line, calling setFilled(true) on the alert branch of the effect.
  • 429 marks fields, V2Register.tsx:152: a rate-limit response is a 4xx, so it marks email and password even though the user typed nothing wrong. Minor.
  • Visual: the status row is drawn without its text for one frame, then grows to full height. It's barely visible. In a background tab the frame waits until the tab is shown again, which is harmless.
  • The forgot-password and 5xx/network fixes are correct.

GATE: PASS

@lilyshen0722 lilyshen0722 left a comment

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.

Final re-stamp (same reviewer) at 6173b37, covering the 429 and status-to-alert fixes.

Both fixes are correct at 6173b372. I read the source diff and didn't run the tests.

  • V2AuthNotice.tsx:14: the non-status branch now calls setFilled(true). A row that turns from status to alert before its frame fires now shows its text instead of staying empty. StrictMode and unmount still behave as before.
  • V2Register.tsx:154: a 429 now marks no field. Other 4xx responses still mark email and password, and network or 5xx failures still mark nothing.

No new defects.

GATE: PASS

@lilyshen0722
lilyshen0722 added this pull request to the merge queue Nov 2, 2026
Merged via the queue into main with commit c1af20e Nov 2, 2026
31 of 32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant