# 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` ```xml ``` **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` ```csharp 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` ```csharp public class ApplicationContractContext : IApplicationContractContext { // ... existing implementations ... // Network & Commission System public CommissionContract.CommissionContractClient Commissions => GetService(); public NetworkMembershipContract.NetworkMembershipContractClient NetworkMemberships => GetService(); public ClubMembershipContract.ClubMembershipContractClient ClubMemberships => GetService(); } ``` --- ### 4️⃣ gRPC Configuration **File**: `/BackOffice.BFF/src/BackOffice.BFF.WebApi/appsettings.json` ```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: ```csharp // محاسبه بالانس های هفتگی 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: ```csharp // دریافت 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: ```csharp // دریافت اطلاعات شبکه یک کاربر 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: ```csharp // فعال کردن عضویت باشگاه 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: ```csharp // دریافت وضعیت عضویت باشگاه 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` ```csharp public record GetUserPayoutsQuery : IRequest { public long UserId { get; init; } public int PageNumber { get; init; } = 1; public int PageSize { get; init; } = 10; } public class GetUserPayoutsQueryHandler : IRequestHandler { private readonly IApplicationContractContext _context; public GetUserPayoutsQueryHandler(IApplicationContractContext context) { _context = context; } public async Task Handle( GetUserPayoutsQuery request, CancellationToken cancellationToken) { var response = await _context.Commissions.GetUserPayoutsAsync( request.Adapt(), cancellationToken: cancellationToken); return response.Adapt(); } } ``` --- ### Example 2: Create Network Tree Query Handler **File**: `/BackOffice.BFF/src/BackOffice.BFF.Application/NetworkCQ/Queries/GetNetworkTree/GetNetworkTreeQuery.cs` ```csharp public record GetNetworkTreeQuery : IRequest { public long RootUserId { get; init; } public int MaxDepth { get; init; } = 5; } public class GetNetworkTreeQueryHandler : IRequestHandler { private readonly IApplicationContractContext _context; public GetNetworkTreeQueryHandler(IApplicationContractContext context) { _context = context; } public async Task Handle( GetNetworkTreeQuery request, CancellationToken cancellationToken) { var response = await _context.NetworkMemberships.GetNetworkTreeAsync( request.Adapt(), cancellationToken: cancellationToken); return response.Adapt(); } } ``` --- ### Example 3: Create Club Activation Command Handler **File**: `/BackOffice.BFF/src/BackOffice.BFF.Application/ClubCQ/Commands/ActivateClub/ActivateClubCommand.cs` ```csharp public record ActivateClubCommand : IRequest { public long UserId { get; init; } public DateTimeOffset? ActivationDate { get; init; } } public class ActivateClubCommandHandler : IRequestHandler { private readonly IApplicationContractContext _context; public ActivateClubCommandHandler(IApplicationContractContext context) { _context = context; } public async Task Handle( ActivateClubCommand request, CancellationToken cancellationToken) { await _context.ClubMemberships.ActivateClubMembershipAsync( request.Adapt(), cancellationToken: cancellationToken); return Unit.Value; } } ``` --- ## 🔐 Authentication & Authorization **JWT Token**: - BackOffice.BFF به CMS با JWT Token متصل می‌شود - Token از `ITokenProvider` گرفته می‌شود - در Header با کلید `Authorization: Bearer {token}` ارسال می‌شود **Implementation در `ConfigureGrpcServices.cs`**: ```csharp private static async Task CallCredentials( AuthInterceptorContext context, Metadata metadata, IServiceProvider serviceProvider) { var provider = serviceProvider.GetRequiredService(); var token = await provider.GetTokenAsync(); metadata.Add("Authorization", $"Bearer {token}"); } ``` --- ## 🧪 Testing ### Test Connection: ```csharp // در یک 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: 1. Start BackOffice.BFF: ```bash cd /home/masoud/Apps/project/FourSat/BackOffice.BFF/src dotnet run --project BackOffice.BFF.WebApi ``` 2. Call API endpoint (example): ```http GET /api/commission/weekly-pool?weekNumber=2025-W48 Authorization: Bearer {your-token} ``` 3. Expected Response: ```json { "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: 1. ✅ Integration completed 2. ⏳ Create Commission/Network/Club CQRS handlers in BFF 3. ⏳ Add API endpoints in BackOffice.BFF.WebApi 4. ⏳ Test integration with real data ### Short-term: 5. ⏳ Add Swagger documentation for new endpoints 6. ⏳ Implement error handling for gRPC calls 7. ⏳ Add logging for commission operations 8. ⏳ Create admin dashboard for network visualization ### Long-term: 9. ⏳ Add real-time notifications (SignalR) for commission updates 10. ⏳ Implement caching for frequently accessed data 11. ⏳ Add reporting/analytics endpoints 12. ⏳ Performance optimization for large network trees --- ## 📞 Troubleshooting ### Issue 1: gRPC Connection Failed **Error**: `Status(StatusCode="Unavailable", Detail="...")` **Solutions**: 1. Check CMS service is running: `https://cms.kbs1.ir` 2. Verify network connectivity 3. Check firewall settings 4. Verify SSL certificate is valid --- ### Issue 2: Authentication Failed **Error**: `Status(StatusCode="Unauthenticated", Detail="...")` **Solutions**: 1. Verify `ITokenProvider` is registered in DI 2. Check JWT token is valid and not expired 3. Verify token has correct claims/permissions 4. Check Authorization header is being sent --- ### Issue 3: Package Version Mismatch **Error**: `The type or namespace 'CommissionContract' could not be found` **Solutions**: 1. Update package version in `.csproj`: ```xml ``` 2. Run `dotnet restore` 3. Clean and rebuild solution --- ### Issue 4: Method Not Found **Error**: `Method 'GetWeeklyPool' not found on service 'CommissionContract'` **Solutions**: 1. Verify CMS service has the latest code deployed 2. Check Protobuf contract matches between CMS and BFF 3. Update both CMS and BFF to latest versions 4. 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