Files
docs/technical/TECH-05-API-INTEGRATION.md
T
masoodafar-web 3c729304db docs: fix all discrepancies based on comprehensive code audit
Corrections verified against actual CMS/BackOffice/FrontOffice source code:

- ClubActivationFee: 25,200,000 (not 25,000,000)
- Tree depth: no limit (15 is commission calculation depth only)
- IPG wallet charge: Balance=56M + Discount=56M
- DayaLoan wallet charge: Balance=56M + Discount=112M (2×)
- Discount: per-product MaxDiscountPercent (not fixed 30%)
- VAT: 10% (ShopVAT) vs 9% (discount store PlaceOrder)
- Kavenegar template: 'Afrino' only (not verify-foursat)
- SMS sender: 1000001110100
- DayaLoan job: every 20min (not 15min)
- Commission job: Sunday 00:05 (not Saturday)
- Network tree: on User entity (not separate NetworkNode table)
- UserWallets entity (not UserWalletBalances)
- OTP: 6 digits, 5 attempts, 2min TTL, 60s cooldown
- Removed non-existent constants (ClubJoiningPercentage, ClubActivationThreshold)
- Fixed Hangfire Chatika interval: every 5min
- Removed InventorySync from recurring jobs list
2026-02-18 22:58:40 +03:30

329 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🔌 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<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)
```csharp
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
```csharp
// هر سرویس در 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
```
CMS/src/Protos/*.proto
pack-protos.sh
Foursat.CMSMicroservice.Protobuf.nupkg (v1.0.x)
Push to BaGet (http://localhost:5555) or Nexus
BackOffice: <PackageReference Include="Foursat.CMSMicroservice.Protobuf" />
FrontOffice: <PackageReference Include="Foursat.CMSMicroservice.Protobuf" />
```
---
## ۶. 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 | ⬜ |