Skip to content

v1.0.4-preview.3#14

Merged
CSCITech merged 1 commit into
mainfrom
cscitech
Jul 10, 2026
Merged

v1.0.4-preview.3#14
CSCITech merged 1 commit into
mainfrom
cscitech

Conversation

@CSCITech

Copy link
Copy Markdown
Contributor

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

📝 变更描述 / Description

(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

  • Closes # (如有)

✅ 提交前检查项 / Checklist

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

📸 运行证明 / Proof of Work

(请在此粘贴截图、关键日志或测试报告,以证明变更生效)

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Quota limits now support substantially larger values.
    • Existing quota balances and additions are validated safely without integer overflow.
  • Bug Fixes

    • Updated database storage for user quotas to support large values.
    • Added automatic migration of existing quota fields for supported databases.
    • Preserved compatibility with SQLite deployments.

Walkthrough

Quota validation now supports int64-scale values. User quota fields map to bigint, and startup migrations convert existing PostgreSQL and MySQL quota columns before ORM auto-migration.

Changes

Quota Capacity Expansion

Layer / File(s) Summary
User quota bigint migration
model/user.go, model/main.go
User quota fields use bigint; both database migration paths convert existing quota columns before auto-migration.
Expanded quota validation
controller/user.go, controller/user_setting_test.go
Quota bounds use the int64 maximum, with overflow-safe addition checks and updated boundary assertions.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant migrateDB
  participant migrateUserQuotaColumnsToBigInt
  participant Database
  migrateDB->>migrateUserQuotaColumnsToBigInt: invoke before AutoMigrate
  migrateUserQuotaColumnsToBigInt->>Database: inspect users quota column types
  Database-->>migrateUserQuotaColumnsToBigInt: return metadata
  migrateUserQuotaColumnsToBigInt->>Database: alter columns to bigint
Loading

Poem

A rabbit bounds through quotas wide,
With bigint carrots piled beside.
Old limits hop, new sums take flight,
Columns bloom from int to bright.
Migration paws make tables right.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is only a version tag and does not describe the change. Use a concise title that summarizes the main change, such as quota bigint migration.
Description check ❓ Inconclusive The description is a PR template and does not describe the implemented changes. Replace the template with a brief human-written summary of the quota and schema migration changes.
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cscitech

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

@CSCITech
CSCITech merged commit e5dca9e into main Jul 10, 2026
3 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 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/user_setting_test.go`:
- Around line 219-230: Extend TestQuotaBoundsValidation to cover the actual
maxUserQuotaValue boundary: verify isValidQuotaOverride accepts the maximum and
rejects values above it, and verify isValidQuotaAddition accepts an
exact-to-maximum sum while rejecting additions that would exceed the maximum,
including a case with a large delta that would previously risk overflow. Keep
the existing int32-boundary assertions.

In `@model/main.go`:
- Around line 669-717: Document the startup migration’s locking and duration
impact for large users tables in migrateUserQuotaColumnsToBigInt, advising
operators to run deployments during off-peak periods and consider an online-DDL
approach for very large tables; do not change the migration SQL behavior.
- Around line 694-703: Update the MySQL ALTER TABLE statement in the UsingMySQL
migration branch to explicitly preserve the column constraint by changing the
generated definition to bigint NOT NULL DEFAULT 0. Keep the existing table and
column identifier handling unchanged.

In `@model/user.go`:
- Around line 67-74: Change User fields Quota, UsedQuota, AffQuota, and
AffHistoryQuota from int to int64 to match their bigint database columns, then
update related quota validation and arithmetic helpers in controller/user.go to
use int64 consistently, including parameters, local variables, comparisons, and
return values.
🪄 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: a4331f30-bd6f-4ac6-b4ad-424c4720c63f

📥 Commits

Reviewing files that changed from the base of the PR and between 1f59068 and 4c4729f.

📒 Files selected for processing (4)
  • controller/user.go
  • controller/user_setting_test.go
  • model/main.go
  • model/user.go
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Backend checks
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for 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 direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.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 supports StreamOptions; if it does, add that channel to streamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first 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 in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for 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 the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • controller/user_setting_test.go
  • model/user.go
  • controller/user.go
  • model/main.go
🔇 Additional comments (2)
model/main.go (1)

281-283: LGTM!

Also applies to: 337-339

controller/user.go (1)

38-38: LGTM!

Also applies to: 999-1007

Comment on lines 219 to 230
func TestQuotaBoundsValidation(t *testing.T) {
legacyInt32Max := 1<<31 - 1
aboveLegacyInt32Max := legacyInt32Max + 1

require.True(t, isValidQuotaOverride(0))
require.True(t, isValidQuotaOverride(maxUserQuotaValue))
require.True(t, isValidQuotaOverride(aboveLegacyInt32Max))
require.False(t, isValidQuotaOverride(-1))
require.False(t, isValidQuotaOverride(maxUserQuotaValue+1))

require.True(t, isValidQuotaAddition(maxUserQuotaValue-1, 1))
require.False(t, isValidQuotaAddition(maxUserQuotaValue, 1))
require.False(t, isValidQuotaAddition(0, maxUserQuotaValue+1))
require.True(t, isValidQuotaAddition(aboveLegacyInt32Max, 1))
require.True(t, isValidQuotaAddition(0, aboveLegacyInt32Max))
require.False(t, isValidQuotaAddition(0, 0))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Test doesn't exercise the actual int64-max boundary or overflow protection.

The updated assertions only prove values beyond the old int32 limit are now accepted; they don't cover the new overflow-safe subtraction check (current <= maxUserQuotaValue-delta) near the real maxUserQuotaValue boundary, which is the actual correctness improvement in isValidQuotaAddition.

✅ Suggested additional boundary cases
 	require.True(t, isValidQuotaAddition(aboveLegacyInt32Max, 1))
 	require.True(t, isValidQuotaAddition(0, aboveLegacyInt32Max))
 	require.False(t, isValidQuotaAddition(0, 0))
+	require.True(t, isValidQuotaOverride(int(maxUserQuotaValue)))
+	require.False(t, isValidQuotaAddition(int(maxUserQuotaValue), 1))
📝 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
func TestQuotaBoundsValidation(t *testing.T) {
legacyInt32Max := 1<<31 - 1
aboveLegacyInt32Max := legacyInt32Max + 1
require.True(t, isValidQuotaOverride(0))
require.True(t, isValidQuotaOverride(maxUserQuotaValue))
require.True(t, isValidQuotaOverride(aboveLegacyInt32Max))
require.False(t, isValidQuotaOverride(-1))
require.False(t, isValidQuotaOverride(maxUserQuotaValue+1))
require.True(t, isValidQuotaAddition(maxUserQuotaValue-1, 1))
require.False(t, isValidQuotaAddition(maxUserQuotaValue, 1))
require.False(t, isValidQuotaAddition(0, maxUserQuotaValue+1))
require.True(t, isValidQuotaAddition(aboveLegacyInt32Max, 1))
require.True(t, isValidQuotaAddition(0, aboveLegacyInt32Max))
require.False(t, isValidQuotaAddition(0, 0))
}
func TestQuotaBoundsValidation(t *testing.T) {
legacyInt32Max := 1<<31 - 1
aboveLegacyInt32Max := legacyInt32Max + 1
require.True(t, isValidQuotaOverride(0))
require.True(t, isValidQuotaOverride(aboveLegacyInt32Max))
require.False(t, isValidQuotaOverride(-1))
require.True(t, isValidQuotaAddition(aboveLegacyInt32Max, 1))
require.True(t, isValidQuotaAddition(0, aboveLegacyInt32Max))
require.False(t, isValidQuotaAddition(0, 0))
require.True(t, isValidQuotaOverride(int(maxUserQuotaValue)))
require.False(t, isValidQuotaAddition(int(maxUserQuotaValue), 1))
}
🤖 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/user_setting_test.go` around lines 219 - 230, Extend
TestQuotaBoundsValidation to cover the actual maxUserQuotaValue boundary: verify
isValidQuotaOverride accepts the maximum and rejects values above it, and verify
isValidQuotaAddition accepts an exact-to-maximum sum while rejecting additions
that would exceed the maximum, including a case with a large delta that would
previously risk overflow. Keep the existing int32-boundary assertions.

Comment thread model/main.go
Comment on lines +669 to +717
func migrateUserQuotaColumnsToBigInt() error {
if DB == nil || common.UsingSQLite || !DB.Migrator().HasTable(&User{}) {
return nil
}

tableName := "users"
columnNames := []string{"quota", "used_quota", "aff_quota", "aff_history"}

for _, columnName := range columnNames {
if !DB.Migrator().HasColumn(&User{}, columnName) {
continue
}

var alterSQL string
if common.UsingPostgreSQL {
var dataType string
if err := DB.Raw(`SELECT data_type FROM information_schema.columns
WHERE table_schema = current_schema() AND table_name = ? AND column_name = ?`,
tableName, columnName).Scan(&dataType).Error; err != nil {
common.SysLog(fmt.Sprintf("Warning: failed to query metadata for %s.%s: %v", tableName, columnName, err))
} else if strings.EqualFold(dataType, "bigint") {
continue
}
alterSQL = fmt.Sprintf(`ALTER TABLE "%s" ALTER COLUMN "%s" TYPE bigint USING "%s"::bigint`,
tableName, columnName, columnName)
} else if common.UsingMySQL {
var columnType string
if err := DB.Raw(`SELECT COLUMN_TYPE FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = ? AND column_name = ?`,
tableName, columnName).Scan(&columnType).Error; err != nil {
common.SysLog(fmt.Sprintf("Warning: failed to query metadata for %s.%s: %v", tableName, columnName, err))
} else if strings.HasPrefix(strings.ToLower(columnType), "bigint") {
continue
}
alterSQL = fmt.Sprintf("ALTER TABLE `%s` MODIFY COLUMN `%s` bigint DEFAULT 0", tableName, columnName)
}

if alterSQL == "" {
continue
}
if err := DB.Exec(alterSQL).Error; err != nil {
return fmt.Errorf("failed to migrate %s.%s to bigint: %w", tableName, columnName, err)
}
common.SysLog(fmt.Sprintf("Successfully migrated %s.%s to bigint", tableName, columnName))
}

return nil
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Raw-SQL pre-migration for a large users table can be slow/locking.

MODIFY COLUMN/ALTER COLUMN TYPE on a large users table can hold a table-level lock for a noticeable duration on MySQL/Postgres during startup migration, delaying app boot. Worth noting for operators with large user tables (consider off-peak deploys or an online-DDL tool for very large tables).

🤖 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/main.go` around lines 669 - 717, Document the startup migration’s
locking and duration impact for large users tables in
migrateUserQuotaColumnsToBigInt, advising operators to run deployments during
off-peak periods and consider an online-DDL approach for very large tables; do
not change the migration SQL behavior.

Comment thread model/main.go
Comment on lines +694 to +703
} else if common.UsingMySQL {
var columnType string
if err := DB.Raw(`SELECT COLUMN_TYPE FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = ? AND column_name = ?`,
tableName, columnName).Scan(&columnType).Error; err != nil {
common.SysLog(fmt.Sprintf("Warning: failed to query metadata for %s.%s: %v", tableName, columnName, err))
} else if strings.HasPrefix(strings.ToLower(columnType), "bigint") {
continue
}
alterSQL = fmt.Sprintf("ALTER TABLE `%s` MODIFY COLUMN `%s` bigint DEFAULT 0", tableName, columnName)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- model/main.go around 660-730 ---'
sed -n '660,730p' model/main.go

echo
echo '--- search quota-related definitions/usages ---'
rg -n "quota|used_quota|aff_quota|aff_history" model . --glob '!**/vendor/**' --glob '!**/node_modules/**'

Repository: MAX-API-Next/MAX-API

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- model/user.go struct around quota fields ---'
sed -n '50,85p' model/user.go

echo
echo '--- search for user table migrations / schema creation ---'
rg -n "AutoMigrate|CreateTable|quota.*not null|used_quota.*not null|aff_quota.*not null|aff_history.*not null|type:bigint;default:0" model --glob '!**/vendor/**' --glob '!**/node_modules/**'

Repository: MAX-API-Next/MAX-API

Length of output: 4935


🌐 Web query:

GORM v2 default tag MySQL AutoMigrate nullable NOT NULL integer field behavior

💡 Result:

In GORM v2, AutoMigrate handles integer field nullable/NOT NULL constraints based on the Go struct type definition and GORM tags [1][2][3]. 1. Field Nullability: By default, Go primitive types (e.g., int, int64) are treated as non-nullable [3]. To make an integer field nullable, use a pointer type (e.g., *int) or sql.NullInt64 [4][5][3]. 2. NOT NULL Constraint: Use the gorm:"not null" tag to explicitly enforce the NOT NULL constraint [6][3]. 3. AutoMigrate Behavior: - GORM v2's AutoMigrate will automatically add or remove the NOT NULL constraint if you change the tag in your Go struct [1][2]. - If you change a column from non-nullable to nullable, GORM will typically issue an ALTER TABLE statement [1][6]. - If you change a column from nullable to non-nullable, the migration may fail if the database already contains NULL values in that column [6]. - Note that AutoMigrate logic for constraints has historically had complexities; GORM specifically checks for tag settings and compares them against existing database schema metadata [7]. 4. Default Tag: Using gorm:"default:..." defines the database-level default value [3]. Be cautious with gorm:"default:null", as it has been reported in some versions/dialects to cause unexpected behavior like repeated table recreations or issues with value handling during persistence [8][9]. For robust handling of nullable integer fields, using pointer types or sql.NullInt64 is the recommended approach to ensure GORM correctly maps the field to a database-level NULL [4][5][3].

Citations:


Preserve the existing NOT NULL constraint in the MySQL migration. ALTER TABLE ... MODIFY COLUMN ... bigint DEFAULT 0 restates only the type/default, so MySQL can drop NOT NULL and any other omitted attributes. Use bigint NOT NULL DEFAULT 0 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 `@model/main.go` around lines 694 - 703, Update the MySQL ALTER TABLE statement
in the UsingMySQL migration branch to explicitly preserve the column constraint
by changing the generated definition to bigint NOT NULL DEFAULT 0. Keep the
existing table and column identifier handling unchanged.

Comment thread model/user.go
Comment on lines +67 to +74
Quota int `json:"quota" gorm:"type:bigint;default:0"`
UsedQuota int `json:"used_quota" gorm:"type:bigint;default:0;column:used_quota"` // used quota
RequestCount int `json:"request_count" gorm:"type:int;default:0;"` // request number
Group string `json:"group" gorm:"type:varchar(64);default:'default'"`
AffCode string `json:"aff_code" gorm:"type:varchar(32);column:aff_code;uniqueIndex"`
AffCount int `json:"aff_count" gorm:"type:int;default:0;column:aff_count"`
AffQuota int `json:"aff_quota" gorm:"type:int;default:0;column:aff_quota"` // 邀请剩余额度
AffHistoryQuota int `json:"aff_history_quota" gorm:"type:int;default:0;column:aff_history"` // 邀请历史额度
AffQuota int `json:"aff_quota" gorm:"type:bigint;default:0;column:aff_quota"` // 邀请剩余额度
AffHistoryQuota int `json:"aff_history_quota" gorm:"type:bigint;default:0;column:aff_history"` // 邀请历史额度

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Assess ripple effect of widening quota fields to int64
rg -nP '\.(Quota|UsedQuota|AffQuota|AffHistoryQuota)\b' --type=go -C2 | rg -v '_test\.go'

Repository: MAX-API-Next/MAX-API

Length of output: 158


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## model/user.go context\n'
sed -n '1,160p' model/user.go

printf '\n## quota-related symbols in Go files\n'
rg -n --glob '*.go' '\b(Quota|UsedQuota|AffQuota|AffHistoryQuota)\b|isValidQuota(Override|Addition)|quota' model controller service pkg -C 2

Repository: MAX-API-Next/MAX-API

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '1,160p' model/user.go

Repository: MAX-API-Next/MAX-API

Length of output: 7113


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'FILE: model/user.go\n'
cat -n model/user.go | sed -n '55,90p'

printf '\nUSAGES:\n'
rg -n --glob '*.go' '\b(Quota|UsedQuota|AffQuota|AffHistoryQuota)\b|isValidQuota(Override|Addition)' .

Repository: MAX-API-Next/MAX-API

Length of output: 22787


Use int64 for the quota fields backed by bigint. Quota, UsedQuota, AffQuota, and AffHistoryQuota are still int, so the model only carries the full bigint range on 64-bit builds. If these values need to exceed 32-bit limits, widen the user quota path together, including the quota validation helpers in controller/user.go.

🤖 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/user.go` around lines 67 - 74, Change User fields Quota, UsedQuota,
AffQuota, and AffHistoryQuota from int to int64 to match their bigint database
columns, then update related quota validation and arithmetic helpers in
controller/user.go to use int64 consistently, including parameters, local
variables, comparisons, and return values.

This was referenced Jul 12, 2026
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