Commit Graph
188 Commits
Author SHA1 Message Date
erio 2f1168a126 Merge remote-tracking branch 'origin/feature/channel' into release/custom-0.1.105
# Conflicts:
#	backend/cmd/server/wire_gen.go
2026-03-30 16:13:52 +08:00
erio c74c6f3f1f feat(channel): 模型价格自动填充 + 默认定价 API
- 新增 GET /admin/channels/model-pricing?model=xxx API
- 从 BillingService 查询 LiteLLM/Fallback 默认定价
- 前端添加模型时自动查询并填充价格($/MTok)
- 仅在所有价格字段为空时才自动填充,不覆盖手动配置
2026-03-30 16:11:49 +08:00
erio 9e9285c25a Merge remote-tracking branch 'origin/feature/channel' into release/custom-0.1.105
# Conflicts:
#	backend/cmd/server/wire_gen.go
#	backend/internal/handler/handler.go
#	backend/internal/handler/wire.go
2026-03-30 02:05:59 +08:00
erio a9117600a5 feat(channel): 渠道管理系统 — 多模式定价 + 统一计费解析
新增渠道管理功能,支持三种计费模式(Token 区间/按次/图片),
统一定价解析链(Channel → LiteLLM → Fallback),
无渠道配置时保持原有计费逻辑不变。

Backend:
- 新增 channels/channel_groups/channel_model_pricing/channel_pricing_intervals 表
- ChannelService: atomic.Value + singleflight 缓存,通配符模型匹配
- ModelPricingResolver: 统一定价解析器
- BillingService: CalculateCostUnified 统一计费入口
- 完整输入验证(BillingMode/价格非负/名称长度)
- 33 个单元测试覆盖核心路径

Frontend:
- ChannelsView.vue: 渠道 CRUD 列表页
- PricingEntryCard.vue + IntervalRow.vue: 定价编辑组件
- 支持三种计费模式切换 + 区间编辑
2026-03-30 02:03:06 +08:00
erio 0393981397 merge: integrate upstream v0.1.105 into release/custom-0.1.105
Merge upstream v0.1.105 (94 commits) with our customizations from
release/custom-0.1.104. Key upstream additions:
- TLS fingerprint profile management
- OpenAI→Anthropic endpoint compatibility routing
- Privacy mode for OpenAI/Antigravity accounts
- Requested model tracking in usage logs
- Error observability enhancements
- Various bug fixes

Conflict resolutions (all "keep both sides"):
- handler.go/wire.go: added both TLSFingerprintProfile and GDriveOAuth
- wire_gen.go: combined internal500CounterCache with TLS fingerprint objects
- accounts.ts: kept setPrivacy + affinity functions
- BulkEditAccountModal.vue: kept OpenAI WS mode + Allow Overages sections

Additional fixes:
- gateway_handler_chat_completions.go, gateway_handler_responses.go:
  added missing sub2apiUserID parameter to SelectAccountWithLoadAwareness
- antigravity_internal500_penalty.go: gofmt fix
2026-03-27 18:23:39 +08:00
shaw 1854050df3 feat(tls-fingerprint): 新增 TLS 指纹 Profile 数据库管理及代码质量优化
新增功能:
- 新增 TLS 指纹 Profile CRUD 管理(Ent schema + 迁移 + Admin API + 前端管理界面)
- 支持账号绑定数据库中的自定义 TLS Profile,或随机选择(profile_id=-1)
- HTTPUpstream.DoWithTLS 接口从 bool 改为 *tlsfingerprint.Profile,支持按账号指定 Profile
- AccountUsageService 注入 TLSFingerprintProfileService,统一 usage 场景与网关的 Profile 解析逻辑

代码优化:
- 删除已被 TLSFingerprintProfileService 完全取代的 registry.go 死代码(418 行)
- 提取 3 个 dialer 的重复 TLS 握手逻辑为 performTLSHandshake() 共用函数
- 修复 GetTLSFingerprintProfileID 缺少 json.Number 处理的 bug
- gateway_service.Forward 中 ResolveTLSProfile 从重试循环内重复调用改为预解析局部变量
- 删除冗余的 buildClientHelloSpec() 单行 wrapper 和 int64(e.ID) 无效转换
- tls_fingerprint_profile_cache.go 日志从 log.Printf 改为 slog 结构化日志
- dialer_capture_test.go 添加 //go:build integration 标签,防止 CI 失败
- 去重 TestProfileExpectation 类型至共享 test_types_test.go
- 修复 9 个测试文件缺少 tlsfingerprint import 的编译错误
- 修复 error_policy_integration_test.go 中 handleError 回调签名被错误替换的问题
2026-03-27 14:33:05 +08:00
erio c668b96e15 feat(antigravity): progressive penalty for consecutive INTERNAL 500 errors
When an antigravity account returns 500 "Internal error encountered."
on all 3 retry attempts, increment a Redis counter and apply escalating
penalties:
- 1st round: temp unschedulable 10 minutes
- 2nd round: temp unschedulable 10 hours
- 3rd round: permanently mark as error

Counter resets on any successful response (< 400).
2026-03-24 20:18:49 +08:00
QTomandClaude Opus 4.6 91b1d812ce feat(openai): Mobile RT 补全 plan_type、精确匹配账号、刷新时自动设置隐私
1. accounts/check 补全 plan_type:当 id_token 缺少 plan_type(如 Mobile RT),
   自动调用 accounts/check 端点获取订阅类型
2. orgID 精确匹配账号:从 JWT 提取 poid 匹配正确账号,避免 Go map
   遍历顺序随机导致 plan_type 不稳定
3. RT 刷新时设置隐私:调用 disableOpenAITraining 关闭训练数据共享,
   结果存入 extra.privacy_mode,后续跳过重复设置

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 14:50:03 +08:00
erio 528ff5d28c fix(antigravity): fast-fail on proxy unavailable, temp-unschedule account
## Problem

When a proxy is unreachable, token refresh retries up to 4 times with
30s timeout each, causing requests to hang for ~2 minutes before
failing with a generic 502 error. The failed account is not marked,
so subsequent requests keep hitting it.

## Changes

### Proxy connection fast-fail
- Set TCP dial timeout to 5s and TLS handshake timeout to 5s on
  antigravity client, so proxy connectivity issues fail within 5s
  instead of 30s
- Reduce overall HTTP client timeout from 30s to 10s
- Export `IsConnectionError` for service-layer use
- Detect proxy connection errors in `RefreshToken` and return
  immediately with "proxy unavailable" error (no retries)

### Token refresh temp-unschedulable
- Add 8s context timeout for token refresh on request path
- Mark account as temp-unschedulable for 10min when refresh fails
  (both background `TokenRefreshService` and request-path
  `GetAccessToken`)
- Sync temp-unschedulable state to Redis cache for immediate
  scheduler effect
- Inject `TempUnschedCache` into `AntigravityTokenProvider`

### Account failover
- Return `UpstreamFailoverError` on `GetAccessToken` failure in
  `Forward`/`ForwardGemini` to trigger handler-level account switch
  instead of returning 502 directly

### Proxy probe alignment
- Apply same 5s dial/TLS timeout to shared `httpclient` pool
- Reduce proxy probe timeout from 30s to 10s
2026-03-19 23:48:37 +08:00
erio 0667cf3cac fix(antigravity): fast-fail on proxy unavailable, temp-unschedule account
- Set proxy TCP dial timeout to 5s and TLS handshake timeout to 5s
  for quick failure detection instead of waiting 30s
- Reduce overall HTTP client timeout from 30s to 10s
- Detect proxy connection errors (IsConnectionError) and skip retries
  immediately with clear "proxy unavailable" error
- Add 8s context timeout for token refresh on request path to cap
  total wait time
- Mark account as temp-unschedulable for 10min when token refresh
  fails (both background and request path)
- Sync temp-unschedulable state to Redis cache for immediate
  scheduler effect
- Return UpstreamFailoverError on GetAccessToken failure to trigger
  account failover instead of returning 502 directly
- Apply same 5s dial timeout to httpclient pool (proxy probe/test)
- Reduce proxy probe timeout from 30s to 10s
2026-03-19 23:20:14 +08:00
erio 1d946b3847 Merge upstream v0.1.102 into release/custom-0.1.102 2026-03-18 12:11:03 +08:00
QTomandClaude Opus 4.6 d4cc9871c4 feat(admin): 分组管理新增容量列(并发/会话/RPM 实时聚合)
复用 GroupCapacityService,在 admin 分组列表中添加容量列,
显示每个分组的实时并发/会话/RPM 使用量和上限。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:06:35 +08:00
QTomandClaude Opus 4.6 961c30e7c0 feat(admin): 分组管理列表新增用量列与账号数分类
分组管理列表增强:

1. 今日/累计用量列:
   - 新增独立端点 GET /admin/groups/usage-summary
   - 一次查询返回所有分组的今日费用和累计费用(actual_cost)
   - 前端异步加载后合并显示在分组列表中

2. 账号数区分可用/限流/总量:
   - 将账号数列从单一总量改为 badge 内多行展示
   - 可用: active + schedulable 的账号数(绿色)
   - 限流: rate_limit/overload/temp_unschedulable 的账号数(橙色,无限流时隐藏)
   - 总量: 全部关联账号数

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:06:35 +08:00
erio 1fc9dd7b68 feat: unified OAuth token refresh API with distributed locking
Introduce OAuthRefreshAPI as the single entry point for all OAuth token
refresh operations, eliminating the race condition where background
refresh and inline refresh could simultaneously use the same
refresh_token (fixes #1035).

Key changes:
- Add OAuthRefreshExecutor interface extending TokenRefresher with CacheKey
- Add OAuthRefreshAPI.RefreshIfNeeded with lock → DB re-read → double-check flow
- Add ProviderRefreshPolicy / BackgroundRefreshPolicy strategy types
- Simplify all 4 TokenProviders to delegate to OAuthRefreshAPI
- Rewrite TokenRefreshService.refreshWithRetry to use unified API path
- Add MergeCredentials and BuildClaudeAccountCredentials helpers
- Add 40 unit tests covering all new and modified code paths
2026-03-16 01:31:54 +08:00
erio d844f3b6b5 feat: unified OAuth token refresh API to fix refresh_token race condition (#1035)
Introduce OAuthRefreshAPI as the single entry point for all OAuth token
refresh operations (both background TokenRefreshService and inline
TokenProvider), eliminating the race condition where two independent
refresh paths consume the same one-time-use refresh_token.

Key changes:
- New OAuthRefreshAPI with distributed lock + DB re-read + double-check
- All 4 platform refreshers implement OAuthRefreshExecutor (CacheKey)
- TokenRefreshService and TokenProviders share the same lock key
- Add errRefreshSkipped sentinel for accurate refresh statistics
- 7 new Path A unit tests covering all RefreshIfNeeded branches

chore: bump version to 0.1.100.2
2026-03-16 01:00:20 +08:00
erio 25a0030450 Merge branch 'main' into release/custom-0.1.99
# Conflicts:
#	backend/cmd/server/wire_gen.go
#	backend/cmd/server/wire_gen_test.go
#	backend/internal/handler/dto/mappers.go
#	backend/internal/service/ratelimit_service.go
#	backend/internal/service/ratelimit_service_401_db_fallback_test.go
#	backend/internal/service/ratelimit_service_401_test.go
#	frontend/src/components/account/AccountCapacityCell.vue
#	frontend/src/components/account/CreateAccountModal.vue
#	frontend/src/components/account/EditAccountModal.vue
#	frontend/src/views/admin/DataManagementView.vue
2026-03-14 21:03:09 +08:00
Wesley Liddick aa4e37d085 Merge pull request #966 from GuangYiDing/feat/db-backup-restore
feat: 数据库定时备份与恢复(S3 兼容存储,支持 Cloudflare R2)
2026-03-14 18:58:56 +08:00
Rose DingandClaude Opus 4.6 1047f973d5 fix: 按 review 意见重构数据库备份服务(安全性 + 架构 + 健壮性)
1. S3 凭证加密存储:使用 SecretEncryptor (AES-256-GCM) 加密 SecretAccessKey,
   防止备份文件中泄露 S3 凭证,兼容旧的未加密数据
2. 修复 saveRecord 竞态条件:添加 recordsMu 互斥锁保护 records 的 load/save
3. 恢复操作增加服务端验证:handler 层要求重新输入管理员密码,通过 bcrypt
   校验,前端弹出密码输入框
4. pg_dump/psql/S3 操作抽象为接口:定义 DBDumper 和 BackupObjectStore 接口,
   实现放入 repository 层,遵循项目依赖注入架构规范
5. 改为流式处理避免大数据库 OOM:备份时 pg_dump stdout -> gzip -> io.Pipe ->
   S3 upload;恢复时 S3 download -> gzip reader -> psql stdin,不再全量加载
6. loadRecords 区分"无数据"和"数据损坏"场景:JSON 解析失败返回明确错误
7. 添加 18 个核心逻辑单元测试:覆盖加密、并发、流式备份/恢复、错误处理等

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 17:48:21 +08:00
erio 5e0a508eca Merge branch 'main' into release/custom-0.1.97
# Conflicts:
#	README.md
#	README_CN.md
#	backend/internal/handler/gateway_handler.go
#	backend/internal/repository/user_group_rate_repo.go
#	backend/internal/service/admin_service_group_rate_test.go
#	backend/internal/service/gateway_service.go
#	frontend/src/components/account/CreateAccountModal.vue
#	frontend/src/views/admin/AccountsView.vue
2026-03-14 14:07:05 +08:00
Wesley Liddick 07bb2a5f3f Merge pull request #952 from xvhuan/feat/billing-ledger-decouple-usage-log-20260312
feat: 解耦计费正确性与 usage_logs 批量写压
2026-03-13 22:46:09 +08:00
Rose DingandClaude Opus 4.6 53ad1645cf feat: 数据库定时备份与恢复(S3 兼容存储,支持 Cloudflare R2)
新增管理员专属的数据库备份与恢复功能:
- 全量 PostgreSQL 备份(pg_dump),gzip 压缩后上传到 S3 兼容存储
- 支持手动备份和 cron 定时备份
- 支持从备份恢复(psql --single-transaction)
- 备份文件自动过期清理(默认 14 天)
- 前端完整管理页面(S3 配置、定时配置、备份列表、恢复/下载/删除)
- 内置 Cloudflare R2 配置教程弹窗
- Dockerfile 从 postgres 镜像多阶段复制 pg_dump/psql,确保版本一致

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:38:19 +08:00
erio c226438a04 merge: integrate release/custom-0.1.94 customizations into 0.1.96
Recovers features lost during 0.1.91->0.1.95 merge (0.1.92-0.1.94
customizations were skipped because main branch was not updated).

Recovered features:
- Antigravity 403 forbidden/validation/ban status detection and display
- Subscription tier badge in account list
- Client affinity scheduling for Anthropic accounts
- Sora async task API and GDrive storage backend
- Swipe-to-select for admin tables
- OpenAI passthrough account selection fix
- Various quota and usage enhancements
2026-03-12 22:23:31 +08:00
QTom a63de12182 feat: GPT 隐私模式 + no-train 前端展示优化 2026-03-12 21:24:01 +08:00
ius 611fd884bd feat: decouple billing correctness from usage log batching 2026-03-12 16:53:18 +08:00
Wesley Liddick 3cc407bc0e Merge pull request #900 from ischanx/feat/admin-bind-subscription-group
feat: 允许管理员为持有有效订阅的用户绑定订阅类型分组
2026-03-10 11:20:47 +08:00
Wesley Liddick ac6bde7a98 Merge pull request #872 from StarryKira/fix/oauth-linuxdo-invitation-required
fix: Linux.do OAuth 注册支持邀请码两步流程 (fix #836)
2026-03-10 09:10:35 +08:00
ischanxandClaude Opus 4.6 767a41e263 feat: 允许管理员为持有有效订阅的用户绑定订阅类型分组
之前管理员无法通过 API 密钥管理将用户绑定到订阅类型分组(直接返回错误)。
现在改为检查用户是否持有该分组的有效订阅,有则允许绑定,无则拒绝。

- admin_service: 新增 userSubRepo 依赖,替换硬拒绝为订阅校验
- admin_service: 区分 ErrSubscriptionNotFound 和内部错误,避免 DB 故障被误报
- wire_gen/api_contract_test: 同步新增参数
- UserApiKeysModal: 管理员分组下拉不再过滤订阅类型分组

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 00:51:43 +08:00
erioandClaude Opus 4.6 028442d00b merge: integrate upstream v0.1.94 into release/custom-0.1.94
Merge upstream v0.1.94 onto our custom branch (based on release/custom-0.1.93).

Key additions beyond upstream:
- Startup stale concurrency slot cleanup on process restart
- iframe language passthrough for embedded payment/custom pages
- embedded-url.spec.ts frontend tests
- Admin payment integration API docs update

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 18:35:16 +08:00
Elysia 106b20cdbf fix claudecode review bug 2026-03-09 01:18:49 +08:00
kyx236 0c29468f90 feat(admin): 支持定时测试自动恢复并统一账号恢复入口
- 为定时测试计划增加 auto_recover 配置,补齐前后端类型、接口、仓储与数据库迁移
- 在定时测试成功后自动恢复账号 error、rate-limit 等可恢复运行时状态
- 新增 /admin/accounts/:id/recover-state 接口,合并原有重置状态与清限流操作
- 更新账号管理菜单与定时测试面板,补充自动恢复开关、说明提示和状态展示
- 补充账号恢复、限流清理与仓储同步相关测试
2026-03-08 06:59:53 +08:00
erioandClaude Opus 4.6 0af1f5841d fix: Sora task API improvements
- selectAccountByID: use original task's account for remix instead of
  random selection, preventing permission issues in OAuth path
- Upstream error passthrough: forward HTTP status code and body from
  upstream instead of always returning 500
- Add accountRepo to SoraTaskService for direct account lookup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 22:43:19 +08:00
shaw a3791104f9 feat: 支持后台设置是否启用整流开关 2026-03-07 21:55:38 +08:00
erioandClaude Opus 4.6 8c412b32d1 feat: add Sora async task API (videos/images)
Add async task management for Sora video/image generation with two
forwarding modes: OAuth (SDK) and API Key (HTTP upstream). Includes
background worker for status polling and 3-layer storage degradation
(S3 > local disk > upstream URL passthrough).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 19:19:11 +08:00
erioandClaude Opus 4.6 1864f41f33 merge: sync upstream/main into release/custom-0.1.92
Merge upstream main branch changes including:
- OpenAI Codex support and websearch adaptation
- API key rate limit auto-reset fix
- golangci-lint v2.11 upgrade for Go 1.26 compatibility
- Go 1.26.1 stdlib security fixes
- Empty stream failover fix
- CCSwitch import improvements
- API key credentials preserve existing fields
- Usage query rate limit optimization
- Setup Token real utilization fix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 12:53:12 +08:00
erioandClaude Opus 4.6 ea5e5dd9c7 feat: display client affinity count badge in account status column
Add colored circle badge showing affinity client count before the account
status indicator. Badge color reflects count severity (gray=0, green=1-5,
yellow=6-15, red=16+). Tooltip shows full client ID list on hover.

Backend: AccountHandler batch queries reverse affinity index via
GetAccountAffinityClientsBatch, returns affinity_client_count and
affinity_clients in DTO. GatewayCache interface extended with the new
batch method backed by a Lua script (get_affinity_clients.lua).

All test mocks synchronized with updated GatewayCache interface.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 04:52:10 +08:00
erioandClaude Opus 4.6 9e107fae73 feat(sora): improve storage management page with split columns, test buttons, quota and video stats
- Split compound "Profile" column into separate Profile ID and Name columns
- Replace "Endpoint" column with "Storage Path" showing bucket/prefix or folder info
- Add GDrive quota display (capacity/used) via new backend API endpoint
- Add video count statistics per storage type via new backend API endpoint
- Add inline test button per profile with 15s timeout and per-profile loading state
- Backend: GetQuotaInfo, CountByStorageType, GetGDriveQuota, GetStorageVideoStats

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 23:58:27 +08:00
erio 298f5c1baf feat(sora): add GDrive full-cycle test endpoint (upload/download/delete) 2026-03-06 22:33:37 +08:00
erioandClaude Opus 4.6 ad54040c07 feat(sora): add Google Drive storage backend with unified storage abstraction
- Define SoraObjectStorage interface abstracting S3 and GDrive backends
- Implement SoraGDriveStorage with OAuth2 and Service Account auth
- Add SoraStorageRouter to route requests based on active profile provider
- Add GDrive OAuth handler for authorization flow (start + callback)
- Extend profile model with provider, auth_type, and GDrive-specific fields
- Update frontend UI with provider selection, dynamic form fields, and i18n
- Migrate API paths from /sora-s3 to /sora-storage (old paths preserved)
- All existing S3 functionality remains backward compatible

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 20:45:51 +08:00
yangjianbo a18bbb5f2f fix(openai): 统一专属倍率计费链路并补齐回归测试
抽取共享的用户分组专属倍率解析器,统一缓存、singleflight 与回退逻辑。\n\n让 OpenAI 独立计费链路复用专属倍率解析,修复 usage 记录与实际扣费未命中用户专属倍率的问题。\n\n补齐 OpenAI 计费与解析器单元测试,并修复全量回归中暴露的 lint 阻塞项。\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:47:51 +08:00
guoyongchangandClaude Opus 4.6 817a491087 simplify: 移除 leader lock,单实例无需分布式锁
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:31:27 +08:00
guoyongchangandClaude Opus 4.6 9a8dacc514 fix: 修复 golangci-lint depguard 和 gofmt 错误
将 redis leader lock 逻辑从 service 层抽取为 LeaderLocker 接口,
实现移至 repository 层,消除 service 层对 redis 的直接依赖。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:28:48 +08:00
guoyongchangandClaude Opus 4.6 3a089242f8 feat: 支持基于 crontab 的定时账号测试
每个测试计划绑定一个账号和一个模型,按 cron 表达式定期执行测试,
保存历史结果并在前端账号管理页面中提供完整的增删改查和结果查看功能。

主要变更:
- 新增 scheduled_test_plans / scheduled_test_results 两张表及迁移
- 后端 service 层:CRUD 服务 + 后台 cron runner(每分钟扫描到期计划并发执行)
- RunTestBackground 方法通过 httptest 在内存中执行账号测试并解析 SSE 输出
- Redis leader lock + pg_try_advisory_lock 双重保障多实例部署只执行一次
- REST API:5 个管理端点(计划 CRUD + 结果查询)
- 前端 ScheduledTestsPanel 组件:计划管理、启用开关、内联编辑、结果展开查看
- 中英文 i18n 支持

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:06:05 +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 a80ec5d8bb feat: apikey支持5h/1d/7d速率控制 2026-03-03 15:01:10 +08:00
QTom a9285b8a94 feat(gateway): 双模式用户消息队列 — 串行队列 + 软性限速
新增 UMQ (User Message Queue) 双模式支持:
- serialize: 账号级分布式串行锁 + RPM 自适应延迟(严格限流)
- throttle: 仅 RPM 自适应前置延迟,不阻塞并发(软性限速)

后端:
- config: 新增 Mode 字段,保留 Enabled 向后兼容
- service: 新增 UserMessageQueueService(Lua 锁/延迟算法/清理 worker)
- repository: 新增 UserMsgQueueCache(Redis Lua acquire/release/force-release)
- handler: 新增 UserMsgQueueHelper(SSE ping + 等待循环 + throttle)
- gateway: 按 mode 分支集成 serialize/throttle 逻辑
- lint: 修复 gofmt rewrite rules、errcheck 类型断言、staticcheck QF1012

前端:
- 三态选择器 UI(关闭/软性限速/串行队列)替代 toggle 开关
- BulkEdit 支持 null 语义(不修改)
- i18n 中英文文案

通过 6 轮专家评审(42 次 review)、golangci-lint、单元测试、集成测试。
2026-03-03 01:05:11 +08:00
zqq61 ec6bcfeb83 fix: OAuth 401 不再永久锁死账号,改用临时不可调度实现自动恢复
OAuth 账号收到 401 时,原逻辑同时设置 expires_at=now() 和 SetError(),
但刷新服务只查询 status=active 的账号,导致 error 状态的账号永远无法
被刷新服务拾取,expires_at=now() 实际上是死代码。

修复:
- OAuth 401 使用 SetTempUnschedulable 替代 SetError,保持 status=active
- 新增 oauth_401_cooldown_minutes 配置项(默认 10 分钟)
- 刷新成功后同步清除 DB 和 Redis 中的临时不可调度状态
- 不可重试错误检查(invalid_grant 等)从 Antigravity 推广到所有平台
- 可重试错误耗尽后不再标记 error,下个刷新周期继续重试

恢复流程:
OAuth 401 → temp_unschedulable + expires_at=now → 刷新服务拾取
  → 成功: 清除 temp_unschedulable → 自动恢复
  → invalid_grant: SetError → 永久禁用
  → 网络错误: 仅记日志 → 下周期重试
2026-03-02 22:54:38 +08:00
PMExtra 7e02082209 feat(settings): add default subscriptions for new users
- add default subscriptions to admin settings

- auto-assign subscriptions on register and admin user creation

- add validation/tests and align settings UI with subscription selector patterns
2026-03-02 03:59:31 +08:00
Wesley Liddick 8c4d22b3f9 Merge pull request #685 from touwaeriol/pr/admin-create-and-redeem-docs
feat(admin): add create-and-redeem endpoint for payment integrations
2026-03-01 18:24:15 +08:00
QTom 4280aca82c feat(gateway): 添加 Claude Code 客户端最低版本检查功能
- 通过 User-Agent 识别 Claude Code 客户端并提取版本号
- 在网关层验证客户端版本是否满足管理员配置的最低要求
- 在管理后台提供版本要求配置选项(英文/中文双语)
- 实现原子缓存 + singleflight 防止并发问题和 thundering herd
- 使用 context.WithoutCancel 隔离 DB 查询,避免客户端断连影响缓存
- 双 TTL 策略:60s 正常、5s 错误恢复,保证性能与可用性
- 仅检查 Claude Code 客户端,其他客户端不受影响
- 添加完整单元测试覆盖版本提取、比对、上下文操作
2026-03-01 15:45:44 +08:00
erio 39ca192c41 feat(admin): add create-and-redeem API and payment integration docs 2026-03-01 00:42:21 +08:00