docs: package-based transformation — complete roadmap + UX impact + feature backlog

New documents:
- roadmap/FEATURE-BACKLOG.md: 12 kept RPCs → feature tasks with priority,
  target pages, and time estimates (F1-F12)
- roadmap/PACKAGE-TRANSFORMATION-UX.md: UX impact analysis —
  before/after wireframes for 19 pages (10 FO + 9 BO),
  customer + admin experience changes, future needs prediction
- roadmap/PACKAGE-TRANSFORMATION-TASKS.md: step-by-step implementation
  plan (6 phases, ~13 day critical path), atomic tasks with
  code diffs, dependency graph, test checklist

Updated:
- cms/GRPC-SERVICES-AUDIT.md: cross-references to new docs

Total: 998 lines of documentation covering:
- 12 RPC feature tasks prioritized by package-based relevance
- 19 page wireframes (before/after comparison)
- 39 transformation tasks broken into 6 phases
- 10 predicted future requirements (N1-N10)
- Risk analysis + rollback plan + calendar
This commit is contained in:
masoodafar-web
2026-02-24 23:18:50 +03:30
parent 3575e483b9
commit 01244f426e
4 changed files with 998 additions and 4 deletions
+418
View File
@@ -0,0 +1,418 @@
# 🔄 نقشه‌راه تحول پکیج‌بیس — تسک‌های گام‌به‌گام
> **وضعیت:** تایید‌شده — آماده شروع
> **تاریخ:** ۱۴۰۴/۱۲/۰۶
> **پیش‌نیاز:** [BIZ-PACKAGE-BASED-SYSTEM.md](../business/BIZ-PACKAGE-BASED-SYSTEM.md) v2
> **هدف:** شکستن ۳۹ تغییر به تسک‌های اتمیک با ترتیب اجرا و وابستگی‌ها
---
## 📊 نمای کلی
```
مرحله ۰: فیکس باگ فوری (۱ روز)
└─→ مرحله ۱: زیرساخت Domain + DB (۳ روز)
├─→ مرحله ۲: منطق کسب‌وکار (۴ روز) ← موازی
│ └─→ مرحله ۴: FrontOffice UI (۳ روز)
└─→ مرحله ۳: پورسانت (۳ روز) ← موازی
└─→ مرحله ۵: BackOffice UI (۳ روز)
└─→ مرحله ۶: تست + استقرار (۲ روز)
مسیر بحرانی: ۰→۱→۲→۴→۶ = ~۱۳ روز
```
---
## مرحله ۰ — فیکس باگ‌های فوری
> ⏱️ ۱ روز | وابستگی: ندارد | ریسک: کم
### ✅ وضعیت باگ‌ها (بررسی اولیه لازم)
| # | باگ | 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)
> ⏱️ ۳ روز | وابستگی: مرحله ۰ | ریسک: متوسط (migration)
### T1.1 — بروزرسانی Package Entity
**فایل:** `CMS/src/CMSMicroservice.Domain/Entities/Package.cs`
```diff
+ 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;
+ 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`
```csharp
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? | توضیح |
|--------|------|-----------|-------|
| ClubMembership | `long? PackageId` | nullable (بعد migration → required) | آخرین پکیج |
| ClubMembershipCycle | `long PackageId` | required | پکیج این چرخه |
| WeeklyCommissionPool | `long PackageId` | required + Unique(WeekDefId, PkgId) | Pool هر پکیج |
| UserCommissionPayout | `long? PackageId` | nullable | ردیابی |
### T1.7 — حذف SystemConstants
**فایل:** `CMS/src/CMSMicroservice.Domain/Common/SystemConstants.cs`
```diff
- 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; // اگر وجود داشت
```
> ⚠️ **قبل از حذف:** grep تمام مصرف‌کننده‌ها → جایگزین با `Package.Property`
### T1.8 — Database Migration
```bash
dotnet ef migrations add AddPackageBasedSystem
```
**شامل:**
- ستون‌های جدید Package
- جدول PackageFeatures
- FKها در 4 entity
- Unique constraint
### T1.9 — Data Migration Script
```sql
-- 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
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;
-- 3. Seed Silver package
INSERT INTO "CMS"."Packages" (...) VALUES ('پکیج نقره‌ای', 5600000, ...);
```
### T1.10 — بروزرسانی Protoها
| Proto File | تغییر |
|-----------|-------|
| package.proto | فیلدهای جدید Package message |
| clubmembership.proto | package_id در request/response |
| commission.proto | package_id در pool/payout messages |
---
## مرحله ۲ — منطق کسب‌وکار
> ⏱️ ۴ روز | وابستگی: مرحله ۱ | ریسک: بالا (رگرسیون)
### 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 بهبود
**تغییرات:**
```diff
- 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 — تغییرات:**
```diff
wallet.WalletMode = WalletMode.Normal;
wallet.MagicCompletedAt = DateTime.UtcNow;
cycle.MagicCompletedAt = DateTime.UtcNow;
+ user.PackagePurchaseMethod = PackagePurchaseMethod.None;
+ membership.IsActive = false;
+ cycle.IsCurrentCycle = false;
```
**Guard تغییرات:**
```diff
- if (user.PackagePurchaseMethod != PackagePurchaseMethod.None)
- throw new RpcException("قبلاً پکیج خریداری شده");
+ if (user.PackagePurchaseMethod != PackagePurchaseMethod.None
+ && !HasCompletedMagicCycle(membership))
+ throw new RpcException("چرخه جاری هنوز تکمیل نشده");
```
### T2.7 — JWT Claims جدید
```diff
claims.Add("HasPurchasedPackage", "true");
+ claims.Add("CanRepurchase", HasCompletedMagicCycle(membership).ToString());
+ claims.Add("PackageId", membership.PackageId?.ToString() ?? "");
+ claims.Add("PackageTitle", package?.Title ?? "");
```
---
## مرحله ۳ — محاسبه پورسانت (موازی با مرحله ۲)
> ⏱️ ۳ روز | وابستگی: مرحله ۱ | ریسک: بحرانی (مالی)
### T3.1-T3.2 — SPs + PackageId
```sql
-- sp_CalculateWeeklyBalances:
ALTER PROCEDURE sp_CalculateWeeklyBalances
@WeekDefinitionId BIGINT,
@PackageId BIGINT -- ← جدید
AS
BEGIN
-- فیلتر بالانس‌ها فقط کاربرانی که این پکیج را دارند
INSERT INTO "CMS"."WeeklyBalances" (...)
SELECT ...
FROM "CMS"."UserWallets" w
INNER JOIN "CMS"."ClubMemberships" m ON m."UserId" = w."UserId"
WHERE m."PackageId" = @PackageId -- ← فیلتر
AND m."IsActive" = true
AND w."WalletMode" = 0; -- Normal only
END;
```
### T3.3 — Loop Service
```csharp
// 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}",
package.Id, package.Title);
await strategy.CalculateWeeklyBalancesAsync(weekId, package.Id);
await strategy.CalculateWeeklyPoolAsync(weekId, package.Id);
}
```
### ⚠️ نکته بحرانی
> پورسانت = پول واقعی. **هر تغییر در SPs باید:**
> 1. ابتدا در staging با داده واقعی تست شود
> 2. نتایج قبل و بعد مقایسه شوند
> 3. Rollback plan آماده باشد
> 4. در production ابتدا read-only اجرا شود (بدون commit)
---
## مرحله ۴ — FrontOffice UI
> ⏱️ ۳ روز | وابستگی: مرحله ۲ | ریسک: متوسط
### T4.1 — کاشی‌های پکیج داینامیک
**فایل:** `FrontOffice/src/.../Pages/Package/Packages.razor`
```razor
@* قبل: hardcoded *@
@* بعد: *@
@foreach (var package in _packages.OrderBy(p => p.SortOrder))
{
<PackageCard Package="@package"
OnPurchase="StartPurchase"
ShowFeatures="true"
ShowPV="true" />
}
```
### T4.2 — مودال پرداخت شرطی
```razor
@if (_selectedPackage.SupportsDirectPurchase)
{
<MudButton OnClick="PayOnline">پرداخت آنلاین</MudButton>
}
@if (_selectedPackage.SupportsDayaPurchase)
{
<MudButton OnClick="PayDaya">اقساط دایا</MudButton>
}
```
### T4.3 — MyPackages + Re-Purchase
```razor
@if (_canRepurchase)
{
<MudAlert Severity="Severity.Success">
🎉 چرخه جادویی تکمیل شد! می‌توانید پکیج جدید بخرید.
</MudAlert>
<MudButton Href="/packages">خرید پکیج جدید</MudButton>
}
else
{
<MagicWalletProgress Wallet="@_wallet" Cycle="@_currentCycle" />
}
```
---
## مرحله ۵ — BackOffice UI
> ⏱️ ۳ روز | وابستگی: مرحله ۳ | ریسک: کم
_(تسک‌ها در PACKAGE-TRANSFORMATION-UX.md بخش ۳ مستند شده)_
---
## مرحله ۶ — تست و استقرار
> ⏱️ ۲ روز | وابستگی: مرحله ۴ و ۵
### Checklist تست
- [ ] خرید پکیج نقره‌ای (ZarinPal)
- [ ] خرید پکیج پایه (ZarinPal)
- [ ] خرید پکیج پایه (Daya Loan)
- [ ] خرید پکیج پایه (Manual Payment)
- [ ] فعالسازی باشگاه با پکیج نقره‌ای → فیچرهای محدود
- [ ] فعالسازی باشگاه با پکیج پایه → همه فیچرها
- [ ] تکمیل چرخه Magic → ریست وضعیت
- [ ] خرید مجدد بعد تکمیل چرخه
- [ ] Commission Pool جداگانه هر پکیج
- [ ] Data Migration — PackageId در رکوردهای قبلی
- [ ] JWT claims جدید (CanRepurchase, PackageId)
- [ ] UI: کاشی‌های داینامیک FrontOffice
- [ ] UI: ماتریس فیچر BackOffice
- [ ] Rollback: بدون data loss
---
## 📅 تقویم پیشنهادی
| هفته | روز | تسک |
|------|-----|------|
| هفته ۱ | روز ۱ | مرحله ۰: فیکس ۴ باگ |
| | روز ۲-۳ | مرحله ۱: Package entity + PackageFeature |
| | روز ۴ | مرحله ۱: FKها + Migration |
| هفته ۲ | روز ۵-۶ | مرحله ۲: Generic handlers + re-purchase |
| | روز ۵-۶ | مرحله ۳: SP + Loop (موازی) |
| | روز ۷-۸ | مرحله ۲: Guards + JWT + Manual |
| هفته ۳ | روز ۹-۱۰ | مرحله ۴: FrontOffice UI |
| | روز ۱۱ | مرحله ۵: BackOffice UI |
| | روز ۱۲-۱۳ | مرحله ۶: تست + deploy |
---
## 🔗 ارجاعات
| مستند | محتوا |
|-------|-------|
| [BIZ-PACKAGE-BASED-SYSTEM.md](../business/BIZ-PACKAGE-BASED-SYSTEM.md) | طراحی فنی — ۳۹ تغییر + باگ‌ها |
| [PACKAGE-TRANSFORMATION-UX.md](PACKAGE-TRANSFORMATION-UX.md) | تاثیر UX بر فرانت‌ها |
| [FEATURE-BACKLOG.md](FEATURE-BACKLOG.md) | بکلاگ ۱۲ RPC آماده |
| [GRPC-SERVICES-AUDIT.md](../cms/GRPC-SERVICES-AUDIT.md) | آدیت ۳۴۲ RPC |
---
*آخرین بروزرسانی: ۱۴۰۴/۱۲/۰۶*