Skip to content

feat: add invite commission feature with configurable ratio - #3030

Closed
nanashiwang wants to merge 5287 commits into
QuantumNous:mainfrom
nanashiwang:custom-main
Closed

feat: add invite commission feature with configurable ratio#3030
nanashiwang wants to merge 5287 commits into
QuantumNous:mainfrom
nanashiwang:custom-main

Conversation

@nanashiwang

@nanashiwang nanashiwang commented Feb 26, 2026

Copy link
Copy Markdown
  • Introduced InviteCommissionEnabled and InviteCommissionRatio constants.
  • Updated option handling to validate and store invite commission settings.
  • Enhanced top-up process to settle invite commissions based on the new settings.
  • Updated frontend components to support invite commission configuration and display.

Summary by CodeRabbit

  • New Features

    • Invite commission support: enable/disable toggle and configurable ratio.
    • Commission info shown in the invitation rewards section.
    • Commission settlement automatically processed when top-up completes.
    • Admin settings updated to manage invite commission parameters.
  • Chores

    • CI workflow added to build and publish Docker images.

feitianbubu and others added 30 commits January 27, 2026 17:33
feat(gemini): map OpenAI stop to Gemini stopSequences
fix: remove disable_parallel_tool_use if tool_choice=none
…t-price

fix: /v1/responses/compact default billing
* feat: 引入通用 HTTP BodyStorage/DiskCache 缓存配置与管理

- 新增 common/body_storage.go 提供 HTTP 请求体存储抽象和文件缓存能力
- 增加 common/disk_cache_config.go 支持全局磁盘缓存配置
- main.go 挂载缓存初始化流程
- 新增和补充 controller/performance.go (及 unix/windows) 用于缓存性能监控接口
- middleware/body_cleanup.go 自动清理缓存文件
- router 挂载相关接口
- 前端 settings 页面新增性能监控设置 PerformanceSetting
- 优化缓存开关状态和模块热插拔能力
- 其他相关文件同步适配缓存扩展

* fix: 修复 BodyStorage 并发安全和错误处理问题

- 修复 diskStorage.Close() 竞态条件,先获取锁再执行 CAS
- 为 memoryStorage 添加互斥锁和 closed 状态检查
- 修复 CreateBodyStorageFromReader 在磁盘存储失败时的回退逻辑
- 添加缓存命中统计调用 (IncrementDiskCacheHits/IncrementMemoryCacheHits)
- 修复 gin.go 中 Seek 错误被忽略的问题
- 在 api-router 添加 BodyStorageCleanup 中间件
- 修复前端 formatBytes 对异常值的处理

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
…uantumNous#2793)

Explicitly cast Blocks, Bavail, and Bfree to uint64 for cross-platform compatibility,
as these fields are int64 on FreeBSD but uint64 on Linux.
feat: Support customizing the success and cancel url of Stripe.
…65bf72572ff8684dd7ef068e576

feat: doubao add first and last image to video
…d7331d0987d96dc78bae181e331

feat: task pre consume modelPrice default use setting value
…3b7b97dbdbd98ade9b372bd6f63

feat: CodeViewer click link and auto wrap
…ling

feat(gemini): support cached token billing
fix(ui): use distinct color palette for group tags
* fix: channel affinity log styles

* fix: Issue with incorrect data storage when switching key sources

* feat: support not retrying after a single rule configuration fails

* fix: render channel affinity tooltip as multiline content

* feat: channel affinity cache hit

* fix: prevent ChannelAffinityUsageCacheModal infinite loading and hide data before fetch

* chore: format backend with gofmt and frontend with prettier/eslint autofix
…st-override-take-effect

fix: make channel Host override take effect
feat: /v1/responses qwen3 max && perplexity
Calcium-Ion and others added 16 commits February 23, 2026 17:42
…-encoding-passthrough

fix: skip Accept-Encoding during header passthrough (QuantumNous#2214)
…detail

feat: move user bindings to dedicated management modal
- Introduced a new test file for StreamScannerHandler, covering various scenarios including nil inputs, empty bodies, chunk processing, order preservation, and handler failures.
- Enhanced error handling and data processing logic in StreamScannerHandler to improve robustness and performance.
feat(web): add custom-model create hint and i18n translations
…uting

- Introduced RouteTag middleware to set route tags for different API endpoints.
- Updated logger to include route tags in log output.
- Applied RouteTag middleware across various routers including API, dashboard, relay, video, and web routers for consistent logging.
- Introduced InviteCommissionEnabled and InviteCommissionRatio constants.
- Updated option handling to validate and store invite commission settings.
- Enhanced top-up process to settle invite commissions based on the new settings.
- Updated frontend components to support invite commission configuration and display.
@coderabbitai

coderabbitai Bot commented Feb 26, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Adds invite commission configuration and settlement: new config variables, option handling, top-up model fields and settlement logic, controller responses, and frontend inputs/displays to manage and show invite commission settings.

Changes

Cohort / File(s) Summary
Configuration & Option Handling
common/constants.go, controller/option.go, model/option.go
Add InviteCommissionEnabled (bool) and InviteCommissionRatio (float64) globals; validate and parse InviteCommissionRatio (0–1) in UpdateOption; propagate options into runtime state.
Top-up Model & Settlement
model/topup.go
Add InviteCommissionSettled (bool) and InviteCommissionQuota (int) to TopUp; implement SettleInviteCommissionByTradeNo(tradeNo string, payerUserID int, rechargeQuota int) error with transaction/locking, idempotency, inviter resolution, commission calc and aff_quota/aff_history updates; call settlement from recharge/manual-complete flows.
Top-up Controller
controller/topup.go
Expose invite_commission_enabled and invite_commission_ratio in GetTopUpInfo response; invoke settlement after successful EpayNotify processing.
Frontend — Settings UI
web/src/components/settings/OperationSetting.jsx, web/src/pages/Setting/Operation/SettingsCreditLimit.jsx
Initialize state for invite commission keys; add Switch and InputNumber controls to enable and set InviteCommissionRatio (disabled when feature off).
Frontend — Top-up UI
web/src/components/topup/InvitationCard.jsx, web/src/components/topup/index.jsx
Pass and display inviteCommissionEnabled and inviteCommissionRatio from API to InvitationCard; show commission status/percentage in rewards UI.
CI Workflow
.github/workflows/docker-image-auto.yml
Add workflow to build and publish multi-arch Docker images to GHCR on pushes/tags and manual dispatch.

Sequence Diagram

sequenceDiagram
    participant User as User
    participant TopUp as Top-Up Controller
    participant Model as Top-Up Model
    participant DB as Database
    participant Inviter as Inviter

    User->>TopUp: Complete payment / notify (EpayNotify)
    TopUp->>Model: Mark top-up successful (update status)
    Model->>DB: Update top-up record
    DB-->>Model: Acknowledge

    TopUp->>Model: SettleInviteCommissionByTradeNo(tradeNo, payerUserID, quota)
    Model->>DB: Begin transaction, SELECT ... FOR UPDATE top-up row
    DB-->>Model: Row locked, record returned

    alt status == success and not already settled
        Model->>DB: Resolve inviter (user -> inviter)
        DB-->>Model: Inviter info

        alt valid inviter and not self-invite
            Model->>Model: commission = floor(quota * ratio)
            alt commission > 0
                Model->>DB: Update inviter.aff_quota, insert aff_history, mark top-up settled with commission
                DB-->>Model: Commit
                Model-->>TopUp: Settlement success
            else Commission <= 0
                Model-->>TopUp: Skip (commission zero)
            end
        else No valid inviter
            Model-->>TopUp: Bail out (no-op)
        end
    else Already settled or invalid status
        Model-->>TopUp: Idempotent return (no-op)
    end

    TopUp-->>User: Finalize response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • 新增 creem 支付 #1823: Adds invite-commission fields and calls SettleInviteCommissionByTradeNo within the RechargeCreem function, integrating with the same model/topup.go flow.

Suggested reviewers

  • seefs001
  • Calcium-Ion

🐰 I hopped to code with a squeak and a grin,
I threaded rewards for invites to win,
Ratios set and settlements neat,
Carrots for friends—what a tasty feat! 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main feature being added: an invite commission feature with a configurable ratio, which aligns with all substantial changes across backend and frontend components.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
web/src/pages/Setting/Operation/SettingsCreditLimit.jsx (1)

172-208: Consider using Chinese translations for consistency with existing UI labels.

The new labels use English text wrapped in t():

  • t('Enable invite commission')
  • t('Invite commission ratio')
  • t('When enabled, inviter receives commission after invitee topup')
  • t('Use a decimal between 0 and 1, e.g. 0.1 means 10%')

Other labels in this file use Chinese text (e.g., t('新用户初始额度'), t('请求预扣费额度')). For consistency with the existing UI, consider using Chinese labels or ensuring these translation keys exist in the i18n files.

The functional implementation is correct:

  • InputNumber has proper min/max constraints matching backend validation
  • Conditional disabled state based on InviteCommissionEnabled is good UX
  • Null coalescing with value ?? '' prevents undefined values
💡 Suggested translation keys for consistency
 <Form.Switch
-  label={t('Enable invite commission')}
+  label={t('启用邀请返佣')}
   field={'InviteCommissionEnabled'}
   extraText={t(
-    'When enabled, inviter receives commission after invitee topup',
+    '启用后,被邀请用户充值时,邀请人可获得返佣',
   )}
   ...
 />
 ...
 <Form.InputNumber
-  label={t('Invite commission ratio')}
+  label={t('邀请返佣比例')}
   field={'InviteCommissionRatio'}
   ...
   extraText={t(
-    'Use a decimal between 0 and 1, e.g. 0.1 means 10%',
+    '请输入 0 到 1 之间的小数,例如 0.1 表示 10%',
   )}
   ...
 />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/Setting/Operation/SettingsCreditLimit.jsx` around lines 172 -
208, The UI strings for the new invite-commission controls (Form.Switch with
field InviteCommissionEnabled and Form.InputNumber with field
InviteCommissionRatio) currently use English keys inside t(...); update these to
use Chinese translation keys consistent with the rest of this file (or add
matching Chinese entries to the i18n resource) — replace t('Enable invite
commission'), t('Invite commission ratio'), t('When enabled, inviter receives
commission after invitee topup'), and t('Use a decimal between 0 and 1, e.g. 0.1
means 10%') with the appropriate Chinese keys/strings (or ensure those keys
exist in i18n) so labels match the existing localization style.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/src/components/topup/InvitationCard.jsx`:
- Around line 209-216: Replace the hardcoded English strings in the
InvitationCard component with i18n calls: use t() for both branches where
inviteCommissionEnabled and commissionPercent are rendered (replace the literal
"Invite commission is enabled. Ratio: ${commissionPercent}%" and "Invite
commission is disabled" with t() keys, e.g. t('invite.commission.enabled', {
percent: commissionPercent }) and t('invite.commission.disabled')); update the
Badge/Text rendering to pass the translated strings and add the corresponding
keys to your translation files to ensure consistent localization.

---

Nitpick comments:
In `@web/src/pages/Setting/Operation/SettingsCreditLimit.jsx`:
- Around line 172-208: The UI strings for the new invite-commission controls
(Form.Switch with field InviteCommissionEnabled and Form.InputNumber with field
InviteCommissionRatio) currently use English keys inside t(...); update these to
use Chinese translation keys consistent with the rest of this file (or add
matching Chinese entries to the i18n resource) — replace t('Enable invite
commission'), t('Invite commission ratio'), t('When enabled, inviter receives
commission after invitee topup'), and t('Use a decimal between 0 and 1, e.g. 0.1
means 10%') with the appropriate Chinese keys/strings (or ensure those keys
exist in i18n) so labels match the existing localization style.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 982dc5c and 05ae423.

📒 Files selected for processing (9)
  • common/constants.go
  • controller/option.go
  • controller/topup.go
  • model/option.go
  • model/topup.go
  • web/src/components/settings/OperationSetting.jsx
  • web/src/components/topup/InvitationCard.jsx
  • web/src/components/topup/index.jsx
  • web/src/pages/Setting/Operation/SettingsCreditLimit.jsx

Comment on lines +209 to +216
<div className='flex items-start gap-2'>
<Badge dot type={inviteCommissionEnabled ? 'success' : 'warning'} />
<Text type='tertiary' className='text-sm'>
{inviteCommissionEnabled
? `Invite commission is enabled. Ratio: ${commissionPercent}%`
: 'Invite commission is disabled'}
</Text>
</div>

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

Internationalization missing for commission status text.

The text strings on lines 213-214 are hardcoded in English, while the rest of the component uses the t() function for internationalization. This will result in mixed-language content for non-English users.

🌐 Proposed fix to use i18n
             <Text type='tertiary' className='text-sm'>
               {inviteCommissionEnabled
-                  ? `Invite commission is enabled. Ratio: ${commissionPercent}%`
-                  : 'Invite commission is disabled'}
+                  ? t('邀请返佣已启用,返佣比例:') + `${commissionPercent}%`
+                  : t('邀请返佣已禁用')}
             </Text>

Note: Please verify that the i18n keys are added to the translation files. The suggested Chinese text is illustrative—adjust to match your existing terminology.

📝 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
<div className='flex items-start gap-2'>
<Badge dot type={inviteCommissionEnabled ? 'success' : 'warning'} />
<Text type='tertiary' className='text-sm'>
{inviteCommissionEnabled
? `Invite commission is enabled. Ratio: ${commissionPercent}%`
: 'Invite commission is disabled'}
</Text>
</div>
<div className='flex items-start gap-2'>
<Badge dot type={inviteCommissionEnabled ? 'success' : 'warning'} />
<Text type='tertiary' className='text-sm'>
{inviteCommissionEnabled
? t('邀请返佣已启用,返佣比例:') + `${commissionPercent}%`
: t('邀请返佣已禁用')}
</Text>
</div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/topup/InvitationCard.jsx` around lines 209 - 216, Replace
the hardcoded English strings in the InvitationCard component with i18n calls:
use t() for both branches where inviteCommissionEnabled and commissionPercent
are rendered (replace the literal "Invite commission is enabled. Ratio:
${commissionPercent}%" and "Invite commission is disabled" with t() keys, e.g.
t('invite.commission.enabled', { percent: commissionPercent }) and
t('invite.commission.disabled')); update the Badge/Text rendering to pass the
translated strings and add the corresponding keys to your translation files to
ensure consistent localization.

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (1)
.github/workflows/docker-image-auto.yml (1)

66-67: Consider enabling provenance and SBOM for supply chain security.

Disabling provenance and sbom removes attestations that help verify image integrity and generate Software Bill of Materials. If disabled intentionally for compatibility or performance reasons, this is fine. Otherwise, enabling these features strengthens supply chain security.

-          provenance: false
-          sbom: false
+          provenance: true
+          sbom: true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/docker-image-auto.yml around lines 66 - 67, Enable
supply-chain attestations by setting the GitHub Actions image build options
provenance: true and sbom: true (replace the current false values for the
provenance and sbom keys); if they were disabled intentionally, add a brief
inline comment explaining the compatibility/performance reason so reviewers know
the decision is deliberate.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.github/workflows/docker-image-auto.yml:
- Around line 66-67: Enable supply-chain attestations by setting the GitHub
Actions image build options provenance: true and sbom: true (replace the current
false values for the provenance and sbom keys); if they were disabled
intentionally, add a brief inline comment explaining the
compatibility/performance reason so reviewers know the decision is deliberate.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 05ae423 and dd7ed46.

📒 Files selected for processing (1)
  • .github/workflows/docker-image-auto.yml

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.