3c729304db
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
262 lines
9.0 KiB
Markdown
262 lines
9.0 KiB
Markdown
# ⚙️ معماری CMS و زیرساخت فنی
|
||
|
||
> **منابع ادغامشده:** `CMS-README.md`, `ICURRENTUSERSERVICE-IMPLEMENTATION.md`, `FILE-MANAGEMENT-ARCHITECTURE.md`, `FRONTOFFICE-CMS-API-COMPATIBILITY.md`, `BFF-REMOVAL-PLAN.md`, `system-constants.md`
|
||
> **آخرین بروزرسانی:** اسفند ۱۴۰۴
|
||
|
||
---
|
||
|
||
## ۱. Stack فنی
|
||
|
||
| لایه | تکنولوژی | نسخه |
|
||
|------|----------|------|
|
||
| **Runtime** | .NET | 9.0 |
|
||
| **ORM** | Entity Framework Core | 9.0 |
|
||
| **Communication** | gRPC (Protobuf) | v3 |
|
||
| **Pattern** | CQRS + MediatR | — |
|
||
| **Database** | SQL Server (MSSQL) | 2022-CU16 |
|
||
| **Job Scheduler** | Hangfire | — |
|
||
| **Auth** | JWT Bearer + Identity | — |
|
||
| **API Gateway** | حذفشده (Direct gRPC) | — |
|
||
|
||
---
|
||
|
||
## ۲. معماری لایهای CMS
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────┐
|
||
│ Presentation Layer │
|
||
│ FrontOffice (Blazor Server) ←─gRPC─→ CMS │
|
||
│ BackOffice (Blazor WASM) ←─gRPC─→ CMS │
|
||
├──────────────────────────────────────────────────────┤
|
||
│ Application Layer │
|
||
│ Commands (MediatR IRequest<T>) │
|
||
│ Queries (MediatR IRequest<T>) │
|
||
│ Validators (FluentValidation) │
|
||
│ Handlers (IRequestHandler<TReq, TRes>) │
|
||
├──────────────────────────────────────────────────────┤
|
||
│ Domain Layer │
|
||
│ Entities, Enums, Value Objects │
|
||
│ Domain Events, Interfaces │
|
||
├──────────────────────────────────────────────────────┤
|
||
│ Infrastructure Layer │
|
||
│ EF Core DbContext (CMSDbContext) │
|
||
│ Repositories, External Services │
|
||
│ Hangfire Jobs, File Storage │
|
||
├──────────────────────────────────────────────────────┤
|
||
│ Database │
|
||
│ SQL Server — Schema: [CMS] │
|
||
└──────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## ۳. CQRS با MediatR
|
||
|
||
### ۳.۱ ساختار فولدرها
|
||
|
||
```
|
||
CMS/src/
|
||
├── CMSMicroservice/
|
||
│ ├── Features/
|
||
│ │ ├── Products/
|
||
│ │ │ ├── Commands/
|
||
│ │ │ │ ├── CreateProductCommand.cs
|
||
│ │ │ │ └── CreateProductCommandHandler.cs
|
||
│ │ │ ├── Queries/
|
||
│ │ │ │ ├── GetProductsQuery.cs
|
||
│ │ │ │ └── GetProductsQueryHandler.cs
|
||
│ │ │ └── Validators/
|
||
│ │ │ └── CreateProductCommandValidator.cs
|
||
│ │ ├── Orders/
|
||
│ │ ├── Users/
|
||
│ │ ├── Club/
|
||
│ │ ├── Payment/
|
||
│ │ └── Blog/
|
||
│ ├── Services/
|
||
│ │ ├── gRPC/ ← gRPC service implementations
|
||
│ │ ├── Background/ ← Hangfire jobs
|
||
│ │ └── External/ ← ZarinPal, Kavenegar, Daya, Chatika
|
||
│ ├── Infrastructure/
|
||
│ │ ├── Persistence/ ← DbContext, Migrations
|
||
│ │ └── Identity/ ← JWT, Claims, ICurrentUserService
|
||
│ └── Protos/ ← .proto files
|
||
```
|
||
|
||
### ۳.۲ مثال Command
|
||
|
||
```csharp
|
||
// Command
|
||
public record CreateProductCommand(
|
||
string Name, string Description, decimal Price,
|
||
Guid CategoryId, string ImageUrl
|
||
) : IRequest<Guid>;
|
||
|
||
// Handler
|
||
public class CreateProductCommandHandler
|
||
: IRequestHandler<CreateProductCommand, Guid>
|
||
{
|
||
private readonly CMSDbContext _db;
|
||
|
||
public async Task<Guid> Handle(
|
||
CreateProductCommand request, CancellationToken ct)
|
||
{
|
||
var product = new Product { /* map fields */ };
|
||
_db.Products.Add(product);
|
||
|
||
// Auto-create inventory record
|
||
_db.Inventories.Add(new Inventory { ProductId = product.Id });
|
||
|
||
await _db.SaveChangesAsync(ct);
|
||
return product.Id;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## ۴. gRPC Services
|
||
|
||
### ۴.۱ لیست سرویسها
|
||
|
||
| سرویس | proto | متدهای اصلی |
|
||
|--------|-------|-------------|
|
||
| `ProductService` | product.proto | GetProducts, GetProduct, Create, Update, Delete |
|
||
| `OrderService` | order.proto | CreateOrder, GetOrders, UpdateStatus |
|
||
| `UserService` | user.proto | Register, Login, GetProfile, UpdateProfile |
|
||
| `ClubService` | club.proto | GetNetworkTree, GetBalance, AcceptContract |
|
||
| `PaymentService` | payment.proto | CreatePayment, VerifyPayment |
|
||
| `BlogService` | blog.proto | GetPosts, GetPost, Create, Update |
|
||
| `InventoryService` | inventory.proto | GetInventory, UpdateStock |
|
||
| `FileService` | file.proto | Upload, Download, Delete |
|
||
| `SitePageService` | sitepage.proto | GetPage, SaveSettings |
|
||
| `CategoryService` | category.proto | GetCategories, Create, Update |
|
||
| `SystemConfigService` | config.proto | GetConfig, UpdateConfig |
|
||
|
||
### ۴.۲ PaginationState (مشترک)
|
||
|
||
```protobuf
|
||
message PaginationState {
|
||
int32 skip = 1;
|
||
int32 take = 2;
|
||
}
|
||
```
|
||
|
||
**Namespace صحیح:**
|
||
```csharp
|
||
using CMSMicroservice.Protobuf.Protos.PaginationState;
|
||
// ⚠️ نه: CMSMicroservice.Protobuf.Protos.PublicMessages.PaginationState
|
||
```
|
||
|
||
---
|
||
|
||
## ۵. Database
|
||
|
||
### ۵.۱ اتصال
|
||
|
||
```
|
||
Staging: Server=194.5.195.53; Database=FourSatCMS; Schema=CMS
|
||
Production: Server=45.149.79.127; Database=FourSatCMS; Schema=CMS
|
||
Engine: MSSQL 2022-CU16, Collation=Arabic_CI_AS
|
||
```
|
||
|
||
### ۵.۲ جداول اصلی
|
||
|
||
| جدول | توضیح | رکوردهای تقریبی |
|
||
|------|--------|----------------|
|
||
| Users | کاربران + فیلدهای شبکه (NetworkParentId, LegPosition) | ~5K |
|
||
| Products | محصولات (+ MaxDiscountPercent) | ~200 |
|
||
| Categories | دستهبندیها | ~30 |
|
||
| Orders | سفارشات | ~2K |
|
||
| Inventories | موجودی | ~200 |
|
||
| BlogPosts | پستهای بلاگ | ~50 |
|
||
| SitePages | صفحات سایت | ~10 |
|
||
| UserClubMemberships | عضویت باشگاه | ~500 |
|
||
| UserContracts | قراردادها (SignGuid, SignedPdfFile) | ~500 |
|
||
| UserWallets | کیفپول (Balance, NetworkBalance, DiscountBalance) | ~5K |
|
||
| Transactions | تراکنشها | ~5K |
|
||
| SystemConfigurations | تنظیمات | ~30 |
|
||
| ChatMessages | پیامهای چاتیکا | ~1K |
|
||
|
||
### ۵.۳ Stored Procedures
|
||
|
||
| SP | کاربرد |
|
||
|----|--------|
|
||
| `SP_GetNetworkTree` | بازگشتی — استخراج درخت باینری |
|
||
| `sp_CalculateWeeklyBalances` | محاسبه بالانس هفتگی هر عضو |
|
||
| `sp_CalculateWeeklyCommissionPool` | توزیع Pool هفتگی |
|
||
|
||
---
|
||
|
||
## ۶. حذف BFF / Gateway
|
||
|
||
### ۶.۱ قبل vs بعد
|
||
|
||
```
|
||
قبل:
|
||
FrontOffice → BFF (REST) → CMS (gRPC)
|
||
BackOffice → BFF (REST) → CMS (gRPC)
|
||
|
||
بعد (فعلی):
|
||
FrontOffice → CMS (gRPC مستقیم)
|
||
BackOffice → CMS (gRPC مستقیم)
|
||
|
||
مزایا:
|
||
✅ حذف لایه واسط → کاهش latency
|
||
✅ حذف maintenance اضافی
|
||
✅ Type-safe از proto تا UI
|
||
✅ کاهش ۱ سرویس در deployment
|
||
```
|
||
|
||
### ۶.۲ سازگاری API
|
||
|
||
```
|
||
FrontOffice Service Layer:
|
||
• ProductService.cs → gRPC client wrapper
|
||
• OrderService.cs → gRPC client wrapper
|
||
• UserService.cs → gRPC client wrapper
|
||
|
||
هر Service:
|
||
• Constructor: inject GrpcChannel
|
||
• Methods: wrap gRPC calls + map to DTOs
|
||
• Error handling: try/catch RpcException
|
||
```
|
||
|
||
---
|
||
|
||
## ۷. Hangfire Jobs
|
||
|
||
| Job | فرکانس (cron) | کاربرد |
|
||
|-----|---------|--------|
|
||
| `WeeklyCommissionCalculation` | `5 0 * * 0` (یکشنبه ۰۰:۰۵) | محاسبه و توزیع کمیسیون |
|
||
| `DayaLoanProcessorJob` | `*/20 * * * *` (هر ۲۰ دقیقه) | پردازش درخواستهای وام |
|
||
| `ChatikaAccountActivation` | `*/5 * * * *` (هر ۵ دقیقه) | فعالسازی حساب چاتیکا |
|
||
|
||
---
|
||
|
||
## ۸. پیکربندی
|
||
|
||
### ۸.۱ appsettings.json ساختار
|
||
|
||
```json
|
||
{
|
||
"ConnectionStrings": {
|
||
"DefaultConnection": "Server=...;Database=FourSatCMS"
|
||
},
|
||
"Jwt": {
|
||
"Secret": "***",
|
||
"Issuer": "FourSat",
|
||
"ExpiryMinutes": 1440
|
||
},
|
||
"Grpc": {
|
||
"CmsUrl": "https://localhost:5001"
|
||
},
|
||
"Hangfire": {
|
||
"DashboardPath": "/hangfire",
|
||
"WorkerCount": 4
|
||
},
|
||
"Kavenegar": { "ApiKey": "***" },
|
||
"ZarinPal": { "MerchantId": "***" },
|
||
"DayaLoan": { "UseMock": true }
|
||
}
|
||
```
|