Commit Graph

1475 Commits

Author SHA1 Message Date
erio
95cf59b2f6 feat: add quota limit for API key accounts
- Add configurable spending limit (quota_limit) for apikey-type accounts
- Atomic quota accumulation via PostgreSQL JSONB operations on TotalCost
- Scheduler filters out over-quota accounts with outbox-triggered snapshot refresh
- Display quota usage ($used / $limit) in account capacity column
- Add "Reset Quota" action in account menu to reset usage to zero
- Editing account settings preserves quota_used (no accidental reset)
- Covers all 3 billing paths: Anthropic, Gemini, OpenAI RecordUsage

chore: bump version to 0.1.90.4
2026-03-05 21:48:37 +08:00
erio
a0f643da0e fix: keep 500 status for upstream errors, pass details in response body
Upstream errors like 401/429 must not be passed through as HTTP status
codes because the frontend routes on status (401 triggers JWT logout).
Keep HTTP 500 but include upstream error details in the message.
2026-03-05 21:03:08 +08:00
erio
99331a5285 fix: throttle Anthropic usage queries and pass through upstream HTTP errors
- Frontend: queue Anthropic OAuth/setup-token usage requests by proxy
  with random 1-1.5s interval to prevent upstream 429
- Backend: return ApplicationError with actual upstream status code
  instead of wrapping all errors as 500
- Handle component unmount to skip stale updates on page navigation
2026-03-05 19:12:49 +08:00
erio
9245e197a8 chore: bump version to 0.1.90.3 2026-03-04 21:50:33 +08:00
erio
0bb683a6f1 chore: bump version to 0.1.90.2 2026-03-04 21:33:39 +08:00
erio
cb3958bac3 fix: use detached context for concurrency batch query to prevent all-zero display
The upstream v0.1.90 changed GetAccountConcurrencyBatch from individual
Lua script calls (which swallowed per-account errors) to a Redis pipeline
approach that propagates errors from rdb.Time() or pipe.Exec(). When the
HTTP request context is cancelled (e.g., browser abort), the entire batch
fails and the handler silently shows all concurrency as 0.

Fix: use context.WithTimeout(context.Background(), 3s) for the Redis call
so HTTP request cancellation doesn't affect the read-only concurrency query.
2026-03-04 21:33:18 +08:00
erio
7895dd65b2 fix: remove duplicate groupExistenceBatchReader declaration in admin_service.go 2026-03-04 20:24:12 +08:00
erio
09f8894906 fix: update go.sum with missing tiktoken-go dependencies 2026-03-04 20:21:09 +08:00
erio
45fdef9da7 fix: remove duplicate IdempotencyRecords declarations in ent/migrate/schema.go 2026-03-04 20:20:40 +08:00
erio
a6026e7ac4 Merge tag 'v0.1.90' into merge/upstream-v0.1.90
注册邮箱域名白名单策略上线,后台大数据场景性能大幅优化。

- 注册邮箱域名白名单:支持管理员配置允许注册的邮箱域名策略
- Keys 页面表单筛选:用户 /keys 页面支持按条件筛选 API Key
- Settings 页面分 Tab 拆分:管理后台设置页面按功能模块分 Tab 展示

- 后台大数据场景加载性能优化:仪表盘/用户/账号/Ops 页面大数据集加载显著提速
- Usage 大表分页优化:默认避免全量 COUNT(*),大幅降低分页查询耗时
- 消除重复的 normalizeAccountIDList,补充新增组件的单元测试
- 清理无用文件和过时文档,精简项目结构
- EmailVerifyView 硬编码英文字符串替换为 i18n 调用

- 修复 Anthropic 平台无限流重置时间的 429 误标记账号限流问题
- 修复自定义菜单页面管理员视角菜单不生效问题
- 修复 Ops 错误详情弹窗未展示真实上游 payload 的问题
- 修复充值/订阅菜单 icon 显示问题

# Conflicts:
#	.gitignore
#	backend/cmd/server/VERSION
#	backend/ent/group.go
#	backend/ent/runtime/runtime.go
#	backend/ent/schema/group.go
#	backend/go.sum
#	backend/internal/handler/admin/account_handler.go
#	backend/internal/handler/admin/dashboard_handler.go
#	backend/internal/pkg/usagestats/usage_log_types.go
#	backend/internal/repository/group_repo.go
#	backend/internal/repository/usage_log_repo.go
#	backend/internal/server/middleware/security_headers.go
#	backend/internal/server/router.go
#	backend/internal/service/account_usage_service.go
#	backend/internal/service/admin_service_bulk_update_test.go
#	backend/internal/service/dashboard_service.go
#	backend/internal/service/gateway_service.go
#	frontend/src/api/admin/dashboard.ts
#	frontend/src/components/account/BulkEditAccountModal.vue
#	frontend/src/components/charts/GroupDistributionChart.vue
#	frontend/src/components/layout/AppSidebar.vue
#	frontend/src/i18n/locales/en.ts
#	frontend/src/i18n/locales/zh.ts
#	frontend/src/views/admin/GroupsView.vue
#	frontend/src/views/admin/SettingsView.vue
#	frontend/src/views/admin/UsageView.vue
#	frontend/src/views/user/PurchaseSubscriptionView.vue
2026-03-04 19:58:38 +08:00
Wesley Liddick
27abae21b8 Merge pull request #724 from PMExtra/feat/registration-email-domain-whitelist
feat(registration): add email domain whitelist policy
2026-03-04 15:51:51 +08:00
shaw
0819c8a51a refactor: 消除重复的 normalizeAccountIDList,补充 PR#754 新增组件的单元测试
- 删除 account_today_stats_cache.go 中重复的 normalizeAccountIDList,统一使用 id_list_utils.go 的 normalizeInt64IDList
- 新增 snapshot_cache_test.go:覆盖 snapshotCache、buildETagFromAny、parseBoolQueryWithDefault
- 新增 id_list_utils_test.go:覆盖 normalizeInt64IDList、buildAccountTodayStatsBatchCacheKey
- 新增 ops_query_mode_test.go:覆盖 shouldFallbackOpsPreagg、cloneOpsFilterWithMode
2026-03-04 15:22:46 +08:00
Wesley Liddick
9dcd3cd491 Merge pull request #754 from xvhuan/perf/admin-core-large-dataset
perf(admin): 优化后台大数据场景加载性能(仪表盘/用户/账号/Ops)
2026-03-04 15:15:13 +08:00
Wesley Liddick
49767cccd2 Merge pull request #755 from xvhuan/perf/admin-usage-fast-pagination-main
perf(admin-usage): 优化 usage 大表分页,默认避免全量 COUNT(*)
2026-03-04 14:15:57 +08:00
xvhuan
f6fe5b552d fix(admin): resolve CI lint and user subscriptions regression 2026-03-04 14:07:17 +08:00
PMExtra
bd0801a887 feat(registration): add email domain whitelist policy 2026-03-04 13:54:18 +08:00
xvhuan
05b1c66aa8 perf(admin-usage): avoid expensive count on large usage_logs pagination 2026-03-04 13:51:27 +08:00
xvhuan
80ae592c23 perf(admin): optimize large-dataset loading for dashboard/users/accounts/ops 2026-03-04 13:45:49 +08:00
shaw
ba6de4c4d4 feat: /keys页面支持表单筛选 2026-03-04 11:29:31 +08:00
shaw
0aa3cf677a chore: 清理一些无用的文件 2026-03-04 10:15:42 +08:00
shaw
72961c5858 fix: Anthropic 平台无限流重置时间的 429 不再误标记账号限流 2026-03-04 09:36:24 +08:00
Wesley Liddick
a11ac188c2 Merge pull request #738 from DaydreamCoding/feat/ungrouped-key-setting
feat(gateway): 系统设置控制未分组 Key 调度 — Handler 层中间件拦截
2026-03-03 21:03:31 +08:00
Wesley Liddick
60350d298a Merge pull request #735 from alfadb/fix/count-tokens-default-ignore
fix(ops): 默认忽略 count_tokens 404 错误
2026-03-03 21:02:46 +08:00
shaw
838dad8759 feat: 重构 /v1/usage 端点,支持 quota_limited 和 unrestricted 双模式
- quota_limited 模式:返回 Key 级别的总额度、速率限制窗口用量和过期时间
- unrestricted 模式:返回订阅限额或钱包余额信息(向后兼容)
- 新增 model_stats 字段,支持 start_date/end_date 参数查询按模型用量统计
- 提取 buildUsageData/parseUsageDateRange 等辅助方法,减少主函数复杂度
- 新增 APIKeyService.GetRateLimitData 和 UsageService.GetAPIKeyModelStats
2026-03-03 20:59:12 +08:00
shaw
a728dfe0c6 refactor: 重构 api_key_auth 中间件,用 skipBilling 替代 7 处散落的 isUsageQuery
将中间件职责拆分为鉴权(Authentication)和计费执行(Billing Enforcement)两层:
- 鉴权层(disabled/IP/用户状态)始终执行
- 计费层(过期/配额/订阅/余额)用单一 skipBilling 守卫整块控制

/v1/usage 端点只需鉴权不需计费,skipBilling 仅出现 2 处(订阅加载错误处理 + 计费块守卫),
取代了之前 isUsageQuery 散布在 7 个 if 分支中的控制流。
2026-03-03 20:58:00 +08:00
QTom
0c7cbe3566 feat(gateway): 系统设置控制未分组 Key 调度 — Handler 层中间件拦截
新增系统设置 allow_ungrouped_key_scheduling(默认关闭),
未分组的 API Key 在网关请求时直接返回 403,
由 RequireGroupAssignment 中间件统一拦截,
支持 Anthropic / Google 两种错误格式响应。

全栈实现:常量 → 结构体 → 解析/更新/初始化 → DTO → 管理接口 →
中间件 → 路由注册 → 前端设置界面 + i18n。
2026-03-03 19:56:27 +08:00
alfadb
832b0185c7 style: fix gofmt formatting in ops_settings.go
Remove extra space before inline comment to pass golangci-lint gofmt check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 18:00:49 +08:00
alfadb
b1719b26d1 fix(ops): 默认忽略 count_tokens 404 错误
将 IgnoreCountTokensErrors 默认值从 false 改为 true。

count_tokens 返回 404 是预期业务行为(上游不支持 endpoint,
客户端应 fallback 到本地 tokenizer 估算),不应被视为错误。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 16:50:13 +08:00
shaw
ccf6a921c7 fix: 修复 PR #723 引入的 CI lint 和 test 编译错误
- wire_gen_test.go: 补充 NewTokenRefreshService 缺失的 tempUnschedCache 参数
- config.go, token_refresh_service.go: 修复 gofmt 格式问题
2026-03-03 16:45:29 +08:00
Wesley Liddick
197c570baa Merge pull request #723 from zqq-nuli/fix/oauth-401-temp-unschedulable
fix: OAuth 401 不再永久锁死账号,改用临时不可调度实现自动恢复
2026-03-03 16:33:07 +08:00
shaw
0fe09f1d40 fix: 恢复 PR #682 中被误替换为占位符的 OAuth client_secret
PR #682 (release → main 全量同步) 将 Antigravity 和 Gemini CLI 的
OAuth client_secret 硬编码值替换为了 "GOCSPX-your-client-secret" 占位符,
导致未配置环境变量的部署环境中 token 刷新失败。

恢复内容:
- antigravity/oauth.go: 恢复真实 client_secret
- antigravity/oauth_test.go: 恢复测试断言中的真实值
- geminicli/constants.go: 恢复真实 client_secret
2026-03-03 16:27:28 +08:00
shaw
4a91954532 fix: correct migration 061 checksum and add missing BillingCache mock methods
- Fix fileChecksum for 061 migration: use TrimSpace hash (66207e7a) instead
  of raw sha256sum (97bdd9a3), matching the actual runtime computation
- Add 222b4a09 as accepted DB checksum for 061 migration
- Add missing GetAPIKeyRateLimit/SetAPIKeyRateLimit/UpdateAPIKeyRateLimitUsage/
  InvalidateAPIKeyRateLimit methods to mock BillingCache in test stubs
- Fix NewBillingCacheService call in singleflight test (add apiKeyRepo param)
2026-03-03 16:11:05 +08:00
shaw
b8b5cec35c fix: resolve CI lint errors and test compilation failures for rate limit feature
- Fix errcheck: properly handle rows.Close() error via named return + defer closure
- Fix gofmt: auto-format billing_cache.go, api_key_service.go, billing_cache_service.go
- Add missing rate limit interface methods to 4 test stubs (GetRateLimitData, IncrementRateLimitUsage, ResetRateLimitWindows)
- Fix NewBillingCacheService calls missing the new apiKeyRepo parameter
2026-03-03 15:43:08 +08:00
Wesley Liddick
43c203333e Merge pull request #733 from DaydreamCoding/fix/group-isolation
fix(gateway): 分组隔离 — 禁止未分组账号被跨组调度
2026-03-03 15:10:30 +08:00
Wesley Liddick
1c6393b131 Merge pull request #732 from xvhuan/perf/admin-dashboard-preagg
perf(admin): 优化 Dashboard 大数据量加载(预聚合趋势+异步用户趋势)
2026-03-03 15:10:20 +08:00
Wesley Liddick
22f04e72e5 Merge pull request #731 from xvhuan/fix/061-bounded-backfill-startup
fix(migrations): 061 迁移改为限时分批回填,避免启动阻塞导致 502
2026-03-03 15:08:18 +08:00
shaw
5f3debf65b chore: add migration for api key rate limit fields 2026-03-03 15:05:15 +08:00
shaw
a80ec5d8bb feat: apikey支持5h/1d/7d速率控制 2026-03-03 15:01:10 +08:00
QTom
530a16291c fix(gateway): 分组隔离 — 禁止未分组账号被跨组调度
当 API Key 无分组时,调度仅从未分组账号池中选取。
修复 isAccountInGroup 在 groupID==nil 时的逻辑,
同时补全 scheduler_snapshot_service 和 gemini_compat_service
中的 SimpleMode 保护,确保分组隔离在所有调度路径生效。

新增 ListSchedulableUngroupedByPlatform/s 方法,
使用 Ent 的 Not(HasAccountGroups()) 谓词实现未分组账号隔离。
新增 17 个单元和端到端隔离测试,覆盖所有分支和边界条件。
2026-03-03 13:20:58 +08:00
xvhuan
7be8f4dc6e perf(admin-dashboard): accelerate trend load with pre-aggregation and async user trend 2026-03-03 11:53:54 +08:00
ius
99f1e3ff35 fix(migrations): avoid startup outage from 061 full-table backfill 2026-03-03 11:01:22 +08:00
Wesley Liddick
b7df7ce5d5 Merge pull request #726 from DaydreamCoding/feat/dual-mode-umq
feat(gateway): 双模式用户消息队列 — 串行队列 + 软性限速
2026-03-03 08:41:34 +08:00
erio
451a851118 fix: remove unused sanitizeCustomMenuItemsJSON function
Replaced by filterUserVisibleMenuItems which includes both array
validation and admin-item filtering.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 07:13:08 +08:00
erio
e97c376681 fix: security hardening and architectural improvements for custom menu
1. (Critical) Filter admin-only menu items from public API responses -
   both GetPublicSettings handler and GetPublicSettingsForInjection now
   exclude visibility=admin items, preventing unauthorized access to
   admin menu URLs.

2. (Medium) Validate JSON array structure in sanitizeCustomMenuItemsJSON -
   use json.Unmarshal into []json.RawMessage instead of json.Valid to
   reject non-array JSON values that would cause frontend runtime errors.

3. (Medium) Decouple router from business JSON parsing - move origin
   extraction logic from router.go to SettingService.GetFrameSrcOrigins,
   eliminating direct JSON parsing of custom_menu_items in the routing
   layer.

4. (Low) Restrict custom menu item ID charset to [a-zA-Z0-9_-] via
   regex validation, preventing route-breaking characters like / ? # or
   spaces.

5. (Low) Handle crypto/rand error in generateMenuItemID - return error
   instead of silently ignoring, preventing potential duplicate IDs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 07:05:01 +08:00
erio
7541e243bc style: fix gofmt alignment in setting_service.go 2026-03-03 06:38:04 +08:00
erio
50a8116ae9 fix: update SecurityHeaders call sites to match new signature 2026-03-03 06:37:50 +08:00
erio
bf6fe5e962 fix: custom menu security hardening and code quality improvements
- Add admin menu permission check in CustomPageView (visibility + role)
- Sanitize SVG content with DOMPurify before v-html rendering (XSS prevention)
- Decouple router.go from dto package using anonymous struct
- Consolidate duplicate parseCustomMenuItems into dto.ParseCustomMenuItems
- Enhance menu item validation (count, length, ID uniqueness limits)
- Add audit logging for purchase_subscription and custom_menu_items changes
- Update API contract test to include custom_menu_items field

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 06:23:56 +08:00
erio
e4f8799323 fix: include custom_menu_items in GetPublicSettingsForInjection 2026-03-03 06:21:23 +08:00
erio
a50d5d351b fix: replace curly quotes with straight quotes in domain_constants.go
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 06:18:35 +08:00
erio
067810fa98 feat: custom menu pages with iframe embedding and CSP injection
Add configurable custom menu items that appear in sidebar, each rendering
an iframe-embedded external page. Includes shared URL builder with
src_host/src_url tracking, CSP frame-src multi-origin deduplication,
admin settings UI, and i18n support.

chore: bump version to 0.1.87.19

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 06:18:20 +08:00