Files
docs/technical/TECH-01-CMS-ARCHITECTURE.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

262 lines
9.0 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.
# ⚙️ معماری 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 }
}
```