1. 27 Apr, 2026 1 commit
  2. 23 Apr, 2026 5 commits
    • erio's avatar
    • erio's avatar
    • erio's avatar
      feat(monitor): proportion-based overall status + reusable auto-refresh · 0dcc0e05
      erio authored
      - Change overall status logic: >50% failed = UNAVAILABLE, any failed
        or degraded = DEGRADED, all ok = OPERATIONAL
      - Extract useAutoRefresh composable with localStorage persistence
      - Create AutoRefreshButton dropdown component (reusable)
      - Integrate auto-refresh into channel status page via MonitorHero
      0dcc0e05
    • erio's avatar
      revert: remove fork-only changes from release sync · 67518a59
      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
      67518a59
    • erio's avatar
      sync: bring over remaining release/custom-0.1.115 changes · 748a84d8
      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
      748a84d8
  3. 22 Apr, 2026 5 commits
  4. 21 Apr, 2026 6 commits
  5. 22 Apr, 2026 1 commit
    • erio's avatar
      fix(available-channels): description as own column, fixed table layout · 25a50355
      erio authored
      - 描述独立成列:渠道名与描述各占一列,均用 rowspan 纵向合并
      - 渠道名单元格 text-center + align-middle,合并后视觉居中
      - table-fixed:给 name/description/platform 显式宽度,groups 和
        supported_models 在剩余空间均分。支持模型列此前在 table-auto 下
        不会换行导致横向溢出遮挡(反馈截图),加 table-fixed 后天然 flex-wrap
      - i18n 增加 availableChannels.columns.description(zh/en)
      25a50355
  6. 21 Apr, 2026 5 commits
    • erio's avatar
      feat(channels): themed model popover + group-badge with rate, subscription & exclusivity · ff4ef1b5
      erio authored
      Pricing popover:
      - Teleport to body + fixed-position re-measuring on hover/scroll/resize so it
        escapes the card's overflow-hidden clip that was chopping off the lower
        half of the panel.
      - Header + border adopt the platform theme via platformBorderClass /
        platformBadgeLightClass so each model card reads at a glance.
      
      Accessible groups:
      - Backend AvailableGroupRef / user DTO now expose subscription_type,
        rate_multiplier and is_exclusive. User-specific rates continue to come
        from /groups/rates (same pattern as the API keys page).
      - Table renders groups through the shared GroupBadge, which already deepens
        subscription-type colors and shows default vs custom rate as
        <s>default</s> <b>custom</b>.
      - Exclusive groups are labelled with a purple shield row, public groups
        with a grey globe row so admins and users can tell at a glance which
        groups they got via explicit grant vs. public access.
      
      i18n keys for exclusive / public / their tooltips added to zh + en.
      ff4ef1b5
    • erio's avatar
      feat(channels): aggregate by channel with platform sections + rowspan table · 3cdd5754
      erio authored
      Switch the user-facing 'Available Channels' view from "one row per
      platform" to "one channel row-group with N platform sections".
      
      Backend: userAvailableChannel now holds Platforms []section instead
      of being exploded. buildPlatformSections replaces
      explodeChannelByPlatform with the same per-platform grouping logic.
      
      Frontend: drop the DataTable wrapper for this view and write a
      four-column grid table (渠道名 / 平台 / 分组 / 支持模型) where the
      channel name only renders on the first platform row of each channel —
      visual rowspan without hacking DataTable.
      
      - api/channels.ts: UserChannelPlatformSection + platforms[]
      - AvailableChannelsTable: rewritten as native grid (header + per-
        channel section with hover row highlight)
      - AvailableChannelsView: search now filters platforms sub-array;
        channel-name / description hits still keep the whole channel
      - i18n: add availableChannels.columns.platform (zh/en)
      3cdd5754
    • IanShaw027's avatar
      7309c02f
    • IanShaw027's avatar
      9742796e
    • IanShaw027's avatar
      09351e94
  7. 20 Apr, 2026 17 commits
    • IanShaw027's avatar
      fix payment resume result consistency · a27a7add
      IanShaw027 authored
      a27a7add
    • IanShaw027's avatar
      fix frontend wechat oauth capability recovery · cd0338fb
      IanShaw027 authored
      cd0338fb
    • IanShaw027's avatar
      c297d011
    • IanShaw027's avatar
      067eb23d
    • IanShaw027's avatar
      Tighten WeChat payment resume flow · 55e8dd55
      IanShaw027 authored
      55e8dd55
    • erio's avatar
      feat(channels): add "Available Channels" aggregate view · 654cfb64
      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
      654cfb64
    • erio's avatar
      feat(channel-monitor): gate UI by feature switch + polish form UX · ba98243c
      erio authored
      - AppSidebar 三处菜单项(管理端渠道监控、用户端/个人页渠道状态)按
        channel_monitor_enabled 条件展开,关闭时隐藏
      - ChannelStatusView setInterval 随开关启停:关闭 clearInterval,
        开启/未知态自动启动,避免禁用功能后仍在轮询
      - MonitorFormDialog provider Select 改为 3 色单选按钮
        (openai=emerald / anthropic=orange / gemini=sky),i18n 文案
        供应商 → 平台 / Provider → Platform
      - MonitorKeyPickerDialog 按钮列表改为 name/key/group 三列表格 +
        搜索框,按 key.group.platform === provider 过滤,避免跨平台误选
      - form.provider 变化时清空 api_key,修复切换平台仍保留旧 key 的
        错配 bug
      - providerPickerClass 抽取到 useChannelMonitorFormat composable,
        统一 emerald/orange/sky 颜色语义,消除硬编码 Tailwind class 重复
      - maskApiKey 工具函数统一(utils/maskApiKey.ts),KeysView 与
        MonitorKeyPickerDialog 共用 slice(0,6)...slice(-4) 策略
      - bump version to 0.1.114.27
      ba98243c
    • IanShaw027's avatar
      16be82b9
    • IanShaw027's avatar
      Refine payment UX for wallet flows · f83fd59d
      IanShaw027 authored
      f83fd59d
    • erio's avatar
      feat(channel-monitor): redesign user dashboard as card grid · a1425b45
      erio authored
      Reference check-cx UI: INTELLIGENCE MONITOR hero + 3-column card grid
      with 60-point timeline bars.
      
      Backend:
      - Add PrimaryPingLatencyMs + Timeline[60] to UserMonitorView
      - ListRecentHistoryForMonitors: batch CTE + ROW_NUMBER() window query
      - indexLatestByModel / indexAvailabilityByModel helpers
      
      Frontend:
      - 7 new components: ProviderIcon, MonitorMetricPair, MonitorAvailabilityRow,
        MonitorTimeline, MonitorHero, MonitorCard, MonitorCardGrid
      - ChannelStatusView 381→~180 lines (delegated to subcomponents)
      - AbortController reload concurrency protection
      - HSL 0-120° availability color mapping
      - Replace emoji with Icon component (bolt / globe)
      - i18n: monitorCommon.* shared namespace, channelStatus.hero.*
      
      Bump VERSION to 0.1.114.24
      a1425b45
    • IanShaw027's avatar
      7ef7fd19
    • IanShaw027's avatar
      feat: resolve payment results by resume token · 9bebf1c1
      IanShaw027 authored
      9bebf1c1
    • erio's avatar
      feat(payment): i18n payment error codes and label localization · 40d4e167
      erio authored
      Pairs with the backend structured payment errors (reason + metadata). The
      frontend now maps reason codes to localized messages with metadata as
      interpolation variables, and automatically localizes raw config-field names
      (e.g. "certSerial" → "证书序列号") using the existing UI-label i18n
      namespace.
      
      - frontend/src/utils/apiError.ts
        - extractApiErrorCode now prefers the string `reason` over the numeric HTTP
          `code`; reason is granular enough to drive i18n lookup, HTTP code is not.
        - New extractApiErrorMetadata to pull interpolation params off the error.
        - New extractI18nErrorMessage(err, t, namespace, fallback): looks up
          `<namespace>.<REASON>` in i18n and substitutes metadata. Before
          substitution, `metadata.key` and `metadata.keys` (slash-joined) are
          re-translated through `admin.settings.payment.field_<key>` so users see
          "缺少必填项:证书序列号" instead of "缺少必填项:certSerial".
      
      - frontend/src/i18n/locales/{zh,en}.ts
        - Add payment.errors entries for every structured reason code returned by
          the backend (PAYMENT_DISABLED, INVALID_AMOUNT, TOO_MANY_PENDING,
          DAILY_LIMIT_EXCEEDED, NO_AVAILABLE_INSTANCE, PAYMENT_PROVIDER_MISCONFIGURED,
          WXPAY_CONFIG_MISSING_KEY / INVALID_KEY_LENGTH / INVALID_KEY, NOT_FOUND,
          FORBIDDEN, CONFLICT, INVALID_ORDER_TYPE, INVALID_STATUS,
          BALANCE_NOT_ENOUGH, REFUND_AMOUNT_EXCEEDED, REFUND_FAILED, and more),
          with placeholders for template variables.
      
      - 13 payment-related Vue files
        - Migrate catch-block error reporting from extractApiErrorMessage to
          extractI18nErrorMessage(err, t, 'payment.errors', fallback).
        - Remove the ad-hoc paymentErrorMap computed in SettingsView.vue, which the
          new helper supersedes (it reads i18n directly via t).
      
      - frontend/src/components/payment/providerConfig.ts
        - wxpay: publicKey and publicKeyId are now required (was optional), matching
          the pubkey-only verifier direction; certSerial is already required.
      
      This PR is drop-in safe: reason-preferring extractApiErrorCode is backward
      compatible with callers that pass their own i18nMap, and error codes missing
      from i18n fall back to the existing message-based path.
      40d4e167
    • IanShaw027's avatar
      test: harden payment result resume flow · 58b2cc38
      IanShaw027 authored
      58b2cc38
    • erio's avatar
      feat(monitor): admin channel monitor MVP with SSRF protection and batch aggregation · 20a4e418
      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 全绿
      20a4e418
    • IanShaw027's avatar
      feat: wire payment return url payloads · b51bc7ee
      IanShaw027 authored
      b51bc7ee
    • IanShaw027's avatar
      feat: add profile auth identity binding flow · c6d85924
      IanShaw027 authored
      c6d85924