- Backend API returns/accepts supported_types as string[] (converts to/from DB comma string)
- Frontend ProviderInstance.supported_types is string[], no more parseTypes
- Remove all split/join conversions for supported_types
- payment_enabled_types also uses string[] consistently
- Backend: PENDING_ORDERS error uses reason+metadata per CLAUDE.md spec
- Block disabling provider when it has pending orders
- ProviderCard: remove bottom hint area, use opacity + title tooltip instead
- min/max/daily = 0 means no limit (no enforcement)
- Quick amounts: show all when no limit set
- Amount validation: skip check when limit is 0
- Placeholder: adaptive (shows range, ≥min, ≤max, or "输入金额")
- Remove card/link from global allPaymentTypes (they belong inside Stripe provider)
- Resolve i18n labels for Stripe sub-methods in provider dialog and card
- Split callback URLs into two independent inputs (notify/return each with own base URL + fixed path)
- Add eye icon toggle for sensitive fields (PKey etc.) to reveal/hide values
- Bump version to 0.1.108.35
- Limits section collapsible (default collapsed, auto-expand if has values)
- Empty input = use global config; reject values <= 0
- Input min changed from 0 to 1, placeholder changed to empty
- Hint: "留空表示使用全局配置"
- Callback URLs now split: editable base URL + read-only fixed path
- Base URL defaults to current domain, user can change it
- notifyUrl/returnUrl computed as baseUrl + fixed webhook path
- Edit loads existing base URL by extracting it from stored notifyUrl
- Dialog width set to wide for more space
- Strict validation: all required fields must be filled on both create/edit
- Edit mode: sensitive fields show ••••••••, must remain filled to save
- Non-sensitive fields pre-filled from backend on edit
- Empty defaults (notifyUrl/returnUrl) auto-filled if backend has no value
- Submit filters out •••••••• to keep existing backend credentials
- All required fields validated regardless of create/edit mode
- Backend: add ListProviderInstancesWithConfig that decrypts config
and masks sensitive fields (keys, secrets) as "••••••••"
- Frontend: pre-fill non-sensitive config values when editing provider
(PID, API base URL, notify URL, return URL, channel IDs etc.)
- Sensitive fields left empty for user to re-enter if needed
Replace the single AdminOrdersView with 4-tab layout with separate pages:
- /admin/orders/dashboard — payment dashboard with 7/30/90 day switcher
- /admin/orders — pure order list (removed channels/plans tabs)
- /admin/orders/config — payment config + provider management
- /admin/orders/plans — subscription plans (group dropdown) + user subscriptions
Delete AdminProvidersView (merged into config page).
Update sidebar to show 4 menu items instead of 1.
- Restore MigrateLegacyPurchaseURL auto-call on startup: converts old
purchase_subscription_url into a custom menu item (id: migrated_purchase_subscription)
and clears the legacy settings
- Delete PurchaseRouter.vue and PurchaseSubscriptionView.vue (replaced
by existing CustomPageView.vue via custom menu system)
- /purchase route now exclusively serves the new built-in payment system
- Remove purchase_subscription_enabled from sidebar, router, settings UI,
TypeScript types, and i18n keys
- Legacy purchase URL users will see their link as a custom menu entry
after upgrade, editable in admin custom menu settings
- Add PurchaseRouter.vue to dynamically render PaymentView or
PurchaseSubscriptionView based on payment_enabled vs
purchase_subscription_enabled settings
- Fix route guard to allow access when either payment system is enabled
- Split sidebar menu: /purchase shows for both systems, /orders only
for built-in payment
- Remove auto-migration that forcibly disabled legacy purchase system
on first startup (MigrateLegacyPurchaseURL)
- Add payment_enabled to PublicSettings API response so frontend can
check both systems from a single endpoint
- Restore legacy purchase link config UI controls in admin Payment tab
- Split payment settings save to use dedicated PUT /admin/payment/config
API instead of mixing into general settings endpoint
- Add admin payment config API functions (getConfig/updateConfig)
Critical:
- Refund idempotency keys now include UnixNano timestamp (alipay/wxpay)
- PaymentView passes qr/pay_url params to QR code page
- Fix dead code branch in order result handling
Quality:
- Currency symbol $ → ¥ in admin stats and refund dialog
- StripePaymentView setTimeout cleanup on unmount
- Webhook body size limited to 1MB (io.LimitReader)
- SubscriptionPlan features type documented
The previous Sora removal missed several frontend references, causing
TypeScript build errors for sora_client_enabled and a missing SoraView.vue
import. Clean up all remaining Sora code from types, router, sidebar,
settings, store, and accounts API.
- AdminOrderTable: reusable order table with search, filters, pagination
- AdminOrderDetail: order detail dialog with field grid and actions
- PaymentMethodChart: horizontal bar chart for payment distribution
- TopUsersLeaderboard: ranked top users table
P0-1: Credits degraded response retry + fail-open
- Add isAntigravityDegradedResponse() to detect transient API failures
- Retry up to 3 times with exponential backoff (500ms/1s/2s)
- Invalidate singleflight cache between retries
- Fail-open after exhausting retries instead of 5h circuit break
P1-1: Fix channel restriction pre-check timing conflict
- Swap checkClaudeCodeRestriction before checkChannelPricingRestriction
- Ensures channel restriction is checked against final fallback groupID
P1-2: Add interval pricing validation (frontend + backend)
- Backend: ValidateIntervals() with boundary, price, overlap checks
- Frontend: validateIntervals() with Chinese error messages
- Rules: MinTokens>=0, MaxTokens>MinTokens, prices>=0, no overlap
P2: Fix cross-platform same-model pricing/mapping override
- Store cache keys using original platform instead of group platform
- Lookup across matching platforms (antigravity→anthropic→gemini)
- Prevents anthropic/gemini same-name models from overwriting each other
- Backend: reject intervals with all-null price fields on save
- Backend: filterValidIntervals skips empty intervals in pricing resolver
- Frontend: red border + asterisk on empty interval rows
- Backend: antigravity groups now match anthropic/gemini channel pricing
- Show channel + account mapping steps using model_mapping_chain field
- Add model_mapping_chain to AdminUsageLog TypeScript type
- Fallback to two-level display when chain is not available
- Fix cost nil guard in Anthropic/Antigravity RecordUsage paths
- Bump version to 0.1.105.31