- Separate title row (日限额 + 告警阈值) from input row
- Widen limit input to w-32 for better alignment with title
- Remove duplicate label from QuotaNotifyToggle (now in title row)
- Fix dropdown to always show $ or % as selected value
- Move dimension labels (日限额/周限额/总限额) inline with input row
- Replace $ / % toggle buttons with a compact dropdown select
- Reduce limit input width (w-28) to give more space for notify toggle
- Overall card height significantly reduced
Move notifyBalanceLow and notifyAccountQuota to goroutines so the
threshold checking logic (DB settings reads, threshold calculation,
crossing detection) no longer blocks the request thread. Both are
fire-and-forget with panic recovery and log-only error handling.
- 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
Priority was wrong:
- Before: custom rules → LiteLLM (when ApplyPricingToAccountStats) → nil
- After: custom rules → totalCost (when ApplyPricingToAccountStats) → LiteLLM → nil
When ApplyPricingToAccountStats is enabled, use the request's actual
client billing cost (before multiplier) as account_stats_cost, instead
of recalculating from LiteLLM per-token prices which produced incorrect
values for per-request billing mode.
LiteLLM model pricing is now the final fallback (priority 3), used only
when neither custom rules nor ApplyPricingToAccountStats apply.
Add slog.Info/Debug logs to notifyBalanceLow, notifyAccountQuota,
CheckBalanceAfterDeduction, and sendEmails to diagnose why balance
and quota notifications are not being sent in beta environment.
The field was present in SystemSettings response DTO and service layer
but missing from:
- UpdateSettingsRequest (admin handler) - saves were silently ignored
- GET/PUT response mapping in admin handler
- UpdateSettingsRequest (non-admin dto)
This caused the toggle to always revert to off after saving.
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.
Replace the stale Redis cache read + invalidation hack with direct DB
transaction RETURNING values:
- deductUsageBillingBalance: add RETURNING balance to get post-deduction balance
- incrementUsageBillingAccountQuota: extend RETURNING to include all 6 quota
dimensions (daily/weekly/total used+limit)
- Expand UsageBillingApplyResult with NewBalance and QuotaState fields
- finalizePostUsageBilling uses result directly, no Redis read needed
- CheckAccountQuotaAfterIncrement accepts optional QuotaState to skip
fetchFreshAccount when DB values are available
This eliminates the race condition where QueueDeductBalance async update
hadn't propagated to Redis before GetUserBalance read, causing oldBalance
to be inflated and threshold crossing detection to always fail.
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
- 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
- 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
Upstream removed sora feature (090_drop_sora.sql) but left i18n keys
and wire.go references. Clean up:
- Remove entire sora i18n block from en.ts and zh.ts (~190 lines)
- Remove sora nav key and unused 'data' settings tab key
- Remove sora_client_enabled from settings (fork-specific)
- Remove SoraMediaCleanupService from wire.go
The db139191 audit incorrectly removed the second URL decode pass.
EasyPay providers send values that need decoding after url.ParseQuery,
causing signature verification to fail on .147+.
Production .146 worked because it still had decodeURLValue.
The PaymentResultView only checked COMPLETED and PAID status, but orders
in RECHARGING state (balance being applied after payment) were incorrectly
shown as failed.
- Replace gradient header in subscription confirm with clean card layout
matching sub2apipay design (platform accent text instead of full gradient)
- Add renewal plan selection modal: when group has multiple plans show
picker, single plan skips directly to payment method selection
- Restyle SubscriptionsView with platform-specific colors (badge, border,
button) instead of hardcoded purple
- Update platformColors to match sub2apipay style (transparent badges,
subtle borders with /20 opacity)
UpdateProvider API returns raw DB entity (encrypted config, string types),
but frontend needs ProviderInstanceResponse (decrypted, array types).
Reload full list after save to ensure correct data and sort order.
- Create OrderTable.vue with shared cell rendering (ID, order number,
amount, payment method, status badge, created time)
- Accepts showUser prop to conditionally show user_email column
- Actions column uses scoped slot for view-specific buttons
- UserOrdersView and AdminOrdersView both use OrderTable
- Removes duplicated DataTable cell templates from both views
chore: bump version to 0.1.108.144