fix(chat): keep the current session in the URL as ?c=
Independent Staging Quality Gate / validate (push) Has been cancelled
Independent Staging Quality Gate / publish (push) Has been cancelled

Refresh, back, and login return were dropping the open conversation because selection lived only in React state.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-01 20:42:21 +08:00
co-authored by Cursor
parent 48174a3cc5
commit 924f420202
8 changed files with 502 additions and 7 deletions
+13
View File
@@ -1091,3 +1091,16 @@
- Payload:列表响应列集合为 `id,title,theme,model_id,session_type,rectification_case_id,chart_profile_* ,updated_at`,消息文本只能出现在详情 GET。多会话账户的字节对比取决于该账户存量消息,合同测试锁的是“列表不含消息文本”这一结构,而不是某一个登录态的绝对字节数。
- `session_full`:本地 PostgreSQL 把会话填到 200 条后再 append,返回 `error_code=session_full`,行内消息数仍为 200。
- 双标签页:同一会话两次 `append_consultation_question`(不同 request_id)后两条用户消息都在;这是改前 last-write-wins 必丢、改后必留的核心形状。
## 2026-09-01 - TASK-session-url:会话选择写入 `?c=`
- 用户主动切换、新建、打开校正用原生 `history.pushState`;删除/归档当前会话、伪造 id、登录回跳用 `replaceState`。默认选中和咨询恢复不写 URL。`popstate` 复用 `selectSession`,以来源标志位避免二次 push。
- 401 在 `redirectToLogin` 把合法 `?c=` 写入 `sessionStorage`;登录页零改动,`successPath` 仍是 `"/" | "/admin"`。落回 `/` 后启动逻辑读暂存、`replaceState` 写回 URL 并清暂存。
- 首页继续只在客户端读 `location.search`,不用 `useSearchParams`,也没有服务端 `searchParams`
- 断言例外(锁住的正是本轮要修的缺陷):
- `chat-navigation-a11y-contract.test.ts`:原值 `function redirectToLogin(): never {\n window.location.replace("/login");`。401 现在会先 `persistLoginSessionReturn()`,登录跳转本身仍是硬 `replace`
- `next build` 路由表:`┌ ○ /`Static)。`/login` 仍是 `ƒ`
- 本地验证:
- `./node_modules/.bin/tsc --noEmit` 通过。
- `npm test`**2424 通过 / fail=0 / skipped=0**(含数据库测试;本轮未改库)。
- 实测:无登录态,浏览器验收(刷新仍在 A、粘贴 `/?c=`、A→B→C 后退、删除死链、流式中切走再 back、401 回跳)未做,由合同测试覆盖。浅色/深色:新文案「该对话不存在或已被删除」走既有 sonner toast`已被删除` 命中 `failedNotice` 用 error 语气,颜色仍是 `--color-canvas` / `--color-ink`