Files
docs/roadmap/PACKAGE-TRANSFORMATION-TASKS.md
T
masoodafar-web 01244f426e 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
2026-02-24 23:18:50 +03:30

419 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🔄 نقشه‌راه تحول پکیج‌بیس — تسک‌های گام‌به‌گام
> **وضعیت:** تایید‌شده — آماده شروع
> **تاریخ:** ۱۴۰۴/۱۲/۰۶
> **پیش‌نیاز:** [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 |
---
*آخرین بروزرسانی: ۱۴۰۴/۱۲/۰۶*