- 21 Apr, 2026 4 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 -
erio authored
The "CHANNEL · STATUS" breadcrumb and the zh/en subtitles above the window-picker were redundant with the existing "渠道状态" page title shown in the layout header. Remove the left column and right-align the 7d/15d/30d tabs + overall chip. Also drop the now-unreferenced channelStatus.hero.* i18n keys from both locales (grep confirms no remaining usage). chore: bump version to 0.1.114.31
-
erio authored
Monitor: - callProvider now returns both textPath-extracted text and raw body; runCheckForModel uses rawBody on non-2xx so history.message stops being "upstream HTTP 503: " with empty body (gjson textPath produces "" for error responses like {"error":{"message":"No available accounts..."}}) - truncateForErrorBody collapses whitespace then caps at 300 bytes (monitorErrorBodySnippetMaxBytes); final truncateMessage still enforces the 500-byte DB column cap Frontend: - MonitorFormDialog: primary_model input text color and ModelTagInput tags now both track form.provider (via new getPlatformTextClass + existing getPlatformTagClass with platform prop). (cherry-picked from 1d3b0418; dropped gateway_handler logging改动,不在本 PR 范围)
-
- 23 Apr, 2026 1 commit
-
-
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
-
- 21 Apr, 2026 1 commit
-
-
erio authored
明细只保留 1 天,超过 1 天聚合到新表 channel_monitor_daily_rollups(按 monitor_id/model/bucket_date 维度),聚合保留 30 天。两张表都用 SoftDeleteMixin 软删除(DELETE 自动改为 UPDATE deleted_at = NOW())。 聚合 + 清理任务由 OpsCleanupService 的 cron 统一调度,与运维监控的清理共享 schedule(默认 0 2 * * *)和 leader lock。ChannelMonitorRunner 的 cleanupLoop 被移除,只保留 dueCheckLoop。 读取路径 ComputeAvailability* 改为 UNION 明细(今天 deleted_at IS NULL)+ 聚合(过去 windowDays 天 deleted_at IS NULL),SUM(ok)/SUM(total) 自然加权 计算可用率,AVG latency 用 SUM(sum_latency_ms)/SUM(count_latency)。 watermark 表 channel_monitor_aggregation_watermark 单行(id=1),记录 last_aggregated_date,重启后从该日期 +1 继续聚合,首次为 nil 则从 today - 30d 开始回填,单次最多 35 天上限避免长事务。 raw SQL 的 ListLatestPerModel / ListLatestForMonitorIDs / ListRecentHistoryForMonitors 都补上 deleted_at IS NULL 过滤(SoftDeleteMixin interceptor 只对 ent query 生效)。 bump version to 0.1.114.28 GroupBadge 在 MonitorKeyPickerDialog 中复用平台主题色 + 倍率/专属倍率 (顺手优化)。
-
- 20 Apr, 2026 5 commits
-
-
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
-
erio authored
Subtitle + breadcrumb already convey context; the giant h1 was visual noise. Drops orphan i18n key `channelStatus.hero.title` and shrinks hero section vertical padding accordingly. Bump VERSION to 0.1.114.26
-
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 -
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
-
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 全绿
-
- 22 Apr, 2026 9 commits
-
-
IanShaw027 authored
-
IanShaw027 authored
-
shaw authored
-
shaw authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
- 21 Apr, 2026 18 commits
-
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
IanShaw027 authored
-
- 20 Apr, 2026 2 commits
-
-
IanShaw027 authored
-
IanShaw027 authored
-