# 📋 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(); ``` **کد پیشنهادی**: ```csharp public class DeleteInactiveUsersJob : BackgroundService { private readonly IServiceProvider _serviceProvider; private readonly ILogger _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(); 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) {

عضویت در باشگاه مشتریان

برای ادامه، لطفاً قرارداد باشگاه مشتریان را مطالعه و امضا کنید.

متن قرارداد...

متن قرارداد را مطالعه کردم و با آن موافقم
امضای قرارداد
} ``` ```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) { 🔗 لینک معرفی شما } else { برای دریافت لینک معرفی، ابتدا عضو باشگاه مشتریان شوید. @if (!User.ClubMembershipId.HasValue) { عضویت در باشگاه } } ``` ```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 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