Files
CMS/docs/binary-tree-registration-guide.md

8.0 KiB

🌳 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

قبل از تغییر:

var entity = request.Adapt<User>();
entity.ReferralCode = UtilExtensions.Generate(digits: 10);
await _context.Users.AddAsync(entity, cancellationToken);

مشکل: فقط ParentId Set می‌شد، NetworkParentId و LegPosition خالی می‌ماند.


بعد از تغییر:

var entity = request.Adapt<User>();
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 مشخص.

var legPosition = await _networkPlacementService.CalculateLegPositionAsync(parentId);

Return Values:

  • NetworkLeg.Left: اگر Parent فرزند چپ ندارد
  • NetworkLeg.Right: اگر Parent فرزند راست ندارد
  • null: اگر Parent پر است (دو فرزند دارد)

2. CanAcceptChildAsync

بررسی اینکه آیا Parent می‌تواند فرزند جدید بپذیرد.

bool canAccept = await _networkPlacementService.CanAcceptChildAsync(parentId);

Return Values:

  • true: اگر Parent کمتر از 2 فرزند دارد
  • false: اگر Parent پر است

3. FindAvailableParentAsync (Auto-Placement)

پیدا کردن اولین Parent خالی در Binary Tree با استفاده از BFS.

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 موفق

// Parent اصلی پر است
// سیستم Parent جدید پیدا می‌کند
_logger.LogWarning("Parent {ParentId} is full. Auto-placing under {NewParentId}");

نتیجه: کاربر با موفقیت در جای دیگری قرار می‌گیرد.


Scenario 2: کل Binary Tree پر است

throw new InvalidOperationException(
    $"شبکه Parent با شناسه {parentId} پر است و نمی‌تواند کاربر جدید بپذیرد.");

نتیجه: Exception پرتاب می‌شود، ثبت کاربر انجام نمی‌شود.

راه حل:

  • افزایش سطح Binary Tree
  • یا تخصیص دستی Parent

Scenario 3: Parent وجود ندارد

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)

var command = new CreateNewUserCommand { Mobile = "09121234567" }; // No ParentId
// Result: ParentId=null, NetworkParentId=null, LegPosition=null

Test 2: فرزند اول

var command = new CreateNewUserCommand { Mobile = "09121234568", ParentId = 1 };
// Result: ParentId=1, NetworkParentId=1, LegPosition=Left

Test 3: فرزند دوم

var command = new CreateNewUserCommand { Mobile = "09121234569", ParentId = 1 };
// Result: ParentId=1, NetworkParentId=1, LegPosition=Right

Test 4: فرزند سوم (Parent پر است)

var command = new CreateNewUserCommand { Mobile = "09121234570", ParentId = 1 };
// Result: Auto-Placement → ParentId=1, NetworkParentId=2 (یا 3), LegPosition=Left

  • 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

  • INetworkPlacementService اضافه شد
  • NetworkPlacementService پیاده‌سازی شد
  • DI Container تنظیم شد
  • 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 استفاده کنید