From 5a0d837d76af819964e3dc7b46eba6512b4d0b2d Mon Sep 17 00:00:00 2001 From: FlyM1ss Date: Wed, 2 Sep 2026 10:33:11 +0800 Subject: [PATCH 1/2] docs(accounts): add reset-password user guide User-facing "Reset a forgotten password" section, explicitly out of scope for the implementation PR #436. Every claim checked against the shipped routes and frontend; sphinx -n -E build clean. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01XXfamqoPKiuxVyJYxV7Y78 --- docs/source/lab/accounts.rst | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/source/lab/accounts.rst b/docs/source/lab/accounts.rst index 27abba1c..420b7ab1 100644 --- a/docs/source/lab/accounts.rst +++ b/docs/source/lab/accounts.rst @@ -38,6 +38,41 @@ Sign in and out dashboard you just left; sign in again to get back to it. +.. _accounts-reset-password: + +Reset a forgotten password +-------------------------- + +If you cannot sign in, reset your password from the sign-in dialog: + +1. Click **Sign in** in the header, then **Forgot password?**. +2. Enter your account email and click **Send code**. A 6-character reset code + goes to that address if it belongs to an account. +3. Enter the code and your new password, then click **Reset password**. +4. Sign in with the new password — the email field is already filled in. + +The new password must meet the same rules as at sign-up. + +A few things worth knowing: + +- **The code expires after 15 minutes**, and five wrong codes cancels the + request. Codes are not case-sensitive. +- **Check your spam folder.** A code sitting in spam looks exactly like a code + that was never sent. +- The confirmation looks the same whether or not the address belongs to an + account, so no code arriving usually means a typo in the address — or an + account under a different email. +- **Need another code?** Go back to sign-in and start over from **Forgot + password?**. One account is sent at most one code every 5 minutes and five + per day; asking again sooner looks like a success but sends nothing, so wait + out the five minutes. +- A successful reset **signs you out of all devices** and cancels any + :ref:`email change ` you had in progress. There is no + automatic sign-in — you sign in fresh with the new password. +- The reverse also holds: changing your password from the **Account** page, or + finishing an email change, cancels an outstanding reset code. + + Manage your profile ------------------- From 338d3c3783e09bdabf0ef5ce06504fd4e358cbb0 Mon Sep 17 00:00:00 2001 From: FlyM1ss Date: Wed, 2 Sep 2026 10:33:13 +0800 Subject: [PATCH 2/2] test: wipe user_entitlements in temp_postgres_store MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #437 — with the mechanism corrected: the issue's leftover-rows story does not reproduce on any repo-created schema, because the user_entitlements FK has carried ON DELETE CASCADE since its first commit (e5daadda), so the fixture's DELETE FROM users already cascade-clears it. 34/34 live postgres:18 runs green on fresh and reused databases, with and without this change. The explicit wipe still lands as hardening: the fixture already wipes three other equally-cascading child tables, and a long-lived dev database mutated by a review branch's divergent DDL is a real local hazard. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01XXfamqoPKiuxVyJYxV7Y78 --- dashboard/backend/tests/test_users_postgres.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dashboard/backend/tests/test_users_postgres.py b/dashboard/backend/tests/test_users_postgres.py index add7802b..4bf22f3d 100644 --- a/dashboard/backend/tests/test_users_postgres.py +++ b/dashboard/backend/tests/test_users_postgres.py @@ -94,6 +94,11 @@ def temp_postgres_store(): cur.execute("DELETE FROM password_reset_requests") cur.execute("DELETE FROM email_change_requests") cur.execute("DELETE FROM auth_sessions") + # Redundant on a schema this repo created (every child table FKs + # users with ON DELETE CASCADE), like the three above -- the + # explicit wipe is what keeps a long-lived dev database honest + # after a review branch's divergent DDL or manual tampering (#437). + cur.execute("DELETE FROM user_entitlements") cur.execute("DELETE FROM users") yield store