Files
BackOffice.BFF/docs/cms-integration.md

18 KiB
Raw Blame History

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:

  1. Start BackOffice.BFF:

    cd /home/masoud/Apps/project/FourSat/BackOffice.BFF/src
    dotnet run --project BackOffice.BFF.WebApi
    
  2. Call API endpoint (example):

    GET /api/commission/weekly-pool?weekNumber=2025-W48
    Authorization: Bearer {your-token}
    
  3. 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

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:

  1. Add Swagger documentation for new endpoints
  2. Implement error handling for gRPC calls
  3. Add logging for commission operations
  4. Create admin dashboard for network visualization

Long-term:

  1. Add real-time notifications (SignalR) for commission updates
  2. Implement caching for frequently accessed data
  3. Add reporting/analytics endpoints
  4. 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:
    <PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.140" />
    
  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