- Phase 7a: Cosmetic cleanup (CMS+FO+BO) - Phase 7b: FrontOffice RPC migration to Customer* RPCs - Phase 7c: Delete 4 deprecated CQRS handlers (1125 lines removed) - Updated overview diagram, commit list, and footer
25 KiB
🔄 نقشهراه تحول پکیجبیس — تسکهای گامبهگام
وضعیت: در حال اجرا — فاز ۰-۶ تکمیل ✅ | فاز ۷a-c تکمیل ✅ | فاز UI باقیمانده
تاریخ: ۱۴۰۴/۱۲/۰۹
پیشنیاز: BIZ-PACKAGE-BASED-SYSTEM.md v3 (تکمیل پورسانت per-package)
هدف: شکستن ۴۸+ تغییر به تسکهای اتمیک با ترتیب اجرا و وابستگیها
کامیتها:
CMS:8b9c317→fe3edd1→ae92ab8→a9cd2fd→8e5c7c5→ccb938e→0002a5a→607f791→7176fe4→d19c569→469d97b→161f796→8446e0e
FrontOffice:b82cac4→71f391a
BackOffice:f1b0085
⚠️ تغییرات v3: پورسانت per-package، carryover مجزا، SP parameters داینامیک، گزارشدهی FO/BO per-package
📊 نمای کلی
مرحله ۰: فیکس باگ فوری (۱ روز) ✅ `8b9c317` + `fe3edd1`
└─→ مرحله ۱: زیرساخت Domain + DB (۴ روز) ✅ `ae92ab8`
└─→ مرحله ۱.۵: Migration + Seed ✅ `a9cd2fd`
├─→ مرحله ۲: منطق کسبوکار (۴ روز) ✅ `8e5c7c5`
│ └─→ مرحله ۳: بازسازی لایه Package ✅ `ccb938e`
│ └─→ مرحله ۴: CRUD + Legacy Fixes ✅ `0002a5a`
│ └─→ مرحله UI (۵ روز) ⬜
└─→ مرحله ۳: پورسانت (۴ روز) ✅ `607f791`+`7176fe4`
└─→ مرحله ۶: Deprecation cleanup ✅ `d19c569`
└─→ مرحله ۷: Migration + Cleanup ✅
├─→ 7a: Cosmetic cleanup ✅ CMS:`469d97b` FO:`b82cac4` BO:`f1b0085`
├─→ 7b: FO RPC migration ✅ CMS:`161f796` FO:`71f391a`
└─→ 7c: Delete deprecated ✅ CMS:`8446e0e`
└─→ مرحله ۵: تست + استقرار (۳ روز) ⬜
مسیر بحرانی: ۰→۱→۱.۵→۲→۳→۴→UI→۵ = ~۱۷ روز | انجامشده: ۰→۷c (~۱۳ روز)
مرحله ۰ — فیکس باگهای فوری ✅
✅ تکمیلشده | کامیت:
8b9c317+fe3edd1
✅ وضعیت باگها (بررسی اولیه لازم)
| # | باگ | Handler | شرح فیکس |
|---|---|---|---|
| B1 | DiscountBalance شارژ نمیشود | VerifyGoldenPackagePurchaseCommandHandler |
اضافه DiscountBalance += Amount × 2 + WalletChangeLog |
| B2 | UserPackagePurchase ساخته نمیشود | VerifyGoldenPackagePurchaseCommandHandler |
ساخت record بعد verify موفق |
| B3 | UserPackagePurchase ساخته نمیشود | VerifyPackagePurchaseCommandHandler |
ساخت record بعد verify موفق |
| B4 | UserPackagePurchase ساخته نمیشود | VerifyBasePackagePaymentCommandHandler |
ساخت record بعد verify موفق |
دستور کار B1:
1. باز کردن VerifyGoldenPackagePurchaseCommandHandler.cs
2. پیدا کردن جایی که Balance شارژ میشود
3. اضافه کردن:
wallet.DiscountBalance += command.Amount * 2;
// + ساخت WalletChangeLog برای DiscountBalance
4. تست: verify → چک DiscountBalance در DB
دستور کار B2-B4 (الگوی مشترک):
1. بعد از verify موفق و شارژ wallet:
var purchase = new UserPackagePurchase
{
UserId = userId,
PackageId = packageId, // فعلاً BasePackageId = 4
PurchaseDate = DateTime.UtcNow,
Amount = amount,
PurchaseMethod = purchaseMethod, // ZarinPal, BFF, etc.
TransactionId = transactionId,
IsVerified = true
};
_context.UserPackagePurchases.Add(purchase);
2. تست: verify → چک UserPackagePurchases table
مرحله ۱ — زیرساخت (Domain + DB) ✅
✅ تکمیلشده | کامیت:
ae92ab8(Phase 1) +a9cd2fd(Phase 1.5 Migration)
T1.1 — بروزرسانی Package Entity (۱۱ فیلد جدید — v3)
فایل: CMS/src/CMSMicroservice.Domain/Entities/Package.cs
+ public int SortOrder { get; set; }
+ public bool IsActive { get; set; } = true;
+ public bool IsBasePackage { get; set; }
+ public bool SupportsDayaPurchase { get; set; }
+ public bool SupportsDirectPurchase { get; set; } = true;
+ public long ActivationFee { get; set; }
+ public decimal DiscountMultiplier { get; set; } = 2.0m;
+ public decimal MagicWalletMultiplier { get; set; } = 2.5m;
+ // === v3: تنظیمات پورسانت per-package ===
+ public int MaxBalancesPerLeg { get; set; } = 300; // نقرهای=۳۰
+ public int MaxNetworkLevel { get; set; } = 15;
+ // === v3: سقف کیفپول جادویی per-package ===
+ public long MagicWalletMaxDeposit { get; set; } = 1_000_000_000;
+ public long MagicWalletMaxCredit { get; set; } = 2_500_000_000;
+
+ public virtual ICollection<PackageFeature> PackageFeatures { get; set; }
EF Config: PackageConfiguration.cs
- حداکثر یک
IsBasePackage = true(Index filter) - Precision for decimal fields
T1.2 — ایجاد PackageFeature Entity
فایل جدید: CMS/src/CMSMicroservice.Domain/Entities/PackageFeature.cs
public class PackageFeature : BaseAuditableEntity
{
public long PackageId { get; set; }
public virtual Package Package { get; set; }
public long ClubFeatureId { get; set; }
public virtual ClubFeature ClubFeature { get; set; }
public bool IsIncluded { get; set; } = true;
}
T1.3-T1.6 — اضافه PackageId به entityها
| Entity | فیلد | Required? | توضیح | v3? |
|---|---|---|---|---|
| ClubMembership | long? PackageId |
nullable (بعد migration → required) | آخرین پکیج | |
| ClubMembershipCycle | long PackageId |
required | پکیج این چرخه | |
| WeeklyCommissionPool | long PackageId |
required + Unique(WeekDefId, PkgId) | Pool هر پکیج | |
| UserCommissionPayout | long? PackageId |
nullable + Unique(UserId, WeekId, PkgId) | ردیابی | 🔄 |
| NetworkWeeklyBalance | long PackageId |
required + Unique(UserId, WeekId, PkgId) | تعادل per-package | 🆕 |
T1.7 — حذف SystemConstants (v3: ۷ ثابت)
فایل: CMS/src/CMSMicroservice.Domain/Common/SystemConstants.cs
- public const long BasePackageAmount = 56_000_000;
- public const long DayaLoanAmount = 56_000_000;
- public const long ClubActivationFee = 25_200_000;
- public const long ClubMembershipGiftValue = 25_200_000;
- public const decimal MagicWalletMultiplier = 2.5m;
- // === v3: انتقال به Package entity ===
- public const int CommissionMaxWeeklyBalancesPerLeg = 300;
- public const int CommissionMaxNetworkLevel = 15;
⚠️ قبل از حذف: grep تمام مصرفکنندهها → جایگزین با
Package.Property
⚠️ v3:CommissionMaxWeeklyBalancesPerLegوCommissionMaxNetworkLevelهم باید per-package شوند
T1.8 — Database Migration
dotnet ef migrations add AddPackageBasedSystem
شامل:
- ستونهای جدید Package
- جدول PackageFeatures
- FKها در 4 entity
- Unique constraint
T1.9 — Data Migration Script
-- 1. بروزرسانی پکیج فعلی (ID=4 → اضافه فیلدهای جدید)
UPDATE "CMS"."Packages" SET
"SortOrder" = 2,
"IsActive" = true,
"IsBasePackage" = true,
"SupportsDayaPurchase" = true,
"SupportsDirectPurchase" = true,
"ActivationFee" = 25200000,
"DiscountMultiplier" = 2.0,
"MagicWalletMultiplier" = 2.5,
-- v3: تنظیمات پورسانت
"MaxBalancesPerLeg" = 300,
"MaxNetworkLevel" = 15,
"MagicWalletMaxDeposit" = 1000000000,
"MagicWalletMaxCredit" = 2500000000
WHERE "Id" = 4;
-- 2. Link existing data to base package
UPDATE "CMS"."ClubMemberships" SET "PackageId" = 4 WHERE "PackageId" IS NULL;
UPDATE "CMS"."ClubMembershipCycles" SET "PackageId" = 4 WHERE "PackageId" IS NULL;
UPDATE "CMS"."WeeklyCommissionPools" SET "PackageId" = 4 WHERE "PackageId" IS NULL;
UPDATE "CMS"."UserCommissionPayouts" SET "PackageId" = 4 WHERE "PackageId" IS NULL;
-- v3: NetworkWeeklyBalance هم PackageId میگیره
UPDATE "CMS"."NetworkWeeklyBalances" SET "PackageId" = 4 WHERE "PackageId" IS NULL;
-- 3. Seed Silver package (شامل فیلدهای v3)
INSERT INTO "CMS"."Packages" (..., "MaxBalancesPerLeg", "MaxNetworkLevel",
"MagicWalletMaxDeposit", "MagicWalletMaxCredit", ...)
VALUES ('پکیج نقرهای', 5600000, ..., 30, 15, 100000000, 250000000, ...);
T1.10 — بروزرسانی Protoها
| Proto File | تغیر | v3? |
|---|---|---|
| package.proto | فیلدهای جدید Package message (۱۱ فیلد) | 🔄 |
| clubmembership.proto | package_id در request/response | |
| commission.proto | package_id + package_title در ۴ message |
🆕 |
| commission.proto | Message جدید: CustomerCommissionPackageSummary |
🆕 |
| commission.proto | فیلتر package_id در Requestها |
🆕 |
T1.11 — اضافه PackageId به NetworkWeeklyBalance (🆕 v3)
فایل: CMS/src/CMSMicroservice.Domain/Entities/NetworkWeeklyBalance.cs
+ public long PackageId { get; set; }
+ public virtual Package Package { get; set; }
EF Config: اضافه Unique Index:
builder.HasIndex(e => new { e.UserId, e.WeekDefinitionId, e.PackageId }).IsUnique();
builder.HasOne(e => e.Package).WithMany().HasForeignKey(e => e.PackageId);
⚠️ تاثیر حجم: رکوردهای تعادل ×N (تعداد پکیج). مثلاً ۱۰۰۰ کاربر × ۲ پکیج = ۲۰۰۰ رکورد هفتگی
T1.12 — Data Migration: NetworkWeeklyBalance (🆕 v3)
-- رکوردهای موجود → پکیج پایه
UPDATE "CMS"."NetworkWeeklyBalances"
SET "PackageId" = (SELECT "Id" FROM "CMS"."Packages" WHERE "IsBasePackage" = true LIMIT 1)
WHERE "PackageId" IS NULL;
مرحله ۲ — منطق کسبوکار ✅
✅ تکمیلشده | کامیت:
8e5c7c5(Phase 2) +ccb938e(Phase 3) +0002a5a(Phase 4)
T2.1 — Generic Verify Handler
هدف: ادغام VerifyGolden + VerifyBase + VerifyGeneric → یک handler
الگوریتم:
1. دریافت TransactionId از request
2. خواندن Transaction → PackageId → Package entity
3. verify با درگاه (ZarinPal/BFF/...)
4. اگر موفق:
a. wallet.Balance += Package.Price
b. wallet.DiscountBalance += Package.Price × Package.DiscountMultiplier
c. ساخت WalletChangeLog (Balance)
d. ساخت WalletChangeLog (DiscountBalance)
e. ساخت UserPackagePurchase record
f. اگر اولین خرید: JoinNetwork
g. بروزرسانی ClubMembershipCycle.PackageId
5. return success + receipt
T2.2 — Generic Purchase Handler
هدف: ادغام PurchaseGolden + PurchasePackage + InitiateBase → یک handler
تغییرات:
- حذف فیلتر
Title.Contains("طلایی") - حذف
BasePackageId = 4 - خواندن Package entity از DB بر اساس
request.PackageId - Gateway URL + Amount از Package.Price
T2.3-T2.4 — ActivateClubMembership بهبود
تغییرات:
- var features = await GetAllFeatureIds(); // همه فیچرها
+ var features = await GetPackageFeatures(packageId); // فیچرهای پکیج
- membership.PackageAmount = SystemConstants.BasePackageAmount;
+ membership.PackageAmount = package.Price;
- var activationFee = SystemConstants.ClubActivationFee;
+ var activationFee = package.ActivationFee;
T2.5-T2.6 — Re-Purchase Logic
EXIT Magic Mode — تغییرات:
wallet.WalletMode = WalletMode.Normal;
wallet.MagicCompletedAt = DateTime.UtcNow;
cycle.MagicCompletedAt = DateTime.UtcNow;
+ user.PackagePurchaseMethod = PackagePurchaseMethod.None;
+ membership.IsActive = false;
+ cycle.IsCurrentCycle = false;
Guard تغییرات:
- if (user.PackagePurchaseMethod != PackagePurchaseMethod.None)
- throw new RpcException("قبلاً پکیج خریداری شده");
+ if (user.PackagePurchaseMethod != PackagePurchaseMethod.None
+ && !HasCompletedMagicCycle(membership))
+ throw new RpcException("چرخه جاری هنوز تکمیل نشده");
T2.7 — JWT Claims جدید
claims.Add("HasPurchasedPackage", "true");
+ claims.Add("CanRepurchase", HasCompletedMagicCycle(membership).ToString());
+ claims.Add("PackageId", membership.PackageId?.ToString() ?? "");
+ claims.Add("PackageTitle", package?.Title ?? "");
مرحله ۳ — محاسبه پورسانت (موازی با مرحله ۲) ✅
✅ تکمیلشده | کامیت:
607f791+7176fe4| ⏱️ ۴ روز | ریسک: بحرانی (مالی)
T3.1-T3.2 — SPs + PackageId + پارامترهای داینامیک (🔄 v3)
-- sp_CalculateWeeklyBalances — v3: حذف hardcode
ALTER PROCEDURE sp_CalculateWeeklyBalances
@WeekDefinitionId BIGINT,
@PackageId BIGINT,
@MaxBalancesPerLeg INT, -- v3: از Package entity (نه ۳۰۰ hardcode!)
@MaxNetworkLevel INT -- v3: از Package entity (نه ۱۵ hardcode!)
AS
BEGIN
-- فیلتر: فقط کاربرانی که این پکیج را دارند
-- carryover: فقط رکوردهای PackageId = @PackageId
-- cap: از @MaxBalancesPerLeg (نه ۳۰۰)
-- depth: CTE تا @MaxNetworkLevel (نه ۱۵)
INSERT INTO "CMS"."NetworkWeeklyBalances" ("PackageId", ...)
SELECT @PackageId, ...
FROM "CMS"."UserWallets" w
INNER JOIN "CMS"."ClubMemberships" m ON m."UserId" = w."UserId"
WHERE m."PackageId" = @PackageId
AND m."IsActive" = true;
END;
T3.3 — Loop Service (🔄 v3: ارسال تنظیمات پکیج)
// WeeklyCommissionCalculationService.cs
var activePackages = await _context.Packages
.Where(p => p.IsActive && !p.IsDeleted)
.ToListAsync();
foreach (var package in activePackages)
{
_logger.LogInformation(
"Calculating commission for package {Id}: {Title} " +
"(MaxBalances={Max}, MaxLevel={Level})",
package.Id, package.Title,
package.MaxBalancesPerLeg, package.MaxNetworkLevel);
// v3: پاس دادن تنظیمات پکیج
await strategy.CalculateWeeklyBalancesAsync(
weekId, package.Id,
package.MaxBalancesPerLeg, package.MaxNetworkLevel);
await strategy.CalculateWeeklyPoolAsync(weekId, package.Id);
}
T3.4 — OrmCommissionCalculationStrategy (🔄 v3)
تغییرات:
- var maxBalances = SystemConstants.CommissionMaxWeeklyBalancesPerLeg; // 300
- var maxLevel = SystemConstants.CommissionMaxNetworkLevel; // 15
+ // پارامتر از بیرون — per-package
+ int maxBalances = maxBalancesPerLeg; // e.g., نقرهای=30, پایه=300
+ int maxLevel = maxNetworkLevel;
- // فیلتر کاربران
+ // فیلتر کاربران بر اساس پکیج
+ .Where(m => m.PackageId == packageId && m.IsActive)
- // carryover
+ // carryover: فقط رکوردهای همان PackageId
+ .Where(b => b.PackageId == packageId && b.WeekDefinitionId == prevWeekId)
T3.5 — SpCommissionCalculationStrategy (🆕 v3)
// قبل: فقط WeekDefinitionId
await connection.ExecuteAsync("CMS.sp_CalculateWeeklyBalances",
new { WeekDefinitionId = weekId, ForceRecalculate = true });
// بعد (v3): پکیج + تنظیمات داینامیک
await connection.ExecuteAsync("CMS.sp_CalculateWeeklyBalances",
new {
WeekDefinitionId = weekId,
PackageId = package.Id,
MaxBalancesPerLeg = package.MaxBalancesPerLeg,
MaxNetworkLevel = package.MaxNetworkLevel,
ForceRecalculate = true
});
T3.6 — Carryover per-package (🆕 v3)
⚠️ بحرانی: week-shifting باید فقط رکوردهای همان PackageId را shift کند
هفته ۱۰ → هفته ۱۱:
علی: carryover_پایه = {Left: surplus, Right: surplus} ← جداگانه
علی: carryover_نقرهای = {Left: 0, Right: 0} ← جداگانه
✖ اشتباه: قاطی کردن carryover پایه و نقرهای!
✔ صحیح: هر PackageId فقط carryover خودش را میبینه
⚠️ نکته بحرانی
پورسانت = پول واقعی. هر تغییر در SPs باید:
- ابتدا در staging با داده واقعی تست شود
- نتایج قبل و بعد مقایسه شوند
- Rollback plan آماده باشد
- در production ابتدا read-only اجرا شود (بدون commit)
مرحله ۷ — Migration + Cleanup (سهگانه) ✅
✅ تکمیلشده | ⏱️ ۱ روز | ریسک: پایین
فاز 7a — Cosmetic Cleanup ✅
کامیت: CMS
469d97b| FOb82cac4| BOf1b0085
CMS:
- حذف orphaned
PurchasePackagehandler (۳ فایل، بدون caller) - فیکس doc-comments:
طلایی→پکیجدر ۶ فایل (enums, entities, handlers)
FrontOffice:
- حذف hardcoded
پکیج طلاییازMyPackages.razorوPackages.razor - اضافه
PackageTitleproperty بهUserPackageStatusDtorecord
BackOffice:
- تغییر label
پکیج طلایی→خرید پکیجدرUserNetworkInfo.razor
فاز 7b — FrontOffice RPC Migration ✅
کامیت: CMS
161f796| FO71f391a
CMS:
CustomerPurchasePackage: embedorderIdدر callback URL قبل از ارسال به درگاه$"{request.CallbackUrl}{separator}orderId={purchase.Id}"
FrontOffice:
Profile/Index.razor.cs: مهاجرتInitiateBasePackagePaymentAsync→CustomerPurchasePackageAsyncProfile/PaymentCallback.razor: مهاجرتVerifyBasePackagePaymentAsync→CustomerVerifyPackagePurchaseAsync- پارامترهای جدید:
PackageId,CallbackUrl,PurchaseMethod,OrderId,Authority,Status
فاز 7c — Delete Deprecated Handlers ✅
کامیت: CMS
8446e0e(14 فایل، 1125 حذف)
حذف ۴ handler CQRS (۱۲ فایل):
PurchaseGoldenPackage/(Command, Handler, Validator)VerifyGoldenPackagePurchase/(Command, Handler, Validator)InitiateBasePackagePayment/(Command, Handler, Validator)VerifyBasePackagePayment/(Command, Handler, Validator)
Cleanup:
PackageService.cs: حذف ۴ gRPC override method (proto RPCs حالا auto-throwUnimplemented)PackageProfile.cs: حذف ۶ Mapster mapping block + ۴ using directive- Build: 0 Error ✅
مرحله ۴ — UI (FrontOffice + BackOffice)
⏱️ ۵ روز (v3: +۲) | وابستگی: مرحله ۲ + ۳ | ریسک: متوسط
T4.1 — کاشیهای پکیج داینامیک
فایل: FrontOffice/src/.../Pages/Package/Packages.razor
@* قبل: hardcoded *@
@* بعد: *@
@foreach (var package in _packages.OrderBy(p => p.SortOrder))
{
<PackageCard Package="@package"
OnPurchase="StartPurchase"
ShowFeatures="true"
ShowPV="true" />
}
T4.2 — مودال پرداخت شرطی
@if (_selectedPackage.SupportsDirectPurchase)
{
<MudButton OnClick="PayOnline">پرداخت آنلاین</MudButton>
}
@if (_selectedPackage.SupportsDayaPurchase)
{
<MudButton OnClick="PayDaya">اقساط دایا</MudButton>
}
T4.3 — MyPackages + Re-Purchase
@if (_canRepurchase)
{
<MudAlert Severity="Severity.Success">
🎉 چرخه جادویی تکمیل شد! میتوانید پکیج جدید بخرید.
</MudAlert>
<MudButton Href="/packages">خرید پکیج جدید</MudButton>
}
else
{
<MagicWalletProgress Wallet="@_wallet" Cycle="@_currentCycle" />
}
T4.8 — FrontOffice: CommissionDashboard per-package (🆕 v3)
فایل: FrontOffice/src/.../Pages/Commission/CommissionDashboardPage.razor
@* v3: کارتهای خلاصه بر اساس پکیج *@
<MudGrid>
@foreach (var summary in _packageSummaries)
{
<MudItem xs="12" md="6">
<MudCard>
<MudCardHeader>@summary.PackageTitle</MudCardHeader>
<MudCardContent>
<p>زیرمجموعه: @summary.DownlineCount نفر</p>
<p>تیم اول: @summary.LeftLegMembers | تیم دوم: @summary.RightLegMembers</p>
<p>تعادل: @summary.TotalBalances</p>
<p>💰 پاداش: @summary.CommissionFormatted</p>
</MudCardContent>
</MudCard>
</MudItem>
}
</MudGrid>
<MudAlert>📦 مجموع پاداش هفته: @_totalCommission</MudAlert>
T4.9 — FrontOffice: WeeklyBalance per-package (🆕 v3)
تعادل تیم اول/دوم به تفکیک هر پکیج نمایش داده شود
T4.10-T4.12 — BackOffice: گزارشهای پورسانت per-package (🆕 v3)
تغییرات مشترک:
- اضافه dropdown فیلتر پکیج (همه / پایه / نقرهای / ...)
- اضافه ستون پکیج در جدولها
- CSV export شامل ستون پکیج
| صفحه | تغییر |
|---|---|
| Commission Dashboard | فیلتر + خلاصه per-package |
| Weekly Reports | فیلتر + CSV per-package |
| Balances Report | فیلتر + ستون پکیج |
| User Payouts | ستون پکیج + فیلتر |
T4.13 — BackOffice: Package CRUD + Quick Access فیچرها (🆕 v3)
ادمین موقع ساخت/ویرایش پکیج، فیچرها را با checkbox در همان فرم تعیین کند
@* در PackageCreateDialog / PackageEditDialog: *@
<MudText Typo="Typo.h6">فیچرهای پکیج</MudText>
@foreach (var feature in _allFeatures)
{
<MudCheckBox @bind-Checked="feature.IsIncluded" Label="@feature.Title" />
}
مرحله ۵ — تست و استقرار
⏱️ ۳ روز (v3: +۱) | وابستگی: مرحله ۴
Checklist تست
خرید + فعالسازی:
- خرید پکیج نقرهای (ZarinPal)
- خرید پکیج پایه (ZarinPal)
- خرید پکیج پایه (Daya Loan)
- خرید پکیج پایه (Manual Payment)
- فعالسازی باشگاه با پکیج نقرهای → فیچرهای محدود
- فعالسازی باشگاه با پکیج پایه → همه فیچرها
چرخه Magic + خرید مجدد:
- تکمیل چرخه Magic → ریست وضعیت
- خرید مجدد بعد تکمیل چرخه (همان پکیج)
- خرید مجدد با پکیج متفاوت (پایه → نقرهای)
پورسانت per-package (v3):
- Commission Pool جداگانه هر پکیج
- تعادل per-package: MaxBalancesPerLeg متفاوت (پایه=۳۰۰, نقرهای=۳۰)
- Carryover مجزا: shift فقط رکوردهای همان PackageId
- SP پارامترها صحیح: @MaxBalancesPerLeg و @MaxNetworkLevel از Package
- NetworkWeeklyBalance رکوردها: ۲ پکیج = ۲× رکورد
گزارش per-package (v3):
- FO: مشتری کارتهای خلاصه per-package را میبیند
- FO: مجموع پاداش = جمع همه پکیجها
- BO: فیلتر dropdown پکیج کار میکند
- BO: CSV export شامل ستون پکیج
Migration + سایر:
- Data Migration — PackageId در رکوردهای قبلی (شامل NetworkWeeklyBalance)
- JWT claims جدید (CanRepurchase, PackageId)
- UI: کاشیهای داینامیک FrontOffice
- UI: ماتریس فیچر + Quick Access BackOffice
- Rollback: بدون data loss
📅 تقویم پیشنهادی (v3)
| هفته | روز | تسک |
|---|---|---|
| هفته ۱ | روز ۱ | مرحله ۰: فیکس ۴ باگ |
| روز ۲-۳ | مرحله ۱: Package entity (۱۱ فیلد) + PackageFeature | |
| روز ۴-۵ | مرحله ۱: FKها + NetworkWeeklyBalance + Migration | |
| هفته ۲ | روز ۶-۷ | مرحله ۲: Generic handlers + re-purchase |
| روز ۶-۸ | مرحله ۳: SP params + carryover per-package (موازی) | |
| روز ۸-۱۰ | مرحله ۲: Guards + JWT + Manual | |
| هفته ۳ | روز ۱۱-۱۲ | مرحله ۴: FrontOffice UI + گزارش per-package |
| روز ۱۳-۱۴ | مرحله ۴: BackOffice UI + گزارش per-package | |
| روز ۱۵-۱۷ | مرحله ۵: تست + deploy |
🔗 ارجاعات
| مستند | محتوا |
|---|---|
| BIZ-PACKAGE-BASED-SYSTEM.md | طراحی فنی — ۴۸+ تغییر (v3) + باگها |
| PACKAGE-TRANSFORMATION-UX.md | تاثیر UX بر فرانتها |
| FEATURE-BACKLOG.md | بکلاگ ۱۲ RPC آماده |
| GRPC-SERVICES-AUDIT.md | آدیت ۳۴۲ RPC |
آخرین بروزرسانی: ۱۴۰۴/۱۲/۰۹ — فاز ۰-۷c تکمیل (۱۶ کامیت: ۱۳ CMS + ۲ FO + ۱ BO) | ۴ deprecated handler حذفشده | FO به Customer RPCs مهاجرتشده | UI باقیمانده*