Files
docs/archive/05-TASKS/NEW-BUSINESS-REQUIREMENTS-TASKS.md
T
masoodafar-web 5965b98728 update
2026-01-03 18:27:49 +03:30

618 lines
20 KiB
Markdown

# 📋 Task List - توضیحات جدید بیزینس 2025-12-08
**تاریخ ایجاد**: 2025-12-08
**آخرین به‌روزرسانی**: 2025-12-09
**منبع**: تحلیل توضیحات شفاهی جدید بیزینس
**وضعیت**: ✅ Task #0 Complete, بقیه آماده برای اجرا
---
## ✅ Completed Tasks
### ~~Task #0: اصلاح محاسبات تعادل و فلش~~ ✅
**شرح**:
کد محاسبه تعادل با توضیحات دقیق بیزینس تطبیق داده شد.
**انجام شده**:
- ✅ ترتیب محاسبات اصلاح شد (تعادل → باقیمانده → سقف → فلش)
- ✅ فلش از هر دو طرف محاسبه می‌شود
- ✅ باقیمانده جداگانه ذخیره می‌شود (چپ و راست)
- ✅ Documentation به‌روزرسانی شد
- ✅ مثال‌های 5 لول عمقی اضافه شد
**فایل‌های تغییر یافته**:
```
CMS/src/.../CalculateWeeklyBalancesCommandHandler.cs (اصلاح شد)
totalDoc/01-BUSINESS/balance-calculation-rules.md (به‌روزرسانی شد)
totalDoc/01-BUSINESS/balance-calculation-examples-5-levels.md (جدید)
```
**تاریخ اتمام**: 2025-12-09
---
## 🔥 Priority 1: Critical Tasks
### Task #1: پیاده‌سازی Worker حذف خودکار کاربران غیرفعال
**شرح**:
کاربرانی که تا 2 هفته بعد از ثبت نام هیچکدام از موارد زیر را انجام ندادند باید به صورت خودکار حذف شوند:
- وام دایا نگرفتند
- پرداخت مستقیم 56 میلیون نکردند
**Acceptance Criteria**:
- [ ] Worker روزانه یک بار اجرا شود (مثلاً ساعت 3 صبح)
- [ ] کاربرانی با `CreatedAt < Now - 14 days` و `IsActive = false` و `ClubMembershipId = null` شناسایی شوند
- [ ] کاربر به صورت Soft Delete حذف شود (یا Hard Delete بر اساس تصمیم)
- [ ] جایگاه شبکه (Network Position) آزاد شود
- [ ] معرف (Parent) بتواند دوباره کاربر جدید جذب کند
- [ ] Log کامل عملیات حذف ثبت شود
**فایل‌های نیاز به ایجاد/تغییر**:
```
CMS/src/CMSMicroservice.WebApi/BackgroundWorkers/
└── DeleteInactiveUsersJob.cs (جدید)
CMS/src/CMSMicroservice.Application/UserCQ/Commands/
└── DeleteInactiveUser/
├── DeleteInactiveUserCommand.cs (جدید)
└── DeleteInactiveUserCommandHandler.cs (جدید)
CMS/src/CMSMicroservice.WebApi/Program.cs
└── services.AddHostedService<DeleteInactiveUsersJob>();
```
**کد پیشنهادی**:
```csharp
public class DeleteInactiveUsersJob : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<DeleteInactiveUsersJob> _logger;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
// محاسبه زمان اجرا (3 صبح)
var now = DateTime.Now;
var next3AM = now.Date.AddDays(1).AddHours(3);
var delay = next3AM - now;
await Task.Delay(delay, stoppingToken);
using var scope = _serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<IApplicationDbContext>();
var twoWeeksAgo = DateTime.Now.AddDays(-14);
var inactiveUsers = await context.Users
.Where(u => u.Created < twoWeeksAgo
&& u.ClubMembershipId == null
&& !u.IsActive)
.ToListAsync(stoppingToken);
_logger.LogInformation($"🧹 حذف {inactiveUsers.Count} کاربر غیرفعال بیش از 2 هفته");
foreach (var user in inactiveUsers)
{
// حذف کاربر
user.IsDeleted = true; // Soft Delete
user.DeletedAt = DateTime.Now;
// آزادسازی جایگاه شبکه
// (NetworkParentId را null نکنید چون تاریخچه نیاز دارد)
_logger.LogWarning($"❌ حذف کاربر: {user.Id} - {user.UserName}");
}
await context.SaveChangesAsync(stoppingToken);
}
}
}
```
**تست**:
1. کاربر جدید با `CreatedAt = DateTime.Now.AddDays(-15)` ایجاد کنید
2. `IsActive = false`, `ClubMembershipId = null`
3. Worker را مجبور به اجرا کنید (یا زمان را تغییر دهید)
4. چک کنید: `user.IsDeleted = true`
**تخمین زمان**: 4-6 ساعت
---
### Task #2: الزامی کردن دیالوگ باشگاه مشتریان
**شرح**:
بعد از پرداخت موفق 56 میلیون تومان، کاربر **باید** قرارداد باشگاه مشتریان را امضا کند. تا زمانی که امضا نکند، نمی‌تواند به سایر بخش‌های سیستم دسترسی داشته باشد و لینک معرفی خود را ببیند.
**Acceptance Criteria**:
- [ ] بعد از تأیید پرداخت، Modal/Dialog باشگاه مشتریان باز شود
- [ ] دکمه Close غیرفعال باشد (یا Modal با `disableBackdropClick` باز شود)
- [ ] کاربر نتواند از دیالوگ خارج شود (ESC هم کار نکند)
- [ ] بعد از امضای قرارداد:
- `ClubMembership` record ایجاد شود
- `User.ClubMembershipId` Set شود
- 25 میلیون تومان به `WeeklyCommissionPool` اضافه شود
- [ ] بعد از امضا، redirect به Dashboard
- [ ] در Dashboard لینک معرفی نمایش داده شود
**فایل‌های نیاز به تغییر**:
```
FrontOffice/src/FrontOffice.Main/Pages/
└── Payment/PaymentSuccess.razor
└── Payment/PaymentSuccess.razor.cs
FrontOffice/src/FrontOffice.Main/Components/
└── ClubMembershipDialog.razor (جدید یا اصلاح)
CMS/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/
└── CreateClubMembership/
├── CreateClubMembershipCommand.cs
└── CreateClubMembershipCommandHandler.cs
```
**کد پیشنهادی (Frontend)**:
```razor
@* PaymentSuccess.razor *@
@if (_showClubDialog)
{
<MudDialog @bind-IsVisible="_showClubDialog"
Options="@(new DialogOptions {
DisableBackdropClick = true,
CloseButton = false
})">
<DialogContent>
<h3>عضویت در باشگاه مشتریان</h3>
<p>برای ادامه، لطفاً قرارداد باشگاه مشتریان را مطالعه و امضا کنید.</p>
<MudPaper Class="pa-4 my-4" Elevation="2">
<p>متن قرارداد...</p>
</MudPaper>
<MudCheckBox @bind-Checked="_agreedToTerms">
متن قرارداد را مطالعه کردم و با آن موافقم
</MudCheckBox>
</DialogContent>
<DialogActions>
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
Disabled="!_agreedToTerms"
OnClick="SignContract">
امضای قرارداد
</MudButton>
</DialogActions>
</MudDialog>
}
```
```csharp
// PaymentSuccess.razor.cs
private bool _showClubDialog = false;
private bool _agreedToTerms = false;
protected override async Task OnInitializedAsync()
{
// بعد از تأیید پرداخت
if (PaymentConfirmed && !User.ClubMembershipId.HasValue)
{
_showClubDialog = true;
}
}
private async Task SignContract()
{
var request = new CreateClubMembershipRequest
{
UserId = User.Id,
InitialContribution = 25000000
};
await ClubMembershipContract.CreateClubMembershipAsync(request);
_showClubDialog = false;
NavigationManager.NavigateTo("/dashboard");
}
```
**تست**:
1. پرداخت 56M انجام دهید
2. بعد از موفقیت، باید Dialog باز شود
3. سعی کنید Close کنید → نشود
4. بدون tick نزدن → دکمه غیرفعال باشد
5. tick بزنید و امضا کنید → redirect به Dashboard
6. لینک معرفی نمایش داده شود
**تخمین زمان**: 6-8 ساعت
---
### Task #3: شرط نمایش لینک معرفی
**شرح**:
لینک معرفی فقط باید برای کاربرانی نمایش داده شود که:
1. پرداخت کرده‌اند (`IsActive = true`)
2. عضو باشگاه مشتریان شده‌اند (`ClubMembershipId != null`)
3. عضویت باشگاه فعال است (`ClubMembership.IsActive = true`)
**Acceptance Criteria**:
- [ ] در صفحه Dashboard یا Profile، شرط بالا چک شود
- [ ] اگر شرایط برقرار نیست:
- پیغام: "برای دریافت لینک معرفی، ابتدا عضو باشگاه مشتریان شوید"
- دکمه "عضویت در باشگاه" (در صورت عدم عضویت)
- [ ] اگر شرایط برقرار است:
- لینک معرفی نمایش داده شود
- دکمه کپی
- QR Code (اختیاری)
**فایل‌های نیاز به تغییر**:
```
FrontOffice/src/FrontOffice.Main/Pages/
└── Dashboard/Dashboard.razor
└── Dashboard/Dashboard.razor.cs
یا
FrontOffice/src/FrontOffice.Main/Pages/
└── Profile/MyProfile.razor
```
**کد پیشنهادی**:
```razor
@if (CanShowReferralLink)
{
<MudCard Class="my-4">
<MudCardHeader>
<CardHeaderContent>
<MudText Typo="Typo.h6">🔗 لینک معرفی شما</MudText>
</CardHeaderContent>
</MudCardHeader>
<MudCardContent>
<MudTextField @bind-Value="_referralLink"
ReadOnly="true"
Adornment="Adornment.End"
AdornmentIcon="@Icons.Material.Filled.ContentCopy"
OnAdornmentClick="CopyLink"/>
</MudCardContent>
</MudCard>
}
else
{
<MudAlert Severity="Severity.Warning" Class="my-4">
برای دریافت لینک معرفی، ابتدا عضو باشگاه مشتریان شوید.
@if (!User.ClubMembershipId.HasValue)
{
<MudButton Color="Color.Primary"
Variant="Variant.Filled"
Class="mt-2"
OnClick="OpenClubDialog">
عضویت در باشگاه
</MudButton>
}
</MudAlert>
}
```
```csharp
private bool CanShowReferralLink =>
User.IsActive
&& User.ClubMembershipId.HasValue
&& User.ClubMembership?.IsActive == true;
```
**تست**:
1. کاربر بدون `ClubMembership` → Alert نمایش داده شود
2. کاربر با `ClubMembership` فعال → لینک نمایش داده شود
3. دکمه کپی کار کند
**تخمین زمان**: 3-4 ساعت
---
## ⚠️ Priority 2: Medium Tasks
### Task #4: Validation دقیق‌تر محدودیت 2 فرزند فعال
**شرح**:
در هنگام ثبت نام با کد معرف، باید بررسی شود که آیا Parent حداکثر **2 فرزند فعال** دارد یا نه (نه فقط 2 فرزند).
**Acceptance Criteria**:
- [ ] Validation در `CreateUserCommandHandler` یا `NetworkPlacementService`
- [ ] شمارش فرزندان با شرط:
```csharp
u.NetworkParentId == parentId
&& u.IsActive
&& u.ClubMembershipId != null
```
- [ ] اگر `activeChildCount >= 2`:
- Exception: "این کاربر تعداد زیرمجموعه‌هاش پر شده و شما نمی‌تونید جزو زیرمجموعه این آدم بشید"
- یا Auto-Placement (بر اساس تصمیم)
**فایل‌های نیاز به تغییر**:
```
CMS/src/CMSMicroservice.Application/Services/
└── NetworkPlacementService.cs
CMS/src/CMSMicroservice.Application/UserCQ/Commands/CreateUser/
└── CreateUserCommandHandler.cs
└── CreateUserCommandValidator.cs
```
**کد پیشنهادی**:
```csharp
public async Task<NetworkLeg?> CalculateLegPositionAsync(long parentId, CancellationToken cancellationToken)
{
var activeChildrenCount = await _context.Users
.CountAsync(u => u.NetworkParentId == parentId
&& u.IsActive
&& u.ClubMembershipId != null,
cancellationToken);
if (activeChildrenCount >= 2)
{
throw new InvalidOperationException(
"این کاربر تعداد زیرمجموعه‌هاش پر شده و شما نمی‌تونید جزو زیرمجموعه این آدم بشید");
}
// بررسی Left و Right
var hasLeft = await _context.Users
.AnyAsync(u => u.NetworkParentId == parentId
&& u.LegPosition == NetworkLeg.Left
&& u.IsActive
&& u.ClubMembershipId != null,
cancellationToken);
if (!hasLeft) return NetworkLeg.Left;
var hasRight = await _context.Users
.AnyAsync(u => u.NetworkParentId == parentId
&& u.LegPosition == NetworkLeg.Right
&& u.IsActive
&& u.ClubMembershipId != null,
cancellationToken);
if (!hasRight) return NetworkLeg.Right;
return null; // هر دو پر است
}
```
**تست**:
1. Parent با 2 فرزند فعال
2. ثبت نام با کد این Parent
3. باید Exception بیاید
**تخمین زمان**: 3-4 ساعت
---
### Task #5: بهبود پیغام خطای کد معرف پر
**شرح**:
در صفحه ثبت نام، اگر کاربر کد معرفی وارد کند که ظرفیتش پر است، باید پیغام خطای واضح و فارسی نمایش داده شود.
**Acceptance Criteria**:
- [ ] در Frontend، بعد از وارد کردن کد معرف، validation شود
- [ ] اگر کد پر بود، پیغام:
> "این کد معرف ظرفیتش پر شده، لطفا از کد معرف دیگری استفاده کنید"
- [ ] Snackbar یا Alert با Severity.Warning
- [ ] فیلد کد معرف هایلایت شود (قرمز)
**فایل‌های نیاز به تغییر**:
```
FrontOffice/src/FrontOffice.Main/Pages/
└── Register.razor
└── Register.razor.cs
```
**کد پیشنهادی**:
```csharp
private async Task ValidateReferralCode()
{
if (string.IsNullOrWhiteSpace(_referralCode))
return;
try
{
var request = new ValidateReferralCodeRequest
{
ReferralCode = _referralCode
};
var response = await UserContract.ValidateReferralCodeAsync(request);
if (!response.IsValid)
{
_referralCodeError = "کد معرف نامعتبر است";
}
else if (response.IsFull)
{
_referralCodeError = "این کد معرف ظرفیتش پر شده، لطفا از کد معرف دیگری استفاده کنید";
Snackbar.Add(_referralCodeError, Severity.Warning);
}
}
catch (Exception ex)
{
_referralCodeError = "خطا در بررسی کد معرف";
}
}
```
**تست**:
1. Parent پر را پیدا کنید
2. کد معرف او را در Register وارد کنید
3. پیغام واضح نمایش داده شود
**تخمین زمان**: 2-3 ساعت
---
## 📝 Priority 3: Documentation Tasks
### Task #6: به‌روزرسانی مستندات
**شرح**:
با توجه به توضیحات جدید، داکیومنت‌های زیر باید Update شوند.
**فایل‌های نیاز به تغییر**:
#### 1. `totalDoc/01-BUSINESS/network-commission-system.md`
```markdown
# اضافه کردن بخش جدید:
## ۱۰. حذف خودکار کاربران غیرفعال
کاربرانی که تا 2 هفته بعد از ثبت نام:
- وام دایا نگرفته‌اند
- پرداخت مستقیم 56 میلیون نکرده‌اند
به صورت خودکار حذف می‌شوند.
**Worker**: `DeleteInactiveUsersJob`
**زمان اجرا**: روزانه ساعت 3 صبح
**منطق**: `CreatedAt < Now - 14 days && !IsActive && ClubMembershipId == null`
---
## ۱۱. شرایط نمایش لینک معرفی
لینک معرفی فقط برای کاربرانی نمایش داده می‌شود که:
1. پرداخت کرده‌اند (IsActive = true)
2. عضو باشگاه مشتریان شده‌اند (ClubMembershipId != null)
3. عضویت باشگاه فعال است (ClubMembership.IsActive = true)
**تا زمانی که این شرایط برقرار نباشد، کاربر نمی‌تواند لینک معرفی خود را ببیند.**
---
## ۱۲. الزامی بودن دیالوگ باشگاه مشتریان
بعد از پرداخت موفق 56 میلیون تومان، کاربر **باید** قرارداد باشگاه مشتریان را امضا کند.
**فرآیند**:
1. پرداخت موفق
2. Dialog باشگاه مشتریان باز می‌شود
3. کاربر نمی‌تواند Dialog را ببندد
4. باید قرارداد را بخواند و امضا کند
5. بعد از امضا → redirect به Dashboard
6. لینک معرفی نمایش داده می‌شود
```
#### 2. `totalDoc/01-BUSINESS/binary-tree-guide.md`
```markdown
# اصلاح بخش Validation:
### محدودیت 2 فرزند **فعال**
هر Parent فقط می‌تواند **2 فرزند فعال** داشته باشد.
**تعریف فعال**:
- IsActive = true
- ClubMembershipId != null
- عضویت باشگاه فعال است
**نکته مهم**: کاربرانی که ثبت نام کرده‌اند اما هنوز فعال نشده‌اند، در شمارش 2 فرزند محسوب نمی‌شوند.
```
#### 3. `totalDoc/03-BACKEND/CMS/implementation-status.md`
```markdown
# افزودن به بخش Background Workers:
### ✅ DeleteInactiveUsersWorker (NEW - 2025-12-08)
**وضعیت**: 🔴 نیاز به پیاده‌سازی
**شرح**: حذف خودکار کاربران غیرفعال بعد از 2 هفته
**منطق**:
- روزانه ساعت 3 صبح اجرا می‌شود
- کاربرانی که `CreatedAt < Now - 14 days`
- و `IsActive = false`
- و `ClubMembershipId = null`
- به صورت Soft Delete حذف می‌شوند
**فایل**: `CMS/BackgroundWorkers/DeleteInactiveUsersJob.cs`
**Dependencies**:
- IApplicationDbContext
- ILogger
```
#### 4. `totalDoc/05-TASKS/BACKLOG.md`
```markdown
# اضافه کردن این 5 Task به Backlog
## 🔥 Critical
- [ ] Task #1: پیاده‌سازی DeleteInactiveUsersWorker (6h)
- [ ] Task #2: الزامی کردن دیالوگ باشگاه (8h)
- [ ] Task #3: شرط نمایش لینک معرفی (4h)
## ⚠️ Medium
- [ ] Task #4: Validation 2 فرزند فعال (4h)
- [ ] Task #5: پیغام خطای کد معرف پر (3h)
## 📝 Low
- [ ] Task #6: Update Documentation (2h)
**زمان کل**: 27 ساعت (~4 روز کاری)
```
**تخمین زمان**: 2-3 ساعت
---
## 📊 خلاصه Task ها
| # | عنوان | Priority | زمان | وضعیت |
|---|--------|----------|------|--------|
| 1 | DeleteInactiveUsersWorker | 🔥 Critical | 6h | ⬜ Todo |
| 2 | الزامی دیالوگ باشگاه | 🔥 Critical | 8h | ⬜ Todo |
| 3 | شرط لینک معرفی | 🔥 Critical | 4h | ⬜ Todo |
| 4 | Validation 2 فرزند فعال | ⚠️ Medium | 4h | ⬜ Todo |
| 5 | پیغام کد معرف پر | ⚠️ Medium | 3h | ⬜ Todo |
| 6 | Update Documentation | 📝 Low | 3h | ⬜ Todo |
**مجموع زمان**: 28 ساعت (~4 روز کاری)
---
## 🎯 پلان اجرا (پیشنهادی)
### روز 1 (8 ساعت):
- [ ] Task #1: DeleteInactiveUsersWorker (6h)
- [ ] شروع Task #2 (2h)
### روز 2 (8 ساعت):
- [ ] ادامه Task #2: Dialog الزامی (6h)
- [ ] شروع Task #3 (2h)
### روز 3 (8 ساعت):
- [ ] ادامه Task #3: شرط لینک (2h)
- [ ] Task #4: Validation (4h)
- [ ] شروع Task #5 (2h)
### روز 4 (4 ساعت):
- [ ] ادامه Task #5 (1h)
- [ ] Task #6: Documentation (3h)
---
## ✅ Definition of Done
هر Task زمانی Complete حساب می‌شود که:
1. ✅ کد نوشته شده و Build موفق
2. ✅ Unit Test / Manual Test انجام شده
3. ✅ Code Review شده
4. ✅ Documentation به‌روز شده
5. ✅ Merge به Main Branch
---
**تهیه‌کننده**: AI Assistant
**تاریخ**: 2025-12-08
**نسخه**: 1.0