421a651975
- All 14 totalDoc files updated with Magic Wallet additions - MAGIC-WALLET-PLAN.md: Phase 1-6 checklist fully marked complete - Business docs: Magic Wallet section, commission filter, new entities - Payment docs: VAT 9%→10%, TransactionType 14+15, ZarinPal 4th usage - Technical docs: UserWallet fields, ClubMembershipCycle, gRPC RPCs - Overview docs: Magic flowchart, ER diagram, changelog, glossary, roadmap
12 KiB
12 KiB
🔌 API، Protobuf و یکپارچهسازی خارجی
منابع ادغامشده:
FRONTOFFICE-CMS-API-COMPATIBILITY.md,REMAINING-TASKS.md,chatika-integration.md,payment-gateway.md,club-feature-management-services.md
آخرین بروزرسانی: اسفند ۱۴۰۴ (بروزرسانی: Magic Wallet gRPC RPCs)
۱. معماری ارتباطات
┌──────────────────────────────────────────────────────────────────┐
│ 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
۲.۱ لیست کامل سرویسها
// ===== 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);
}
// ===== userwallet.proto ===== (NEW — Magic Wallet)
service UserWalletService {
rpc GetCustomerWallet (GetCustomerWalletRequest) returns (GetCustomerWalletResponse);
rpc InitiateMagicCharge (InitiateMagicChargeRequest) returns (InitiateMagicChargeResponse);
rpc GetMagicWalletStatus (GetMagicWalletStatusRequest) returns (MagicWalletStatusResponse);
}
۲.۲ Shared Messages
// ===== 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 (پرداخت)
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)
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 (وام)
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<LoanResult> 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)
public class ChatikaService : IAiChatService
{
// Hangfire job — هر ۵ دقیقه
// Polly retry: 3 attempts
// Only for active club members
public async Task<string> GetResponseAsync(string userMessage)
{
var response = await _httpClient.PostAsync(
$"{_baseUrl}/api/chat",
new { Message = userMessage });
return response.Content.ReadAsStringAsync();
}
}
۴. API Compatibility Layer
۴.۱ FrontOffice Service Pattern
// هر سرویس در FrontOffice یک wrapper بر gRPC client است
public class ProductService : IProductService
{
private readonly ProductServiceClient _client;
public ProductService(ProductServiceClient client)
{
_client = client;
}
public async Task<ProductListResult> 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
flowchart TD
A["CMS/src/Protos/*.proto"] --> B["pack-protos.sh"]
B --> C["Foursat.CMSMicroservice.Protobuf.nupkg\nv1.0.x"]
C --> D["Push to BaGet / Nexus"]
D --> E["BackOffice\nPackageReference"]
D --> F["FrontOffice\nProjectReference ✅"]
⚠️ FrontOffice از NuGet package به ProjectReference مستقیم سوییچ شده (برای دسترسی به پروتوهای جدید Magic Wallet)
۶. 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 | ⬜ |