Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8b6b2ed
feat: add sessionId filter for usage logs
YangQing-Lin Jan 14, 2026
afa7fde
feat: add seconds-level time filters for logs
YangQing-Lin Jan 14, 2026
3cd5477
feat: wire sessionId into logs URL filters
YangQing-Lin Jan 14, 2026
f0c52db
chore: add i18n keys for logs sessionId
YangQing-Lin Jan 14, 2026
bb211a8
feat: add sessionId column to logs tables
YangQing-Lin Jan 14, 2026
861c6cf
feat: add sessionId suggestions for logs
YangQing-Lin Jan 14, 2026
d1fab94
docs: document dashboard logs call chain
YangQing-Lin Jan 14, 2026
ee066a5
test: add logs sessionId/time filter coverage config
YangQing-Lin Jan 14, 2026
c77720e
fix: keep sessionId search input focused
YangQing-Lin Jan 14, 2026
60bf8f2
fix: drop leaked page param on logs apply
YangQing-Lin Jan 14, 2026
d011c74
fix: reload sessionId suggestions on scope change
YangQing-Lin Jan 14, 2026
d573e23
fix: harden logs url params and time parsing
YangQing-Lin Jan 14, 2026
95c732b
fix: avoid keys join for sessionId suggestions
YangQing-Lin Jan 14, 2026
6be3ff3
test: strengthen empty sessionId filter assertions
YangQing-Lin Jan 14, 2026
b543fff
chore: format logs sessionId suggestions test
YangQing-Lin Jan 14, 2026
85390b9
Update src/actions/usage-logs.ts
YangQing-Lin Jan 15, 2026
f94b53d
feat: 补充公共静态变量 SESSION_ID_SUGGESTION_LIMIT
YangQing-Lin Jan 15, 2026
d6108c2
fix: use prefix LIKE for sessionId suggestions
YangQing-Lin Jan 15, 2026
2bd209e
refactor: centralize usage logs sessionId suggestion constants
YangQing-Lin Jan 15, 2026
7994026
refactor: simplify logs url filters parsing
YangQing-Lin Jan 15, 2026
7b6e918
refactor: reuse clipboard util for sessionId copy
YangQing-Lin Jan 15, 2026
b383d06
chore(db): add sessionId prefix index
YangQing-Lin Jan 15, 2026
cef3c49
docs: clarify sessionId suggestion semantics
YangQing-Lin Jan 15, 2026
d262c39
test: add escapeLike unit tests
YangQing-Lin Jan 15, 2026
11f9d31
chore: apply biome fixes for sessionId search
YangQing-Lin Jan 15, 2026
d74be83
Merge branch 'dev' into feat/logs-sessionid-time-filter
YangQing-Lin Jan 19, 2026
26e1e0b
feat: include session id in error responses
YangQing-Lin Jan 19, 2026
d8bd2f6
test: add coverage suite for session id errors
YangQing-Lin Jan 19, 2026
233f96a
docs: add guide for error session id
YangQing-Lin Jan 19, 2026
98dac81
chore: format code (feat-logs-sessionid-time-filter-233f96a)
github-actions[bot] Jan 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
/coverage-my-usage
/coverage-proxy-guard-pipeline
/coverage-thinking-signature-rectifier
/coverage-logs-sessionid-time-filter
/coverage-usage-logs-sessionid-search

# next.js
/.next/
Expand Down
119 changes: 119 additions & 0 deletions docs/dashboard-logs-callchain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Dashboard Logs(Usage Logs)入口与调用链盘点

本文用于锁定 `/dashboard/logs` 的真实入口与关键调用链边界,避免后续需求实现与验收口径跑偏。

## 1) 路由入口(Server)

- 路由:`/dashboard/logs`
- 入口页面:`src/app/[locale]/dashboard/logs/page.tsx`
- 登录态校验:`getSession()`(未登录重定向到 `/login`)
- 数据区块入口:`UsageLogsDataSection`(`src/app/[locale]/dashboard/logs/_components/usage-logs-sections.tsx`)

## 2) 真实渲染链路(Client)

当前页面实际使用“虚拟列表”链路:

- 虚拟列表入口:`UsageLogsViewVirtualized`(`src/app/[locale]/dashboard/logs/_components/usage-logs-view-virtualized.tsx`)
- URL -> filters 解析:`parseLogsUrlFilters()`(`src/app/[locale]/dashboard/logs/_utils/logs-query.ts`)
- filters -> URL 回填:`buildLogsUrlQuery()`(`src/app/[locale]/dashboard/logs/_utils/logs-query.ts`)
- Filters 面板:`UsageLogsFilters`
- 列表:`VirtualizedLogsTable`
- 统计面板:`UsageLogsStatsPanel`

仓库内仍存在“非虚拟表格”实现(目前不被路由引用,属于历史/备用路径):

- `UsageLogsView`(`src/app/[locale]/dashboard/logs/_components/usage-logs-view.tsx`)
- `UsageLogsTable`(`src/app/[locale]/dashboard/logs/_components/usage-logs-table.tsx`)

## 3) 过滤器 / URL / 时间语义

- URL 参数解析/构建(统一入口):`src/app/[locale]/dashboard/logs/_utils/logs-query.ts`
- `sessionId`:字符串(trim 后空值不落盘)
- `startTime/endTime`:毫秒时间戳
- 秒级时间工具:`src/app/[locale]/dashboard/logs/_utils/time-range.ts`
- UI endTime 为“包含式”秒;对后端转换为“排他上界”(`endExclusive = endInclusive + 1s`)
- 后端查询语义保持:`created_at >= startTime` 且 `created_at < endTime`

## 4) 数据获取链路(Actions -> Repository)

### 列表(无限滚动)

- Action:`src/actions/usage-logs.ts#getUsageLogsBatch`
- Repo:`src/repository/usage-logs.ts#findUsageLogsBatch`

### 统计(折叠面板按需加载)

- Action:`src/actions/usage-logs.ts#getUsageLogsStats`
- Repo:`src/repository/usage-logs.ts#findUsageLogsStats`

### 导出 CSV

- Action:`src/actions/usage-logs.ts#exportUsageLogs`
- Repo:`src/repository/usage-logs.ts#findUsageLogsWithDetails`
- CSV 生成:`src/actions/usage-logs.ts#generateCsv`

### Session ID 联想(候选查询)

- Action:`src/actions/usage-logs.ts#getUsageLogSessionIdSuggestions`
- Repo:`src/repository/usage-logs.ts#findUsageLogSessionIdSuggestions`

#### 匹配语义与边界(2026-01-15 更新)

- **前端约束**:
- 最小长度:`SESSION_ID_SUGGESTION_MIN_LEN`(`src/lib/constants/usage-logs.constants.ts`)
- 最大长度截断:`SESSION_ID_SUGGESTION_MAX_LEN`(`src/actions/usage-logs.ts` 内对输入 trim 后截断)
- 每次返回数量:`SESSION_ID_SUGGESTION_LIMIT`
- **后端匹配**:
- 语义:仅支持「字面量前缀匹配」(`term%`),不再支持包含匹配(`%term%`)
- 安全:输入中的 `%` / `_` / `\\` 会被统一转义,避免被当作 LIKE 通配符
- SQL(核心条件):`session_id LIKE '<escapedTerm>%' ESCAPE '\\'`
- 转义实现:`src/repository/_shared/like.ts#escapeLike`
- **行为变更示例**:
- 之前:输入 `abc` 可能命中 `xxxabcxxx`(包含匹配)
- 之后:仅命中 `abc...`(前缀匹配)
- 之前:输入 `%` / `_` 可主动触发通配
- 之后:`%` / `_` 按字面量处理(例如输入 `%a` 只匹配以 `%a` 开头的 session_id)

#### 索引与迁移(前缀匹配性能)

- 已有索引:`idx_message_request_session_id`(`message_request.session_id`,partial: `deleted_at IS NULL`)
- 新增索引(前缀匹配):`idx_message_request_session_id_prefix`
- opclass:`varchar_pattern_ops`
- partial:`deleted_at IS NULL AND (blocked_by IS NULL OR blocked_by <> 'warmup')`
- 迁移文件:`drizzle/0055_neat_stepford_cuckoos.sql`

## 5) 本需求相关影响面(文件/符号清单)

**前端(logs 页面内聚)**:

- URL/过滤器:`src/app/[locale]/dashboard/logs/_utils/logs-query.ts`
- 秒级时间:`src/app/[locale]/dashboard/logs/_utils/time-range.ts`
- 过滤器 UI:`src/app/[locale]/dashboard/logs/_components/usage-logs-filters.tsx`
- 虚拟列表:`src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx`
- 非虚拟表格:`src/app/[locale]/dashboard/logs/_components/usage-logs-table.tsx`
- 统计面板:`src/app/[locale]/dashboard/logs/_components/usage-logs-stats-panel.tsx`

**后端(Actions/Repo)**:

- Actions:`src/actions/usage-logs.ts`
- `getUsageLogsBatch/getUsageLogsStats/exportUsageLogs/getUsageLogSessionIdSuggestions`
- Repo:`src/repository/usage-logs.ts`
- `findUsageLogsBatch/findUsageLogsWithDetails/findUsageLogsStats/findUsageLogSessionIdSuggestions`

**i18n(用户可见文案)**:

- `messages/*/dashboard.json`(`dashboard.logs.filters.*` / `dashboard.logs.columns.*`)

## 6) 边界说明(在范围内 / 不在范围内)

在范围内(本次需求直接相关):

- `sessionId` 精确筛选 + URL 回填 + UI 展示(列/复制/tooltip)
- 秒级时间输入与 `endExclusive` 语义对齐(`< endTime`)
- Session ID 联想(最小成本:minLen + debounce + limit)

不在范围内(需另开 issue/评审确认后再做):

- 针对联想查询的索引/物化/离线表(优化类工程)
- 大规模改动数据库 schema 或重建索引策略(例如 CONCURRENTLY/离线重建)
- Logs 页面其它过滤项语义调整(非本需求验收口径)
26 changes: 26 additions & 0 deletions docs/error-session-id-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Error Session ID Guide

When reporting an API error, include the CCH session id so maintainers can locate the exact request.

## Where to find it

1. **Preferred**: response header `x-cch-session-id`
2. **Fallback**: `error.message` suffix `cch_session_id: <id>`

If the response does not include a session id, the server could not determine it for that request.

## Example (curl)

```bash
curl -i -sS \\
-H "Authorization: Bearer <your-key>" \\
-H "Content-Type: application/json" \\
-d '{"model":"gpt-4.1-mini","messages":[{"role":"user","content":"hi"}]}' \\
http://localhost:13500/v1/chat/completions
```

In the response:

- Check header: `x-cch-session-id: ...`
- If missing, check JSON: `{"error":{"message":"... (cch_session_id: ...)"} }`

1 change: 1 addition & 0 deletions drizzle/0055_neat_stepford_cuckoos.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CREATE INDEX IF NOT EXISTS "idx_message_request_session_id_prefix" ON "message_request" USING btree ("session_id" varchar_pattern_ops) WHERE "message_request"."deleted_at" IS NULL AND ("message_request"."blocked_by" IS NULL OR "message_request"."blocked_by" <> 'warmup');
Loading