- 14 Apr, 2026 38 commits
-
-
erio authored
- EditAccountModal width changed from "normal" to "wide" (match CreateAccountModal) - CreateAccountModal now passes all quota notify props to QuotaLimitCard - QuotaLimitCard: when global notify disabled, hide title row, input takes full width - Quota alert email: show remaining quota + threshold (fixed/$, percentage/%) instead of usage trigger point
-
erio authored
-
erio authored
-
erio authored
- Quota alert email now shows account ID and platform - Balance low email includes a "Top Up Now" button when recharge URL is configured - New setting: balance_low_notify_recharge_url in admin settings
-
erio authored
-
erio authored
Threshold now represents remaining quota instead of usage amount: - Fixed ($): threshold=400, limit=1000 → alert when remaining drops to $400 (i.e., usage reaches $600) - Percentage (%): threshold=30%, limit=1000 → alert when remaining drops to 30% (i.e., usage reaches $700) Also: - Rename 告警阈值 → 提醒阈值 in i18n - Widen type dropdown to w-16 for proper $ / % display
-
erio authored
Move QuotaNotifyToggle to the same row as the limit $ input for all three dimensions (daily/weekly/total), significantly reducing card height.
-
erio authored
- QuotaLimitCard: add collapse/expand toggle (chevron icon + click header) - QuotaNotifyToggle: show $ or % suffix in threshold input - Reduce vertical spacing between reset mode hint and notify toggle
-
erio authored
- QuotaNotifyToggle: add $ or % suffix to threshold input based on type - QuotaLimitCard: combine reset mode and notify toggle on same row to reduce vertical height for daily/weekly sections - Remove redundant ml-4 indentation from QuotaNotifyToggle
-
erio authored
- "默认(跟随渠道)" → "默认", "Default (follow channel)" → "Default" - Move "follows channel config" info to description text - Reduce select width from w-32 to w-24 in both Edit and Create modals
-
erio authored
QuotaLimitCard now requires quotaNotifyGlobalEnabled prop to control visibility of QuotaNotifyToggle components. When the global account quota notification is disabled in admin settings, per-account threshold toggles are hidden in both Edit and Create account modals.
-
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
-
erio authored
Backend fixes: - Fix balance notify ignoring percentage threshold type (was treating percentage value as fixed USD amount) - Remove dead code parseJSONStringArray - Add ImageOutputTokens to tryModelFilePricing calculation - Unify zero-value check: cost == 0 → cost <= 0 in calculateTokenStatsCost - Use MarshalNotifyEmails instead of json.Marshal for consistency - Rename quotaDim.oldUsed → currentUsed for clarity - Extract HTML email templates to const variables (function ≤30 lines) Test fixes: - Rewrite account_websearch_test.go for GetWebSearchEmulationMode tri-state - Add 6 tryModelFilePricing test cases Frontend fixes: - Replace hardcoded '未命名' with i18n key - Extract getBillingModeLabel/getBillingModeBadgeClass to shared utils - Replace inline type with imported NotifyEmailEntry - Pass platform to AccountStats pricing rules via inferRulePlatform() - Add billing mode constants (BILLING_MODE_TOKEN/PER_REQUEST/IMAGE)
-
erio authored
WebSearch tri-state switch: - Account-level web_search_emulation changed from bool to tri-state string: "default" (follow channel) / "enabled" / "disabled" - shouldEmulateWebSearch checks channel config when account is "default" - SQL migration converts old bool values - Frontend select replaces toggle in Edit/CreateAccountModal Account stats pricing: - resolveAccountStatsCost uses upstream model (post-mapping) for matching - Priority: custom rules → model pricing file (when toggle on) → default - Custom rules always configurable, independent of toggle - Account ID field changed to searchable selector filtered by platform - Description updated to reflect new behavior Quota notification cache fix: - CheckAccountQuotaAfterIncrement fetches real-time account from DB - Reconstructs pre-increment usage for accurate threshold crossing detection - New AccountQuotaReader interface (minimal: GetByID only) Usage tooltip: - Per-request/image billing shows per-request price instead of $0 token price - Token billing continues to show input/output price per million tokens
-
erio authored
- resolveAccountStatsCost now uses the final upstream model (after account-level mapping) to match custom pricing rules, fixing the issue where requested model (e.g. claude-sonnet-4-5) didn't match rules configured for upstream model (e.g. claude-opus-4-6) - Remove tryChannelPricing fallback — only custom rules are applied, unmatched requests use default formula (total_cost × rate) - Remove unused billingService and serviceTier parameters - Update description: "启用后将支持自定义账号统计的模型价格"
-
erio authored
- Add "verify" button next to saved unverified emails in ProfileBalanceNotifyCard (send code → enter code → verify) - Backend: VerifyAndAddNotifyEmail now marks existing unverified emails as verified instead of returning "already exists" - Inline verification UI with countdown timer and resend button
-
erio authored
- Fix cached balance causing threshold crossing to never trigger: read real-time balance from billingCacheService instead of stale API key auth snapshot - Remove email="" placeholder concept; all emails are user-managed - Only send notifications to verified && non-disabled emails - Frontend: pre-fill user's email in add input when list is empty - Remove FilterEnabledEmails/IsPrimaryDisabled helpers (no longer needed)
-
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 -
erio authored
Replace blur-based auto-save with an explicit Save button so users know when their threshold is persisted. Shows success toast on save.
-
erio authored
-
erio authored
- Show system default threshold as placeholder in custom threshold input - Display user's primary email with "Primary" badge - Support adding multiple pending emails before verification - Each pending email has independent send/verify/resend flow - Expose balance_low_notify_threshold in PublicSettings API - Clean up timers on unmount to prevent leaks
-
erio authored
Only show the inline eye/copy buttons when provider.api_key has a value. When only api_key_configured is true (saved key, not loaded), buttons are hidden since there's nothing to show/copy.
-
erio authored
- Basic settings now only shows the global toggle - Custom pricing rules appear inside each platform tab when toggle is on - Group selector in rules scoped to the current platform's groups - Remove unused allFormGroupIds computed
-
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
-
erio authored
- Add global toggle for account quota notification in admin settings - Add percentage-based threshold type for per-account quota alerts - Hide balance notify card on user profile when global toggle is off - Expose balance_low_notify_enabled and account_quota_notify_enabled in PublicSettings - Add threshold type (fixed/percentage) to QuotaNotifyToggle with $ / % switcher
-
erio authored
- API Key show/copy buttons moved inside input field (inline icons) - Proxy selector and test button on same row to save vertical space - Test opens a dialog modal instead of inline display - Hide all websearch config in channels/accounts when global toggle is off
-
erio authored
Balance low notification only supports fixed USD amount threshold. Percentage threshold is a quota concept, not applicable to balance. Reverted threshold_type from admin settings, user profile, and all backend/frontend layers. DB fields (balance_notify_threshold_type, total_recharged) retained for potential future quota use.
-
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
-
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
-
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
-
erio authored
- Fix accountCost calculation in finalizePostUsageBilling to match postUsageBilling (always multiply by AccountRateMultiplier) - Use strings.EqualFold for email dedup in collectBalanceNotifyRecipients - Extract CheckAccountQuotaAfterIncrement into smaller functions: buildQuotaDims + asyncSendQuotaAlert (< 30 lines each) - Add "not splittable" comments for HTML template functions - Extract QuotaNotifyToggle.vue sub-component to reduce QuotaLimitCard.vue from 404 to 339 lines
-
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
-
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)
-
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)
-
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
-
erio authored
Backend: - Define OrderTypeBalance/Subscription, EntityStatusActive, DeductionType*, NotificationStatus* constants in payment/types.go - Replace all magic strings in payment_order, payment_fulfillment, payment_refund - Add local constants in easypay.go (tradeStatusSuccess, signTypeMD5) - Add 27 unit tests for load balancer (filterByLimits, pickLeastAmount, getInstanceChannelLimits, startOfDay) Frontend: - Remove all `any` types in SettingsView.vue (18 catch blocks + 1 payload) - Fix bare catch blocks in PaymentResultView, PaymentView - Add `unknown` type annotation to all catch blocks chore: bump version to 0.1.108.140
-
erio authored
Backend: - Extract YuanToFen/FenToYuan to payment/amount.go using shopspring/decimal - Require alipay publicKey in config validation - Fix wxpay webhook response to return JSON per V3 spec - Remove wxpay certSerial fallback to publicKeyId - Define magic strings as named constants in wxpay/alipay providers - Add slog warning for wxpay H5→Native payment downgrade - Make EncryptionKey validation return error on invalid (non-empty) key - Make decryptConfig propagate errors instead of returning nil - Add idempotency check in doBalance to prevent stuck FAILED retries Frontend: - Fix dashboard currency symbol from $ to ¥ - Fix AdminPaymentPlansView any type to proper SubscriptionPlan type - Make quick amount buttons follow selected payment method limits - Center help image with larger height and text below
-
erio authored
-
- 13 Apr, 2026 2 commits
-
-
knowsky404 authored
-
erio authored
Closes #1607
-