Skip to content

feat: add per-channel billing ratio and channel stats dashboard#4894

Open
JacksonsY wants to merge 3 commits into
QuantumNous:mainfrom
JacksonsY:feat/channel-billing-ratio
Open

feat: add per-channel billing ratio and channel stats dashboard#4894
JacksonsY wants to merge 3 commits into
QuantumNous:mainfrom
JacksonsY:feat/channel-billing-ratio

Conversation

@JacksonsY
Copy link
Copy Markdown

@JacksonsY JacksonsY commented May 15, 2026

📝 变更描述 / Description

为每个渠道增加一个可配置的「计费倍率」,用于折算渠道维度的用量统计(channel.used_quota 与数据面板),但不改变用户实际扣费

实现思路:用户扣费仍完全由分组倍率决定、保持不变;渠道维度的成本统计单独走一条口径——在 UpdateChannelUsedQuota 内部通过渠道缓存解析该渠道的倍率,把累加进 used_quota 的额度乘以倍率,因此所有现有计费调用点都无需改动。消费日志在写入时把当时的倍率快照进 Log.channel_ratio,保证历史统计不受后续改倍率影响;普通用户的日志接口会清掉该字段,仅管理员可见。数据面板新增一个管理员接口,按小时聚合渠道维度成本时间序列。

说明:此描述为草稿,提交前请按你自己的理解整理与确认。

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix)
  • ✨ 新功能 (New feature)
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

  • Closes # (暂无)

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

image image image image

Summary by CodeRabbit

  • New Features

    • Channel billing ratio: per-channel multiplier for channel-side usage/cost reporting.
    • Admin-only channel stats API and dashboard section: channel cost ranking, trend charts, Top‑N and time-range controls.
  • UI/UX Improvements

    • Channel editor: new channel billing ratio field (advanced settings).
    • Tables, tooltips and billing details: show channel ratio and computed channel cost for admins.
    • Added localized strings for channel billing/analytics.
  • Tests

    • Unit tests covering channel ratio behavior.

Review Change Stack

Add a configurable billing ratio on each channel that scales
channel-side usage statistics only, without affecting user billing.

Backend:
- Add Channel.ChannelRatio field (>=0, default 1) with GetChannelRatio()
- UpdateChannelUsedQuota applies the ratio when accumulating used_quota
- Snapshot the ratio into Log.channel_ratio at consume time; hide it
  from non-admin users in formatUserLogs
- New admin endpoint GET /api/data/channel returning the hourly
  channel-dimension cost time series

Frontend (web/default + web/classic):
- Channel edit form: billing ratio input
- Usage log: per-row channel cost line for admins
- New admin-only "Channel Stats" dashboard section with overview
  cards and channel cost ranking/trend charts
- i18n for all locales
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 15, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5834d121-8d4c-436e-bdf1-c13065c3cb0c

📥 Commits

Reviewing files that changed from the base of the PR and between 919a254 and 24677fe.

📒 Files selected for processing (6)
  • web/classic/src/components/table/channels/modals/EditChannelModal.jsx
  • web/classic/src/components/table/usage-logs/UsageLogsColumnDefs.jsx
  • web/classic/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/ja.json
  • web/default/src/i18n/locales/vi.json
✅ Files skipped from review due to trivial changes (3)
  • web/classic/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/vi.json
  • web/default/src/i18n/locales/fr.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • web/classic/src/components/table/usage-logs/UsageLogsColumnDefs.jsx
  • web/classic/src/components/table/channels/modals/EditChannelModal.jsx

Walkthrough

This PR adds per-channel billing ratios, snapshots ratios on consume logs, records channel-adjusted quota for hourly aggregation, exposes an admin API to fetch channel quota time-series, and updates classic/default frontends with configuration, columns, charts, and translations.

Changes

Channel Billing Ratio & Cost Reporting

Layer / File(s) Summary
Channel Ratio Model & Quota Adjustment
model/channel.go
Adds nullable ChannelRatio (*float64) with GetChannelRatio() normalizer, applyChannelRatio() helper using cache and math.Round, and applies adjusted quota in UpdateChannelUsedQuota.
Log Snapshot Capture & Quota Pre-aggregation
model/log.go, model/usedata.go
Log gains ChannelRatio snapshot; RecordConsumeLog computes channelRatio via cache and writes channelQuota (rounded) into quota pre-aggregation; quota cache and DB flush now include channel_id and channel_quota.
Admin Endpoint & Routing
controller/usedata.go, router/api-router.go
Adds GetChannelQuotaDates handler parsing start_timestamp/end_timestamp, enforces max 1-month window, calls model.GetChannelQuotaData, and registers GET /api/data/channel under admin auth.
Quota Reporting Types & Getter
model/usedata.go
Adds ChannelQuotaTrendPoint, ChannelQuotaMeta, ChannelQuotaResult and GetChannelQuotaData(startTime,endTime) aggregating hourly per-channel points and enriching channel metadata.
Channel Ratio Unit Test
model/channel_ratio_test.go
Adds TestChannel_GetChannelRatio covering nil, negative, zero, fractional, >1, and nil receiver cases.
Classic UI: Channel Configuration
web/classic/src/components/table/channels/*, web/classic/src/hooks/channels/useChannelsData.jsx
Adds CHANNEL_RATIO column, EditChannelModal default channel_ratio, auto-open advanced settings when non-default, and numeric input for channel_ratio (min 0, step 0.1).
Classic UI: Usage Logs Display
web/classic/src/components/table/usage-logs/UsageLogsColumnDefs.jsx
Channel tooltip shows channel_ratio when numeric and ≠1; Cost column appends admin-only channel cost (rounded quota × ratio).
Classic UI: i18n
web/classic/src/i18n/locales/*.json
Adds translations for channel ratio labels, default/0 semantics, and explanatory note across multiple locales.
Default UI: Channel Schema & Form
web/default/src/features/channels/types.ts, .../lib/channel-form.ts
channelSchema adds channel_ratio (nullish, default 1); form defaults include channel_ratio: 1; payload transforms include channel_ratio with fallback to 1.
Default UI: Channel Components & Drawer
web/default/src/features/channels/components/*, .../constants.ts
Adds Channel Billing Ratio column (renders ratio or 1), FIELD_DESCRIPTIONS.CHANNEL_RATIO, and channel-mutate-drawer numeric input (step 0.01, min 0, placeholder 1).
Dashboard API & Types
web/default/src/features/dashboard/api.ts, .../types.ts
Exports getChannelQuotaDates() calling /api/data/channel; adds ChannelQuotaResult/TrendPoint/Meta TS interfaces.
Default UI: ChannelCharts Component
web/default/src/features/dashboard/components/channels/channel-charts.tsx
New ChannelCharts component fetching channel quota data, managing time range/granularity/top-N, lazy-loading ThemeManager, computing totals, and rendering summary cards and rank/trend charts.
Default UI: Dashboard Integration
web/default/src/features/dashboard/index.tsx, .../section-registry.tsx
Adds admin-only channels dashboard section, lazy-loads ChannelCharts with Suspense, and grants visibility to admins only.
Default UI: Usage Logs Integration
web/default/src/features/usage-logs/data/schema.ts, .../components/*
usageLogSchema adds channel_ratio (nullish, default 1); usage log columns and billing breakdown render ratio and computed channel cost for admins.
Default UI: i18n
web/default/src/i18n/locales/*.json
Adds channel-cost analytics translations across multiple languages (labels, totals, ranking/trend, saved, explanatory text).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • seefs001
  • Calcium-Ion

"🐰 I hopped through code with nimble feet,
Ratios recorded, quotas rounded neat.
Charts now sparkle on admin screens,
Labels translated into many scenes.
A tiny carrot cheers this merged feat."

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main features added: per-channel billing ratio and channel stats dashboard. It is concise, specific, and directly reflects the primary changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (10)
web/default/src/features/usage-logs/components/columns/common-logs-columns.tsx (2)

705-716: 💤 Low value

Consider adding a tooltip or aria-label to explain the 'A' prefix.

The 'A' prefix on the channel cost badge (line 714) likely stands for "Admin" or "Adjusted," but this is not immediately clear to users. Consider adding a tooltip or aria-label for better UX.

💡 Example with tooltip

Wrap the badge in a tooltip:

const channelCostNode = showChannelCost ? (
  <TooltipProvider>
    <Tooltip>
      <TooltipTrigger asChild>
        <span className='inline-flex w-fit items-center rounded-md border border-amber-200 bg-amber-50 px-1.5 py-0.5 font-mono text-[11px] leading-none font-medium text-amber-700 tabular-nums dark:border-amber-800 dark:bg-amber-950/40 dark:text-amber-300'>
          A {formatLogQuota(Math.round(quota * (channelRatio as number)))}
        </span>
      </TooltipTrigger>
      <TooltipContent>{t('Channel Cost')}</TooltipContent>
    </Tooltip>
  </TooltipProvider>
) : null
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@web/default/src/features/usage-logs/components/columns/common-logs-columns.tsx`
around lines 705 - 716, The channel cost badge (channelCostNode) shows an
unexplained 'A' prefix when showChannelCost is true (uses channelRatio and
formatLogQuota); add accessible explanatory text by wrapping the badge in a
tooltip or adding an aria-label/title that explains the 'A' (e.g.,
"Admin/Adjusted channel cost") so screen readers and hover users understand the
prefix; ensure the tooltip/aria-label text is localized and attach it to the
same span that renders A {formatLogQuota(Math.round(quota * (channelRatio as
number)))} so the hint appears for both visual and assistive users.

373-378: ⚡ Quick win

Format channel ratio consistently with other ratios.

Other ratios in this file (group ratio, user group ratio) are formatted using formatRatioCompact() with an 'x' suffix (see lines 86, 209, 240). For consistency, consider formatting the channel ratio similarly.

♻️ Proposed formatting for consistency
                    {typeof log.channel_ratio === 'number' &&
                      log.channel_ratio !== 1 && (
                        <p className='text-muted-foreground text-xs'>
-                          {t('Channel Billing Ratio')}: {log.channel_ratio}
+                          {t('Channel Billing Ratio')}: {formatRatioCompact(log.channel_ratio)}x
                        </p>
                      )}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@web/default/src/features/usage-logs/components/columns/common-logs-columns.tsx`
around lines 373 - 378, Replace the raw channel_ratio output with the same
compact formatter used for other ratios: call formatRatioCompact on
log.channel_ratio (and append or pass the 'x' suffix the same way group and user
group ratios do) inside the JSX conditional that checks typeof log.channel_ratio
and !== 1, so the Channel Billing Ratio rendering uses
formatRatioCompact(log.channel_ratio, ...) consistent with the other ratio
displays.
web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx (1)

317-331: ⚡ Quick win

Consider using formatRatioCompact for ratio display consistency.

For consistency with other ratio formatting throughout the codebase (e.g., group ratios in the columns file use formatRatioCompact()), consider formatting the channel ratio here as well.

♻️ Proposed formatting for consistency

Add the import at the top if not already present:

import { formatRatioCompact } from '../lib/format' // or wherever it's exported

Then update the ratio display:

    rows.push({
      label: t('Channel Billing Ratio'),
-      value: `${log.channel_ratio}x`,
+      value: `${formatRatioCompact(log.channel_ratio)}x`,
    })

Note: formatRatioCompact is defined in common-logs-columns.tsx at lines 67-72. You may need to move it to a shared utility file or re-implement it here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx`
around lines 317 - 331, The channel ratio is currently shown as
`${log.channel_ratio}x`; change this to use the shared formatter by importing
formatRatioCompact and calling it where the ratio row is added (update the
rows.push call that uses log.channel_ratio), e.g., replace the raw string
construction in the rows.push for label t('Channel Billing Ratio') with
formatRatioCompact(log.channel_ratio) and add the appropriate import for
formatRatioCompact (re-export or move it to a shared util if needed) so the
component uses the same ratio formatting as other components.
web/default/src/i18n/locales/en.json (1)

4355-4366: ⚡ Quick win

Scope these new i18n keys to avoid collisions with generic labels.

"Cost Trend" is a shared/generic key, but its value was changed to channel-specific wording. Please add feature-scoped keys (e.g., dashboard.channels.*) and keep generic labels generic.

💡 Proposed i18n key refactor
-    "Channel Billing Ratio": "Channel Billing Ratio",
-    "Channel Cost": "Channel Cost",
-    "Channel Stats": "Channel Stats",
-    "Total Channel Cost": "Total Channel Cost",
-    "Total Raw Cost": "Total Raw Cost",
-    "Overall Ratio": "Overall Ratio",
-    "Saved": "Saved",
-    "Channel Cost Ranking": "Channel Cost Ranking",
-    "Cost Trend": "Channel Cost Trend",
-    "Top Channels": "Top Channels",
-    "View channel-dimension cost statistics": "View channel-dimension cost statistics",
-    "Channel billing ratio. Only scales channel-side usage stats (used quota / dashboard), does not affect user billing. 0 means this channel is not counted.": "Channel billing ratio. Only scales channel-side usage stats (used quota / dashboard), does not affect user billing. 0 means this channel is not counted.",
+    "dashboard.channels.channelBillingRatio": "Channel Billing Ratio",
+    "dashboard.channels.channelCost": "Channel Cost",
+    "dashboard.channels.title": "Channel Stats",
+    "dashboard.channels.totalChannelCost": "Total Channel Cost",
+    "dashboard.channels.totalRawCost": "Total Raw Cost",
+    "dashboard.channels.overallRatio": "Overall Ratio",
+    "dashboard.channels.savings": "Saved",
+    "dashboard.channels.costRanking": "Channel Cost Ranking",
+    "dashboard.channels.costTrend": "Channel Cost Trend",
+    "dashboard.channels.topChannels": "Top Channels",
+    "dashboard.channels.description": "View channel-dimension cost statistics",
+    "channels.form.channelBillingRatio.help": "Channel billing ratio. Only scales channel-side usage stats (used quota / dashboard), does not affect user billing. 0 means this channel is not counted.",

As per coding guidelines, web/default/src/i18n/**/*.{ts,tsx,json} should “Use hierarchical and semantically clear translation key names such as dashboard.overview.title and maintain naming consistency”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/default/src/i18n/locales/en.json` around lines 4355 - 4366, The new
channel-specific i18n entries should be moved from generic keys into a
feature-scoped namespace to avoid collisions: rename keys like "Cost Trend",
"Top Channels", "Channel Cost", "Channel Billing Ratio", "Channel Stats", "Total
Channel Cost", "Total Raw Cost", "Overall Ratio", "Saved", "Channel Cost
Ranking", and the long description into hierarchical keys such as
dashboard.channels.costTrend, dashboard.channels.topChannels,
dashboard.channels.channelCost, dashboard.channels.billingRatio,
dashboard.channels.stats, dashboard.channels.totalChannelCost,
dashboard.channels.totalRawCost, dashboard.channels.overallRatio,
dashboard.channels.saved, dashboard.channels.costRanking, and
dashboard.channels.billingRatioDescription (or similar), and keep any existing
generic "Cost Trend" key intact; update any code references that read the old
flat keys (search for usages of "Cost Trend", "Top Channels", etc.) to the new
dashboard.channels.* keys so translations resolve correctly.
web/default/src/i18n/locales/fr.json (1)

4355-4366: 🏗️ Heavy lift

Use hierarchical i18n keys for the new channel-stats strings.

These new entries use sentence-style keys instead of hierarchical keys (e.g., dashboard.channels.totalCost), which breaks the i18n naming rule for this path and will keep key naming inconsistent.

As per coding guidelines, "Use hierarchical and semantically clear translation key names such as dashboard.overview.title and maintain naming consistency".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/default/src/i18n/locales/fr.json` around lines 4355 - 4366, The new flat
sentence-style translation keys ("Channel Billing Ratio", "Channel Cost",
"Channel Stats", "Total Channel Cost", "Total Raw Cost", "Overall Ratio",
"Saved", "Channel Cost Ranking", "Cost Trend", "Top Channels", "View
channel-dimension cost statistics", "Channel billing ratio. Only scales
channel-side usage stats (used quota / dashboard), does not affect user billing.
0 means this channel is not counted.") must be converted to hierarchical keys to
match the i18n convention (e.g., dashboard.channels.billingRatio,
dashboard.channels.cost, dashboard.channels.stats, dashboard.channels.totalCost,
dashboard.channels.totalRawCost, dashboard.channels.overallRatio,
dashboard.channels.saved, dashboard.channels.costRanking,
dashboard.channels.costTrend, dashboard.channels.topChannels,
dashboard.channels.viewStats, dashboard.channels.billingRatioDescription);
update fr.json to replace the flat keys with these hierarchical keys (preserving
the corresponding French translations), and ensure any code that references the
old flat keys (components or templates using these strings) is updated to use
the new hierarchical keys consistently.
web/default/src/i18n/locales/ru.json (1)

4355-4366: ⚡ Quick win

Use hierarchical, context-specific i18n keys for these new entries.

These additions use flat phrase keys (and "Saved" is especially ambiguous). Please switch to scoped keys (e.g., dashboard.channels.totalSaved, dashboard.channels.costTrend) to keep semantics stable and avoid collisions.

As per coding guidelines, use “hierarchical and semantically clear translation key names such as dashboard.overview.title and maintain naming consistency”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/default/src/i18n/locales/ru.json` around lines 4355 - 4366, Replace the
flat translation keys with hierarchical, context-specific keys under a common
scope (e.g., dashboard.channels) to avoid collisions and clarify semantics:
rename "Channel Billing Ratio" -> "dashboard.channels.billingRatio", "Channel
Cost" -> "dashboard.channels.cost", "Channel Stats" ->
"dashboard.channels.stats", "Total Channel Cost" ->
"dashboard.channels.totalCost", "Total Raw Cost" ->
"dashboard.channels.totalRawCost", "Overall Ratio" ->
"dashboard.channels.overallRatio", "Saved" -> "dashboard.channels.totalSaved"
(avoid ambiguous single-word keys), "Channel Cost Ranking" ->
"dashboard.channels.costRanking", "Cost Trend" ->
"dashboard.channels.costTrend", "Top Channels" -> "dashboard.channels.top",
"View channel-dimension cost statistics" ->
"dashboard.channels.viewChannelCostStats", and "Channel billing ratio. Only
scales channel-side usage stats..." ->
"dashboard.channels.billingRatioDescription"; update any code references to the
original flat keys to use these new hierarchical keys and ensure the Russian
values remain unchanged.
web/default/src/i18n/locales/zh.json (1)

4355-4366: ⚡ Quick win

Use hierarchical i18n keys for the newly added channel-stats labels.

These new keys should follow semantic hierarchical naming (for example under dashboard.channels.*) instead of phrase-as-key literals to stay consistent with the i18n guideline and keep key management maintainable.

As per coding guidelines, "Use hierarchical and semantically clear translation key names such as dashboard.overview.title and maintain naming consistency".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/default/src/i18n/locales/zh.json` around lines 4355 - 4366, The new i18n
entries use phrase-as-key literals (e.g., "Channel Billing Ratio", "Channel
Cost", "Channel Stats", "Total Channel Cost", "Total Raw Cost", "Overall Ratio",
"Saved", "Channel Cost Ranking", "Cost Trend", "Top Channels", "View
channel-dimension cost statistics", "Channel billing ratio. Only scales
channel-side usage stats (...)")—replace these with hierarchical, semantically
clear keys under a common namespace such as dashboard.channels (for example
dashboard.channels.billingRatio, dashboard.channels.cost,
dashboard.channels.stats, dashboard.channels.totalCost,
dashboard.channels.totalRawCost, dashboard.channels.overallRatio,
dashboard.channels.saved, dashboard.channels.costRanking,
dashboard.channels.costTrend, dashboard.channels.topChannels,
dashboard.channels.viewStats, dashboard.channels.billingRatioDescription) and
move the existing Chinese translations as the values; update any components that
reference the old literal keys to use the new dashboard.channels.* keys.
controller/usedata.go (1)

30-43: 💤 Low value

Consider adding time range validation for performance protection.

While the endpoint correctly follows the existing admin pattern (no time limits), unbounded date ranges could cause slow queries or timeouts on large log databases. Adding an optional warning or soft limit (e.g., 3-6 months) could improve admin UX without breaking legitimate use cases.

Note: The ignored strconv.ParseInt errors are acceptable here per established codebase patterns for query parameter parsing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@controller/usedata.go` around lines 30 - 43, The GetChannelQuotaDates handler
currently passes startTimestamp/endTimestamp directly to
model.GetChannelQuotaData allowing unbounded ranges; add a time-range
validation/cap: compute the duration between startTimestamp and endTimestamp (or
from a default when one side missing), and if it exceeds a configurable soft
limit (e.g., 90 days) either return a 400 with a clear message or automatically
cap the range to the max and include a "warning" field in the JSON response;
update GetChannelQuotaDates to enforce this check before calling
model.GetChannelQuotaData and document the chosen behaviour (soft cap vs error)
in the handler.
model/log.go (1)

479-509: ⚡ Quick win

Consider adding ORDER BY for deterministic result ordering.

The query lacks an ORDER BY clause, so results may be returned in arbitrary database-dependent order. While the frontend can sort client-side, ordering in the database is more efficient and ensures consistent results across calls.

📊 Suggested ORDER BY clause
 	if endTime != 0 {
 		tx = tx.Where("created_at <= ?", endTime)
 	}
-	if err := tx.Group("channel_id, (created_at - (created_at % 3600))").Find(&points).Error; err != nil {
+	if err := tx.Group("channel_id, (created_at - (created_at % 3600))").Order("created_at ASC, channel_id ASC").Find(&points).Error; err != nil {
 		return nil, err
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@model/log.go` around lines 479 - 509, The query in GetChannelQuotaData lacks
a deterministic ORDER BY; update the query builder (tx) before the Find call to
add an explicit ordering, e.g. Order("channel_id ASC, (created_at - (created_at
% 3600)) ASC") (or use the alias/column names you prefer) so the returned points
slice is consistently ordered by channel and hour; make this change near the
tx.Group(...).Find(&points) call in the GetChannelQuotaData function.
model/channel.go (1)

821-833: 💤 Low value

Consider the implications of rounding at the individual quota level.

The use of math.Round on each quota update means rounding happens per-transaction rather than on aggregated totals. While this provides consistency, cumulative rounding errors could cause the sum of adjusted quotas to diverge slightly from SUM(original_quota) * ratio. Since this affects only channel-dimension statistics (not user billing), the impact is low, but be aware that high-volume channels may see minor discrepancies in analytics.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@model/channel.go` around lines 821 - 833, applyChannelRatio currently rounds
each adjusted quota per transaction using math.Round, causing cumulative
rounding error; change applyChannelRatio to return a float64 (remove math.Round)
so it returns float64(quota) * ratio and adjust callers that consume
applyChannelRatio to aggregate the float64 values and perform rounding only when
persisting/reporting channel-level used_quota; keep references to
applyChannelRatio, CacheGetChannel and channel.GetChannelRatio() so you update
call sites accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/classic/src/components/table/channels/modals/EditChannelModal.jsx`:
- Line 1035: The advanced-settings auto-expand condition treats null as
non-default; normalize channel_ratio before comparing by replacing checks like
(data.channel_ratio !== undefined && data.channel_ratio !== 1) with a normalized
comparison using a default of 1 (e.g. use ( (data.channel_ratio ?? 1) !== 1 ) or
assign const ratio = data.channel_ratio ?? 1 and compare ratio !== 1) so null
(and undefined) are treated as the default value when deciding to auto-expand;
update the condition in the auto-expand logic referencing data.channel_ratio
accordingly.

In `@web/classic/src/components/table/usage-logs/UsageLogsColumnDefs.jsx`:
- Around line 833-843: The gating for channel-cost display uses parseInt(text)
which truncates fractional values; update the showChannelCost condition (where
channelRatio, showChannelCost, and channelCostNode are defined and renderQuota
is used) to parse the value numerically using Number (or parseFloat) and guard
with Number.isFinite, e.g. replace parseInt(text) > 0 with a check like
Number.isFinite(Number(text)) && Number(text) > 0 so fractional positive costs
(e.g., "0.5") are correctly considered.

In `@web/classic/src/i18n/locales/fr.json`:
- Around line 2312-2313: The two FR translations for the keys "渠道倍率" and
"渠道计费倍率" use "Coefficient" but must match the project's existing terminology by
using "Ratio"; update the values for "渠道倍率" and "渠道计费倍率" to use "Ratio" (e.g.,
"Ratio du canal" and "Ratio de facturation du canal" or equivalent consistent
phrasing used elsewhere) so they align with other French locale entries.

In
`@web/default/src/features/channels/components/drawers/channel-mutate-drawer.tsx`:
- Around line 2549-2552: The current input for channel_ratio uses
value={field.value ?? 1} and onChange calling
field.onChange(Number(e.target.value)), which coerces an empty string to 0;
change it to allow an empty string to be stored and only convert to number when
the input is non-empty: set the input value to field.value ?? '' and in the
onChange call pass e.target.value as '' when empty or Number(e.target.value)
otherwise, invoking field.onChange accordingly so clearing the field does not
set channel_ratio to 0 (targets: the value prop and the onChange that calls
field.onChange for the channel_ratio field).

In `@web/default/src/features/channels/lib/channel-form.ts`:
- Line 38: The validation message for channel_ratio is hardcoded; import the
i18next translator in this non-React module (import { t } from 'i18next') and
replace the literal message in the z.number().min(...) for channel_ratio with a
call to t('...') using an appropriate translation key (e.g.
'validation.channel_ratio_min') so the schema uses i18n; ensure the import is
added at the top of the module and the zod rule references
t('validation.channel_ratio_min') instead of the hardcoded string.

In `@web/default/src/features/dashboard/components/channels/channel-charts.tsx`:
- Around line 122-127: The query currently swallows failures by mapping failed
responses to null in the select, causing the UI to display 0s as if data were
valid; update the useQuery call (queryKey: ['dashboard','channel-quota',
timeRange], queryFn: getChannelQuotaDates) to surface errors (stop converting
failures to null in select), include isError and error from useQuery, and render
an explicit error state in the component when isError is true (e.g., show an
error message or fallback UI instead of totals); ensure getChannelQuotaDates
rejects/throws on HTTP errors so useQuery can mark isError and provide the real
error.

In `@web/default/src/i18n/locales/fr.json`:
- Line 4361: The "Saved" locale entry currently uses the past-participle value
"Économisé"; update the JSON key "Saved" in the French locale so the label is
the noun form "Économies" instead of "Économisé" (i.e., replace the value for
"Saved" with "Économies" in fr.json).

In `@web/default/src/i18n/locales/ja.json`:
- Line 4361: The Japanese translation for the metric label key "Saved" is
ambiguous; update the value for the "Saved" entry in ja.json from "節約" to the
clearer metric label "節約額" (i.e., change the string value for the "Saved" key to
"節約額").
- Around line 4355-4366: The new flat i18n entries ("Channel Billing Ratio",
"Channel Cost", "Channel Stats", "Total Channel Cost", "Total Raw Cost",
"Overall Ratio", "Saved", "Channel Cost Ranking", "Cost Trend", "Top Channels",
"View channel-dimension cost statistics", "Channel billing ratio. Only scales
channel-side usage stats...") must be migrated to hierarchical, feature-scoped
keys (e.g., dashboard.channelStats.totalCost,
dashboard.channelStats.topChannels, usage.channel.billingRatio,
usage.channel.billingRatio.description) and the code references updated to use
those new keys; rename each string to a semantic key under an appropriate
feature namespace (dashboard or usage/usageLogs), replace usages in UI
components and templates to the new keys (search for literal keys like "Channel
Cost" and "Channel Billing Ratio" in code), and keep the original Japanese
translations as values under the new keys to preserve content.

In `@web/default/src/i18n/locales/vi.json`:
- Line 4361: The translation for the i18n key "Saved" is currently the verb
"Tiết kiệm" which reads like an action; update the value for the "Saved" key to
a noun phrase appropriate for a dashboard metric such as "Khoản tiết kiệm" or
"Tiền tiết kiệm" so the label clearly represents a savings amount rather than an
action.

---

Nitpick comments:
In `@controller/usedata.go`:
- Around line 30-43: The GetChannelQuotaDates handler currently passes
startTimestamp/endTimestamp directly to model.GetChannelQuotaData allowing
unbounded ranges; add a time-range validation/cap: compute the duration between
startTimestamp and endTimestamp (or from a default when one side missing), and
if it exceeds a configurable soft limit (e.g., 90 days) either return a 400 with
a clear message or automatically cap the range to the max and include a
"warning" field in the JSON response; update GetChannelQuotaDates to enforce
this check before calling model.GetChannelQuotaData and document the chosen
behaviour (soft cap vs error) in the handler.

In `@model/channel.go`:
- Around line 821-833: applyChannelRatio currently rounds each adjusted quota
per transaction using math.Round, causing cumulative rounding error; change
applyChannelRatio to return a float64 (remove math.Round) so it returns
float64(quota) * ratio and adjust callers that consume applyChannelRatio to
aggregate the float64 values and perform rounding only when persisting/reporting
channel-level used_quota; keep references to applyChannelRatio, CacheGetChannel
and channel.GetChannelRatio() so you update call sites accordingly.

In `@model/log.go`:
- Around line 479-509: The query in GetChannelQuotaData lacks a deterministic
ORDER BY; update the query builder (tx) before the Find call to add an explicit
ordering, e.g. Order("channel_id ASC, (created_at - (created_at % 3600)) ASC")
(or use the alias/column names you prefer) so the returned points slice is
consistently ordered by channel and hour; make this change near the
tx.Group(...).Find(&points) call in the GetChannelQuotaData function.

In
`@web/default/src/features/usage-logs/components/columns/common-logs-columns.tsx`:
- Around line 705-716: The channel cost badge (channelCostNode) shows an
unexplained 'A' prefix when showChannelCost is true (uses channelRatio and
formatLogQuota); add accessible explanatory text by wrapping the badge in a
tooltip or adding an aria-label/title that explains the 'A' (e.g.,
"Admin/Adjusted channel cost") so screen readers and hover users understand the
prefix; ensure the tooltip/aria-label text is localized and attach it to the
same span that renders A {formatLogQuota(Math.round(quota * (channelRatio as
number)))} so the hint appears for both visual and assistive users.
- Around line 373-378: Replace the raw channel_ratio output with the same
compact formatter used for other ratios: call formatRatioCompact on
log.channel_ratio (and append or pass the 'x' suffix the same way group and user
group ratios do) inside the JSX conditional that checks typeof log.channel_ratio
and !== 1, so the Channel Billing Ratio rendering uses
formatRatioCompact(log.channel_ratio, ...) consistent with the other ratio
displays.

In `@web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx`:
- Around line 317-331: The channel ratio is currently shown as
`${log.channel_ratio}x`; change this to use the shared formatter by importing
formatRatioCompact and calling it where the ratio row is added (update the
rows.push call that uses log.channel_ratio), e.g., replace the raw string
construction in the rows.push for label t('Channel Billing Ratio') with
formatRatioCompact(log.channel_ratio) and add the appropriate import for
formatRatioCompact (re-export or move it to a shared util if needed) so the
component uses the same ratio formatting as other components.

In `@web/default/src/i18n/locales/en.json`:
- Around line 4355-4366: The new channel-specific i18n entries should be moved
from generic keys into a feature-scoped namespace to avoid collisions: rename
keys like "Cost Trend", "Top Channels", "Channel Cost", "Channel Billing Ratio",
"Channel Stats", "Total Channel Cost", "Total Raw Cost", "Overall Ratio",
"Saved", "Channel Cost Ranking", and the long description into hierarchical keys
such as dashboard.channels.costTrend, dashboard.channels.topChannels,
dashboard.channels.channelCost, dashboard.channels.billingRatio,
dashboard.channels.stats, dashboard.channels.totalChannelCost,
dashboard.channels.totalRawCost, dashboard.channels.overallRatio,
dashboard.channels.saved, dashboard.channels.costRanking, and
dashboard.channels.billingRatioDescription (or similar), and keep any existing
generic "Cost Trend" key intact; update any code references that read the old
flat keys (search for usages of "Cost Trend", "Top Channels", etc.) to the new
dashboard.channels.* keys so translations resolve correctly.

In `@web/default/src/i18n/locales/fr.json`:
- Around line 4355-4366: The new flat sentence-style translation keys ("Channel
Billing Ratio", "Channel Cost", "Channel Stats", "Total Channel Cost", "Total
Raw Cost", "Overall Ratio", "Saved", "Channel Cost Ranking", "Cost Trend", "Top
Channels", "View channel-dimension cost statistics", "Channel billing ratio.
Only scales channel-side usage stats (used quota / dashboard), does not affect
user billing. 0 means this channel is not counted.") must be converted to
hierarchical keys to match the i18n convention (e.g.,
dashboard.channels.billingRatio, dashboard.channels.cost,
dashboard.channels.stats, dashboard.channels.totalCost,
dashboard.channels.totalRawCost, dashboard.channels.overallRatio,
dashboard.channels.saved, dashboard.channels.costRanking,
dashboard.channels.costTrend, dashboard.channels.topChannels,
dashboard.channels.viewStats, dashboard.channels.billingRatioDescription);
update fr.json to replace the flat keys with these hierarchical keys (preserving
the corresponding French translations), and ensure any code that references the
old flat keys (components or templates using these strings) is updated to use
the new hierarchical keys consistently.

In `@web/default/src/i18n/locales/ru.json`:
- Around line 4355-4366: Replace the flat translation keys with hierarchical,
context-specific keys under a common scope (e.g., dashboard.channels) to avoid
collisions and clarify semantics: rename "Channel Billing Ratio" ->
"dashboard.channels.billingRatio", "Channel Cost" -> "dashboard.channels.cost",
"Channel Stats" -> "dashboard.channels.stats", "Total Channel Cost" ->
"dashboard.channels.totalCost", "Total Raw Cost" ->
"dashboard.channels.totalRawCost", "Overall Ratio" ->
"dashboard.channels.overallRatio", "Saved" -> "dashboard.channels.totalSaved"
(avoid ambiguous single-word keys), "Channel Cost Ranking" ->
"dashboard.channels.costRanking", "Cost Trend" ->
"dashboard.channels.costTrend", "Top Channels" -> "dashboard.channels.top",
"View channel-dimension cost statistics" ->
"dashboard.channels.viewChannelCostStats", and "Channel billing ratio. Only
scales channel-side usage stats..." ->
"dashboard.channels.billingRatioDescription"; update any code references to the
original flat keys to use these new hierarchical keys and ensure the Russian
values remain unchanged.

In `@web/default/src/i18n/locales/zh.json`:
- Around line 4355-4366: The new i18n entries use phrase-as-key literals (e.g.,
"Channel Billing Ratio", "Channel Cost", "Channel Stats", "Total Channel Cost",
"Total Raw Cost", "Overall Ratio", "Saved", "Channel Cost Ranking", "Cost
Trend", "Top Channels", "View channel-dimension cost statistics", "Channel
billing ratio. Only scales channel-side usage stats (...)")—replace these with
hierarchical, semantically clear keys under a common namespace such as
dashboard.channels (for example dashboard.channels.billingRatio,
dashboard.channels.cost, dashboard.channels.stats, dashboard.channels.totalCost,
dashboard.channels.totalRawCost, dashboard.channels.overallRatio,
dashboard.channels.saved, dashboard.channels.costRanking,
dashboard.channels.costTrend, dashboard.channels.topChannels,
dashboard.channels.viewStats, dashboard.channels.billingRatioDescription) and
move the existing Chinese translations as the values; update any components that
reference the old literal keys to use the new dashboard.channels.* keys.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f359f915-6ae2-4fc7-a557-0f35185f255f

📥 Commits

Reviewing files that changed from the base of the PR and between 18282e6 and 2944de8.

📒 Files selected for processing (33)
  • controller/usedata.go
  • model/channel.go
  • model/log.go
  • router/api-router.go
  • web/classic/src/components/table/channels/ChannelsColumnDefs.jsx
  • web/classic/src/components/table/channels/modals/EditChannelModal.jsx
  • web/classic/src/components/table/usage-logs/UsageLogsColumnDefs.jsx
  • web/classic/src/hooks/channels/useChannelsData.jsx
  • web/classic/src/i18n/locales/en.json
  • web/classic/src/i18n/locales/fr.json
  • web/classic/src/i18n/locales/ja.json
  • web/classic/src/i18n/locales/ru.json
  • web/classic/src/i18n/locales/vi.json
  • web/classic/src/i18n/locales/zh-TW.json
  • web/default/src/features/channels/components/channels-columns.tsx
  • web/default/src/features/channels/components/drawers/channel-mutate-drawer.tsx
  • web/default/src/features/channels/constants.ts
  • web/default/src/features/channels/lib/channel-form.ts
  • web/default/src/features/channels/types.ts
  • web/default/src/features/dashboard/api.ts
  • web/default/src/features/dashboard/components/channels/channel-charts.tsx
  • web/default/src/features/dashboard/index.tsx
  • web/default/src/features/dashboard/section-registry.tsx
  • web/default/src/features/dashboard/types.ts
  • web/default/src/features/usage-logs/components/columns/common-logs-columns.tsx
  • web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx
  • web/default/src/features/usage-logs/data/schema.ts
  • web/default/src/i18n/locales/en.json
  • web/default/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/ja.json
  • web/default/src/i18n/locales/ru.json
  • web/default/src/i18n/locales/vi.json
  • web/default/src/i18n/locales/zh.json

Comment thread web/classic/src/components/table/channels/modals/EditChannelModal.jsx Outdated
Comment thread web/classic/src/components/table/usage-logs/UsageLogsColumnDefs.jsx
Comment thread web/classic/src/i18n/locales/fr.json Outdated
Comment thread web/default/src/features/channels/components/drawers/channel-mutate-drawer.tsx Outdated
model_mapping: z.string().optional(),
priority: z.number().optional(),
weight: z.number().optional(),
channel_ratio: z.number().min(0, 'Channel ratio must be >= 0').optional(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Localize the new schema validation message.

The channel_ratio error text is hardcoded in a non-React .ts module, so it won’t follow i18n conventions used elsewhere.

💡 Suggested fix
 import { z } from 'zod'
+import { t } from 'i18next'
@@
-  channel_ratio: z.number().min(0, 'Channel ratio must be >= 0').optional(),
+  channel_ratio: z.number().min(0, t('Channel ratio must be >= 0')).optional(),

As per coding guidelines, "web/default/**/*.ts: In non-React environments (utility functions, constants, class methods), use import { t } from 'i18next' for translations; note this will not auto-update on language changes."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
channel_ratio: z.number().min(0, 'Channel ratio must be >= 0').optional(),
import { z } from 'zod'
import { t } from 'i18next'
channel_ratio: z.number().min(0, t('Channel ratio must be >= 0')).optional(),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/default/src/features/channels/lib/channel-form.ts` at line 38, The
validation message for channel_ratio is hardcoded; import the i18next translator
in this non-React module (import { t } from 'i18next') and replace the literal
message in the z.number().min(...) for channel_ratio with a call to t('...')
using an appropriate translation key (e.g. 'validation.channel_ratio_min') so
the schema uses i18n; ensure the import is added at the top of the module and
the zod rule references t('validation.channel_ratio_min') instead of the
hardcoded string.

Comment thread web/default/src/i18n/locales/fr.json Outdated
Comment on lines +4355 to +4366
"Channel Billing Ratio": "チャネル課金倍率",
"Channel Cost": "チャネルコスト",
"Channel Stats": "チャネル統計",
"Total Channel Cost": "チャネルコスト合計",
"Total Raw Cost": "元コスト合計",
"Overall Ratio": "総合倍率",
"Saved": "節約",
"Channel Cost Ranking": "チャネルコストランキング",
"Cost Trend": "チャネルコスト推移",
"Top Channels": "人気チャネル",
"View channel-dimension cost statistics": "チャネル単位のコスト統計を表示",
"Channel billing ratio. Only scales channel-side usage stats (used quota / dashboard), does not affect user billing. 0 means this channel is not counted.": "チャネル課金倍率:チャネル単位の使用統計(使用済みクォータ/ダッシュボード)のみに反映され、ユーザーの課金には影響しません。0 はこのチャネルをコスト計上しないことを意味します。",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Use feature-scoped hierarchical i18n keys for these new entries.

Lines 4355-4366 add raw text keys instead of semantic keys, which makes namespace ownership and reuse harder (e.g., dashboard.channelStats.totalCost, usageLogs.channel.billingRatio, etc.). Please migrate these new keys to a hierarchical scheme and align call sites.

As per coding guidelines, use “hierarchical and semantically clear translation key names such as dashboard.overview.title and maintain naming consistency”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/default/src/i18n/locales/ja.json` around lines 4355 - 4366, The new flat
i18n entries ("Channel Billing Ratio", "Channel Cost", "Channel Stats", "Total
Channel Cost", "Total Raw Cost", "Overall Ratio", "Saved", "Channel Cost
Ranking", "Cost Trend", "Top Channels", "View channel-dimension cost
statistics", "Channel billing ratio. Only scales channel-side usage stats...")
must be migrated to hierarchical, feature-scoped keys (e.g.,
dashboard.channelStats.totalCost, dashboard.channelStats.topChannels,
usage.channel.billingRatio, usage.channel.billingRatio.description) and the code
references updated to use those new keys; rename each string to a semantic key
under an appropriate feature namespace (dashboard or usage/usageLogs), replace
usages in UI components and templates to the new keys (search for literal keys
like "Channel Cost" and "Channel Billing Ratio" in code), and keep the original
Japanese translations as values under the new keys to preserve content.

Comment thread web/default/src/i18n/locales/ja.json Outdated
Comment thread web/default/src/i18n/locales/vi.json Outdated
@JacksonsY JacksonsY marked this pull request as draft May 15, 2026 18:02
Follow-up refinements to the per-channel billing ratio feature:

- Source the channel stats dashboard from the pre-aggregated
  quota_data table instead of the logs table; add channel_id and
  channel_quota columns to quota_data
- Cap the channel stats time range at 1 month, mirroring
  GetUserQuotaDates
- Fix the channel billing ratio form input so an empty value
  defaults to 1 instead of 0 (0 remains a deliberate value)
- Use int for ChannelQuotaTrendPoint.ChannelQuota to match the
  quota_data column type
- i18n: rename the "Cost Trend" key to "Channel Cost Trend" and
  show the ratio with an "x" suffix consistently
- Add a unit test for Channel.GetChannelRatio
@JacksonsY JacksonsY marked this pull request as ready for review May 15, 2026 19:34
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@controller/usedata.go`:
- Around line 31-35: The handler currently parses startTimestamp and
endTimestamp and only checks the span length, allowing zero or negative/missing
timestamps to pass and cause unbounded aggregation; ensure you validate that
parsed startTimestamp and endTimestamp are > 0 and that endTimestamp >=
startTimestamp before calling model.GetChannelQuotaData (and return an
appropriate JSON error via c.JSON if validation fails). Update the
parsing/validation logic around startTimestamp/endTimestamp (where
strconv.ParseInt and c.Query are used) to check both bounds and ordering, and
reject invalid inputs prior to invoking model.GetChannelQuotaData.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6725d98a-1e73-4460-be56-cf74f5770c96

📥 Commits

Reviewing files that changed from the base of the PR and between 2944de8 and eebad99.

📒 Files selected for processing (15)
  • controller/usedata.go
  • model/channel.go
  • model/channel_ratio_test.go
  • model/log.go
  • model/usedata.go
  • web/classic/src/components/table/usage-logs/UsageLogsColumnDefs.jsx
  • web/default/src/features/channels/components/drawers/channel-mutate-drawer.tsx
  • web/default/src/features/dashboard/components/channels/channel-charts.tsx
  • web/default/src/features/usage-logs/components/columns/common-logs-columns.tsx
  • web/default/src/i18n/locales/en.json
  • web/default/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/ja.json
  • web/default/src/i18n/locales/ru.json
  • web/default/src/i18n/locales/vi.json
  • web/default/src/i18n/locales/zh.json
✅ Files skipped from review due to trivial changes (4)
  • web/default/src/i18n/locales/zh.json
  • web/default/src/i18n/locales/ru.json
  • web/default/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/en.json
🚧 Files skipped from review as they are similar to previous changes (5)
  • web/default/src/i18n/locales/vi.json
  • web/classic/src/components/table/usage-logs/UsageLogsColumnDefs.jsx
  • web/default/src/features/dashboard/components/channels/channel-charts.tsx
  • web/default/src/features/usage-logs/components/columns/common-logs-columns.tsx
  • model/channel.go

Comment thread controller/usedata.go
- web/classic: treat a null channel ratio as the default (1) when
  deciding whether to auto-expand advanced channel settings
- web/classic: gate the channel cost line with numeric parsing
  (Number + isFinite) instead of parseInt to avoid truncation
- web/classic: use "Ratio" instead of "Coefficient" for the French
  channel ratio labels, matching the rest of the locale
- i18n: refine the fr/ja/vi wording of the "Saved" metric label
@JacksonsY JacksonsY force-pushed the feat/channel-billing-ratio branch from 919a254 to 24677fe Compare May 15, 2026 20:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant