1. 20 Apr, 2026 1 commit
    • erio's avatar
      feat(monitor): admin channel monitor MVP with SSRF protection and batch aggregation · 20a4e418
      erio authored
      新增 admin「渠道监控」模块(参考 BingZi-233/check-cx),独立于现有 Channel 体系。
      admin 配置 + 后台定时调用上游 LLM chat completions 健康检查 + 所有登录用户只读可见。
      
      后端:
      - ent: channel_monitor + channel_monitor_history(AES-256-GCM 加密 api_key)
      - service 按职责拆分:service/aggregator/validate/checker/runner/ssrf
      - provider strategy map 替代 switch(openai/anthropic/gemini)
      - repository batch 聚合(ListLatestForMonitorIDs + ComputeAvailabilityForMonitors)消除 N+1
      - runner: ticker(5s) + pond worker pool(5) + inFlight 防并发 + TrySubmit 防雪崩
        + 凌晨 3 点 cron 清理 30 天历史
      - SSRF 防护:强制 https + 私网/loopback/云元数据 IP 拒绝(127/8、10/8、172.16/12、
        192.168/16、169.254/16、100.64/10、::1、fc00::/7、fe80::/10)+ DialContext
        在 socket 层防 DNS rebinding
      - API key sanitize:擦除 url.Error 与上游响应 body 中的 sk-/sk-ant-/AIza/JWT 模式
      - APIKeyDecryptFailed 标志位 + 单 monitor 路径检测,避免空 key 调用上游
      
      handler:
      - admin: CRUD + 手动触发 + 历史接口(api_key 脱敏)
      - user: 只读列表 + 状态详情(去除 api_key/endpoint)
      - ParseChannelMonitorID 共用 + dto.ChannelMonitorExtraModelStatus 共用
      
      前端:
      - 路由 /admin/channels/{pricing,monitor} + /monitor(用户只读)
      - AppSidebar 父项 expandOnly 支持
      - ChannelMonitorView 拆为 8 个子组件 + ChannelStatusView 拆出 detail dialog
      - composables/useChannelMonitorFormat + constants/channelMonitor 共享
      - i18n monitorCommon namespace 消除 admin/user 两 view 重复
      
      合规:所有文件符合 CLAUDE.md(Go ≤ 500 行 / Vue ≤ 300 行 / 函数 ≤ 30 行)
      CI: go build / gofmt / golangci-lint(0 issues) / make test-unit / pnpm build 全绿
      20a4e418
  2. 22 Apr, 2026 4 commits
  3. 21 Apr, 2026 4 commits
  4. 20 Apr, 2026 8 commits
  5. 14 Apr, 2026 10 commits
    • erio's avatar
      fix: merge 30 general improvements from release branch · 6ac8ccde
      erio authored
      Bug fixes:
      - Detached context for GetAccountConcurrencyBatch (prevent all-zero on request cancel)
      - Filter soft-deleted users in GetByGroupID
      - Stripe CSP policy (allow Stripe.js in script-src and frame-src)
      - WebSearch API key validation on save
      - RECHARGING status in payment result success check
      - Windows test fixes (logger Sync deadlock, config path escaping)
      
      Feature enhancements:
      - Webhook multi-instance dispatch (extractOutTradeNo + GetWebhookProvider)
      - EasyPay mobile H5 payment (device param + PayURL2)
      - SSE error propagation in WebSearch emulation
      - AccountStatsCost DTO field for admin usage logs
      - Plans sort by sort_order instead of created_at
      - UsageMapHook for streaming response usage data
      - apicompat Instructions field passthrough
      - EffectiveLoadFactor for ops concurrency/metrics
      - Usage billing RETURNING balance for notify system
      - BulkUpdate mixed channel warning with details
      - println to slog migration in auth cache
      - Wire ProviderSet cleanup
      - CI cache-dependency-path optimization
      
      Frontend:
      - Refund eligibility check per provider (canRequestRefund)
      - Plan sort_order editing
      - Dead code cleanup (simulate_claude_max, client_affinity)
      - GroupsView platform switch guard
      - channels features_config API type
      - UsageView account_stats_cost export
      6ac8ccde
    • erio's avatar
      feat: add per-provider allow_user_refund control and align wildcard matching · f1297a36
      erio authored
      allow_user_refund:
      - Add allow_user_refund field to PaymentProviderInstance ent schema
      - Migration 103: ALTER TABLE payment_provider_instances ADD COLUMN
      - Cascade logic: disabling refund_enabled auto-disables allow_user_refund
      - User refund validation: check provider instance allows user refund
      - Admin refund validation: check provider instance allows admin refund
      - Subscription refund: deduct days on refund, rollback on failure
      - New endpoint: GET /payment/orders/refund-eligible-providers
      - Frontend: ToggleSwitch in ProviderCard/Dialog, cascade in SettingsView
      
      Wildcard matching:
      - Change findPricingForModel from "longest prefix wins" to "config order
        priority (first match wins)", aligning with channel service behavior
      f1297a36
    • erio's avatar
      fix: resolve upstream CI failures (lint, test, gofmt) · 6a08efee
      erio authored
      - Fix errcheck: handle Write/Encode return values in brave_test.go
      - Fix errcheck: defer resp.Body.Close() with _ assignment in tavily.go
      - Fix gofmt: payment.go, channel.go, payment_config_providers.go
      - Fix unused: remove dead decodeURLValue in easypay.go
      - Restore shouldFallbackGeminiModel function (deleted during cherry-pick)
      - Add missing balanceNotifyService param to NewGatewayService in test
      - Fix platform default test expectation (empty stays empty)
      - Fix wildcard pricing test (longest prefix wins, not config order)
      - Fix subscription group test (SUBSCRIPTION_REPOSITORY_UNAVAILABLE)
      6a08efee
    • erio's avatar
      feat: websearch quota enhancements and balance notify hint · 7c729293
      erio authored
      - QuotaLimit changed to *int64 (null=unlimited, >0=limited)
      - Add reset-usage endpoint (POST /admin/settings/web-search-emulation/reset-usage)
      - Show quota usage in header always (collapsed and expanded)
      - Add reset quota button in expanded provider view
      - Quota input: empty=unlimited with ∞ placeholder, must be >0 if set
      - Add email verification hint on balance notify card
      7c729293
    • erio's avatar
      feat(notify): convert email lists to NotifyEmailEntry struct with toggle support · 915b7a4a
      erio authored
      - Change balance_notify_extra_emails and account_quota_notify_emails
        from []string to []NotifyEmailEntry{email, disabled, verified}
      - Add per-email enable/disable toggle for both user and admin notifications
      - Add PUT /user/notify-email/toggle API endpoint
      - Fix critical bug: API key auth cache snapshot missing balance notify
        fields (Email, Username, BalanceNotifyEnabled, etc.), causing
        notifications to never fire on cached request paths
      - Bump cache snapshot version 3→4 to invalidate stale entries
      - Add SQL migration 104 to convert old format data
      - Backward compatible: parseNotifyEmails auto-detects old/new format
      - User balance notify: max 3 emails (primary + 2 extra)
      - Admin quota notify: unlimited emails, each with toggle
      915b7a4a
    • erio's avatar
      feat(websearch): settings UI overhaul and quota improvements · d0674e0f
      erio authored
      - Remove Priority field, auto load-balance by quota remaining
      - Replace QuotaRefreshInterval (daily/weekly/monthly) with SubscribedAt
        (subscription date, monthly lazy refresh via Redis TTL)
      - Add collapsible provider cards, API key show/copy, usage progress bar
      - Add test endpoint (POST /web-search-emulation/test) bypassing quota
      - Wire WebSearchManagerBuilder on startup (was never called before)
      - Fix nextMonthlyReset day-of-month overflow (Jan 31 → Feb 28)
      - Fix non-deterministic sort in selectByQuotaWeight
      - Map ProxyID in builder for provider-level proxy tracking
      - Fix frontend timezone drift in subscribed_at date picker
      - Fix provider deletion index shift for expandedProviders state
      d0674e0f
    • erio's avatar
      feat(notify): add balance low & account quota notification system · b32d1a2c
      erio authored
      - User balance low notification: email alert when balance drops below
        configurable threshold (user email + verified extra emails)
      - Account quota notification: broadcast email to admin-configured
        recipients when daily/weekly/total quota usage exceeds alert threshold
      - Admin settings: global enable/disable, default threshold, quota
        notification email list (Email Settings tab)
      - User profile: enable/disable, custom threshold, add/remove extra
        notification emails with verification code flow
      - Account quota: per-dimension alert toggle and threshold in quota
        control card
      - Trigger logic: first-crossing only (old >= threshold && new < threshold
        for balance; old < threshold && new >= threshold for quota), naturally
        prevents duplicate notifications without Redis dedup
      b32d1a2c
    • erio's avatar
      feat(gateway): add web search emulation for Anthropic API Key accounts · 1b53ffca
      erio authored
      Inject web search capability for Claude Console (API Key) accounts that
      don't natively support Anthropic's web_search tool. When a pure
      web_search request is detected, the gateway calls Brave Search or Tavily
      API directly and constructs an Anthropic-protocol-compliant SSE/JSON
      response without forwarding to upstream.
      
      Backend:
      - New `pkg/websearch/` SDK: Brave and Tavily provider implementations
        with io.LimitReader, proxy support, and Redis-based quota tracking
        (Lua atomic INCR + TTL, DECR rollback on failure)
      - Global config via `settings.web_search_emulation_config` (JSON) with
        in-process cache + singleflight, input validation, API key merge on
        save, and sanitized API responses
      - Channel-level toggle via `channels.features_config` JSONB column
        (DB migration 101)
      - Account-level toggle via `accounts.extra.web_search_emulation`
      - Request interception in `Forward()` with SSE streaming response
        construction using json.Marshal (no manual string concatenation)
      - Manager hot-reload: `RebuildWebSearchManager()` called on config save
        and startup via `SetWebSearchRedisClient()`
      - 70 unit tests covering providers, manager, config validation,
        sanitization, tool detection, query extraction, and response building
      
      Frontend:
      - Settings → Gateway tab: Web Search Emulation config card with global
        toggle, provider list (add/remove, API key, priority, quota, proxy)
      - Channels → Anthropic tab: web search emulation toggle with global
        state linkage (disabled when global off)
      - Account Create/Edit modals: web search emulation toggle for API Key
        type with Toggle component
      - Full i18n coverage (zh + en)
      1b53ffca
    • erio's avatar
      fix(payment): critical audit fixes for security, idempotency and correctness · c738cfec
      erio authored
      Backend fixes:
      - #1: doSub subscription idempotency via audit log check
      - #2: markFailed only when status=RECHARGING (prevents overwriting COMPLETED)
      - #3: ExpireTimedOutOrders checks upstream payment before expiring
      - #4: Public verify endpoint for payment result page (no auth required)
      - #5: EasyPay QueryOrder returns amount, confirmPayment handles zero amount
      - #6: WxPay notifyUrl priority: request-first, config-fallback
      - #7: EasyPay remove double URL decode in VerifyNotification
      - #8: checkPaid/cancelUpstreamPayment use order's provider instance
      - #9: Amount NaN/Inf/negative validation in order creation and refund
      - #10: Refund amount comparison uses tolerance instead of float64 ==
      - #11: Skip balance deduction on retry when previous rollback failed
      - #12: checkPaid logs fulfillment errors instead of silently ignoring
      - #13: WxPay certSerial added to required config fields
      
      Frontend fixes:
      - Payment result page no longer requires authentication
      - Public verify API fallback for expired sessions
      c738cfec
    • erio's avatar
      refactor: remove PaymentChannel, reuse upstream Channel with features field · 794e8172
      erio authored
      - Delete payment_channels table and PaymentChannel Ent schema
      - Add `features` column to upstream channels table (migration 095)
      - Add Features field to Channel struct, input types, handler request/response
      - Payment user/admin handlers now use ChannelService directly
      - Remove Channel CRUD from PaymentConfigService and admin payment routes
      - Remove "渠道管理" tab from admin orders page (use /admin/channels)
      794e8172
  6. 11 Apr, 2026 1 commit
  7. 09 Apr, 2026 1 commit
  8. 05 Apr, 2026 2 commits
  9. 04 Apr, 2026 2 commits
  10. 27 Mar, 2026 1 commit
    • shaw's avatar
      feat(tls-fingerprint): 新增 TLS 指纹 Profile 数据库管理及代码质量优化 · 1854050d
      shaw authored
      新增功能:
      - 新增 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 回调签名被错误替换的问题
      1854050d
  11. 25 Mar, 2026 1 commit
    • QTom's avatar
      feat(antigravity): 自动设置隐私并支持后台手动重试 · c2965c0f
      QTom authored
      新增 Antigravity OAuth 隐私设置能力,在账号创建、刷新、导入和后台
      Token 刷新路径自动调用 setUserSettings + fetchUserInfo 关闭遥测;
      持久化后同步内存 Extra,错误处理改为日志记录。
      
      Made-with: Cursor
      c2965c0f
  12. 23 Mar, 2026 1 commit
    • Ethan0x0000's avatar
      feat(routes): add platform-based routing split for /v1/responses and /v1/chat/completions · d927c0e4
      Ethan0x0000 authored
      Mirror the existing /v1/messages platform split pattern:
      - OpenAI groups → OpenAIGateway handlers (existing, unchanged)
      - Non-OpenAI groups → Gateway handlers (new Anthropic-upstream path)
      
      Updated both /v1 prefixed routes and non-prefixed alias routes
      (/responses, /chat/completions). WebSocket route (/v1/responses GET)
      remains OpenAI-only as Anthropic has no WebSocket equivalent.
      d927c0e4
  13. 19 Mar, 2026 1 commit
    • QTom's avatar
      feat(admin): 用户管理新增分组列、分组筛选与专属分组一键替换 · ba7d2aec
      QTom authored
      - 新增分组列:展示用户的专属/公开分组,支持 hover 查看详情
      - 新增分组筛选:下拉选择或模糊搜索分组名过滤用户
      - 专属分组替换:点击专属分组弹出操作菜单,选择目标分组后
        自动授予新分组权限、迁移绑定的 Key、移除旧分组权限
      - 后端新增 POST /admin/users/:id/replace-group 端点,事务内
        完成分组替换并失效认证缓存
      ba7d2aec
  14. 18 Mar, 2026 3 commits