- 27 Apr, 2026 4 commits
-
-
- 修复返利不到账的根因:tryClaimAffiliateRebateAudit 中 PostgreSQL 参数类型推断冲突 - 补全 OAuth 注册路径(LinuxDo/OIDC/WeChat/Pending Flow)的邀请码绑定 - 前端 OAuth 注册页面传递 aff_code 参数 - 新增返利冻结期机制:可配置冻结时间,到期后自动解冻(懒解冻) - 新增返利有效期:绑定后 N 天内有效,过期不再产生返利 - 新增单人返利上限:超出上限部分精确截断 - 增强返利流程 slog 结构化日志,便于排查问题 - 已邀请用户列表增加返利明细列
-
- 在系统设置「功能开关」中新增邀请返利总开关,默认关闭; 关闭态:菜单隐藏、注册忽略 aff、新充值不返利,但已有 quota 仍可转余额 - 支持管理员为指定用户设置专属邀请码(覆盖随机码,全局唯一) - 支持管理员为指定用户设置专属返利比例(覆盖全局比例,可单条/批量调整) - 在系统设置邀请返利卡片内嵌入专属用户管理表格(搜索/编辑/批量/删除), 删除采用项目通用 ConfirmDialog,会同时清除专属比例并把邀请码重置为系统随机码 - /affiliate 用户页新增「我的返利比例」卡片与动态使用说明,让用户直观看到 分享后能拿到多少(同源 resolveRebateRatePercent 计算,与实际充值一致) - 新增数据库迁移 132 添加 aff_rebate_rate_percent 与 aff_code_custom 列 - 新增 admin 路由组 /api/v1/admin/affiliates/users/* 共 5 个端点 - AffiliateService 改为只依赖 *SettingService,去除冗余的 SettingRepository - 邀请码格式校验放宽到 [A-Z0-9_-]{4,32},兼容旧 12 位系统码与新自定义码 - 补充单元测试与集成测试覆盖新方法、冲突路径与边界值
-
- 23 Apr, 2026 3 commits
-
-
erio authored
Revert payment/wechat, sora/claude-max cleanup, fork-only migrations, and cosmetic changes that were brought in by the release sync commit. Keep only channel-monitor related improvements: - PublicSettingsInjectionPayload named struct with drift test - ChannelMonitorRunner graceful shutdown in wire - image_output_price in SupportedModelChip - Simplified buildSelfNavItems in AppSidebar - Gateway WARN logs for 503 branches
-
erio authored
- Extract PublicSettingsInjectionPayload named struct with drift test - Add channel_monitor_default_interval_seconds to SSR injection - Add image_output_price to SupportedModelChip - Simplify AppSidebar buildSelfNavItems (admins see available channels) - Add gateway WARN logs for 503 no-available-accounts branches - Wire ChannelMonitorRunner into provideCleanup for graceful shutdown - Add migrations 130/131 (CC template userid fix + mimicry field cleanup) - Clean up fork-only features (sora, claude max simulation, client affinity) - Remove ~320 obsolete i18n keys - Add codexUsage utility, WechatServiceButton, BulkEditAccountModal - Tidy go.sum
-
james-6-23 authored
P0: - rpm_override 嵌入 Auth Cache Snapshot,消除每请求 DB 查询 (snapshot v6→v7) - 429 RPM 响应返回 Retry-After 头(当前分钟剩余秒数) P1: - ClearAll 按钮直连 DELETE API,带 loading 防重复 - 新增 GET /admin/users/:id/rpm-status 管理员 RPM 用量查询端点 优化: - checkRPM 从级联互斥改为并行取最严,user.rpm_limit 作为全局硬上限始终生效 - Override/Group 变更后自动失效 auth cache - fail-open 语义不变,Redis 故障不阻塞业务
-
- 22 Apr, 2026 5 commits
-
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
- 21 Apr, 2026 8 commits
-
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
erio authored
Add a DB-backed soft switch "available_channels_enabled" controlling the user-facing /channels/available endpoint and sidebar entry. Default to false (opt-in) — the feature stays invisible until an admin enables it under Admin Settings > Features. - domain_constants: SettingKeyAvailableChannelsEnabled - settings_view: AllSettings/PublicSettings + AvailableChannelsEnabled - setting_service: public+all read/write, seed default "false", GetAvailableChannelsRuntime helper (fail-closed on read error) - admin setting_handler: UpdateSettingsRequest *bool + update branch + audit diff entry - public setting_handler: expose via GET /api/v1/settings - available_channel_handler: featureEnabled() guard — returns empty list after auth when disabled (401 precedes the feature check to preserve existing behavior)
-
erio authored
Remove the admin-side "Available Channels" aggregate view — admins already see full channel configuration (groups, pricing, model mappings) in the channel edit dialog, making a read-only admin aggregate view redundant. The user-side "可用渠道" remains. Backend: - Delete handler/admin/available_channel_handler.go (+ test) - Drop AdminHandlers.AvailableChannel field and wire injection - Remove /admin/channels/available route Frontend: - Delete views/admin/AvailableChannelsView.vue - Drop /admin/available-channels router entry - Strip AvailableChannel types + listAvailable from api/admin/channels.ts
-
IanShaw027 authored
-
erio authored
- service: add normalizeBillingModelSource helper, apply in Create/GetByID/Update/List/ListAvailable outputs - handler: drop channelToResponse fallback now that service owns the default; add passthrough test - frontend: replace ternary status/billing-source lookups with Record<Enum, ...> maps so new union members fail the build - chip/table: drop local type aliases, reuse UserSupportedModel/UserPricingInterval directly - tests: assert short-circuit on ListAll error, wrap-prefix preservation, and Name-based default lookup
-
- 20 Apr, 2026 4 commits
-
-
IanShaw027 authored
-
IanShaw027 authored
-
erio authored
Follow-up to the available-channels review pass. No behavior change for end users; tightens internals based on three independent code reviews. Backend - service/channel.go: collapse buildPricingLookup + pricedNamesFor into a single platformPricingIndex (byLower + originalCase + ordered names), built once per SupportedModels call. Fixes a casing- consistency bug where the same logical model appeared with mapping case in the exact branch but pricing case in the wildcard branch — pricing's original case now wins everywhere. - service/channel.go: doc that a mapping key of just "*" expands to every priced model on the platform (intentional "passthrough all"). - service/channel_available.go: normalize empty BillingModelSource to channel_mapped at construction time, removing the same fallback duplicated in the admin DTO mapper and the admin Vue template. - handler/admin/available_channel_handler.go: unexport availableChannelToAdminResponse (same-package usage only); mapper is now a pure passthrough. - handler/available_channel_handler.go: drop the middleware2 alias (no name collision in this file). Frontend - utils/pricing.ts: extract formatScaled, used by SupportedModelChip and PricingRow. - api/admin/channels.ts: re-export BillingMode from constants/channel; tighten Channel.status / billing_model_source to ChannelStatus / BillingModelSource (and same for AvailableChannel). - components/channels/AvailableChannelsTable.vue: drop dead withDefaults wrapper (loading is required, both call sites pass it). - views/admin/AvailableChannelsView.vue: drop the redundant || BILLING_MODEL_SOURCE_CHANNEL_MAPPED fallback (now applied in service layer); remove unused import. - i18n zh + en: delete unused tierLabel and tokenRange keys from both availableChannels.pricing and admin.availableChannels.pricing. Tests - New: SupportedModels_ExactKeyUsesPricedCaseWhenAvailable locks the pricing-case-wins rule. - New: SupportedModels_AsteriskOnlyMappingExpandsAllPriced documents the "*" expansion rule. - Admin handler: existing tests adjusted to pass an explicit BillingModelSource (default-fill is now exercised by service tests).
-
erio authored
Add a read-only aggregate view per channel: its linked groups and a deterministic wildcard-free supported-model list with pricing details. Backend - service.Channel.SupportedModels(): combine ModelMapping keys with same-platform ModelPricing.Models; trailing "*" keys expand via pricing prefix match; platforms without a mapping produce no entries (intentional "no mapping = not shown" rule). - Extract splitWildcardSuffix() shared with toModelEntry. - Build a per-call pricing lookup map (platform+lowerName -> *pricing) to avoid O(N*M) scans in SupportedModels. - ChannelService.ListAvailable() aggregates channels + active groups; filters out group IDs no longer active. - Admin route GET /api/v1/admin/channels/available returns the full DTO (id, status, billing_model_source, restrict_models, groups, supported_models). - User route GET /api/v1/channels/available applies three filters: Status==active, visible-group intersection, and platform filter on supported_models (prevents cross-platform leak when a channel links to both a user-accessible group and an inaccessible one on another platform). Response is a plain array (matches the /groups/available sibling shape). Field whitelist omits billing_model_source, restrict_models, ids, status, sort_order. Frontend - New /admin/available-channels and /available-channels views backed by a shared AvailableChannelsTable component (admin adds status + billing-source columns via slots). - PricingRow extracted to its own SFC; SupportedModelChip references shared billing-mode constants in constants/channel.ts. - Sidebar: new entry above "渠道管理" for admin; matching entry in user nav. - i18n: zh + en coverage for both namespaces. Tests - SupportedModels: wildcard-only pricing skipped, prefix-matches- nothing, cross-platform bleed, case-insensitive dedup, empty platform mapping. - ListAvailable: nil groupRepo, inactive-group-ID dropped, stable case-insensitive name sort. - User handler: 401 on unauthenticated, visible-group intersection, platform filter on supported_models, JSON whitelist. - Admin handler: full DTO including default BillingModelSource fallback. Refs: issue #1729
-
- 21 Apr, 2026 2 commits
-
-
erio authored
Apply flow: - POST /admin/channel-monitor-templates/:id/apply now requires monitor_ids (non-empty array). Service applies the template only to the selected subset, gated by AND template_id = :id (so users can't sneak in unrelated monitor IDs). - New GET /admin/channel-monitor-templates/:id/monitors returns the associated monitor briefs (id/name/provider/enabled) for the picker. - ApplyToMonitors signature gains monitorIDs []int64; empty list returns ErrChannelMonitorTemplateApplyEmpty. Frontend: - New MonitorTemplateApplyPickerDialog.vue: list of associated monitors with checkboxes (default all checked), 全选 / 全不选 shortcuts, live selected/total count. Submit calls apply(id, ids). - MonitorTemplateManagerDialog replaces the old ConfirmDialog flow with the picker; onApplied refetches the list to refresh associated counts. i18n: applyPicker* + common.selectAll keys. chore: bump version to 0.1.114.33 The CC 2.1.114 (sdk-cli) UA / APIKeyBetaHeader / JSON metadata.user_id baseline (already verified working via the in-process apply on prod template id=1) is documented in internal/pkg/claude/constants.go and is what the seed template in the manager UI should follow.
-
erio authored
Problem: Upstream channels can reject monitor probes based on client fingerprint (e.g. "only Claude Code clients allowed"). The monitor had no way to customize the outgoing request to bypass such restrictions. Solution: Introduce reusable request templates that carry extra_headers plus an optional body override; monitors reference a template and receive a snapshot copy on apply. Template edits do NOT auto-propagate — users must click "apply to associated monitors" to refresh snapshots, so a bad template edit cannot instantly break all production monitors. Data model (migration 112): - channel_monitor_request_templates: id, name, provider, description, extra_headers jsonb, body_override_mode ('off'|'merge'|'replace'), body_override jsonb. Unique (provider, name). - channel_monitors: +template_id (FK, ON DELETE SET NULL), +extra_headers, +body_override_mode, +body_override (the three runtime snapshot fields). Checker (channel_monitor_checker.go): - callProvider + runCheckForModel accept a CheckOptions carrying the snapshot fields. mergeHeaders applies user headers on top of adapter defaults (forbidden list: Host / Content-Length / Transfer-Encoding / Connection / Content-Encoding). - buildRequestBody: off -> adapter default body merge -> shallow-merge over default; per-provider deny list (model/messages/contents) protects the challenge contract replace -> user body verbatim - Replace mode skips challenge validation; instead HTTP 2xx + non-empty extracted response text = operational, empty = failed. - 4 new unit tests cover all three modes + replace/empty-response case. Admin API: - /admin/channel-monitor-templates CRUD + /:id/apply (overwrite snapshot on all template_id=id monitors, returns affected count). - channel_monitor request/response DTOs gain the 4 new fields. Frontend: - channelMonitorTemplate.ts API client. - MonitorAdvancedRequestConfig.vue shared component for headers textarea + body mode radio + body JSON editor; used by both template and monitor forms. - MonitorTemplateManagerDialog.vue: provider tabs, list/create/edit/ delete/apply, live "associated monitors" count per row. - MonitorFiltersBar: new 模板管理 button next to 新增监控. - MonitorFormDialog: collapsible 高级 section with template dropdown (filtered by form.provider, clears on provider change) + embedded AdvancedRequestConfig. Picking a template copies its fields into the form (snapshot semantics mirrored on the client). - i18n zh/en entries for all new copy. chore: bump version to 0.1.114.32
-
- 20 Apr, 2026 7 commits
-
-
erio authored
Settings: - New "功能开关" tab between 通用设置 and 安全与认证 - ChannelMonitorEnabled toggle: runner skips scheduling when false, user-facing list returns empty - ChannelMonitorDefaultIntervalSeconds (15-3600): pre-fills interval when creating a new monitor; each monitor can still override Bug fix: - ModelTagInput now commits pending input on blur, not just Enter/Tab. Previously clicking "save" with an un-Enter'd extra model would drop the value (DB stored extra_models=[] even when user typed entries). Backend: - domain_constants: SettingKeyChannelMonitor{Enabled,DefaultIntervalSeconds} - SettingService.GetChannelMonitorRuntime: lightweight getter used by runner tick + user handler per-request (fail-open on DB error) - Runner tickDueChecks: bails early when feature disabled - ChannelMonitorUserHandler: checks feature flag before serving - Comment on runner doc: scheduler state is implicit (every tick re-reads ListEnabled from DB), so CRUD ops on monitors self-maintain the schedule Bump VERSION to 0.1.114.25 -
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
erio authored
新增 admin「渠道监控」模块(参考 BingZi-233/check-cx),独立于现有 Channel 体系。 admin 配置 + 后台定时调用上游 LLM chat completions 健康检查 + 所有登录用户只读可见。 后端: - ent: channel_monitor + channel_monitor_history(AES-256-GCM 加密 api_key) - service 按职责拆分:service/aggregator/validate/checker/runner/ssrf - provider strategy map 替代 switch(openai/anthropic/gemini) - repository batch 聚合(ListLatestForMonitorIDs + ComputeAvailabilityForMonitors)消除 N+1 - runner: ticker(5s) + pond worker pool(5) + inFlight 防并发 + TrySubmit 防雪崩 + 凌晨 3 点 cron 清理 30 天历史 - SSRF 防护:强制 https + 私网/loopback/云元数据 IP 拒绝(127/8、10/8、172.16/12、 192.168/16、169.254/16、100.64/10、::1、fc00::/7、fe80::/10)+ DialContext 在 socket 层防 DNS rebinding - API key sanitize:擦除 url.Error 与上游响应 body 中的 sk-/sk-ant-/AIza/JWT 模式 - APIKeyDecryptFailed 标志位 + 单 monitor 路径检测,避免空 key 调用上游 handler: - admin: CRUD + 手动触发 + 历史接口(api_key 脱敏) - user: 只读列表 + 状态详情(去除 api_key/endpoint) - ParseChannelMonitorID 共用 + dto.ChannelMonitorExtraModelStatus 共用 前端: - 路由 /admin/channels/{pricing,monitor} + /monitor(用户只读) - AppSidebar 父项 expandOnly 支持 - ChannelMonitorView 拆为 8 个子组件 + ChannelStatusView 拆出 detail dialog - composables/useChannelMonitorFormat + constants/channelMonitor 共享 - i18n monitorCommon namespace 消除 admin/user 两 view 重复 合规:所有文件符合 CLAUDE.md(Go ≤ 500 行 / Vue ≤ 300 行 / 函数 ≤ 30 行) CI: go build / gofmt / golangci-lint(0 issues) / make test-unit / pnpm build 全绿 -
IanShaw027 authored
-
- 14 Apr, 2026 7 commits
-
-
erio authored
- Fix gofmt alignment in setting_handler.go, settings.go, payment_config_service.go - Add payment_balance_recharge_multiplier and payment_recharge_fee_rate to API contract test expected JSON
-
erio authored
- Add recharge_fee_rate system setting (percentage fee on top of recharge amount) - Full backend chain: config constant, PaymentConfig struct, update validation, read/write persistence, DTO, handler GET/PUT responses - Frontend: settings input with preview, i18n (zh/en), API types - Fix provider card toggle layout: labels above switches to save width - Fix Chinese translation: "EasyPay" → "易支付" in provider description
-
erio authored
- Add balance_recharge_multiplier system setting (e.g. 1.2 = charge 100 get 120) - Separate order_amount (credited balance) from pay_amount (actual payment) - Refund calculates gateway amount proportionally from pay_amount - Frontend shows both amounts in order details, payment status, refund dialog - Admin settings UI for configuring recharge multiplier
-
erio authored
Backend: - gateway_handler: pass subject.UserID instead of int64(0) for user-level routing - setting_handler: add missing BalanceLowNotifyRechargeURL to UpdateSettings response - openai_gateway_service: use applyAccountStatsCost for account stats pricing integration - embed_on: add local file override (data/public/) for embedded frontend assets Frontend: - useTableSelection: add batchUpdate method for batch operations - AccountsView: virtual scrolling params, Set-based isSelected, swipe virtualization - ProxiesView: add batchUpdate to selection and swipe-select - BulkEditAccountModal: fix submit handler to prevent event object as argument - SettingsView: move payload construction outside try block - i18n: add general translation keys (saved, deleted, view, validation, allowUserRefund) - api/client: reorder error fields for consistency - stores/payment: clarify pollOrderStatus JSDoc
-
erio authored
- gateway_handler: pass ParsedRequest to RecordUsage + set in gin.Context - channel_handler: add FeaturesConfig to CRUD (WebSearch channel toggle) - channel_repo: features_config JSONB persistence (Create/Get/Update/List) - security_headers: add Stripe CSP domains (script-src + frame-src)
-
erio authored
Bug fixes: - Detached context for GetAccountConcurrencyBatch (prevent all-zero on request cancel) - Filter soft-deleted users in GetByGroupID - Stripe CSP policy (allow Stripe.js in script-src and frame-src) - WebSearch API key validation on save - RECHARGING status in payment result success check - Windows test fixes (logger Sync deadlock, config path escaping) Feature enhancements: - Webhook multi-instance dispatch (extractOutTradeNo + GetWebhookProvider) - EasyPay mobile H5 payment (device param + PayURL2) - SSE error propagation in WebSearch emulation - AccountStatsCost DTO field for admin usage logs - Plans sort by sort_order instead of created_at - UsageMapHook for streaming response usage data - apicompat Instructions field passthrough - EffectiveLoadFactor for ops concurrency/metrics - Usage billing RETURNING balance for notify system - BulkUpdate mixed channel warning with details - println to slog migration in auth cache - Wire ProviderSet cleanup - CI cache-dependency-path optimization Frontend: - Refund eligibility check per provider (canRequestRefund) - Plan sort_order editing - Dead code cleanup (simulate_claude_max, client_affinity) - GroupsView platform switch guard - channels features_config API type - UsageView account_stats_cost export
-
erio authored
- Fix errcheck: handle Write/Encode return values in brave_test.go - Fix errcheck: defer resp.Body.Close() with _ assignment in tavily.go - Fix gofmt: payment.go, channel.go, payment_config_providers.go - Fix unused: remove dead decodeURLValue in easypay.go - Restore shouldFallbackGeminiModel function (deleted during cherry-pick) - Add missing balanceNotifyService param to NewGatewayService in test - Fix platform default test expectation (empty stays empty) - Fix wildcard pricing test (longest prefix wins, not config order) - Fix subscription group test (SUBSCRIPTION_REPOSITORY_UNAVAILABLE)
-