Commit Graph
2659 Commits
Author SHA1 Message Date
erio f3d2c1931c fix(lint): resolve depguard violation — remove redis import from service layer
Service layer must not import redis directly (depguard rule). Replace
*redis.Client field with WebSearchManagerBuilder callback injected by
the infra layer. Also fix remaining errcheck in manager_test.go.
2026-04-12 00:28:21 +08:00
erio 6df42dd4bd fix(lint): resolve golangci-lint errcheck and gofmt issues
- Add errcheck handling for w.Write, json.Encode in test handlers
- Use defer func() { _ = resp.Body.Close() }() pattern
- Use safe two-return type assertions in websearch_config.go
- Fix gofmt alignment in setting_service.go struct fields
2026-04-12 00:17:52 +08:00
erio 15452fdacf fix(test): add web_search_emulation_enabled to API contract test
The settings API response now includes the new field; update the
expected snapshot in TestAPIContracts to match.
2026-04-12 00:09:28 +08:00
erio c2deb0939d feat(gateway): add web search emulation for Anthropic API Key accounts
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)
2026-04-12 00:02:26 +08:00
erio 6c96aaec8c chore: bump version to 0.1.110.4 2026-04-11 19:03:34 +08:00
erio 989c5faad5 Merge remote-tracking branch 'upstream/main' into release/custom-0.1.110
# Conflicts:
#	.github/audit-exceptions.yml
#	backend/cmd/server/VERSION
#	backend/go.sum
#	backend/internal/handler/admin/setting_handler.go
#	backend/internal/handler/dto/settings.go
#	backend/internal/repository/channel_repo.go
#	backend/internal/service/channel_service.go
#	backend/internal/service/setting_service.go
#	backend/internal/service/settings_view.go
#	frontend/src/api/admin/settings.ts
#	frontend/src/stores/app.ts
#	frontend/src/types/index.ts
#	frontend/src/views/admin/SettingsView.vue
2026-04-11 18:41:54 +08:00
erio f18d4ebbba chore: remove all sora dead code and fork-specific sora_client_enabled
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
2026-04-11 18:13:38 +08:00
erio 6d7e0642a0 chore: remove unused decodeURLValue and clean up formatting 2026-04-11 16:29:51 +08:00
erio a5a5d93de7 chore: bump version to 0.1.110.3 2026-04-11 16:10:09 +08:00
erio d60015f1d1 revert(payment): remove active upstream sync, keep webhook-only approach
Reverts the sync polling mechanism that queried upstream providers on
each frontend poll. Keep the Stripe expiresAt countdown fix.
2026-04-11 16:10:09 +08:00
erio 017f23bfa3 chore: bump version to 0.1.110.2 2026-04-11 15:46:43 +08:00
erio 576c34bbf7 fix(payment): add active upstream sync to polling and fix Stripe countdown
- Add POST /payment/orders/:id/sync endpoint that queries upstream
  provider on each poll, complementing webhooks for timely payment
  detection when webhooks are delayed or unreachable
- Fix Stripe payment countdown: pass expires_at to PaymentStatusPanel
  instead of empty string (was falling back to hardcoded 30 minutes)
- Idempotent: toPaid uses atomic UPDATE WHERE status=PENDING, so
  concurrent webhook + sync calls won't double-credit
2026-04-11 15:46:28 +08:00
erio b3d4ea5aa6 chore: bump version to 0.1.110.1 2026-04-11 14:49:36 +08:00
erio b5b5e35757 refactor(payment): code standards fixes and file organization
Cherry-picked from PR branch (feat/payment-system-v2).
- Use payment.Type* constants instead of magic strings in factory
- Add wxpay success response constants
- Add validity unit constants (week/month)
- Add constants for easypay popup mode
- Split payment_order.go into payment_order_lifecycle.go
- Extract shared order utilities to orderUtils.ts
- Improve admin order components to use shared utilities
- Removed duplicate migration (097 already exists)
2026-04-11 13:24:17 +08:00
erio f4e4b1539b feat(payment): add H5/mobile payment support
Cherry-picked from PR branch (feat/payment-system-v2).
- EasyPay: parse payurl2 for H5 mobile links, prefer on mobile
- EasyPay: add device=mobile for popup mode on mobile
- Backend: expand isMobile() to detect iPad/iPod
- Frontend: auto-redirect on mobile instead of popup
- Frontend: fallback to redirect when popup blocked
- Stripe: use mobile_web client for WeChat Pay on mobile
- StripePopup: typed interface, extractApiErrorMessage
2026-04-11 13:22:12 +08:00
IanShaw027 f480e57344 fix: align table defaults and preserve sidebar svg colors 2026-04-10 18:27:53 +08:00
IanShaw027 7dc7ff22d2 fix: preserve messages dispatch config in repository hydration 2026-04-10 18:13:18 +08:00
IanShaw027 67a05dfccd fix: honor table defaults and preserve dispatch mappings 2026-04-10 17:55:37 +08:00
erio 4a3383ecdd fix(payment): widen popup window to 1000px for Alipay+ checkout
Alipay+ checkout page needs ~960px to display QR code and order details
side by side. Previous 680px forced users to manually resize.
2026-04-10 16:45:47 +08:00
erio 9d4b02688f Revert "fix(payment): restore decodeURLValue in EasyPay webhook verification"
This reverts commit 1430c82078.
2026-04-10 16:43:21 +08:00
erio 1430c82078 fix(payment): restore decodeURLValue in EasyPay webhook verification
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.
2026-04-10 16:40:42 +08:00
erio 7547ea9f4e fix(payment): include RECHARGING in result page success states
The PaymentResultView only checked COMPLETED and PAID status, but orders
in RECHARGING state (balance being applied after payment) were incorrectly
shown as failed.
2026-04-10 16:23:23 +08:00
erio 0113bf60fd feat(payment): renewal modal, clean confirm card, platform color refresh
- 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)
2026-04-10 16:12:28 +08:00
erio 9df96a45c7 feat(payment): redesign Stripe popup to match sub2apipay clean card style
Replace purple gradient header with clean white card layout, method-specific
colored amount text and spinner, larger card and spinner sizes.
2026-04-10 15:50:28 +08:00
erio 8bf91c0915 revert: remove double URL decode, provider-side encoding issue 2026-04-10 14:34:50 +08:00
erio 9b38e44e1d fix(payment): restore double URL decode for EasyPay webhook values
EasyPay callbacks arrive with double-encoded query values (e.g. %25E5 instead
of %E5) due to redirect chains. url.ParseQuery decodes once; decodeURLValue
applies a second safe decode so the sign matches what EasyPay computed.
Also removes temporary debug logging.
2026-04-10 14:27:44 +08:00
erio 72f7677815 debug: log webhook raw body and sign comparison 2026-04-10 14:17:39 +08:00
erio 7ea6cafadb debug: add webhook provider lookup logging 2026-04-10 14:10:37 +08:00
erio 0f32416d5d chore: bump version to 0.1.108.148 2026-04-10 14:04:19 +08:00
erio d642a16f79 fix(payment): webhook uses order's provider instance for signature verification
When multiple provider instances exist (e.g. 3 EasyPay accounts), the webhook
handler now extracts out_trade_no from the callback, looks up the order, and
uses the order's original provider instance for verification instead of picking
an arbitrary instance from the registry.
2026-04-10 14:03:59 +08:00
erio a92c0eabbc chore: bump version to 0.1.108.147 2026-04-10 10:42:30 +08:00
erio cd1bbebb77 feat(payment): subscription renewal UI, payment button colors, QR branding, refund day deduction
- Add btn-alipay/btn-wxpay CSS classes; confirm button color follows payment method
- Subscription confirm header uses platform gradient (Anthropic orange, Gemini blue, etc.)
- Subscription confirm page shows plan details (rate, limits, validity)
- SubscriptionPlanCard: show "Renew" button when user has active subscription
- SubscriptionsView: add renewal button on active subscription cards
- QR code display: brand-color border + center logo overlay (Alipay blue, WeChat green)
- StripePaymentView: WeChat QR green border + logo, Alipay spinner brand color
- Backend: fix subscription refund to deduct days (ExtendSubscription -days or Revoke)
- Backend: rollback subscription days on gateway failure
2026-04-10 10:42:06 +08:00
IanShaw027 1312405966 fix(settings): 补齐公开设置中的表格分页字段返回 2026-04-10 09:18:48 +08:00
erio db139191e3 fix(payment): critical audit fixes for security, idempotency and correctness
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
2026-04-10 02:23:19 +08:00
erio 72b77306da fix(admin): reload provider list after save to get correct data format
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.
2026-04-10 01:28:54 +08:00
erio e45c774ab9 fix(payment): refresh provider registry on config changes
- Call RefreshProviders after Create/Update/Delete provider instance
- Call RefreshProviders after saving payment settings
- Auto-save settings when provider dialog saves
- Fixes webhook signature verification using stale pkey
2026-04-10 00:50:12 +08:00
erio 62e9453ddc refactor(frontend): extract shared OrderTable component
- 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
2026-04-09 23:49:47 +08:00
erio 753a87dee3 feat(admin): add user info and keyword search to admin order list
Backend:
- Add Keyword field to OrderListParams
- AdminListOrders supports keyword search on out_trade_no, user_email, user_name
- PaymentOrder already has user_email/user_name/user_notes fields (no join needed)

Frontend:
- Replace inline status badge with OrderStatusBadge component
- Replace user_id column with user_email (shows email, fallback to username, with notes)
- Keyword search matches order number and user info

chore: bump version to 0.1.108.143
2026-04-09 23:41:59 +08:00
erio e9aa1b1330 fix(payment): use order's original provider instance for refund
Previously gwRefund used registry.GetProvider(paymentType) which returns
an arbitrary instance for that type. When multiple instances share the
same payment type (e.g., two EasyPay merchants both supporting alipay),
the refund would be sent to the wrong merchant.

Now getRefundProvider() reads the order's ProviderInstanceID, loads that
instance's config, and creates the correct provider. Falls back to
registry lookup for legacy orders without an instance ID.

chore: bump version to 0.1.108.142
2026-04-09 23:21:38 +08:00
erio 69f885eb5f style: fix gofmt formatting in payment_handler.go 2026-04-09 22:52:11 +08:00
erio 63c4172dd9 fix(ci): upgrade Go to 1.26.2 for security fixes, fix flaky WS test
- Upgrade Go from 1.26.1 to 1.26.2 in go.mod and Dockerfile to fix
  govulncheck findings (GO-2026-4947, GO-2026-4946, GO-2026-4870, etc.)
- Fix flaky PassthroughModeRelaysByCaddyAdapter test: tolerate
  StatusNormalClosure error from server after client closes connection
2026-04-09 22:38:39 +08:00
IanShaw027 269c7a065c fix(test): restore integration expectations 2026-04-09 22:08:42 +08:00
IanShaw027 b6946e78a2 fix(lint): restore repository sort helpers 2026-04-09 21:49:10 +08:00
erio cc858c3cc9 feat(admin): enhance refund workflow to match sub2apipay
Admin order list:
- Add REFUND_REQUESTED "approve refund" button with amount badge
- Add REFUND_FAILED "retry refund" button
- Add missing status filters (REFUND_REQUESTED, REFUND_FAILED)
- Order detail dialog: show refund request info + audit logs

Admin refund dialog:
- Show refund request info card (violet) when user requested
- Display user balance with insufficient balance warning
- Add "no deduction" info when deduct_balance unchecked
- Add force refund checkbox (shown when requireForce=true)
- Add warning display prop
- Pre-fill reason from user's refund request
- Default deduct_balance to true

chore: bump version to 0.1.108.141
2026-04-09 21:47:39 +08:00
IanShaw027 2b70d1d332 merge upstream main into fix/bug-cleanup-main 2026-04-09 21:35:48 +08:00
IanShaw027 b37afd68ec fix(lint): format setting service 2026-04-09 21:31:48 +08:00
erio ceee2d0584 fix: audit fixes - magic strings to constants, frontend any/catch, LB tests
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
2026-04-09 21:29:49 +08:00
erio 44a9d91c8f refactor(payment): rewrite load balancer with complete limit checking
- Batch-query daily usage in one SQL (GroupBy) instead of N queries
- Include PENDING orders in daily usage to prevent over-committing
- Check remaining capacity (used + orderAmount > limit) not just used >= limit
- Check SingleMin/SingleMax per-channel limits
- Pre-attach usage to candidates, reuse across filter and strategy pick
- Fallback to full list with warn log when all instances exhausted

chore: bump version to 0.1.108.139
2026-04-09 21:20:13 +08:00
Wesley Liddick 00c08c574e Merge pull request #1539 from warksu/fix/loadfactor-not-synced-to-scheduler-cache
fix: 同步 LoadFactor 到调度快照缓存
2026-04-09 21:15:40 +08:00
erio 8808910ee7 fix(frontend): unify currency to $ and add order number to admin orders
- Replace all ¥ / ¥ with $ across all payment views and components
- Add out_trade_no column to admin order list table
- Add order number field to admin order detail dialog

chore: bump version to 0.1.108.138
2026-04-09 21:14:57 +08:00