# 🌳 Binary Tree Network Registration Guide ## 📋 Overview از این پس، هر کاربر جدید که در سیستم ثبت می‌شود، **هم‌زمان** در دو ساختار قرار می‌گیرد: 1. **Old System**: `User.ParentId` (برای Backward Compatibility) 2. **New Binary Tree System**: `User.NetworkParentId` + `User.LegPosition` (Left/Right) این تغییر تضمین می‌کند که: - ✅ کاربران جدید بلافاصله در محاسبات Commission شرکت می‌کنند - ✅ نیازی به Migration اضافی نیست - ✅ Binary Tree Constraint رعایت می‌شود (حداکثر 2 فرزند) --- ## 🔧 Changes in Registration Flow ### قبل از تغییر: ```csharp var entity = request.Adapt(); entity.ReferralCode = UtilExtensions.Generate(digits: 10); await _context.Users.AddAsync(entity, cancellationToken); ``` **مشکل**: فقط `ParentId` Set می‌شد، `NetworkParentId` و `LegPosition` خالی می‌ماند. --- ### بعد از تغییر: ```csharp var entity = request.Adapt(); entity.ReferralCode = UtilExtensions.Generate(digits: 10); // === محاسبه موقعیت در Binary Tree === if (request.ParentId.HasValue) { var legPosition = await _networkPlacementService.CalculateLegPositionAsync( request.ParentId.Value, cancellationToken); if (legPosition.HasValue) { entity.NetworkParentId = request.ParentId.Value; entity.LegPosition = legPosition.Value; // Left یا Right } else { // Parent پر است! Auto-Placement یا Error var availableParent = await _networkPlacementService.FindAvailableParentAsync( request.ParentId.Value, cancellationToken); // ... Set کردن NetworkParentId و LegPosition با Parent جدید } } await _context.Users.AddAsync(entity, cancellationToken); ``` **مزایا**: - ✅ `NetworkParentId` و `LegPosition` به صورت خودکار محاسبه می‌شود - ✅ Binary Tree Constraint چک می‌شود - ✅ اگر Parent پر باشد، Auto-Placement انجام می‌شود --- ## 📐 Binary Tree Logic ### قوانین: 1. هر Parent فقط **2 فرزند** می‌تواند داشته باشد (Left & Right) 2. فرزند اول: `LegPosition = Left` 3. فرزند دوم: `LegPosition = Right` 4. اگر Parent پر باشد، سیستم به صورت BFS دنبال Parent خالی می‌گردد ### مثال: ``` User1 (Root) / \ User2 (L) User3 (R) / \ User4(L) User5(R) ``` - User2 → Parent=User1, Leg=Left - User3 → Parent=User1, Leg=Right - User4 → Parent=User2, Leg=Left - User5 → Parent=User2, Leg=Right اگر کاربر جدید با `ParentId=User1` بیاید: - User1 پر است! (دو فرزند دارد) - سیستم به User2 می‌رود (BFS) - User2 هم پر است! - به User3 می‌رود → User3 خالی است - کاربر جدید → Parent=User3, Leg=Left --- ## 🛠️ NetworkPlacementService API ### 1. CalculateLegPositionAsync محاسبه موقعیت (Left/Right) برای کاربر جدید زیر یک Parent مشخص. ```csharp var legPosition = await _networkPlacementService.CalculateLegPositionAsync(parentId); ``` **Return Values**: - `NetworkLeg.Left`: اگر Parent فرزند چپ ندارد - `NetworkLeg.Right`: اگر Parent فرزند راست ندارد - `null`: اگر Parent پر است (دو فرزند دارد) --- ### 2. CanAcceptChildAsync بررسی اینکه آیا Parent می‌تواند فرزند جدید بپذیرد. ```csharp bool canAccept = await _networkPlacementService.CanAcceptChildAsync(parentId); ``` **Return Values**: - `true`: اگر Parent کمتر از 2 فرزند دارد - `false`: اگر Parent پر است --- ### 3. FindAvailableParentAsync (Auto-Placement) پیدا کردن اولین Parent خالی در Binary Tree با استفاده از BFS. ```csharp long? availableParentId = await _networkPlacementService.FindAvailableParentAsync(rootParentId); ``` **Use Case**: - زمانی که Parent مورد نظر پر است - سیستم به صورت خودکار Parent جایگزین پیدا می‌کند - از BFS استفاده می‌کند (Level-by-Level) **Return Values**: - `long`: شناسه Parent مناسب - `null`: اگر هیچ Parent خالی پیدا نشد (تمام Binary Tree پر است!) --- ## ⚠️ Error Handling ### Scenario 1: Parent پر است و Auto-Placement موفق ```csharp // Parent اصلی پر است // سیستم Parent جدید پیدا می‌کند _logger.LogWarning("Parent {ParentId} is full. Auto-placing under {NewParentId}"); ``` **نتیجه**: کاربر با موفقیت در جای دیگری قرار می‌گیرد. --- ### Scenario 2: کل Binary Tree پر است ```csharp throw new InvalidOperationException( $"شبکه Parent با شناسه {parentId} پر است و نمی‌تواند کاربر جدید بپذیرد."); ``` **نتیجه**: Exception پرتاب می‌شود، ثبت کاربر انجام نمی‌شود. **راه حل**: - افزایش سطح Binary Tree - یا تخصیص دستی Parent --- ### Scenario 3: Parent وجود ندارد ```csharp var parentExists = await _context.Users.AnyAsync(u => u.Id == parentId); if (!parentExists) { return null; // Parent نامعتبر } ``` **نتیجه**: `null` برگردانده می‌شود، Exception پرتاب می‌شود. --- ## 📊 Logging & Monitoring سیستم Log های زیر را می‌نویسد: ### Success: ``` User 123 placed in Binary Tree: Parent=45, Leg=Left ``` ### Warning (Auto-Placement): ``` Parent 45 has no available leg! Finding alternative parent... User 123 auto-placed under alternative Parent=67, Leg=Right ``` ### Error (Binary Tree Full): ``` No available parent found in network for ParentId=45 ``` --- ## 🧪 Testing Scenarios ### Test 1: کاربر اول (Root) ```csharp var command = new CreateNewUserCommand { Mobile = "09121234567" }; // No ParentId // Result: ParentId=null, NetworkParentId=null, LegPosition=null ``` --- ### Test 2: فرزند اول ```csharp var command = new CreateNewUserCommand { Mobile = "09121234568", ParentId = 1 }; // Result: ParentId=1, NetworkParentId=1, LegPosition=Left ``` --- ### Test 3: فرزند دوم ```csharp var command = new CreateNewUserCommand { Mobile = "09121234569", ParentId = 1 }; // Result: ParentId=1, NetworkParentId=1, LegPosition=Right ``` --- ### Test 4: فرزند سوم (Parent پر است) ```csharp var command = new CreateNewUserCommand { Mobile = "09121234570", ParentId = 1 }; // Result: Auto-Placement → ParentId=1, NetworkParentId=2 (یا 3), LegPosition=Left ``` --- ## 🔗 Related Files - **Service Interface**: `CMSMicroservice.Application/Common/Interfaces/INetworkPlacementService.cs` - **Service Implementation**: `CMSMicroservice.Infrastructure/Services/NetworkPlacementService.cs` - **Handler**: `CMSMicroservice.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommandHandler.cs` - **DI Registration**: `CMSMicroservice.Infrastructure/ConfigureServices.cs` (خط 23) --- ## ✅ Checklist - [x] `INetworkPlacementService` اضافه شد - [x] `NetworkPlacementService` پیاده‌سازی شد - [x] DI Container تنظیم شد - [x] `CreateNewUserCommandHandler` اصلاح شد - [ ] Unit Tests نوشته شود - [ ] Integration Tests انجام شود - [ ] Manual Testing با Postman/gRPC Client --- ## 🚀 Next Steps 1. **Test کردن**: ثبت چند کاربر با Parent مشابه و بررسی LegPosition 2. **Load Testing**: بررسی Performance با 10,000 کاربر 3. **Edge Cases**: تست Binary Tree Full scenario 4. **Documentation**: Update کردن API Docs --- ## 📞 Support اگر مشکلی پیش آمد: - Log های `NetworkPlacementService` را بررسی کنید - چک کنید که DI به درستی تنظیم شده باشد - از `CanAcceptChildAsync` برای Pre-Validation استفاده کنید