1. 27 Apr, 2026 2 commits
    • shaw's avatar
      feat(affiliate): add feature toggle and per-user custom invite settings · ae317432
      shaw authored and 陈曦's avatar 陈曦 committed
      - 在系统设置「功能开关」中新增邀请返利总开关,默认关闭;
        关闭态:菜单隐藏、注册忽略 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 位系统码与新自定义码
      - 补充单元测试与集成测试覆盖新方法、冲突路径与边界值
      ae317432
    • VpSanta33's avatar
      feat: add affiliate invite rebate flow and admin rebate-rate setting · 2b67e632
      VpSanta33 authored and 陈曦's avatar 陈曦 committed
      2b67e632
  2. 24 Apr, 2026 2 commits
  3. 23 Apr, 2026 1 commit
    • 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
  4. 21 Apr, 2026 3 commits
    • erio's avatar
      feat(sidebar+groups): available-channels above channel-status; show rate for subscription groups · 9dae6c7a
      erio authored
      - Sidebar user-side order: /available-channels now sits directly above
        /monitor (渠道状态) for regular users, mirroring the admin section where
        it sits above /admin/channels.
      - GroupBadge gains an alwaysShowRate prop. Subscription groups default to
        a "订阅"/days-remaining label; the new flag swaps that for the rate
        multiplier while keeping the subscription theme color, so the Available
        Channels page can surface rates on every group type.
      9dae6c7a
    • erio's avatar
      fix(settings): inject channel_monitor & available_channels into SSR payload · 84b03efa
      erio authored
      Root cause: GetPublicSettingsForInjection used an inline struct that silently
      drifted from dto.PublicSettings and omitted channel_monitor_enabled /
      available_channels_enabled. On refresh window.__APP_CONFIG__ lacked these
      keys, so cachedPublicSettings.available_channels_enabled resolved to
      undefined and the opt-in sidebar entry (=== true) disappeared.
      
      Backend: extract PublicSettingsInjectionPayload as a named type with all
      feature-flag fields wired, and add a reflect-based drift test in the dto
      package so forgetting a future flag fails CI instead of the browser.
      
      Frontend: introduce utils/featureFlags.ts as the single registry for
      public-settings-driven toggles, with explicit opt-in / opt-out modes that
      encode the pre-load fallback. AppSidebar switches to makeSidebarFlag() so
      adding a new switch only touches the registry.
      84b03efa
    • IanShaw027's avatar
      d08757ce
  5. 20 Apr, 2026 2 commits
    • IanShaw027's avatar
      fix: close admin settings review gaps · 030da8c2
      IanShaw027 authored
      030da8c2
    • 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
  6. 23 Apr, 2026 1 commit
    • erio's avatar
      fix(channel-monitor): drop soft delete, refactor feature flag to declarative form · ef6ec8a1
      erio authored
      ### 后端修复:日志表不该用软删除
      
      channel_monitor_histories / channel_monitor_daily_rollups 都是日志/聚合表,
      没有恢复需求。110 里加的 SoftDeleteMixin 会让 DELETE 自动变成 UPDATE deleted_at,
      导致行和索引只增不减,徒增磁盘占用和查询成本。
      
      改回分批物理删(参考 OpsCleanupService.deleteOldRowsByID 模板):
      
      - ent schema 移除 SoftDeleteMixin,重新 go generate
      - repo 新增 deleteChannelMonitorBatched 辅助 + 两条 prune SQL 常量
        (WITH batch AS SELECT id LIMIT 5000 → DELETE IN batch)
      - DeleteHistoryBefore / DeleteRollupsBefore 改调分批 raw SQL
      - 移除 ComputeAvailability / ComputeAvailabilityForMonitors / UpsertDailyRollupsFor /
        ListLatestPerModel / ListLatestForMonitorIDs / ListRecentHistoryForMonitors 等
        raw SQL 中的 deleted_at IS NULL 过滤
      - UpsertDailyRollupsFor 的 ON CONFLICT 去掉 deleted_at = NULL 重置
      - migration 111 DROP COLUMN deleted_at + 对应索引(110 已部署但 maintenance
        首跑在次日 02:00,此时尚无业务数据在依赖软删除)
      
      ### 前端重构:feature flag 声明式 + 复用
      
      AppSidebar.vue 里 7 处 `...(flag ? [item] : [])` 样板代码删光,改为 NavItem 加
      featureFlag?: () => boolean | undefined 字段,加一个 applyFeatureFlags 递归
      过滤(含 children)。语义统一为 `!== false`(宽容策略,undefined 时默认显示,
      避免 public settings 未加载完成时菜单闪烁消失 — 对应用户反馈"刷新后菜单消失
      要去保存设置才回来")。
      
      - 集中声明 4 个 flag getter:flagChannelMonitor / flagPayment /
        flagOpsMonitoring / flagAdminPayment
      - 提取 buildSelfNavItems 复用用户端主菜单和管理员"我的账户"子菜单
      - 未来新增开关:在统一位置加一个 flag getter + 给对应 NavItem 加字段
        (不用再动渲染逻辑)
      
      bump 0.1.114.29
      ef6ec8a1
  7. 20 Apr, 2026 2 commits
    • 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
    • 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
  8. 14 Apr, 2026 1 commit
  9. 11 Apr, 2026 1 commit
    • erio's avatar
      fix(payment): resolve PR audit issues · e1547d78
      erio authored
      - Add payment navigation to AppSidebar (user orders + admin payment menu group with collapse)
      - Add 5 missing nav i18n keys (myOrders, orderManagement, paymentDashboard, paymentConfig, paymentPlans)
      - Renumber payment migrations 090-100 → 092-102 to avoid conflict with upstream 090/091
      - Remove non-payment sora_client_enabled change, restore upstream purchase_subscription fields
      - Remove extra 'data' from SettingsTab type union
      e1547d78
  10. 10 Apr, 2026 2 commits
  11. 09 Apr, 2026 1 commit
  12. 08 Apr, 2026 1 commit
  13. 06 Apr, 2026 1 commit
  14. 05 Apr, 2026 1 commit
    • shaw's avatar
      fix: remove remaining Sora references from frontend · a0729677
      shaw authored
      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.
      a0729677
  15. 04 Apr, 2026 1 commit
  16. 03 Apr, 2026 1 commit
  17. 14 Mar, 2026 1 commit
    • shaw's avatar
      refactor(frontend): 将备份和数据管理页面合并为设置页的标签页 · 616930f9
      shaw authored
      将独立的 /admin/backup 和 /admin/data-management 页面整合到设置页,
      作为「备份」和「Sora 存储」标签页,减少侧边栏条目,集中管理配置。
      
      - 移除 BackupView 和 DataManagementView 的 AppLayout 包装
      - 在 SettingsView 中以子组件形式嵌入,使用 v-show 切换标签
      - 删除独立路由和侧边栏菜单入口
      - 备份/数据标签页下隐藏主保存按钮(各自有独立保存)
      - 优化标签栏样式适配7个标签,PC端支持细滚动条
      - 清理未使用的图标组件和 i18n 键
      616930f9
  18. 13 Mar, 2026 1 commit
    • Rose Ding's avatar
      feat: 数据库定时备份与恢复(S3 兼容存储,支持 Cloudflare R2) · 53ad1645
      Rose Ding authored
      
      
      新增管理员专属的数据库备份与恢复功能:
      - 全量 PostgreSQL 备份(pg_dump),gzip 压缩后上传到 S3 兼容存储
      - 支持手动备份和 cron 定时备份
      - 支持从备份恢复(psql --single-transaction)
      - 备份文件自动过期清理(默认 14 天)
      - 前端完整管理页面(S3 配置、定时配置、备份列表、恢复/下载/删除)
      - 内置 Cloudflare R2 配置教程弹窗
      - Dockerfile 从 postgres 镜像多阶段复制 pg_dump/psql,确保版本一致
      Co-Authored-By: default avatarClaude Opus 4.6 <noreply@anthropic.com>
      53ad1645
  19. 11 Mar, 2026 1 commit
    • John Doe's avatar
      feat: add Backend Mode toggle to disable user self-service · 6826149a
      John Doe authored
      
      
      Add a system-wide "Backend Mode" that disables user self-registration
      and self-service while keeping admin panel and API gateway fully
      functional. When enabled, only admin can log in; all user-facing
      routes return 403.
      
      Backend:
      - New setting key `backend_mode_enabled` with atomic cached reads (60s TTL)
      - BackendModeUserGuard middleware blocks non-admin authenticated routes
      - BackendModeAuthGuard middleware blocks registration/password-reset auth routes
      - Login/Login2FA/RefreshToken handlers reject non-admin when enabled
      - TokenPairWithUser struct for role-aware token refresh
      - 20 unit tests (middleware + service layer)
      
      Frontend:
      - Router guards redirect unauthenticated users to /login
      - Admin toggle in Settings page
      - Login page hides register link and footer in backend mode
      - 9 unit tests for router guard logic
      - i18n support (en/zh)
      
      27 files changed, 833 insertions(+), 17 deletions(-)
      Co-Authored-By: default avatarClaude Opus 4.6 <noreply@anthropic.com>
      6826149a
  20. 04 Mar, 2026 2 commits
  21. 03 Mar, 2026 1 commit
    • erio's avatar
      fix(frontend): admin custom menu items not showing in sidebar · 5ba71cd2
      erio authored
      The public settings API filters out menu items with visibility='admin',
      so customMenuItemsForAdmin was always empty when reading from
      cachedPublicSettings. Fix by loading custom menu items from the admin
      settings API (via adminSettingsStore) which returns all items unfiltered.
      
      Changes:
      - adminSettings store: store custom_menu_items from admin settings API
      - AppSidebar: read admin menu items from adminSettingsStore instead of
        cachedPublicSettings
      - CustomPageView: merge public and admin menu items so admin users can
        access admin-only custom pages
      5ba71cd2
  22. 02 Mar, 2026 3 commits
  23. 28 Feb, 2026 2 commits
  24. 13 Feb, 2026 2 commits
  25. 02 Feb, 2026 2 commits
    • song's avatar
      merge upstream main · 0170d19f
      song authored
      0170d19f
    • shaw's avatar
      feat: 重新设计公告系统为Header铃铛通知 · bbdc8663
      shaw authored
      - 新增 AnnouncementBell 组件,支持 Modal 弹窗和 Markdown 渲染
      - 移除 Dashboard 横幅和独立公告页面
      - 铃铛位置在 Header 文档按钮左侧,显示未读红点
      - 支持点击查看详情、标记已读、全部已读等操作
      - 完善国际化,移除所有硬编码中文
      - 修复 AnnouncementTargetingEditor watch 循环问题
      bbdc8663
  26. 30 Jan, 2026 1 commit
    • ducky's avatar
      feat(announcements): add admin/user announcement system · b7f69844
      ducky authored
      Implements announcements end-to-end (admin CRUD + read status, user list + mark read) with OR-of-AND targeting. Also breaks the ent<->service import cycle by moving schema-facing constants/targeting into a new domain package.
      b7f69844
  27. 28 Jan, 2026 1 commit