1. 21 Apr, 2026 4 commits
  2. 20 Apr, 2026 9 commits
  3. 19 Apr, 2026 1 commit
    • erio's avatar
      fix: delete scheduled test plans when account is deleted · 6579f28b
      erio authored
      Accounts use soft-delete (setting deleted_at), so PostgreSQL's
      ON DELETE CASCADE on scheduled_test_plans.account_id never fires.
      Add plan deletion to the existing account deletion transaction
      to ensure atomicity.
      
      Closes Wei-Shaw/sub2api#1728
      6579f28b
  4. 16 Apr, 2026 1 commit
  5. 15 Apr, 2026 3 commits
    • erio's avatar
      feat(usage): add account cost to breakdown sub-table and admin usage log · db27e8f0
      erio authored
      - UserBreakdownItem: add AccountCost field + SQL aggregation
      - UserBreakdownSubTable: add orange account cost column
      - Admin usage table: add account_cost column (after cost, default visible)
      - Column settings: add account_cost toggle option
      db27e8f0
    • erio's avatar
      test(usage): add unit tests for account_cost and fix gofmt · 22680dc6
      erio authored
      - Fix mock for GetModelStatsWithFilters: add account_cost column
      - Add assertion: GetStatsWithFilters always returns TotalAccountCost
      - New test: GetModelStatsAccountCostColumn verifies scan of AccountCost
      - New test: GetGroupStatsAccountCostColumn verifies scan of AccountCost
      - New test: GetStatsWithFiltersAlwaysReturnsAccountCost (no AccountID filter)
      - Integration test: add TotalAccountCost/TodayAccountCost assertions
      - Fix gofmt alignment in usage_log_types.go
      22680dc6
    • erio's avatar
      feat(usage): add account cost display to admin dashboard and usage pages · 6ade6d30
      erio authored
      - Add account_cost column to dashboard aggregation tables (migration 107)
      - DashboardStats: add TotalAccountCost/TodayAccountCost fields
      - ModelStat/GroupStat: add AccountCost field with SQL aggregation
      - GetStatsWithFilters: always return TotalAccountCost (remove accountID filter)
      - Dashboard Token cards: show user(green)/cost(orange)/standard(gray)
      - Usage stats card: show account cost and standard below main value
      - Model/Group distribution tables: add orange cost column
      6ade6d30
  6. 14 Apr, 2026 18 commits
    • erio's avatar
      fix: merge 5 PR-related improvements · 58677dd5
      erio authored
      - gateway_handler: pass ParsedRequest to RecordUsage + set in gin.Context
      - channel_handler: add FeaturesConfig to CRUD (WebSearch channel toggle)
      - channel_repo: features_config JSONB persistence (Create/Get/Update/List)
      - security_headers: add Stripe CSP domains (script-src + frame-src)
      58677dd5
    • 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
      fix: resolve cherry-pick conflicts and restore compilation · d6965b06
      erio authored
      - Restore gateway_cache.go to upstream (no lua embeds)
      - Restore payment_order.go to upstream (use out_trade_no lookup)
      - Restore payment_fulfillment.go to upstream (same reason)
      - Add FeaturesConfig field and IsWebSearchEmulationEnabled to Channel
      - Add applyAccountStatsCost wrapper function
      - Add SettingKeyWebSearchEmulationConfig constant
      - Add WebSearchEmulationEnabled to SystemSettings
      - Add notify code rate limiting methods to EmailCache interface
      - Remove AllowUserRefund references (ent schema not present)
      - Fix duplicate import in payment_handler.go
      - Fix wire_gen.go argument mismatches
      d6965b06
    • erio's avatar
      fix: audit round-3 — proxy safety, intervals persistence, SMTP timeout, sort fix · 0a4ece5f
      erio authored
      - Skip websearch provider when ProxyID is set but proxy not found (prevent
        silent direct connection bypass)
      - Fix sortByStableRandomWeight: pair factors with items so sort.Slice swap
        keeps weights aligned
      - Allow empty platform in account_stats_pricing_rules (wildcard matching),
        only force anthropic default for main model_pricing
      - Add channel_account_stats_pricing_intervals table and repo layer support
        for interval-based pricing in account stats rules
      - calculateTokenStatsCost now uses interval pricing when available
      - Replace smtp.SendMail/tls.Dial with net.Dialer timeout (10s dial, 20s IO)
        to prevent goroutine leak on SMTP hang
      - Fix gofmt formatting issues
      - Web Search label: black text with red warning hint
      0a4ece5f
    • erio's avatar
      fix: round-2 audit fixes — security, code quality, and UI improvements · a9880ee7
      erio authored
      Security (HIGH):
      - Normalize all Redis cache keys to lowercase (verifyCode, passwordReset)
      - Fix verify code TTL renewal on failed attempts: use remaining TTL via
        ExpiresAt field instead of resetting to full 15-minute window
      - Add 3 missing fields to diffSettings audit log (promo_code, invitation_code,
        custom_endpoints)
      
      Code quality (MEDIUM):
      - Extract filterVerifiedEmails shared helper (balance_notify_service.go)
      - Add Pricing array non-empty validation for channel pricing rules
      - Add platform token semantics comment in gateway_service.go
      - Complete validatePlanPatch test coverage (+10 test cases)
      - Replace string types with QuotaThresholdType/QuotaResetMode across frontend
      - Remove duplicate getPlatformTextColor/getRateBadgeClass in ChannelsView
      - Return EMAIL_NOT_FOUND error on RemoveNotifyEmail miss
      
      UI improvements:
      - Reorder cost tooltip: user billing above separator, account billing below
      - Add NaN guard to accountBilled function
      - Move timezone selector inline into reset-mode row (no longer standalone)
      a9880ee7
    • erio's avatar
      fix: address audit findings for websearch, email verification, and pricing · 74f8a30f
      erio authored
      - Fix websearch provider failover: proxy error from provider-specific proxy
        now continues to next provider instead of aborting the entire loop
      - Fix SMTP failure locking users out: send email first, then write cache
        and increment rate counter
      - Fix notify email cache key case sensitivity: normalize to lowercase
      - Add OriginalPrice validation to validatePlanPatch and validatePlanRequired
      - Add empty scope validation for channel pricing rules (group_ids/account_ids)
      - Add platform color to account search dropdown in channel pricing rules
      74f8a30f
    • erio's avatar
      fix: batch 1 audit fixes — quota SQL fixed mode, public recharge URL,... · ed8a9d97
      erio authored
      fix: batch 1 audit fixes — quota SQL fixed mode, public recharge URL, WebSearch bool fallback, UpdatePlan validation
      
      H1: incrementUsageBillingAccountQuota now uses shared dailyExpiredExpr/weeklyExpiredExpr
          constants (supporting fixed reset mode) instead of hardcoded '24 hours'/'168 hours'
      H4: public settings endpoint now maps balance_low_notify_recharge_url
      H6: GetWebSearchEmulationMode tolerates legacy bool values (true→enabled)
      H7: UpdatePlan validates non-nil patch fields (rejects negative price, empty name, etc.)
      H8: UsageTable accountBilled() helper with total_cost ?? 0 null guard
      H9: AdminUsageLog TS type adds channel_id + billing_tier
      M2: account.go "fixed" literals replaced with thresholdTypeFixed constant
      M13: SystemSettings TS type adds web_search_emulation_enabled
      UI: QuotaLimitCard title labels now use flex-1 to align with flex-1 input boxes
      ed8a9d97
    • erio's avatar
      fix: audit fixes for websearch, notifications, and channel pricing · b7fb2e43
      erio authored
      P0: fix wildcard matching test assertion (config order, not longest prefix)
      P0: add TotalRecharged to auth cache snapshot (v5) for percentage threshold
      P1: move pricing rules into per-platform sections in ChannelsView
      P1: populate account name cache when editing existing channel rules
      P1: sanitize email subject headers to prevent SMTP injection
      P1: make Redis INCR+EXPIRE idempotent for rate limiting
      P1: deep copy FeaturesConfig in Channel.Clone()
      P2: clean up stale email="" placeholder comments
      P2: replace log.Printf with slog in email_service.go
      b7fb2e43
    • 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
      fix: address audit findings for notify, websearch and security · 4e96a6fa
      erio authored
      - Fix GetByKeyForAuth missing user.FieldEmail and user.FieldUsername (notifications sent to empty address)
      - Guard against empty email in collectBalanceNotifyRecipients
      - Remove non-atomic TotalRecharged read-modify-write in admin balance adjustment
      - HTML-escape userName/siteName/accountName in notification email templates
      - Fix timer leak in ProfileBalanceNotifyCard (add onUnmounted cleanup)
      - Add warning log on websearch proxy URL resolution failure
      4e96a6fa
    • erio's avatar
      fix: address audit findings for websearch and balance notification · 9e33d0c4
      erio authored
      - Fix GetByKeyForAuth not selecting balance notify fields (notifications
        never triggered in gateway path)
      - Fix provider-level ProxyURL never resolved: inject ProxyRepository into
        SettingService, resolve proxy URLs when building Manager
      - Fix admin manual balance adjustment not updating total_recharged
      - Add threshold_type input validation (reject invalid values)
      - Fix user threshold_type inheritance: custom threshold defaults to "fixed"
        instead of inheriting global type (prevents $5 being treated as 5%)
      - Add try-catch for clipboard.writeText (fails on non-HTTPS)
      - Add SetTotalRecharged to user Update for admin balance operations
      9e33d0c4
    • erio's avatar
      feat(notify): add percentage threshold type for balance low notification · f694afbb
      erio authored
      - Add threshold_type field (fixed/percentage) to system and user settings
      - Add total_recharged field to users table, auto-incremented on balance credit
      - Percentage mode: effective threshold = total_recharged × percentage / 100
      - User-level threshold_type inherits from system default when not set
      - Update admin settings UI with radio selector (fixed amount / percentage)
      - Migration: 102_add_balance_notify_threshold_type.sql
      f694afbb
    • 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(channels): add custom account stats pricing rules · 7535e312
      erio authored
      Allow channels to configure independent model pricing for account
      statistics cost calculation, decoupled from user billing.
      
      Backend:
      - Migration 101: channels.apply_pricing_to_account_stats toggle,
        channel_account_stats_pricing_rules/model_pricing tables,
        usage_logs.account_stats_cost column
      - resolveAccountStatsCost: match rules by group/account, then channel
        pricing, fallback to original formula when unconfigured
      - Integrate into both GatewayService.recordUsageCore and
        OpenAIGatewayService.RecordUsage
      - Update 8 account stats SQL queries to use
        COALESCE(account_stats_cost, total_cost) * account_rate_multiplier
      - 23 unit tests for matching, pricing lookup, and cost calculation
      
      Frontend:
      - Channel edit dialog: toggle + custom rules UI with group/account
        multi-select and pricing entry cards
      - API types and i18n (zh/en)
      7535e312
    • 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(channel): add missing features column to List query · 1c63ea14
      erio authored
      The paginated List query was selecting 9 columns but scanning 10 fields,
      missing c.features. GetByID and ListAll already included it correctly.
      1c63ea14
    • 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
    • erio's avatar
      style: apply gofmt formatting · 1cd033e5
      erio authored
      
      Co-Authored-By: default avatarClaude Opus 4.6 <noreply@anthropic.com>
      1cd033e5
  7. 10 Apr, 2026 1 commit
  8. 09 Apr, 2026 3 commits