- Merge amount fields, toggles and limits into fewer rows
- Put payment types + load balance strategy on same line
- Compact provider cards (single-line info, inline edit/delete buttons)
- Reduce padding and gaps throughout
Add formatOrderID/parseOrderID helpers to prepend "sub2_" prefix to
order IDs sent to EasyPay, Alipay, Wxpay, and Stripe. This makes our
orders identifiable in third-party dashboards and prevents ID collision.
Callback handlers strip the prefix before looking up the DB record.
Internal audit logs keep using raw DB IDs.
- Delete AdminPaymentConfigView.vue (duplicated in SettingsView Payment tab)
- Remove /admin/orders/config route
- Plans table: show red "缺失/Missing" badge for deleted groups
- Plans table: group_id column shows group name or missing indicator
- Create utils/apiError.ts with extractApiErrorMessage() utility
- Replace all raw err.message/String(err) patterns in payment views
- Fix error display for API client interceptor's plain object errors
- Update CLAUDE.md with API error handling convention (section 13)
- Copy CLAUDE.md to AGENTS.md
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.
Replace Go startup code with SQL migration 096 to migrate
purchase_subscription_url to custom_menu_items. Database migrations
run exactly once and are tracked by the migration system.
- 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)
- payment_service: split GetDashboardStats (131→35 lines) into 4 sub-functions,
extract applyPagination helper, replace bubble sort with sort.Slice,
use sync.Once for EnsureProviders, define magic number constants
- providers: merge duplicate PC/Mobile functions in alipay/wxpay,
extract loadKeyPair/queryOrderTotalFen in wxpay, add centsToYuan in stripe,
define constants for success codes, currencies, event types
- handlers: extract requireAuth and parseIDParam helpers to eliminate
repeated auth/ID-parsing boilerplate
- registry: remove dead seen map in GetProviderByKey
- types: centralize order status constants in payment package
- load_balancer+config_service: unify duplicated containsType into
exported InstanceSupportsType function
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.
Antigravity groups were incorrectly matching pricing and model mapping
entries from anthropic/gemini platform tabs. Each platform should be
strictly isolated — antigravity groups only use antigravity-tagged pricing.
Restore gateway_service.go, setting_handler.go, routes/admin.go,
dto/settings.go, group_repo.go, api_key_repo.go, wire_gen.go to
upstream/main versions and surgically remove only Sora references.
This preserves upstream-only features (RequireOauthOnly, RequirePrivacySet,
GroupResolution, etc.) that were missing when using release branch versions.
C1: Add EnsureProviders() lazy initialization to populate Registry
from PaymentProviderInstance DB rows at first use
C2: Delete stale payment/provider_factory.go dead code
C3: Add PaymentOrderExpiryService background ticker (60s interval)
C4: Expand DashboardStats with daily_series, payment_methods, top_users
C5+C6: Add 152 payment i18n keys (en + zh) for admin and settings pages
C7: Fix Stripe global key race — use per-instance client.API
I1: Remove old purchase_subscription_enabled/url from settings form
I2: Add MigrateLegacyPurchaseURL to auto-convert old URL to custom menu
I3: Add migration 092 no-op placeholder for numbering continuity