Skip to content

feat(subscription): 支持套餐绑定分组,实现渠道/分组级别的订阅消耗限制#4246

Open
Mobaitt wants to merge 2 commits intoQuantumNous:mainfrom
Mobaitt:feat/subscription-plan-groups
Open

feat(subscription): 支持套餐绑定分组,实现渠道/分组级别的订阅消耗限制#4246
Mobaitt wants to merge 2 commits intoQuantumNous:mainfrom
Mobaitt:feat/subscription-plan-groups

Conversation

@Mobaitt
Copy link
Copy Markdown

@Mobaitt Mobaitt commented Apr 14, 2026

📝 变更描述 / 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

image

Summary by CodeRabbit

  • New Features
    • Admins can restrict subscription plans to specific user groups via a new multi-select when creating or editing plans.
    • Consumption now checks a plan’s allowed groups; users may only use plans that apply to their group, with clear errors when groups are invalid.
    • UI shows applicable groups in plan tables, popovers, modals, and cards, displaying "unrestricted" when no groups are set.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 14, 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: ec83c8be-5c98-4c1b-a1cd-acd7131dfb98

📥 Commits

Reviewing files that changed from the base of the PR and between 5f88110 and 6faaf47.

📒 Files selected for processing (1)
  • controller/subscription.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • controller/subscription.go

Walkthrough

Adds group-based restrictions to subscription plans: new allowed_groups field, normalization/validation in controllers, group-aware pre-consumption in the model, passing a resolved billing group through billing/funding, and frontend UI to edit and display allowed groups.

Changes

Cohort / File(s) Summary
Database & Model
model/main.go, model/subscription.go
Add allowed_groups column to SQLite DDL. Add AllowedGroups on SubscriptionPlan, NormalizeSubscriptionAllowedGroups, subscriptionPlanAllowsGroup, and change PreConsumeUserSubscription(..., usingGroup string, ...) to enforce group-aware consumption and return a clear "no active subscription for group" error when none match.
Controller Validation
controller/subscription.go
Normalize req.Plan.AllowedGroups before validation; split and verify each group exists via ratio_setting.GetGroupRatioCopy(); abort on first missing group. Persist normalized allowed_groups on update.
Billing & Funding Flow
service/billing_session.go, service/funding_source.go
Resolve usingGroup in NewBillingSession via resolveSubscriptionBillingGroup (handles "auto" and relay info) and set SubscriptionFunding.usingGroup. Forward usingGroup into model.PreConsumeUserSubscription during PreConsume.
Frontend — Table & Modal
web/src/components/table/subscriptions/SubscriptionsColumnDefs.jsx, web/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx
Display allowed groups in plan popover and new table column (适用分组) as tags or "不限制分组". Add multi-select form field in add/edit modal; serialize array → comma-separated string for API.
Frontend — Plans Card
web/src/components/topup/SubscriptionPlansCard.jsx
Add allowedGroupsLabel into plan benefits so allowed groups appear on subscription plan cards.

Sequence Diagram

sequenceDiagram
    participant Admin as Admin/UI
    participant Controller as Controller
    participant Model as Model
    participant DB as Database
    participant Billing as BillingSession
    participant Funding as FundingService

    Note over Admin,DB: Create/Update Subscription Plan
    Admin->>Controller: POST/PUT plan (allowed_groups:"g1,g2")
    Controller->>Model: NormalizeSubscriptionAllowedGroups("g1,g2")
    Model-->>Controller: "g1,g2"
    Controller->>Controller: Validate groups exist via ratio_setting
    Controller->>DB: Save plan with allowed_groups
    DB-->>Controller: OK
    Controller-->>Admin: Success

    Note over Billing,Funding: Consumption with Group
    Admin->>Billing: Request billing (relay.using_group / auto)
    Billing->>Billing: resolveSubscriptionBillingGroup(...)
    Billing->>Funding: Create SubscriptionFunding(usingGroup)
    Funding->>Model: PreConsumeUserSubscription(..., usingGroup, ...)
    Model->>DB: Query active subscriptions for user
    DB-->>Model: [sub1, sub2]
    Model->>Model: For each plan: subscriptionPlanAllowsGroup(plan, usingGroup)
    alt Any plan allows group
        Model-->>Funding: Approve pre-consume (quota reserved)
        Funding-->>Billing: Success
    else No plan allows group
        Model-->>Funding: Error "no active subscription for group <group>"
        Funding-->>Billing: Error
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • PR #2808: Modifies subscription controller and model fields — strong overlap in subscription plan schema and consumption logic.
  • PR #2879: Also changes NewBillingSession / billing flow — likely to conflict on group resolution and billing logic.
  • PR #2878: Frontend changes affecting subscription plan UI/components (possible merge conflicts with allowed_groups display).

Suggested labels

enhancement

Suggested reviewers

  • Calcium-Ion
  • 6639835

Poem

🐰 I hop with joy, a tiny cheer,
Plans now carry group names clear,
From DB roots to UI tags bright,
Only the right groups may take flight,
Hooray for rules that guide each bite! 🥕

🚥 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 change: adding support for binding subscription plans to groups and implementing group-level subscription consumption restrictions.

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

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

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.

🧹 Nitpick comments (1)
controller/subscription.go (1)

154-163: Consider consistent error message language.

The error message "allowed group does not exist" is in English, while other validation messages in this handler are in Chinese (e.g., "套餐标题不能为空", "升级分组不存在"). Consider using Chinese for consistency:

-				common.ApiErrorMsg(c, "allowed group does not exist")
+				common.ApiErrorMsg(c, "适用分组不存在")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controller/subscription.go` around lines 154 - 163, The validation currently
returns an English message for missing allowed groups; change the error text to
the existing Chinese phrasing used elsewhere to keep messages consistent. In the
block that iterates req.Plan.AllowedGroups (using
ratio_setting.GetGroupRatioCopy() and common.ApiErrorMsg), replace the "allowed
group does not exist" message with the Chinese message used elsewhere (e.g.,
"升级分组不存在") so that the call common.ApiErrorMsg(c, ...) uses the Chinese string.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@controller/subscription.go`:
- Around line 154-163: The validation currently returns an English message for
missing allowed groups; change the error text to the existing Chinese phrasing
used elsewhere to keep messages consistent. In the block that iterates
req.Plan.AllowedGroups (using ratio_setting.GetGroupRatioCopy() and
common.ApiErrorMsg), replace the "allowed group does not exist" message with the
Chinese message used elsewhere (e.g., "升级分组不存在") so that the call
common.ApiErrorMsg(c, ...) uses the Chinese string.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 26363a76-3611-4d66-a33d-dead3476d59e

📥 Commits

Reviewing files that changed from the base of the PR and between 8c8661d and 5f88110.

⛔ Files ignored due to path filters (1)
  • web/bun.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • controller/subscription.go
  • model/main.go
  • model/subscription.go
  • service/billing_session.go
  • service/funding_source.go
  • web/src/components/table/subscriptions/SubscriptionsColumnDefs.jsx
  • web/src/components/table/subscriptions/modals/AddEditSubscriptionModal.jsx
  • web/src/components/topup/SubscriptionPlansCard.jsx

Copy link
Copy Markdown
Author

@Mobaitt Mobaitt left a comment

Choose a reason for hiding this comment

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

LGTM,功能实现完整,代码符合规范

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