01244f426e
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
419 lines
14 KiB
Markdown
419 lines
14 KiB
Markdown
# 🔄 نقشهراه تحول پکیجبیس — تسکهای گامبهگام
|
||
|
||
> **وضعیت:** تاییدشده — آماده شروع
|
||
> **تاریخ:** ۱۴۰۴/۱۲/۰۶
|
||
> **پیشنیاز:** [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 |
|
||
|
||
---
|
||
|
||
*آخرین بروزرسانی: ۱۴۰۴/۱۲/۰۶*
|