Commit Graph
3645 Commits
Author SHA1 Message Date
erio f059ad02be chore: bump version to 0.1.110.8 2026-04-12 13:18:30 +08:00
erio 9d3376cbdb Merge branch 'worktree-feature+balance_notify' into release/custom-0.1.110
# Conflicts:
#	backend/internal/handler/admin/setting_handler.go
#	backend/internal/service/domain_constants.go
#	backend/internal/service/setting_service.go
#	backend/internal/service/settings_view.go
2026-04-12 13:17:28 +08:00
erio 21e6d68925 feat(websearch): settings UI overhaul and quota improvements
- 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
2026-04-12 13:11:46 +08:00
erio 48488652f2 fix(notify): per-recipient timeout and return user on email removal
- Use per-recipient context timeout in sendEmails to prevent later
  recipients from failing due to shared timeout exhaustion
- Return updated user object from RemoveNotifyEmail handler for
  frontend state consistency (matching VerifyNotifyEmail pattern)
2026-04-12 12:50:27 +08:00
erio 10166c72e6 fix(notify): address review findings - accountCost formula, dedup, refactor
- 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
2026-04-12 12:48:17 +08:00
erio 8f93b69584 feat(notify): add balance low & account quota notification system
- 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
2026-04-12 02:48:57 +08:00
erio 6f24322ee6 chore: bump version to 0.1.110.7 2026-04-12 02:27:19 +08:00
erio d65efd6f5c fix(websearch): improve isProxyError detection and add manager tests
- Add TLS error detection to isProxyError (RecordHeaderError, handshake)
- Case-insensitive error string matching
- Add 19 unit tests for: isProviderAvailable, resolveProxyID,
  isProxyError, isProxyAvailable, selectByQuotaWeight, newHTTPClient
2026-04-12 02:20:02 +08:00
erio e869c26789 fix: gofmt websearch manager 2026-04-12 01:55:00 +08:00
erio 4e5072df3c feat(websearch): proxy failover, timeout, quota-weighted load balancing
- Use proxyutil.ConfigureTransportProxy for unified proxy protocol support
  (HTTP/HTTPS/SOCKS5/SOCKS5H), replacing ad-hoc HTTP-only proxy code
- Proxy errors return ErrProxyUnavailable → gateway triggers account switch
  via UpstreamFailoverError instead of fallback to direct connection
- Timeout: proxy dial 3s, TLS handshake 3s, data transfer 60s
- Mark proxy unavailable for 5 minutes in Redis on connectivity failure
- Quota-weighted load balancing: providers with quota_limit>0 are selected
  by remaining quota (weighted random); quota_limit=0 providers treated as
  0% weight and placed last
2026-04-12 01:48:06 +08:00
erio 6986546d06 chore: bump version to 0.1.110.6 2026-04-12 01:06:31 +08:00
erio 0622fc71ee merge: integrate websearch emulation feature from worktree branch
Merge worktree-feature+websearch_support into release/custom-0.1.110.
Resolved conflicts in channel repo/service/handler/frontend (both
features_config and account_stats_pricing fields kept).
Fixed ProxySelector missing proxies prop in SettingsView.
2026-04-12 01:00:14 +08:00
erio 4d9d48fade feat(channels): add custom account stats pricing rules
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)
2026-04-12 00:31:57 +08:00
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 473746a09d chore: bump version to 0.1.110.5 2026-04-11 20:58:12 +08:00
erio 1ed3b4bd8e feat(settings): add EasyPay provider recommendation link below enabled providers 2026-04-11 20:57:36 +08:00
erio 59b2c9a424 docs: align English ZPay referral description with Chinese version 2026-04-11 20:52:12 +08:00
erio aed7d2e5e3 docs: clarify ZPay referral code belongs to Sub2ApiPay author @touwaeriol 2026-04-11 20:48:44 +08:00
erio a91e06b228 feat(settings): add payment config guide link in payment settings header 2026-04-11 20:46:47 +08:00
erio 98837e454c docs: show ZPay URL explicitly in parentheses 2026-04-11 20:39:28 +08:00
erio 3a44a9ba64 docs: move ZPay recommendation to overview section 2026-04-11 20:35:57 +08:00
erio 6294e36de0 docs: add ZPay referral recommendation to EasyPay section 2026-04-11 20:30:50 +08:00
erio d707f3c22e fix(docs): correct webhook paths and provider config in payment guide
- Fix webhook URLs: /payment/webhook/<provider> not /payment/<provider>/notify
- Remove notifyUrl/returnUrl from provider config tables (auto-generated by UI)
- Adjust wxpay publicKeyId/certSerial to match frontend optional marking
2026-04-11 20:15:59 +08:00
erio 27e2a51f31 docs: add built-in payment guide and update README ecosystem section
- Add docs/PAYMENT.md and docs/PAYMENT_CN.md with full payment configuration guide
- Mark Sub2ApiPay as deprecated (strikethrough) in all 3 READMEs, link to built-in payment docs
- Add built-in payment system to features list
2026-04-11 19:54:25 +08:00
erio 0401b77204 fix: resolve TS errors from upstream merge
- Fix ApiResponse cast to Record<string,unknown> via double assertion
- Add missing default_mapped_model to editForm reactive (lost in merge)
2026-04-11 19:09:31 +08:00
erio 6c96aaec8c chore: bump version to 0.1.110.4 2026-04-11 19:03:34 +08:00
erio 94d91d69a9 chore: clean up sora_client_enabled and purchase_subscription residuals
- Remove sora_client_enabled from PublicSettings type and store defaults
- Remove purchase_subscription form defaults and save payload from SettingsView
- Remove dead 'data' tab type from SettingsTab union
2026-04-11 18:55:32 +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 d3d3a55f1f fix(payment): propagate reason/metadata in API error responses
The API client's error interceptor was dropping the reason and metadata
fields from backend error responses. This caused PaymentView to miss
specific error codes (TOO_MANY_PENDING, CANCEL_RATE_LIMITED) and fall
back to generic error messages.
2026-04-11 17:52:15 +08:00
erio dc31732b7a fix(deps): upgrade axios to 1.15.0 to fix GHSA-fvcv-3m26-pcqx 2026-04-11 16:46:26 +08:00
Wesley Liddick 1ef3782dd4 Merge pull request #1538 from IanShaw027/fix/bug-cleanup-main
fix: 修复多个 UI 和功能问题 - 表格排序搜索、导出逻辑、分页配置和状态筛选
2026-04-11 16:29:55 +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 75deeb6e17 docs: update CLAUDE.md with correct PR and release workflows
- Release flow: start from our release branch, merge upstream in (not reverse)
- PR flow: base on upstream/main, cherry-pick from release, never merge PR into release
- Add forbidden files list, PR checklist, reverse sync instructions
- Add feat/* branch to branch strategy table
2026-04-11 14:50:07 +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