feat: 分渠道额度(互斥模式+周期重置)+ 对话详情独立库(管理员可见) - #8
Open
LoSealL wants to merge 18 commits into
Open
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds two token-scoped features to new-api: (1) per-channel token quota mode with periodic resets, and (2) admin-only chat log detail storage in a standalone database, plus corresponding admin UI in web/default.
Changes:
- Implement per-channel quota mode (
token_channel_quotas) and route token billing/pre-consume/settle/refund through channel rows when enabled. - Add chat-log standalone DB initialization/migration + request/response capture and admin-only query APIs (
/api/chat_logs). - Add admin UI pages/routes for Chat Logs, plus per-channel quota editor in the token edit drawer (with i18n updates).
Reviewed changes
Copilot reviewed 50 out of 50 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| web/default/src/routeTree.gen.ts | Registers the new authenticated /chat-logs route. |
| web/default/src/routes/_authenticated/chat-logs/index.tsx | Adds admin-gated route loader + search schema for Chat Logs page. |
| web/default/src/hooks/use-sidebar-data.ts | Adds “Chat Logs” entry to admin sidebar. |
| web/default/src/features/chat-logs/api.ts | Adds frontend API client for chat log list/detail endpoints. |
| web/default/src/features/chat-logs/types.ts | Defines chat log DTOs used by the UI. |
| web/default/src/features/chat-logs/index.tsx | Adds Chat Logs page layout wrapper. |
| web/default/src/features/chat-logs/components/chat-logs-table.tsx | Implements admin table view + filters + detail sheet trigger. |
| web/default/src/features/chat-logs/components/chat-log-detail-sheet.tsx | Implements chat log detail viewer with request/response JSON display. |
| web/default/src/features/keys/types.ts | Extends token schema/types with channel_quota_mode and per-channel quota DTOs. |
| web/default/src/features/keys/api.ts | Adds token per-channel quota GET/PUT client calls. |
| web/default/src/features/keys/lib/api-key-form.ts | Adds form fields/defaults and payload mapping for channel_quota_mode. |
| web/default/src/features/keys/components/channel-quota-editor.tsx | New per-channel quota editor UI component. |
| web/default/src/features/keys/components/api-keys-mutate-drawer.tsx | Integrates per-channel quota mode toggle + quota editor + API calls in token drawer. |
| web/default/src/i18n/locales/en.json | Adds new UI translation keys for per-channel quota + chat logs. |
| web/default/src/i18n/locales/zh.json | Adds new UI translation keys for per-channel quota + chat logs. |
| web/default/src/i18n/locales/zh-TW.json | Adds new keys for zh-TW (some values currently left as English). |
| web/default/src/i18n/locales/fr.json | Adds new UI translation keys for per-channel quota + chat logs. |
| web/default/src/i18n/locales/ru.json | Adds new UI translation keys for per-channel quota + chat logs. |
| web/default/src/i18n/locales/ja.json | Adds new UI translation keys for per-channel quota + chat logs. |
| web/default/src/i18n/locales/vi.json | Adds new UI translation keys for per-channel quota + chat logs. |
| common/database.go | Adds chat-log database-type tracking helpers. |
| model/main.go | Adds CHATLOG_DB handle + InitChatLogDB + chat log DB migration logic; migrates TokenChannelQuota in main DB. |
| model/token.go | Adds channel_quota_mode and chat_log_enabled to Token and updates selectable update fields. |
| model/token_channel_quota.go | Introduces token_channel_quotas model and CRUD/atomic quota updates. |
| model/token_reset.go | Extends quota reset to reset all channel rows when channel quota mode is enabled. |
| model/chat_log.go | Adds chat log model and query helpers for standalone DB. |
| service/quota.go | Adds PreConsumeTokenQuotaChannel with channel-row enforcement + no-row unlimited semantics. |
| service/pre_consume_quota.go | Disables trust bypass for channel quota mode; routes pre-consume through PreConsumeTokenQuotaChannel. |
| service/billing_session.go | Routes pre-consume/settle/refund/reserve through per-channel quota logic when enabled. |
| service/chat_log_capture.go | Implements response writer wrapper to buffer response bytes (currently missing WriteString capture). |
| service/chat_log_persist.go | Installs capture wrapper conditionally and persists request/response to chat-log DB asynchronously. |
| router/chat-log-router.go | Adds admin-only chat log API routing. |
| router/api-router.go | Registers chat log routes and token channel quota endpoints. |
| controller/token.go | Adds token per-channel quota GET/PUT endpoints. |
| controller/relay.go | Conditionally installs chat log capture + persists on successful relay. |
| controller/chat_log.go | Adds admin-only list/detail chat log APIs. |
| main.go | Initializes chat log DB at startup. |
| service/task_billing_test.go | Updates test DB setup to include new models/handles. |
| service/quota_channel_test.go | Adds tests for per-channel pre-consume behavior. |
| service/billing_session_channel_test.go | Adds tests for channel-mode settle/refund behavior. |
| service/chat_log_capture_test.go | Tests capture buffering/truncation/status behavior. |
| service/chat_log_persist_test.go | Tests recorder persistence into chat log DB. |
| model/token_channel_quota_test.go | Adds model-level tests for per-channel quotas. |
| model/token_reset_test.go | Adds tests for channel-mode periodic reset behavior. |
| model/chat_log_test.go | Adds model tests for chat log insert/query. |
| model/task_cas_test.go | Updates test DB setup to include new models/handles. |
| controller/token_channel_quota_handler_test.go | Adds controller tests for token channel quota endpoints. |
| controller/chat_log_test.go | Adds controller tests for admin chat log APIs. |
| docs/superpowers/specs/2026-07-24-per-channel-quota-and-chat-detail-db-design.md | Adds design documentation for both features. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+54
to
+58
| func (w *chatLogCaptureWriter) capturedBytes() (string, bool) { | ||
| w.mu.Lock() | ||
| defer w.mu.Unlock() | ||
| return w.buffer.String(), w.truncated | ||
| } |
Comment on lines
+426
to
+430
| if err := model.ReplaceTokenChannelQuotas(tokenId, req.Items); err != nil { | ||
| c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) | ||
| return | ||
| } | ||
| c.JSON(http.StatusOK, gin.H{"success": true}) |
Comment on lines
+201
to
+210
| if s.channelQuotaMode { | ||
| s.channelHit = s.channelHit || hit | ||
| } | ||
|
|
||
| s.preConsumedQuota += delta | ||
| s.tokenConsumed += delta | ||
| if s.channelQuotaMode && s.channelHit { | ||
| s.channelConsumed += delta | ||
| } else if !s.channelQuotaMode { | ||
| s.tokenConsumed += delta | ||
| } |
Comment on lines
+218
to
+232
| if (data.channel_quota_mode) { | ||
| try { | ||
| const cqResult = await updateTokenChannelQuotas( | ||
| currentRow.id, | ||
| data.channel_quotas ?? [] | ||
| ) | ||
| if (!cqResult.success) { | ||
| toast.error( | ||
| cqResult.message || t(ERROR_MESSAGES.UPDATE_FAILED) | ||
| ) | ||
| } | ||
| } catch (error) { | ||
| handleServerError(error) | ||
| } | ||
| } |
Comment on lines
772
to
776
| "Chat Client Name": "聊天用戶端名稱", | ||
| "Chat client name is required": "聊天用戶端名稱為必填項", | ||
| "Chat configuration JSON": "聊天設定 JSON", | ||
| "Chat Logs": "Chat Logs", | ||
| "Chat preset not found": "未找到聊天預設", |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Important
AI 辅助声明: 本分支代码由 AI(opencode + GLM-5.2,subagent-driven-development 流程)在人工设计与审查下辅助生成并提交。提交者
Wenyi Tang非仓库历史核心维护者。每个任务均经过 spec compliance + code quality 双重审查与回归验证。📝 变更描述 / Description
围绕单个 API-Key(令牌)实现两个相互独立、均可独立开关的功能:
功能一:分渠道额度(互斥模式)
channel_quota_mode开关。开启后令牌总额度remain_quota不再生效,改为按「令牌 × 渠道」独立额度(新表token_channel_quotas)。PreConsumeTokenQuotaChannel命中已配置渠道则扣减渠道行,未配置渠道不限额(不自动建行),额度不足返回 403。BillingSession的preConsume/Settle/Refund/Reserve/reserveToken/shouldTrust均按渠道模式路由;信任旁路在渠道模式下强制禁用以保证精确记账。reset_period+next_reset_time,到点批量重置该令牌所有渠道行(各自恢复到自己的reset_quota)。GET/PUT /api/token/:id/channel_quotas(令牌所有者或管理员)。功能二:对话详情独立库(管理员可见)
chat_log_enabled开关。开启且配置了CHAT_LOG_SQL_DSN时,完整请求/响应 JSON 写入独立库(未配置则静默禁用)。CHATLOG_DB句柄与InitChatLogDB(仿InitLogDB),支持 SQLite/MySQL/PostgreSQL;MySQL 上将大文本列升为 LONGTEXT,PG/SQLite 用 TEXT(无限长)。chatLogCaptureWriter包装gin.ResponseWriter,缓冲响应字节(默认上限 256KB,超限截断并标记),流式与非流式统一覆盖(嵌入类型透传 Flush/Hijack)。controller/relay.go的Relay在令牌开启且库已配置时条件式安装采集器,成功路径异步落库(gopool 闭包内不访问 gin context,避免回收竞态)。GET /api/chat_logs(分页 + 元数据)、GET /api/chat_logs/:id(含请求/响应体),挂载在AdminAuth中间件之后。role >= ADMIN可见,侧边栏入口已加。向后兼容
两个新开关默认
false,CHAT_LOG_SQL_DSN默认未设 → 对存量令牌与部署零行为变化。🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
gorm.Expr、信任旁路在渠道模式禁用、gin context 不在 goroutine 内访问)已核对。go build ./...通过;后端 26 个新增测试全部 PASS(model/service/controller 三层);前端bun run build与bun run typecheck通过;既有 3 个失败用例(TestChannelFieldsAreClassified、TestDetectKeyLimitParsesChineseQuota、TestObserveChannelAffinityUsageCacheByRelayFormat_*)已在 base74af36d3复现,与本 PR 无关。common.*封装;DB 代码三库兼容(GORM 方法 +gorm.Expr,仅 MySQL LONGTEXT 升级为有意为之的方言分支)。📸 运行证明 / Proof of Work
后端测试结果(
go test,节选):前端:
bun run build→ready built in 5.78s;bun run typecheck→ 0 errors。设计与实现文档
docs/superpowers/specs/2026-07-24-per-channel-quota-and-chat-detail-db-design.mddocs/superpowers/plans/2026-07-24-per-channel-quota-and-chat-detail-db.md配置说明(部署方需知)
reset_period。CHAT_LOG_SQL_DSN(与SQL_DSN/LOG_SQL_DSN同格式,支持 SQLite/MySQL/PostgreSQL),并在需要记录的令牌上开启「对话详情记录」。未配置 DSN 时该功能静默禁用。