docs(tasks): session list brief adds cursor pagination (5.6)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
This commit is contained in:
Jesse_Chen
2026-09-06 03:36:48 +00:00
parent 5e06a218f6
commit d8a0f615c7
2 changed files with 18 additions and 7 deletions
+1 -1
View File
@@ -56,7 +56,7 @@
| `TASK-rectification-family-collect-continue-fix-20260905.md` | `PROGRESS-rectification-family-collect-continue-20260905.md` | `998406ce` 修复单:家人之后的 dated 补采集无条件抢在现成区分卡之前(choice-card A/B 卡用例回归),另两条顺序断言缺三栏说明 | 已验收通过(浏览器走查欠) | `cd704a92`BUG-547 |
| `TASK-rectification-probe-answer-covers-domain-20260905.md` | `PROGRESS-rectification-probe-answer-covers-domain-20260905.md` | 区分卡答 A/B 后紧接着又问同领域"哪年…"采集题:点选答案只进推断层不写账本,计划层领域覆盖只看账本;改为 yes/weak_yes 视为该领域采集已覆盖(不写账本、不动门) | 待验收 | `988d97ae`BUG-549 |
| `TASK-composer-live-input-and-stop-20260906.md` | `PROGRESS-composer-live-input-and-stop-20260906.md` | 生成中输入框整个禁用致焦点丢失、回车丢消息(改为永不禁用 + 排队发送);生时校正停止呈现为红色告警且选择题等待中停止无效(改为中性停止态、所有 fetch 挂 abort | 待执行 | `codex/composer-live-input-and-stop-20260906`BUG-551、552 |
| `TASK-session-list-title-and-order-20260906.md` | `PROGRESS-session-list-title-and-order-20260906.md` | 历史对话标题改为首轮模型总结(一次、不扣点数、校正/今日运势保持日期标题)、侧栏去资料前缀;排序只按置顶排且元数据 PATCH 推进 `updated_at`(改为置顶 + 活动时间,改名/收藏/换模型不动顺序);历史区加 今天/昨天/7天/30天/更早 分组 | 待执行(串行:在 composer 单之后) | `codex/session-list-title-and-order-20260906`BUG-553 |
| `TASK-session-list-title-and-order-20260906.md` | `PROGRESS-session-list-title-and-order-20260906.md` | 历史对话标题改为首轮模型总结(一次、不扣点数、校正/今日运势保持日期标题)、侧栏去资料前缀;排序只按置顶排且元数据 PATCH 推进 `updated_at`(改为置顶 + 活动时间,改名/收藏/换模型不动顺序);历史区加 今天/昨天/7天/30天/更早 分组;列表按游标分页(每页 40、置顶首页全量、滚到底静默续取) | 待执行(串行:在 composer 单之后) | `codex/session-list-title-and-order-20260906`BUG-553 |
| `TASK-settings-dialog-and-billing-pane-20260906.md` | `PROGRESS-settings-dialog-and-billing-pane-20260906.md` | 设置弹窗尺寸随分区跳变、星盘资料格无条件铺开整张添加表单(改为固定尺寸四分区、列表→详情);「账户与点数」成为弹窗分区,删除 `/membership``/membership/orders` 页面并重定向,七处入口改回调 | 待执行(串行:在会话列表单之后) | `codex/settings-dialog-and-billing-pane-20260906`BUG-554 |
| `TASK-rectification-collect-vs-offer-consistency-20260905.md` | `PROGRESS-rectification-collect-vs-offer-consistency-20260905.md` | 带年份采集没问完就出采用卡 + 报告,同一轮又被搬家采集题把卡挤掉:决策层判 `adopt_representative` 而计划层仍有 dated 采集(BUG-546 只修了一半);改为剩余采集未完保持 `collect_evidence`,出牌轮才出卡写报告 | 已验收通过 `ca4e2408`2026-09-05staging 部署仍停在 `afd14948``deploy-staging``c295b853` 起连续失败,先解决 `bab07187` 的待迁移) | `codex/rectification-collect-vs-offer-consistency-20260905`BUG-550 |
| `TASK-api-not-configured-mislabel-20260904.md` | — | 16 处路由把数据库瞬断(部署切换窗口)兜底翻译成 503「服务尚未配置」;改为仅配置错误用该文案,其余 `service_unavailable`,收敛为共享 helper | 待执行 | `codex/api-not-configured-mislabel-20260904`BUG-542 起) |
@@ -3,10 +3,10 @@
- 基线:`origin/staging` @ `985c3258`
- 分支:`codex/session-list-title-and-order-20260906`
- 执行方:coding agent;验收:Claude
- 涉及文件:`frontend/src/app/api/consult/route.ts`(只加一次调用与一个事件,新逻辑进独立模块)、新建 `frontend/src/lib/session-title-agent.ts`、新建 `frontend/src/lib/session-groups.ts``frontend/src/hooks/use-consultation-run.ts``frontend/src/hooks/use-session-management.ts``frontend/src/app/api/sessions/[id]/route.ts``frontend/src/lib/home-profile.ts``frontend/src/components/app-sidebar.tsx``frontend/src/app/page.tsx`(只改 `visibleSessions` 的排序一行,**不得增行**)、`frontend/DESIGN.md``frontend/docs/VOICE.md`
- 涉及文件:`frontend/src/app/api/consult/route.ts`(只加一次调用与一个事件,新逻辑进独立模块)、新建 `frontend/src/lib/session-title-agent.ts`、新建 `frontend/src/lib/session-groups.ts``frontend/src/hooks/use-consultation-run.ts``frontend/src/hooks/use-session-management.ts``frontend/src/app/api/sessions/[id]/route.ts``frontend/src/app/api/sessions/route.ts`GET 加分页参数)、`frontend/src/lib/home-cloud-sync.ts``frontend/src/lib/home-profile.ts``frontend/src/components/app-sidebar.tsx``frontend/src/app/page.tsx`(只改 `visibleSessions` 的排序一行,**不得增行**)、`frontend/DESIGN.md``frontend/docs/VOICE.md`
- BUG 编号起点:**BUG-553**(开工时 `grep -o "^## BUG-5[0-9][0-9]" docs/BUG_HISTORY.md | tail -1` 复核;BUG-551/552 已由 `TASK-composer-live-input-and-stop-20260906.md` 预留,BUG-542 由 `TASK-api-not-configured-mislabel-20260904.md` 预留)
- 串行:本单改 `page.tsx``use-consultation-run.ts`。同日三份单的顺序是 **composer551/552)→ 本单 → 设置弹窗单**;本单开工前先把已合入 staging 的 composer 分支拉进来,不得并行改同一文件。
- 不改数据库结构;不动迁移;不改 `/api/sessions` 列表 SQL
- 不改数据库结构;不动迁移(分页不加索引,见 5.6
## 1. 事故实证(staging2026-09-06,产品实测)
@@ -15,6 +15,7 @@
| 1 | 标题就是第一句话的前 14 个字加省略号(如「我想问一下最近半年换工…」),侧栏里再前缀一个资料名,一行根本读不出主题 | 一个 6–12 字的主题总结(「半年内换工作时机」),一眼能分辨 |
| 2 | 刚聊过的会话不在最上面;改个名、收藏一下、换个模型,刷新后旧会话反而跳到最顶 | 只有真正的对话活动改变顺序;置顶始终在前 |
| 3 | 历史列表是一根长条,没有今天 / 昨天 / 更早的分段 | 按时间分组 |
| 4 | (产品追问)会话多了怎么办:现在 `/api/sessions` 一次返回该用户**全部**会话元数据,侧栏一次渲染全部行 | 首屏只取最近一页,滚到底再取下一页 |
## 2. 根因(按符号定位,行号以基线为准)
@@ -29,6 +30,7 @@
4. `/api/sessions``updated_at desc` 返回,但 `page.tsx` L380392 的 `visibleSessions``.sort((l, r) => Number(r.pinned) - Number(l.pinned))`——不按 `updatedAt` 排。页面开着期间新活动只改 `updatedAt` 不改位置;`Array.prototype.sort` 稳定,顺序冻结到下次整页加载。
5. `api/sessions/[id]/route.ts::metadataUpdateValues` L31 对任何元数据 PATCH(改名、收藏、归档、换模型、换资料)都写 `updated_at = now()``use-session-management.ts::renameSession` L188 也在客户端顺手 `updatedAt: timestamp()`。于是非对话操作会让会话在下次加载时跳到最顶。发消息真正的 bump 在 `append_consultation_question``updated_at = clock_timestamp()`,这条是对的。
6. `app-sidebar.tsx` L113–114 只分「收藏 / 历史」两组,没有时间分组。
7. `api/sessions/route.ts` L1418`select(...).eq("user_id").order("updated_at")`,无 `limit`、无游标;`home-cloud-sync.ts` L421 一次拿完;`page.tsx``showArchivedSessions` 过滤在客户端做。每行约 300 字节,元数据本身不重(消息已经按会话懒加载,`ensureSessionMessages`),真正的开销是上千行 DOM 与一次性 JSON;再往后若数据库层有 max-rows 上限还会**静默截断**。
## 3. 决策记录(产品已授权,2026-09-06)
@@ -39,7 +41,8 @@
5. **侧栏只显示标题**:删除 `sessionSidebarTitle` 的「资料名 · 」前缀。分析对象不是本人(`chartProfileRole !== "self"`)时在标题下加一行小字显示资料名;是本人不显示。产品偏好是删多余入口,不是再叠一层。
6. **排序规则**:置顶在前;组内按 `updatedAt` 倒序;`updatedAt` 只由**对话活动**推进(发问、回答落库、校正会话的回合落库)。改名、收藏、归档、换模型、换资料一律不动 `updatedAt`(服务端 PATCH 不再写 `updated_at`;客户端相应操作不再 `timestamp()`)。
7. **日期分组**:只对「历史」组分段:今天 / 昨天 / 最近 7 天 / 最近 30 天 / 更早,按浏览器本地时间、以 `updatedAt` 归组;空组不渲染;「收藏」组不分段。分组标题用现有 overline 字号,不加新的视觉元素。
8. 不在本单:改名仍用 `window.prompt`(Claude 是行内改名)——产品若要,另开单;`<!--AYANAM_TITLE:-->` 注释解析留着当防御,不动
8. **分页(产品 2026-09-06 追加)**:列表按游标分页,每页 40 条,游标 `(updated_at, id)` 复合、倒序;**置顶会话第一页全量返回**,后续页只含非置顶;归档视图改为服务端参数(`archived=1`)、独立游标。侧栏滚到底部自动取下一页(`IntersectionObserver` 哨兵),**没有 spinner、没有「加载更多」文字**,新行直接接在「更早」组末尾;取完为止,末尾不显示「没有更多」。不加数据库索引(`user_id` 上已有索引,排序在几千行内可忽略;真慢了另开迁移单并跑 `test:db`)。通过 URL 深链打开、但不在已加载页里的会话,沿用现有按 id 单取 `/api/sessions/[id]` 后插入列表的路径。标题去重(`existingTitles`)只看已加载的会话,接受
9. 不在本单:改名仍用 `window.prompt`(Claude 是行内改名)——产品若要,另开单;`<!--AYANAM_TITLE:-->` 注释解析留着当防御,不动。
## 4. 硬红线
@@ -76,15 +79,23 @@
- `home-profile.ts::sessionSidebarTitle` 改为只返回标题;新增 `sessionSidebarSubtitle(session, library): string | null`(非本人时返回资料名,含「资料已删除 · 」前缀逻辑,本人返回 null)。`app-sidebar.tsx` 渲染副标题行。
- 验收:`tests/chart-library-session.test.ts``tests/sidebar-contract.test.ts` 中断言前缀的用例按三栏表改;新增本人 / 他人 / 已删除资料三例。
### 5.6 列表分页
- `api/sessions/route.ts` GET:读取 `limit`(默认 40,钳到 1100)、`before``<updated_at ISO>,<id>`)、`archived``0|1`,默认 0);第一页(无 `before`)额外并入该用户全部 `pinned = true` 且归档状态匹配的会话;返回 `{ sessions, nextCursor: string | null }`。游标解析与生成放 `frontend/src/lib/session-cursor.ts` 纯函数(编码 / 解码 / 非法值返回 null → 400)。
- `home-cloud-sync.ts::fetchSessions`:接受 `{ before?, archived? }`,返回 `{ sessions, nextCursor }`;旧调用点改为第一页语义。
- `use-session-management.ts`:新增 `sessionsCursor`(按归档视图各一份)、`loadMoreSessions()`(进行中去重、按 id 合并、已存在的行不覆盖本地更新的 `updatedAt`)。切换归档视图时重新取第一页。
- `app-sidebar.tsx`:历史列表末尾一个 `<div aria-hidden>` 哨兵,进入视口调用 `onLoadMore``nextCursor === null` 时不渲染哨兵。
- `page.tsx``showArchivedSessions` 过滤改由服务端承担后,L381 的客户端归档过滤改为透传(仍不得增行)。
- 验收:`tests/session-cursor.test.ts` 新建(编码往返、非法字符串 null、时间相同按 id 比较);`tests/chat-session-*`/路由合同测试加——`limit` 超界钳制、第一页含置顶且后续页不含、`archived=1` 只返回归档;`tests/sidebar-contract.test.ts` 加——有游标时渲染哨兵、无游标不渲染、源码中不存在「加载更多」「没有更多」文案;`tests/sidebar-state.test.ts` 加——`loadMoreSessions` 合并去重且并发调用只发一次请求。
### 5.5 记录
- `docs/BUG_HISTORY.md`:BUG-553(列表只按置顶排、元数据 PATCH 推进 `updated_at`;关联 BUG-024 侧栏标题记录)。
- `CHANGELOG.md`:一条写清「标题改为模型总结(首轮一次、不扣点数)、排序改活动时间、历史分组、侧栏去资料前缀」。
- `CHANGELOG.md`:一条写清「标题改为模型总结(首轮一次、不扣点数)、排序改活动时间、历史分组、侧栏去资料前缀、列表分页(每页 40、滚到底续取)」。
- `frontend/DESIGN.md` Sidebar shell / Navigation item:分组标签与副标题行;`frontend/docs/VOICE.md`:分组标签文案「今天 / 昨天 / 最近 7 天 / 最近 30 天 / 更早」与起名提示词的措辞边界(不复述出生资料)。
- `docs/tasks/PROGRESS-session-list-title-and-order-20260906.md``docs/testing/session-list-title-and-order-20260906.md`(真实环境:新会话首轮回答期间或结束后标题变成总结;改名 / 收藏 / 换模型后刷新不改变顺序;新发一条后该会话到组首;分组标签正确;停止回答后标题不出现错误提示)。
- `docs/tasks/PROGRESS-session-list-title-and-order-20260906.md``docs/testing/session-list-title-and-order-20260906.md`(真实环境:新会话首轮回答期间或结束后标题变成总结;改名 / 收藏 / 换模型后刷新不改变顺序;新发一条后该会话到组首;分组标签正确;停止回答后标题不出现错误提示;账号超过 40 个会话时首屏只见最近 40 条 + 全部收藏,滚到底静默续出,归档视图同样分页)。
## 6. 让步顺序
5.2 → 5.4 → 5.3 → 5.1。5.1 若模型端 `generate` 在测试环境无法 mock,可先交付 5.1 的纯函数与事件契约并在进度记录写明;5.2 不可省。
5.2 → 5.6 → 5.4 → 5.3 → 5.1。5.1 若模型端 `generate` 在测试环境无法 mock,可先交付 5.1 的纯函数与事件契约并在进度记录写明;5.2 不可省。
## 7. 开工前置命令