# 🔌 API، Protobuf و یکپارچه‌سازی خارجی > **منابع ادغام‌شده:** `FRONTOFFICE-CMS-API-COMPATIBILITY.md`, `REMAINING-TASKS.md`, `chatika-integration.md`, `payment-gateway.md`, `club-feature-management-services.md` > **آخرین بروزرسانی:** اسفند ۱۴۰۴ --- ## ۱. معماری ارتباطات ``` ┌──────────────────────────────────────────────────────────────────┐ │ External Services │ │ ┌─────────┐ ┌──────────┐ ┌─────────┐ ┌─────────┐ │ │ │ ZarinPal│ │ Kavenegar│ │ DayaLoan│ │ Chatika │ │ │ │ (IPG) │ │ (SMS) │ │ (Loan) │ │ (AI) │ │ │ └────┬────┘ └────┬─────┘ └────┬────┘ └────┬────┘ │ │ │ │ │ │ │ │ ┌────▼───────────▼────────────▼────────────▼────┐ │ │ │ CMS Microservice │ │ │ │ (gRPC Server + Hangfire + EF Core) │ │ │ └────────────────┬───────────────────────────────┘ │ │ │ gRPC (Protobuf v3) │ │ ┌───────────┼───────────┐ │ │ ┌────▼────┐ ┌────▼────┐ │ │ │BackOffice│ │FrontOffice│ │ │ │(Blazor │ │(Blazor │ │ │ │ WASM) │ │ Server) │ │ │ └─────────┘ └──────────┘ │ └──────────────────────────────────────────────────────────────────┘ ``` --- ## ۲. gRPC Proto Definitions ### ۲.۱ لیست کامل سرویس‌ها ```protobuf // ===== product.proto ===== service ProductService { rpc GetProducts (GetProductsRequest) returns (GetProductsResponse); rpc GetProductById (GetProductByIdRequest) returns (ProductMessage); rpc CreateProduct (CreateProductRequest) returns (CreateProductResponse); rpc UpdateProduct (UpdateProductRequest) returns (UpdateProductResponse); rpc DeleteProduct (DeleteProductRequest) returns (Empty); rpc GetProductsPaged (GetProductsPagedRequest) returns (GetProductsPagedResponse); } // ===== order.proto ===== service OrderService { rpc CreateOrder (CreateOrderRequest) returns (CreateOrderResponse); rpc GetOrders (GetOrdersRequest) returns (GetOrdersResponse); rpc GetOrderById (GetOrderByIdRequest) returns (OrderMessage); rpc UpdateOrderStatus (UpdateOrderStatusRequest) returns (Empty); } // ===== user.proto ===== service UserService { rpc Register (RegisterRequest) returns (AuthResponse); rpc Login (LoginRequest) returns (AuthResponse); rpc GetProfile (GetProfileRequest) returns (UserProfileMessage); rpc UpdateProfile (UpdateProfileRequest) returns (Empty); rpc SendOtp (SendOtpRequest) returns (SendOtpResponse); rpc VerifyOtp (VerifyOtpRequest) returns (VerifyOtpResponse); } // ===== club.proto ===== service ClubService { rpc GetNetworkTree (GetNetworkTreeRequest) returns (NetworkTreeResponse); rpc GetBalance (GetBalanceRequest) returns (BalanceResponse); rpc ReadContract (ReadContractRequest) returns (ContractResponse); rpc RequestContractOtp (RequestOtpRequest) returns (OtpResponse); rpc VerifyContractOtp (VerifyOtpRequest) returns (VerifyOtpResponse); rpc AcceptContract (AcceptContractRequest) returns (AcceptContractResponse); rpc GetClubFeatures (GetFeaturesRequest) returns (FeaturesResponse); } // ===== payment.proto ===== service PaymentService { rpc CreatePayment (CreatePaymentRequest) returns (CreatePaymentResponse); rpc VerifyPayment (VerifyPaymentRequest) returns (VerifyPaymentResponse); rpc GetPaymentStatus (PaymentStatusRequest) returns (PaymentStatusResponse); } // ===== blog.proto ===== service BlogService { rpc GetPosts (GetPostsRequest) returns (GetPostsResponse); rpc GetPostBySlug (GetPostBySlugRequest) returns (BlogPostMessage); rpc CreatePost (CreatePostRequest) returns (CreatePostResponse); rpc UpdatePost (UpdatePostRequest) returns (Empty); rpc DeletePost (DeletePostRequest) returns (Empty); } // ===== inventory.proto ===== service InventoryService { rpc GetInventory (GetInventoryRequest) returns (InventoryMessage); rpc UpdateStock (UpdateStockRequest) returns (Empty); rpc GetAllInventories (GetAllRequest) returns (InventoryListResponse); } // ===== sitepage.proto ===== service SitePageService { rpc GetPage (GetPageRequest) returns (SitePageMessage); rpc SaveSettings (SaveSettingsRequest) returns (Empty); rpc GetAllPages (Empty) returns (PageListResponse); } // ===== file.proto ===== service FileService { rpc Upload (stream UploadRequest) returns (UploadResponse); rpc Download (DownloadRequest) returns (stream DownloadResponse); rpc Delete (DeleteFileRequest) returns (Empty); } // ===== category.proto ===== service CategoryService { rpc GetCategories (GetCategoriesRequest) returns (CategoryListResponse); rpc CreateCategory (CreateCategoryRequest) returns (CreateCategoryResponse); rpc UpdateCategory (UpdateCategoryRequest) returns (Empty); } // ===== config.proto ===== service SystemConfigService { rpc GetConfig (GetConfigRequest) returns (ConfigResponse); rpc UpdateConfig (UpdateConfigRequest) returns (Empty); rpc GetAllConfigs (Empty) returns (ConfigListResponse); } ``` ### ۲.۲ Shared Messages ```protobuf // ===== common.proto ===== message PaginationState { int32 skip = 1; int32 take = 2; } message PaginatedResponse { int32 totalCount = 1; int32 pageSize = 2; int32 currentPage = 3; } message Empty {} ``` --- ## ۳. External Service Integration ### ۳.۱ ZarinPal (پرداخت) ```csharp public class ZarinPalService : IPaymentGateway { // Config private readonly string _merchantId; private readonly bool _isSandbox; // Endpoints const string PAYMENT_URL = "https://api.zarinpal.com/pg/v4/payment/request.json"; const string VERIFY_URL = "https://api.zarinpal.com/pg/v4/payment/verify.json"; const string SANDBOX_URL = "https://sandbox.zarinpal.com/pg/v4/payment/request.json"; // Flow // 1. CreatePayment → Authority token // 2. Redirect → https://www.zarinpal.com/pg/StartPay/{Authority} // 3. Callback → VerifyPayment(Authority, Amount) // 4. Result → RefID (reference number) } ``` ### ۳.۲ Kavenegar (SMS) ```csharp public class KavenegarService : ISmsService { // Templates — فقط یک تمپلیت در کد موجود است const string OTP_TEMPLATE = "Afrino"; // تنها تمپلیت استفاده‌شده // Sender: "1000001110100" // Rate Limiting // ۱ SMS per phone per 60 seconds // ۵ SMS per phone per hour // ۲۰ SMS per phone per day public async Task SendOtpAsync(string phone, string code) { await _api.VerifyLookup(phone, code, OTP_TEMPLATE); } } ``` ### ۳.۳ Daya Loan (وام) ```csharp public class DayaLoanService : ILoanService { // Hangfire job — هر ۲۰ دقیقه (*/20 * * * *) // Polly retry: 3 attempts, exponential backoff (2s, 4s, 8s) // Mock mode for staging (auto-approve) public async Task RequestLoanAsync(Guid userId, decimal amount) { if (_options.UseMock) return LoanResult.Approved(amount); var response = await _httpClient.PostAsync( $"{_baseUrl}/api/loans/request", new { UserId = userId, Amount = amount }); return MapResponse(response); } } ``` ### ۳.۴ Chatika (AI) ```csharp public class ChatikaService : IAiChatService { // Hangfire job — هر ۵ دقیقه // Polly retry: 3 attempts // Only for active club members public async Task GetResponseAsync(string userMessage) { var response = await _httpClient.PostAsync( $"{_baseUrl}/api/chat", new { Message = userMessage }); return response.Content.ReadAsStringAsync(); } } ``` --- ## ۴. API Compatibility Layer ### ۴.۱ FrontOffice Service Pattern ```csharp // هر سرویس در FrontOffice یک wrapper بر gRPC client است public class ProductService : IProductService { private readonly ProductServiceClient _client; public ProductService(ProductServiceClient client) { _client = client; } public async Task GetProductsPagedAsync( int skip, int take, Guid? categoryId = null, string? search = null) { try { var request = new GetProductsPagedRequest { Pagination = new PaginationState { Skip = skip, Take = take }, CategoryId = categoryId?.ToString() ?? "", SearchTerm = search ?? "" }; var response = await _client.GetProductsPagedAsync(request); return new ProductListResult( response.Products.Select(MapToDto).ToList(), response.TotalCount); } catch (RpcException ex) when (ex.StatusCode == StatusCode.Unavailable) { // CMS is down — show cached data or error throw new ServiceUnavailableException("CMS service unavailable"); } } } ``` ### ۴.۲ Error Handling | gRPC Status | HTTP Equivalent | Handling | |------------|-----------------|----------| | `OK` | 200 | Return data | | `NotFound` | 404 | Show "not found" message | | `InvalidArgument` | 400 | Show validation errors | | `Unauthenticated` | 401 | Redirect to login | | `PermissionDenied` | 403 | Show "access denied" | | `Unavailable` | 503 | Show "service down" | | `Internal` | 500 | Show generic error | --- ## ۵. Proto Package Distribution ``` CMS/src/Protos/*.proto │ ▼ pack-protos.sh │ ▼ Foursat.CMSMicroservice.Protobuf.nupkg (v1.0.x) │ ▼ Push to BaGet (http://localhost:5555) or Nexus │ ▼ BackOffice: FrontOffice: ``` --- ## ۶. Remaining Tasks / Integration Gaps | آیتم | اولویت | وضعیت | |------|---------|--------| | Product Bundle API | Medium | ⬜ Proto + Handler needed | | Manual Payment API | Low | ⬜ Design only | | SignalR for Chatika | Low | ⬜ Replace polling | | File upload streaming | Done | ✅ | | Blog search | Done | ✅ | | Inventory autocomplete | Done | ✅ | | Lazy load pagination | Done | ✅ | | Rate limiting (API level) | Medium | ⬜ | | API versioning | Low | ⬜ |