18 KiB
BackOffice.BFF - CMS Integration Documentation
Date: 2025-11-30
Status: ✅ Integrated
CMS Package Version: 0.0.140
📋 Overview
BackOffice.BFF به CMS Microservice متصل شد و حالا میتواند به سرویسهای Network-Club-Commission دسترسی داشته باشد.
این Integration به BackOffice امکان میدهد:
- مدیریت کامیسیونهای کاربران
- مشاهده ساختار شبکه Binary Tree
- فعال/غیرفعال کردن عضویت باشگاه
- مشاهده گزارشات هفتگی کمیسیون
🏗️ Architecture
┌─────────────────────────────────────────────────────────┐
│ BackOffice.BFF (API Gateway) │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ IApplicationContractContext │ │
│ │ - Users (existing) │ │
│ │ - Products (existing) │ │
│ │ - Orders (existing) │ │
│ │ ✨ Commissions (NEW) │ │
│ │ ✨ NetworkMemberships (NEW) │ │
│ │ ✨ ClubMemberships (NEW) │ │
│ └──────────────────────────────────────────────────┘ │
│ ↓ gRPC │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ CMS Microservice │
│ https://cms.kbs1.ir │
│ │
│ ┌─────────────────────┐ ┌─────────────────────────┐ │
│ │ CommissionContract │ │ NetworkMembershipContract│ │
│ │ - GetWeeklyPool │ │ - GetUserNetworkInfo │ │
│ │ - GetUserPayouts │ │ - GetNetworkTree │ │
│ │ - ProcessWithdrawal │ │ - CalculateLegBalances │ │
│ └─────────────────────┘ └─────────────────────────┘ │
│ │
│ ┌─────────────────────┐ │
│ │ ClubMembershipContract│ │
│ │ - ActivateClub │ │
│ │ - DeactivateClub │ │
│ │ - GetClubStatus │ │
│ └─────────────────────┘ │
└─────────────────────────────────────────────────────────┘
📦 Integration Details
1️⃣ NuGet Package
Package: Foursat.CMSMicroservice.Protobuf
Version: 0.0.140 (Updated from 0.0.137)
File: /BackOffice.BFF/src/BackOffice.BFF.Domain/BackOffice.BFF.Domain.csproj
<PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.140" />
What's New in 0.0.140:
- ✨
commission.proto- Commission system contracts - ✨
networkmembership.proto- Binary tree network contracts - ✨
clubmembership.proto- Club membership contracts - ✨
configuration.proto- System configuration contracts
2️⃣ Interface Definition
File: /BackOffice.BFF/src/BackOffice.BFF.Application/Common/Interfaces/IApplicationContractContext.cs
public interface IApplicationContractContext
{
// ... existing services ...
// Network & Commission System (NEW)
CommissionContract.CommissionContractClient Commissions { get; }
NetworkMembershipContract.NetworkMembershipContractClient NetworkMemberships { get; }
ClubMembershipContract.ClubMembershipContractClient ClubMemberships { get; }
}
3️⃣ Implementation
File: /BackOffice.BFF/src/BackOffice.BFF.Infrastructure/Services/ApplicationContractContext.cs
public class ApplicationContractContext : IApplicationContractContext
{
// ... existing implementations ...
// Network & Commission System
public CommissionContract.CommissionContractClient Commissions
=> GetService<CommissionContract.CommissionContractClient>();
public NetworkMembershipContract.NetworkMembershipContractClient NetworkMemberships
=> GetService<NetworkMembershipContract.NetworkMembershipContractClient>();
public ClubMembershipContract.ClubMembershipContractClient ClubMemberships
=> GetService<ClubMembershipContract.ClubMembershipContractClient>();
}
4️⃣ gRPC Configuration
File: /BackOffice.BFF/src/BackOffice.BFF.WebApi/appsettings.json
{
"GrpcChannelOptions": {
"FMSMSAddress": "https://dl.afrino.co",
"CMSMSAddress": "https://cms.kbs1.ir"
}
}
Auto-Registration:
- gRPC clients به صورت خودکار توسط
ConfigureGrpcServices.BatchRegisterGrpcClients()ثبت میشوند - بر اساس نام Assembly (
CMSMicroservice.Protobuf) - با Address مشخص شده در
appsettings.json
🔌 Available Services
1️⃣ CommissionContract
Namespace: CMSMicroservice.Protobuf.Protos.Commission
Commands:
// محاسبه بالانس های هفتگی
await _context.Commissions.CalculateWeeklyBalancesAsync(
new CalculateWeeklyBalancesRequest { WeekNumber = "2025-W48" });
// محاسبه Pool هفتگی
await _context.Commissions.CalculateWeeklyCommissionPoolAsync(
new CalculateWeeklyCommissionPoolRequest { WeekNumber = "2025-W48" });
// پردازش Payout های کاربران
await _context.Commissions.ProcessUserPayoutsAsync(
new ProcessUserPayoutsRequest { WeekNumber = "2025-W48" });
// درخواست برداشت توسط کاربر
await _context.Commissions.RequestWithdrawalAsync(
new RequestWithdrawalRequest
{
UserId = 123,
Amount = 500000
});
// پردازش برداشت (توسط Admin)
await _context.Commissions.ProcessWithdrawalAsync(
new ProcessWithdrawalRequest
{
PayoutId = 456,
Status = WithdrawalStatus.Approved
});
Queries:
// دریافت Pool هفتگی
var pool = await _context.Commissions.GetWeeklyCommissionPoolAsync(
new GetWeeklyCommissionPoolRequest { WeekNumber = "2025-W48" });
// دریافت Payout های یک کاربر
var payouts = await _context.Commissions.GetUserPayoutsAsync(
new GetUserPayoutsRequest
{
UserId = 123,
PageNumber = 1,
PageSize = 10
});
// دریافت تاریخچه Withdrawal ها
var withdrawals = await _context.Commissions.GetWithdrawalHistoryAsync(
new GetWithdrawalHistoryRequest
{
UserId = 123,
Status = WithdrawalStatus.Pending
});
2️⃣ NetworkMembershipContract
Namespace: CMSMicroservice.Protobuf.Protos.NetworkMembership
Queries:
// دریافت اطلاعات شبکه یک کاربر
var networkInfo = await _context.NetworkMemberships.GetUserNetworkInfoAsync(
new GetUserNetworkInfoRequest { UserId = 123 });
// دریافت درخت شبکه (Binary Tree)
var tree = await _context.NetworkMemberships.GetNetworkTreeAsync(
new GetNetworkTreeRequest
{
RootUserId = 123,
MaxDepth = 5
});
// دریافت بالانس های هفتگی
var balances = await _context.NetworkMemberships.GetUserWeeklyBalancesAsync(
new GetUserWeeklyBalancesRequest
{
UserId = 123,
WeekNumber = "2025-W48"
});
// محاسبه بالانس Leg های یک کاربر
var legBalances = await _context.NetworkMemberships.CalculateLegBalancesAsync(
new CalculateLegBalancesRequest { UserId = 123 });
3️⃣ ClubMembershipContract
Namespace: CMSMicroservice.Protobuf.Protos.ClubMembership
Commands:
// فعال کردن عضویت باشگاه
await _context.ClubMemberships.ActivateClubMembershipAsync(
new ActivateClubMembershipRequest
{
UserId = 123,
ActivationDate = Timestamp.FromDateTime(DateTime.UtcNow)
});
// غیرفعال کردن عضویت باشگاه
await _context.ClubMemberships.DeactivateClubMembershipAsync(
new DeactivateClubMembershipRequest
{
UserId = 123,
Reason = "User request"
});
Queries:
// دریافت وضعیت عضویت باشگاه
var status = await _context.ClubMemberships.GetClubMembershipStatusAsync(
new GetClubMembershipStatusRequest { UserId = 123 });
// لیست تمام اعضای باشگاه
var members = await _context.ClubMemberships.GetAllClubMembersAsync(
new GetAllClubMembersRequest
{
IsActive = true,
PageNumber = 1,
PageSize = 20
});
📝 Usage Example in BFF
Example 1: Create Commission Query Handler
File: /BackOffice.BFF/src/BackOffice.BFF.Application/CommissionCQ/Queries/GetUserPayouts/GetUserPayoutsQuery.cs
public record GetUserPayoutsQuery : IRequest<GetUserPayoutsResponseDto>
{
public long UserId { get; init; }
public int PageNumber { get; init; } = 1;
public int PageSize { get; init; } = 10;
}
public class GetUserPayoutsQueryHandler
: IRequestHandler<GetUserPayoutsQuery, GetUserPayoutsResponseDto>
{
private readonly IApplicationContractContext _context;
public GetUserPayoutsQueryHandler(IApplicationContractContext context)
{
_context = context;
}
public async Task<GetUserPayoutsResponseDto> Handle(
GetUserPayoutsQuery request,
CancellationToken cancellationToken)
{
var response = await _context.Commissions.GetUserPayoutsAsync(
request.Adapt<GetUserPayoutsRequest>(),
cancellationToken: cancellationToken);
return response.Adapt<GetUserPayoutsResponseDto>();
}
}
Example 2: Create Network Tree Query Handler
File: /BackOffice.BFF/src/BackOffice.BFF.Application/NetworkCQ/Queries/GetNetworkTree/GetNetworkTreeQuery.cs
public record GetNetworkTreeQuery : IRequest<GetNetworkTreeResponseDto>
{
public long RootUserId { get; init; }
public int MaxDepth { get; init; } = 5;
}
public class GetNetworkTreeQueryHandler
: IRequestHandler<GetNetworkTreeQuery, GetNetworkTreeResponseDto>
{
private readonly IApplicationContractContext _context;
public GetNetworkTreeQueryHandler(IApplicationContractContext context)
{
_context = context;
}
public async Task<GetNetworkTreeResponseDto> Handle(
GetNetworkTreeQuery request,
CancellationToken cancellationToken)
{
var response = await _context.NetworkMemberships.GetNetworkTreeAsync(
request.Adapt<GetNetworkTreeRequest>(),
cancellationToken: cancellationToken);
return response.Adapt<GetNetworkTreeResponseDto>();
}
}
Example 3: Create Club Activation Command Handler
File: /BackOffice.BFF/src/BackOffice.BFF.Application/ClubCQ/Commands/ActivateClub/ActivateClubCommand.cs
public record ActivateClubCommand : IRequest<Unit>
{
public long UserId { get; init; }
public DateTimeOffset? ActivationDate { get; init; }
}
public class ActivateClubCommandHandler
: IRequestHandler<ActivateClubCommand, Unit>
{
private readonly IApplicationContractContext _context;
public ActivateClubCommandHandler(IApplicationContractContext context)
{
_context = context;
}
public async Task<Unit> Handle(
ActivateClubCommand request,
CancellationToken cancellationToken)
{
await _context.ClubMemberships.ActivateClubMembershipAsync(
request.Adapt<ActivateClubMembershipRequest>(),
cancellationToken: cancellationToken);
return Unit.Value;
}
}
🔐 Authentication & Authorization
JWT Token:
- BackOffice.BFF به CMS با JWT Token متصل میشود
- Token از
ITokenProviderگرفته میشود - در Header با کلید
Authorization: Bearer {token}ارسال میشود
Implementation در ConfigureGrpcServices.cs:
private static async Task CallCredentials(
AuthInterceptorContext context,
Metadata metadata,
IServiceProvider serviceProvider)
{
var provider = serviceProvider.GetRequiredService<ITokenProvider>();
var token = await provider.GetTokenAsync();
metadata.Add("Authorization", $"Bearer {token}");
}
🧪 Testing
Test Connection:
// در یک Controller یا Handler:
var pool = await _context.Commissions.GetWeeklyCommissionPoolAsync(
new GetWeeklyCommissionPoolRequest { WeekNumber = "2025-W48" });
Console.WriteLine($"Total Pool Value: {pool.TotalPoolValue}");
Console.WriteLine($"Active Members: {pool.ActiveMembersCount}");
Expected Output:
Total Pool Value: 50000000
Active Members: 120
Test with Postman/Swagger:
-
Start BackOffice.BFF:
cd /home/masoud/Apps/project/FourSat/BackOffice.BFF/src dotnet run --project BackOffice.BFF.WebApi -
Call API endpoint (example):
GET /api/commission/weekly-pool?weekNumber=2025-W48 Authorization: Bearer {your-token} -
Expected Response:
{ "weekNumber": "2025-W48", "totalPoolValue": 50000000, "activeMembersCount": 120, "isCalculated": true }
📊 Status & Metrics
| Component | Status | Version | Notes |
|---|---|---|---|
| CMS Protobuf Package | ✅ Active | 0.0.140 | With Network-Club-Commission |
| gRPC Connection | ✅ Configured | - | https://cms.kbs1.ir |
| Auto-Registration | ✅ Active | - | Via BatchRegisterGrpcClients |
| Commission Client | ✅ Ready | - | All commands & queries available |
| Network Client | ✅ Ready | - | Binary tree queries available |
| Club Client | ✅ Ready | - | Activation/Deactivation available |
| Authentication | ✅ Configured | JWT | Via ITokenProvider |
🔗 Related Documentation
CMS Side:
- Implementation Progress:
/CMS/docs/implementation-progress.md - Network System Design:
/CMS/docs/network-club-commission-system.md - Monitoring Setup:
/CMS/docs/monitoring-alerts-consolidated-report.md - Migration Guide:
/CMS/docs/migration-network-parent-guide.md - Binary Tree Registration:
/CMS/docs/binary-tree-registration-guide.md
BFF Side:
- This Document:
/BackOffice.BFF/docs/cms-integration.md - README:
/BackOffice.BFF/README.md
🚀 Next Steps
Immediate:
- ✅ Integration completed
- ⏳ Create Commission/Network/Club CQRS handlers in BFF
- ⏳ Add API endpoints in BackOffice.BFF.WebApi
- ⏳ Test integration with real data
Short-term:
- ⏳ Add Swagger documentation for new endpoints
- ⏳ Implement error handling for gRPC calls
- ⏳ Add logging for commission operations
- ⏳ Create admin dashboard for network visualization
Long-term:
- ⏳ Add real-time notifications (SignalR) for commission updates
- ⏳ Implement caching for frequently accessed data
- ⏳ Add reporting/analytics endpoints
- ⏳ Performance optimization for large network trees
📞 Troubleshooting
Issue 1: gRPC Connection Failed
Error: Status(StatusCode="Unavailable", Detail="...")
Solutions:
- Check CMS service is running:
https://cms.kbs1.ir - Verify network connectivity
- Check firewall settings
- Verify SSL certificate is valid
Issue 2: Authentication Failed
Error: Status(StatusCode="Unauthenticated", Detail="...")
Solutions:
- Verify
ITokenProvideris registered in DI - Check JWT token is valid and not expired
- Verify token has correct claims/permissions
- Check Authorization header is being sent
Issue 3: Package Version Mismatch
Error: The type or namespace 'CommissionContract' could not be found
Solutions:
- Update package version in
.csproj:<PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.140" /> - Run
dotnet restore - Clean and rebuild solution
Issue 4: Method Not Found
Error: Method 'GetWeeklyPool' not found on service 'CommissionContract'
Solutions:
- Verify CMS service has the latest code deployed
- Check Protobuf contract matches between CMS and BFF
- Update both CMS and BFF to latest versions
- Restart both services
🎯 Summary
✅ Completed:
- CMS Protobuf package updated to 0.0.140
- 3 new gRPC clients added to BFF:
- CommissionContract (8+ methods)
- NetworkMembershipContract (6+ methods)
- ClubMembershipContract (4+ methods)
- Auto-registration configured
- Authentication via JWT configured
- Build successful (0 errors)
⏳ Pending:
- Create CQRS handlers for Commission operations
- Create CQRS handlers for Network operations
- Create CQRS handlers for Club operations
- Add API Controllers/Endpoints
- Add Swagger documentation
- Integration testing
🔑 Key Points:
- No manual registration needed: gRPC clients auto-register via
BatchRegisterGrpcClients() - Authentication handled: JWT token automatically added to all requests
- Type-safe: All Protobuf contracts are strongly typed
- Easy to use: Simple interface via
IApplicationContractContext
Last Updated: 2025-11-30
Build Status: ✅ Success
Ready for: Handler implementation & API endpoint creation