Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughQuota conversion and saturation metadata are centralized, provider billing usage is normalized, and clamp information flows into validation, settlement, and logs. Verification codes gain transactional claiming, quota limits become JavaScript-safe, and billing settings gain an unset-models view with localized states. ChangesQuota and billing pipeline
Verification and quota safety
Unset-model pricing
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Provider
participant Relay
participant BillingUsage
participant QuotaService
participant ConsumeLog
Provider->>Relay: return usage metadata
Relay->>BillingUsage: normalize provider billing usage
BillingUsage->>QuotaService: provide effective usage
QuotaService->>QuotaService: convert quota with clamp tracking
QuotaService->>ConsumeLog: attach billing path and saturation metadata
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (1 warning, 2 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
service/convert.go (1)
939-945: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winMirror the total-token fallback in the streaming path.
The non-stream converter falls back to
PromptTokens + CompletionTokenswhenTotalTokensis zero, but the streaming path assigns zero directly. Providers that omittotal_tokenswill therefore produce incorrect Gemini usage metadata.Proposed fix
geminiResponse.UsageMetadata.PromptTokenCount = openAIResponse.Usage.PromptTokens geminiResponse.UsageMetadata.CandidatesTokenCount = openAIResponse.Usage.CompletionTokens - geminiResponse.UsageMetadata.TotalTokenCount = openAIResponse.Usage.TotalTokens + totalTokens := openAIResponse.Usage.TotalTokens + if totalTokens == 0 { + totalTokens = openAIResponse.Usage.PromptTokens + openAIResponse.Usage.CompletionTokens + } + geminiResponse.UsageMetadata.TotalTokenCount = totalTokens🤖 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 `@service/convert.go` around lines 939 - 945, The streaming conversion path should mirror the non-stream total-token fallback: when populating Gemini usage metadata from openAIResponse.Usage, use PromptTokens plus CompletionTokens if TotalTokens is zero, while preserving the provided TotalTokens when nonzero. Update the streaming converter’s usage assignment near geminiBillingMetadataFromOpenAIUsage.
🤖 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 `@common/quota_math.go`:
- Around line 65-79: Update saturateQuota’s boundary comparisons so exact
MaxQuota and MinQuota values are treated as valid representable quotas rather
than overflow or underflow; only values beyond those limits should create
QuotaClamp entries, log via SysError, and be rejected by strict callers.
Preserve the existing NaN handling and clamped return behavior.
In `@service/billing.go`:
- Around line 21-36: Extract the shared QuotaClamp and negative preConsumedQuota
validation from PreConsumeBilling and PreConsumeQuota into a helper, then invoke
that helper from both paths. Preserve the existing error construction, status
code, and skip-retry option, and return any validation error before each path
continues.
In `@service/log_info_generate.go`:
- Around line 31-39: Update attachQuotaSaturation to return without logging when
other is nil, while preserving the existing nil checks for relayInfo and
QuotaClamp and the attachment/logging behavior for non-nil maps.
- Around line 19-29: The attachQuotaSaturationToOther function must not
overwrite a non-map other["admin_info"] value. Preserve the existing value or
return without modification when the field has an incompatible type, while
continuing to initialize admin_info only when it is absent and updating
quota_saturation for valid maps.
In
`@web/default/src/features/system-settings/models/model-ratio-visual-editor.tsx`:
- Around line 1039-1047: Refactor the empty-state text rendering in the table
component to remove the three-level nested ternary. Use an IIFE with early
returns or equivalent conditional logic: return the global-filter message first,
then handle unset-filter mode with its loading and no-prices messages, and
finally return the default no-models message.
---
Outside diff comments:
In `@service/convert.go`:
- Around line 939-945: The streaming conversion path should mirror the
non-stream total-token fallback: when populating Gemini usage metadata from
openAIResponse.Usage, use PromptTokens plus CompletionTokens if TotalTokens is
zero, while preserving the provided TotalTokens when nonzero. Update the
streaming converter’s usage assignment near
geminiBillingMetadataFromOpenAIUsage.
🪄 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: ASSERTIVE
Plan: Pro Plus
Run ID: 7b859845-e410-4fce-9c7f-a1908d0ddeab
📒 Files selected for processing (44)
common/quota_math.gocommon/quota_math_test.godto/billing_usage.godto/billing_usage_test.godto/claude.godto/gemini.godto/openai_response.gomodel/ability.gopkg/billingexpr/round.gopkg/billingexpr/settle.gopkg/billingexpr/types.gorelay/channel/claude/relay-claude.gorelay/channel/gemini/relay-gemini-native.gorelay/channel/gemini/relay-gemini.gorelay/channel/gemini/relay_responses.gorelay/channel/openai/relay-openai.gorelay/channel/openai/relay_image.gorelay/channel/openai/relay_responses.gorelay/channel/openai/relay_responses_compact.gorelay/common/relay_info.gorelay/helper/price.gorelay/relay_task.goservice/billing.goservice/billing_usage.goservice/convert.goservice/log_info_generate.goservice/openaicompat/chat_to_responses_response.goservice/openaicompat/responses_to_chat.goservice/pre_consume_quota.goservice/quota.goservice/task_billing.goservice/text_quota.goservice/text_quota_test.goservice/tiered_settle.goweb/default/src/features/system-settings/billing/section-registry.tsxweb/default/src/features/system-settings/models/model-ratio-form.tsxweb/default/src/features/system-settings/models/model-ratio-visual-editor.tsxweb/default/src/features/system-settings/models/ratio-settings-card.tsxweb/default/src/i18n/locales/en.jsonweb/default/src/i18n/locales/fr.jsonweb/default/src/i18n/locales/ja.jsonweb/default/src/i18n/locales/ru.jsonweb/default/src/i18n/locales/vi.jsonweb/default/src/i18n/locales/zh.json
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: CodeRabbit
🧰 Additional context used
📓 Path-based instructions (6)
**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType) and must not directly callencoding/jsonfor actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid directAUTO_INCREMENT/SERIAL, usecommonGroupCol/commonKeyColandcommonTrueVal/commonFalseValfor DB-specific SQL, branch withcommon.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supportsStreamOptions; if it does, add that channel tostreamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types withomitemptyso explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, readpkg/billingexpr/expr.mdfirst and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.
**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType) instead of directly importing or callingencoding/jsonfor actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with thecommon.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQLflags when need...
Files:
relay/channel/openai/relay_responses_compact.gorelay/channel/openai/relay_image.gorelay/channel/gemini/relay-gemini-native.gomodel/ability.goservice/pre_consume_quota.gorelay/channel/openai/relay_responses.godto/claude.gopkg/billingexpr/types.goservice/billing.gopkg/billingexpr/settle.goservice/openaicompat/responses_to_chat.gorelay/channel/openai/relay-openai.goservice/tiered_settle.gorelay/common/relay_info.godto/billing_usage_test.gopkg/billingexpr/round.gorelay/channel/gemini/relay_responses.gorelay/helper/price.goservice/openaicompat/chat_to_responses_response.goservice/billing_usage.goservice/convert.godto/gemini.godto/openai_response.goservice/quota.goservice/log_info_generate.godto/billing_usage.gorelay/relay_task.gorelay/channel/claude/relay-claude.gocommon/quota_math_test.goservice/task_billing.gocommon/quota_math.goservice/text_quota_test.gorelay/channel/gemini/relay-gemini.goservice/text_quota.go
relay/channel/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
When implementing a new channel, confirm whether the provider supports
StreamOptions; if it does, add the channel tostreamSupportedChannels.
Files:
relay/channel/openai/relay_responses_compact.gorelay/channel/openai/relay_image.gorelay/channel/gemini/relay-gemini-native.gorelay/channel/openai/relay_responses.gorelay/channel/openai/relay-openai.gorelay/channel/gemini/relay_responses.gorelay/channel/claude/relay-claude.gorelay/channel/gemini/relay-gemini.go
web/default/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (web/default/AGENTS.md)
web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用useTranslation()取得t,并通过t()渲染用户可见文本;子组件也应自行使用useTranslation()保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用any,优先使用具体类型或unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用import type。
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用props.xxx以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的types中。
在 React 中应合理使用useMemo、useCallback、React.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态import。
React Query 的数据获取应使用useQuery、变更应使用useMutation;每个查询需配置唯一queryKey,并在成功后对相关查询执行invalidateQueries;服务端错误应统一交给handleServerError。
Axios 请求应使用项目统一的api实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用handleServerError,展示层应使用toast.error等统一方式;文案需走 i18n;路由级错误应由errorComponent承接;表单错误应通过form.setError等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用cn()合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与dark:处理。
应使用语义化 HTML、正确关联label与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用aria-hidden="true"。
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用dangerouslySetInnerHTML;跨域与 Cookie 需配合withCredentials并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过.env读取,并使用VITE_前缀;代码中不得硬编码密钥。
Files:
web/default/src/features/system-settings/billing/section-registry.tsxweb/default/src/features/system-settings/models/model-ratio-form.tsxweb/default/src/features/system-settings/models/ratio-settings-card.tsxweb/default/src/features/system-settings/models/model-ratio-visual-editor.tsx
web/default/src/features/**
📄 CodeRabbit inference engine (web/default/AGENTS.md)
功能模块应放在
src/features/<feature>/,并按需包含components/、lib/、hooks/、api.ts、types.ts、constants.ts等;通用组件应放在src/components/,通用工具与类型应放在src/lib/。
Files:
web/default/src/features/system-settings/billing/section-registry.tsxweb/default/src/features/system-settings/models/model-ratio-form.tsxweb/default/src/features/system-settings/models/ratio-settings-card.tsxweb/default/src/features/system-settings/models/model-ratio-visual-editor.tsx
dto/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
For request structs parsed from client JSON and then re-marshaled to upstream providers, especially in relay/convert paths, optional scalar fields must use pointer types with
omitemptyso that absent fields stay omitted while explicit zero/false values are preserved.
Files:
dto/claude.godto/billing_usage_test.godto/gemini.godto/openai_response.godto/billing_usage.go
pkg/billingexpr/**/*.{go,md}
📄 CodeRabbit inference engine (AGENTS.md)
When working on tiered/dynamic billing expression pricing, first read
pkg/billingexpr/expr.mdand ensure all code changes in the billing expression system follow the documented design, architecture, token normalization, quota conversion, and versioning patterns.
Files:
pkg/billingexpr/types.gopkg/billingexpr/settle.gopkg/billingexpr/round.go
🔇 Additional comments (51)
relay/channel/openai/relay_responses_compact.go (1)
42-45: LGTM!relay/channel/openai/relay_image.go (1)
63-70: LGTM!web/default/src/features/system-settings/billing/section-registry.tsx (1)
115-115: LGTM!relay/channel/claude/relay-claude.go (2)
663-682: LGTM!
913-915: 🩺 Stability & Availability
buildMessageDeltaPatchUsage(nil, claudeInfo)is nil-safe here.> Likely an incorrect or invalid review comment.web/default/src/features/system-settings/models/model-ratio-form.tsx (1)
83-99: LGTM!common/quota_math_test.go (1)
12-137: LGTM!web/default/src/features/system-settings/models/ratio-settings-card.tsx (1)
279-297: LGTM!Also applies to: 371-371, 460-462, 541-551
web/default/src/features/system-settings/models/model-ratio-visual-editor.tsx (1)
221-347: LGTM!Also applies to: 429-491
relay/channel/gemini/relay-gemini-native.go (1)
42-43: LGTM!model/ability.go (1)
54-58: LGTM!relay/channel/openai/relay_responses.go (1)
54-57: LGTM!Also applies to: 148-151
relay/relay_task.go (1)
225-227: LGTM!Also applies to: 378-390
service/task_billing.go (1)
58-58: LGTM!Also applies to: 198-198, 248-250, 315-318
service/pre_consume_quota.go (1)
34-39: 🩺 Stability & AvailabilityGuard
relayInfobefore dereferencing itmodel.GetUserQuota(relayInfo.UserId, false)will panic ifrelayInfocan be nil here.dto/claude.go (1)
567-567: LGTM!web/default/src/i18n/locales/ja.json (1)
1860-1860: LGTM!Also applies to: 2966-2966, 4815-4815
pkg/billingexpr/types.go (1)
57-65: LGTM!Clampis correctly excluded from JSON serialization viajson:"-"since it's for internal auditing only.web/default/src/i18n/locales/vi.json (1)
1860-1860: LGTM!Also applies to: 2966-2966, 4815-4815
pkg/billingexpr/settle.go (1)
21-38: 🎯 Functional CorrectnessNo issue
web/default/src/i18n/locales/fr.json (1)
1860-1860: LGTM!Also applies to: 2966-2966, 4815-4815
service/convert.go (1)
836-852: LGTM!Also applies to: 1008-1035
service/log_info_generate.go (1)
5-17: LGTM!web/default/src/i18n/locales/zh.json (1)
1860-1860: LGTM!Also applies to: 2966-2966, 4815-4815
web/default/src/i18n/locales/en.json (1)
1860-1860: LGTM!Also applies to: 2966-2966, 4815-4815
relay/channel/openai/relay-openai.go (1)
594-598: LGTM!service/tiered_settle.go (2)
106-117: LGTM!
21-26: 🎯 Functional CorrectnessDrop this comment
CacheCreationTokensTotal()returnsmax(CachedCreationTokens, CacheWriteTokens)and clamps negatives to 0, so it does not sum 5m+1h sub-fields.> Likely an incorrect or invalid review comment.service/openaicompat/responses_to_chat.go (1)
138-150: 🗄️ Data Integrity & IntegrationCloneBillingUsage already handles nil and deep-copies the nested usage fields.
web/default/src/i18n/locales/ru.json (1)
1860-1860: LGTM!Also applies to: 2966-2966, 4815-4815
service/quota.go (1)
50-57: LGTM!Also applies to: 86-86, 139-140, 203-204, 252-252, 334-335, 383-383
relay/common/relay_info.go (1)
169-172: LGTM!dto/billing_usage_test.go (1)
1-89: LGTM!Source: Coding guidelines
pkg/billingexpr/round.go (1)
3-14: LGTM!relay/helper/price.go (1)
116-129: LGTM!Also applies to: 210-227, 289-292
service/openaicompat/chat_to_responses_response.go (1)
148-165: LGTM!service/billing_usage.go (1)
1-205: LGTM!relay/channel/gemini/relay_responses.go (1)
35-35: 🎯 Functional CorrectnessNo action needed: empty Gemini usage metadata already falls back to text-based usage estimation.
> Likely an incorrect or invalid review comment.dto/gemini.go (1)
457-505: LGTM!dto/openai_response.go (2)
223-244: LGTM!
256-274: 🗄️ Data Integrity & Integration
CacheCreationTokensTotalshould keep the max of the two aliases, not sum them.CachedCreationTokensandCacheWriteTokensare carried through as alternate representations of the same cache-creation amount, and downstream billing already normalizes on that single total.> Likely an incorrect or invalid review comment.dto/billing_usage.go (2)
1-71: LGTM!Also applies to: 102-216
72-101: 🗄️ Data Integrity & Integration
InputTokensDetails != nilis not a billing bug
service/openaicompat/chat_to_responses_response.goonly setsusage.InputTokensDetailswhen the source detail fields are already non-zero, and the other paths just copy an existing pointer. The fallback does not mask real usage in the current codebase.> Likely an incorrect or invalid review comment.common/quota_math.go (1)
3-63: LGTM aside from the boundary issue flagged insaturateQuotaabove (all of these delegate to it).Also applies to: 81-130
service/text_quota_test.go (1)
321-486: LGTM!relay/channel/gemini/relay-gemini.go (2)
1061-1070: LGTM aside from the nil-deref risk flagged inpatchGeminiZeroCompletionUsageabove, which these call sites all inherit.Also applies to: 1099-1144, 1465-1466, 1475-1480, 1617-1617, 1653-1653
1072-1097: 🩺 Stability & AvailabilityNo issue here —
service.ResponseText2Usagealways returns a non-nil*dto.Usage, soestimated.PromptTokensandestimated.CompletionTokensare safe to read.> Likely an incorrect or invalid review comment.service/text_quota.go (4)
141-170: LGTM!
288-291: LGTM! Good defensive clamp onbaseTokens, and clean integration with the new checked-decimal quota API.Also applies to: 307-309, 319-321, 334-334
462-462: LGTM!Also applies to: 513-523
370-396: 🩺 Stability & Availability
effectiveBillingUsagecannot return nil here.PostTextConsumeQuotaonly enters this block whenusage != nil, andeffectiveBillingUsagereturns the originalusagewhenever it doesn't build a replacement.> Likely an incorrect or invalid review comment.
| if relayInfo != nil && relayInfo.QuotaClamp != nil { | ||
| return types.NewErrorWithStatusCode( | ||
| relayInfo.QuotaClamp, | ||
| types.ErrorCodeModelPriceError, | ||
| http.StatusBadRequest, | ||
| types.ErrOptionWithSkipRetry(), | ||
| ) | ||
| } | ||
| if preConsumedQuota < 0 { | ||
| return types.NewErrorWithStatusCode( | ||
| fmt.Errorf("pre-consume quota cannot be negative: %d", preConsumedQuota), | ||
| types.ErrorCodeModelPriceError, | ||
| http.StatusBadRequest, | ||
| types.ErrOptionWithSkipRetry(), | ||
| ) | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🔵 Trivial | 💤 Low value
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the relevant files and call sites.
for f in service/billing.go service/pre_consume_quota.go; do
echo "===== $f ====="
wc -l "$f"
cat -n "$f" | sed -n '1,220p'
echo
done
echo "===== call sites for PreConsumeBilling ====="
rg -n "PreConsumeBilling\(" -S .
echo "===== call sites for NewBillingSession ====="
rg -n "NewBillingSession\(" -S .
echo "===== definition of RelayInfo ====="
rg -n "type RelayInfo struct|type RelayInfo" -S .Repository: MAX-API-Next/MAX-API
Length of output: 8839
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "===== service/billing.go ====="
cat -n service/billing.go | sed -n '1,220p'
echo "===== service/pre_consume_quota.go ====="
cat -n service/pre_consume_quota.go | sed -n '1,220p'
echo "===== NewBillingSession definition ====="
rg -n "func NewBillingSession|NewBillingSession\(" service -S -A 20 -B 5
echo "===== RelayInfo definition ====="
rg -n "type RelayInfo struct|type RelayInfo" -S -A 30 -B 5 .Repository: MAX-API-Next/MAX-API
Length of output: 13818
Extract the shared pre-consume validation
PreConsumeBilling and PreConsumeQuota duplicate the same QuotaClamp and negative-quota checks. Pull them into a helper so both paths stay aligned.
🤖 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 `@service/billing.go` around lines 21 - 36, Extract the shared QuotaClamp and
negative preConsumedQuota validation from PreConsumeBilling and PreConsumeQuota
into a helper, then invoke that helper from both paths. Preserve the existing
error construction, status code, and skip-retry option, and return any
validation error before each path continues.
There was a problem hiding this comment.
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 `@service/billing_usage.go`:
- Line 120: Consolidate the duplicated InputTokenDetails-to-PromptTokensDetails
mapping by extracting one shared helper in the dto package, then update
fillPromptTokenDetailsFromInputDetails and UsageFromResponsesUsage to call it.
Preserve the existing conditional-if-zero behavior in
fillPromptTokenDetailsFromInputDetails while ensuring both paths use the same
six-field mapping.
🪄 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: ASSERTIVE
Plan: Pro Plus
Run ID: e3f255c0-3d6d-471d-91df-a9ee9e85c18a
📒 Files selected for processing (10)
common/quota_math.gocommon/quota_math_test.goservice/billing.goservice/billing_usage.goservice/log_info_generate.goservice/log_info_generate_test.goservice/pre_consume_quota.goservice/pre_consume_validation_test.goservice/text_quota_test.goweb/default/src/features/system-settings/models/model-ratio-visual-editor.tsx
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
- GitHub Check: CodeRabbit
- GitHub Check: Backend checks
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType) and must not directly callencoding/jsonfor actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid directAUTO_INCREMENT/SERIAL, usecommonGroupCol/commonKeyColandcommonTrueVal/commonFalseValfor DB-specific SQL, branch withcommon.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supportsStreamOptions; if it does, add that channel tostreamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types withomitemptyso explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, readpkg/billingexpr/expr.mdfirst and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.
**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType) instead of directly importing or callingencoding/jsonfor actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with thecommon.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQLflags when need...
Files:
service/billing.goservice/pre_consume_validation_test.goservice/log_info_generate_test.goservice/pre_consume_quota.goservice/log_info_generate.goservice/text_quota_test.gocommon/quota_math_test.gocommon/quota_math.goservice/billing_usage.go
web/default/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (web/default/AGENTS.md)
web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用useTranslation()取得t,并通过t()渲染用户可见文本;子组件也应自行使用useTranslation()保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用any,优先使用具体类型或unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用import type。
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用props.xxx以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的types中。
在 React 中应合理使用useMemo、useCallback、React.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态import。
React Query 的数据获取应使用useQuery、变更应使用useMutation;每个查询需配置唯一queryKey,并在成功后对相关查询执行invalidateQueries;服务端错误应统一交给handleServerError。
Axios 请求应使用项目统一的api实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用handleServerError,展示层应使用toast.error等统一方式;文案需走 i18n;路由级错误应由errorComponent承接;表单错误应通过form.setError等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用cn()合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与dark:处理。
应使用语义化 HTML、正确关联label与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用aria-hidden="true"。
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用dangerouslySetInnerHTML;跨域与 Cookie 需配合withCredentials并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过.env读取,并使用VITE_前缀;代码中不得硬编码密钥。
Files:
web/default/src/features/system-settings/models/model-ratio-visual-editor.tsx
web/default/src/features/**
📄 CodeRabbit inference engine (web/default/AGENTS.md)
功能模块应放在
src/features/<feature>/,并按需包含components/、lib/、hooks/、api.ts、types.ts、constants.ts等;通用组件应放在src/components/,通用工具与类型应放在src/lib/。
Files:
web/default/src/features/system-settings/models/model-ratio-visual-editor.tsx
🔇 Additional comments (16)
web/default/src/features/system-settings/models/model-ratio-visual-editor.tsx (6)
998-1009: LGTM!
777-791: LGTM!
1042-1053: LGTM!
1132-1137: LGTM!
1168-1191: LGTM!
428-502: 🩺 Stability & Availability
isBasePricingUnsetalready handlesundefined— it takesrow?: ModelRow, sosavedByName.get(row.name)is safe.> Likely an incorrect or invalid review comment.common/quota_math.go (1)
65-79: LGTM!common/quota_math_test.go (1)
86-106: LGTM!service/log_info_generate.go (1)
19-42: LGTM!service/log_info_generate_test.go (1)
53-123: LGTM!service/billing.go (2)
18-36: Extraction correctly addresses the earlier duplicate-validation feedback.
validatePreConsumedQuotanow centralizes theQuotaClampand negative-quota checks shared byPreConsumeBillingandPreConsumeQuota, resolving the previously flagged duplication.
19-26: 🎯 Functional CorrectnessNo issue here
*common.QuotaClampimplementserror, andtypes.NewErrorWithStatusCodeaccepts anerror, so this call is valid.> Likely an incorrect or invalid review comment.service/billing_usage.go (1)
103-125: LGTM!service/pre_consume_quota.go (1)
33-36: Good — resolves the previously flagged duplication.This now delegates to the shared
validatePreConsumedQuota(defined inservice/billing.go), eliminating the duplicateQuotaClamp/negative-quota checks that were previously inlined separately inPreConsumeBillingandPreConsumeQuota, exactly as requested in the earlier review. Behavior is covered by the newTestPreConsumeValidationSharedByBillingAndQuotatest.service/pre_consume_validation_test.go (1)
1-61: LGTM!service/text_quota_test.go (1)
14-14: LGTM!Also applies to: 450-507
| if usage.TotalTokens == 0 { | ||
| usage.TotalTokens = usage.PromptTokens + usage.CompletionTokens | ||
| } | ||
| fillPromptTokenDetailsFromInputDetails(&usage.PromptTokensDetails, usage.InputTokensDetails) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Consider consolidating with the identical mapping in UsageFromResponsesUsage.
fillPromptTokenDetailsFromInputDetails maps the same six InputTokenDetails fields (CachedTokens, CachedCreationTokens, CacheWriteTokens, TextTokens, ImageTokens, AudioTokens) that UsageFromResponsesUsage in service/openaicompat/responses_to_chat.go already copies from InputTokensDetails into PromptTokensDetails (unconditionally there, conditionally-if-zero here). Two independent implementations of the same field list increase the risk that a future addition to InputTokenDetails gets updated in one place but not the other, silently dropping a billing-relevant field.
Consider extracting a single shared helper (e.g. in dto package) used by both call sites.
Also applies to: 127-149
🤖 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 `@service/billing_usage.go` at line 120, Consolidate the duplicated
InputTokenDetails-to-PromptTokensDetails mapping by extracting one shared helper
in the dto package, then update fillPromptTokenDetailsFromInputDetails and
UsageFromResponsesUsage to call it. Preserve the existing conditional-if-zero
behavior in fillPromptTokenDetailsFromInputDetails while ensuring both paths use
the same six-field mapping.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/default/src/features/users/components/user-quota-dialog.tsx (1)
68-83: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMinor duplication: reuse
adjustmentValueinstead of recomputing.The override branch recomputes
parseQuotaFromDollars(amountValue), duplicating the same computation already stored inadjustmentValue.♻️ Proposed simplification
case 'override': { - const overrideQuota = parseQuotaFromDollars(amountValue) - return `${t('Current quota')}: ${formatQuota(current)} → ${formatQuota(overrideQuota)}` + return `${t('Current quota')}: ${formatQuota(current)} → ${formatQuota(adjustmentValue)}` }🤖 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/users/components/user-quota-dialog.tsx` around lines 68 - 83, In getPreviewText, update the override branch to reuse the existing adjustmentValue rather than calling parseQuotaFromDollars(amountValue) again, while preserving the current quota preview formatting.
🤖 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/default/src/features/users/lib/quota-safety.ts`:
- Around line 21-25: Simplify isSafeQuotaValue to rely solely on
Number.isSafeInteger(value) and remove the redundant Math.abs(value) <=
Number.MAX_SAFE_INTEGER condition, preserving the function’s existing boolean
behavior.
---
Outside diff comments:
In `@web/default/src/features/users/components/user-quota-dialog.tsx`:
- Around line 68-83: In getPreviewText, update the override branch to reuse the
existing adjustmentValue rather than calling parseQuotaFromDollars(amountValue)
again, while preserving the current quota preview formatting.
🪄 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: ASSERTIVE
Plan: Pro Plus
Run ID: f50cb7b6-afb6-422a-b5e3-a58de8ca67ec
📒 Files selected for processing (19)
common/verification.gocommon/verification_test.gocontroller/misc.gocontroller/user.gocontroller/user_setting_test.godto/billing_usage_test.godto/openai_response.goservice/billing_usage.goservice/openaicompat/responses_compat_test.goservice/openaicompat/responses_to_chat.goweb/default/src/features/users/components/user-quota-dialog.tsxweb/default/src/features/users/lib/quota-safety.test.tsweb/default/src/features/users/lib/quota-safety.tsweb/default/src/i18n/locales/en.jsonweb/default/src/i18n/locales/fr.jsonweb/default/src/i18n/locales/ja.jsonweb/default/src/i18n/locales/ru.jsonweb/default/src/i18n/locales/vi.jsonweb/default/src/i18n/locales/zh.json
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: CodeRabbit
🧰 Additional context used
📓 Path-based instructions (6)
web/default/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (web/default/AGENTS.md)
web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用useTranslation()取得t,并通过t()渲染用户可见文本;子组件也应自行使用useTranslation()保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用any,优先使用具体类型或unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用import type。
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用props.xxx以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的types中。
在 React 中应合理使用useMemo、useCallback、React.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态import。
React Query 的数据获取应使用useQuery、变更应使用useMutation;每个查询需配置唯一queryKey,并在成功后对相关查询执行invalidateQueries;服务端错误应统一交给handleServerError。
Axios 请求应使用项目统一的api实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用handleServerError,展示层应使用toast.error等统一方式;文案需走 i18n;路由级错误应由errorComponent承接;表单错误应通过form.setError等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用cn()合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与dark:处理。
应使用语义化 HTML、正确关联label与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用aria-hidden="true"。
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用dangerouslySetInnerHTML;跨域与 Cookie 需配合withCredentials并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过.env读取,并使用VITE_前缀;代码中不得硬编码密钥。
Files:
web/default/src/features/users/lib/quota-safety.test.tsweb/default/src/features/users/lib/quota-safety.tsweb/default/src/features/users/components/user-quota-dialog.tsx
web/default/src/features/**/lib/**/*.ts
📄 CodeRabbit inference engine (web/default/AGENTS.md)
表单应使用 React Hook Form + Zod:在功能模块的
lib/下定义 schema,并用z.infer导出表单类型;useForm应配合@hookform/resolvers/zod进行校验。
Files:
web/default/src/features/users/lib/quota-safety.test.tsweb/default/src/features/users/lib/quota-safety.ts
web/default/src/features/**
📄 CodeRabbit inference engine (web/default/AGENTS.md)
功能模块应放在
src/features/<feature>/,并按需包含components/、lib/、hooks/、api.ts、types.ts、constants.ts等;通用组件应放在src/components/,通用工具与类型应放在src/lib/。
Files:
web/default/src/features/users/lib/quota-safety.test.tsweb/default/src/features/users/lib/quota-safety.tsweb/default/src/features/users/components/user-quota-dialog.tsx
web/default/src/**/*.test.ts
📄 CodeRabbit inference engine (web/default/AGENTS.md)
工具函数与纯逻辑应优先编写单元测试;测试文件应命名为
*.test.ts。
Files:
web/default/src/features/users/lib/quota-safety.test.ts
**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType) and must not directly callencoding/jsonfor actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid directAUTO_INCREMENT/SERIAL, usecommonGroupCol/commonKeyColandcommonTrueVal/commonFalseValfor DB-specific SQL, branch withcommon.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supportsStreamOptions; if it does, add that channel tostreamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types withomitemptyso explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, readpkg/billingexpr/expr.mdfirst and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.
**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType) instead of directly importing or callingencoding/jsonfor actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with thecommon.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQLflags when need...
Files:
controller/misc.goservice/openaicompat/responses_compat_test.godto/openai_response.godto/billing_usage_test.gocommon/verification_test.gocommon/verification.gocontroller/user.goservice/openaicompat/responses_to_chat.gocontroller/user_setting_test.goservice/billing_usage.go
dto/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
For request structs parsed from client JSON and then re-marshaled to upstream providers, especially in relay/convert paths, optional scalar fields must use pointer types with
omitemptyso that absent fields stay omitted while explicit zero/false values are preserved.
Files:
dto/openai_response.godto/billing_usage_test.go
🔇 Additional comments (22)
web/default/src/features/users/lib/quota-safety.test.ts (1)
1-55: LGTM!web/default/src/features/users/lib/quota-safety.ts (1)
27-39: LGTM!web/default/src/i18n/locales/ja.json (1)
1860-1860: LGTM!Also applies to: 2966-2966, 3605-3605, 4816-4816
service/openaicompat/responses_compat_test.go (1)
292-292: LGTM!Also applies to: 321-321
web/default/src/features/users/components/user-quota-dialog.tsx (1)
60-66: LGTM!Also applies to: 88-101, 185-196
web/default/src/i18n/locales/ru.json (1)
1860-1860: LGTM!Also applies to: 2966-2966, 3605-3605, 4816-4816
controller/misc.go (1)
351-358: LGTM!web/default/src/i18n/locales/zh.json (1)
1857-1861: LGTM!Also applies to: 2965-2967, 3604-3606, 4815-4817
web/default/src/i18n/locales/vi.json (1)
1860-1860: LGTM!Also applies to: 2966-2966, 3605-3605, 4816-4816
common/verification_test.go (1)
3-7: LGTM! Good coverage of the failure/panic/concurrent-claim edge cases for the new claim-based verification flow.Also applies to: 25-45, 47-67, 69-111
common/verification.go (1)
11-15: LGTM! Solid claim/reserve pattern: exclusive concurrent access, panic-safe rollback via defer, and correct no-op guard against concurrent re-registration.Also applies to: 48-57, 59-94, 96-102
controller/user.go (1)
38-40: LGTM! The JS-safe-integer bound and symmetric subtraction guard are consistent with the existing addition/override validation and are backed by matching unit tests.Also applies to: 1004-1017, 1105-1113
controller/user_setting_test.go (3)
220-249: LGTM! Bounds assertions correctly mirror the new isValidQuotaSubtraction implementation.
251-287: LGTM! Good regression test for the "code stays valid on DB failure" fix — forces a real GORM update error and checks both the code and the password remain unchanged.
302-332: Minor: description says "replaced," but the old test is still present.The line-range summary states this test replaced the previous quota upper-bound test, but
TestManageUserRejectsQuotaValueAboveInt64Max(unchanged, above this block) is still in the file — so it was added alongside, not replacing it. Not a code issue, just a documentation nuance; the new test itself is correctly implemented and more robust (avoids the int64-JSON-overflow ambiguity of the older test).service/billing_usage.go (1)
127-129: Resolves prior duplication concern.This consolidates the InputTokenDetails→PromptTokensDetails field mapping into the shared
dto.CopyInputTokenDetailshelper, addressing the previously flagged duplication between this function andUsageFromResponsesUsage.web/default/src/i18n/locales/en.json (1)
1857-1861: LGTM!Also applies to: 2965-2967, 3604-3606, 4815-4817
dto/openai_response.go (2)
224-230: LGTM!
259-287: LGTM!web/default/src/i18n/locales/fr.json (1)
1860-1860: LGTM!Also applies to: 2966-2966, 3605-3605, 4816-4816
dto/billing_usage_test.go (1)
66-104: LGTM!service/openaicompat/responses_to_chat.go (1)
138-143: LGTM!
There was a problem hiding this comment.
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 `@web/default/src/features/users/lib/quota-safety.ts`:
- Around line 21-22: Update isSafeQuotaValue to explicitly annotate its return
type as boolean while preserving the existing Number.isSafeInteger validation.
🪄 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: ASSERTIVE
Plan: Pro Plus
Run ID: 8e7c6d72-55fb-42e9-92b6-fed8fb377213
📒 Files selected for processing (1)
web/default/src/features/users/lib/quota-safety.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: CodeRabbit
🧰 Additional context used
📓 Path-based instructions (3)
web/default/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (web/default/AGENTS.md)
web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用useTranslation()取得t,并通过t()渲染用户可见文本;子组件也应自行使用useTranslation()保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用any,优先使用具体类型或unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用import type。
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用props.xxx以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的types中。
在 React 中应合理使用useMemo、useCallback、React.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态import。
React Query 的数据获取应使用useQuery、变更应使用useMutation;每个查询需配置唯一queryKey,并在成功后对相关查询执行invalidateQueries;服务端错误应统一交给handleServerError。
Axios 请求应使用项目统一的api实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用handleServerError,展示层应使用toast.error等统一方式;文案需走 i18n;路由级错误应由errorComponent承接;表单错误应通过form.setError等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用cn()合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与dark:处理。
应使用语义化 HTML、正确关联label与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用aria-hidden="true"。
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用dangerouslySetInnerHTML;跨域与 Cookie 需配合withCredentials并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过.env读取,并使用VITE_前缀;代码中不得硬编码密钥。
Files:
web/default/src/features/users/lib/quota-safety.ts
web/default/src/features/**/lib/**/*.ts
📄 CodeRabbit inference engine (web/default/AGENTS.md)
表单应使用 React Hook Form + Zod:在功能模块的
lib/下定义 schema,并用z.infer导出表单类型;useForm应配合@hookform/resolvers/zod进行校验。
Files:
web/default/src/features/users/lib/quota-safety.ts
web/default/src/features/**
📄 CodeRabbit inference engine (web/default/AGENTS.md)
功能模块应放在
src/features/<feature>/,并按需包含components/、lib/、hooks/、api.ts、types.ts、constants.ts等;通用组件应放在src/components/,通用工具与类型应放在src/lib/。
Files:
web/default/src/features/users/lib/quota-safety.ts
Important
📝 变更描述 / Description
(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)
🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。📸 运行证明 / Proof of Work
(请在此粘贴截图、关键日志或测试报告,以证明变更生效)