feat: Add monitoring alerts skeleton and enhance worker with notifications
This commit is contained in:
281
docs/binary-tree-registration-guide.md
Normal file
281
docs/binary-tree-registration-guide.md
Normal file
@@ -0,0 +1,281 @@
|
||||
# 🌳 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<User>();
|
||||
entity.ReferralCode = UtilExtensions.Generate(digits: 10);
|
||||
await _context.Users.AddAsync(entity, cancellationToken);
|
||||
```
|
||||
|
||||
**مشکل**: فقط `ParentId` Set میشد، `NetworkParentId` و `LegPosition` خالی میماند.
|
||||
|
||||
---
|
||||
|
||||
### بعد از تغییر:
|
||||
|
||||
```csharp
|
||||
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 مشخص.
|
||||
|
||||
```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 استفاده کنید
|
||||
Reference in New Issue
Block a user