360 lines
16 KiB
Markdown
360 lines
16 KiB
Markdown
# 🏗️ BackOffice — مرجع معماری و الگوها
|
||
|
||
> **تاریخ:** ۱۴۰۴/۱۱/۲۴ (February 13, 2026)
|
||
> **پروژه:** BackOffice Admin Panel (Blazor WebAssembly)
|
||
|
||
---
|
||
|
||
## ۱. معماری کلی
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────┐
|
||
│ BackOffice │
|
||
│ (Blazor WebAssembly) │
|
||
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
|
||
│ │ MudBlazor│ │ Mapster │ │ DateTimeCvt │ │
|
||
│ │ v8 │ │ (mapping)│ │ (تاریخ شمسی) │ │
|
||
│ └──────────┘ └──────────┘ └──────────────┘ │
|
||
│ │ │ │ │
|
||
│ ┌─────────────────────────────────────────┐ │
|
||
│ │ Pages / Components / Shared │ │
|
||
│ │ BasePageComponent, Hub Pages, Dialogs │ │
|
||
│ └─────────────────────────────────────────┘ │
|
||
│ │ │
|
||
│ ┌──────────────┐ ┌──────────────────┐ │
|
||
│ │ gRPC Clients │ │ HTTP REST Services│ │
|
||
│ │ (Protobuf) │ │ (DiscountShop) │ │
|
||
│ └──────┬───────┘ └────────┬─────────┘ │
|
||
└─────────┼──────────────────────┼─────────────────┘
|
||
│ │
|
||
▼ ▼
|
||
┌──────────────────────────────────────────┐
|
||
│ CMS Microservice │
|
||
│ (ASP.NET Core + gRPC) │
|
||
│ Domain → Application (CQRS) → Infra │
|
||
└──────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## ۲. Technology Stack
|
||
|
||
| لایه | تکنولوژی | نسخه |
|
||
|------|----------|------|
|
||
| Frontend Framework | Blazor WebAssembly | .NET 9 |
|
||
| UI Library | MudBlazor | v8 |
|
||
| Backend Communication (عادی) | gRPC / Protobuf | — |
|
||
| Backend Communication (تخفیفی) | HTTP REST | — |
|
||
| Object Mapping | Mapster | — |
|
||
| تاریخ شمسی | DateTimeConverterCL | — |
|
||
| Client State | Blazored.LocalStorage | — |
|
||
| Auth | JWT Role-based | Administrator, Admin, Author |
|
||
| Permission | IAuthorizationService.HasPermissionAsync | 18 permission |
|
||
|
||
---
|
||
|
||
## ۳. ساختار پوشهها
|
||
|
||
```
|
||
BackOffice/src/BackOffice/
|
||
├── Common/
|
||
│ ├── BaseComponents/ ← کامپوننتهای پایه (BasePageComponent, DateRangePicker, Image)
|
||
│ ├── Utilities/ ← RouteConstance, Extensions, Helpers
|
||
│ └── ...
|
||
├── Pages/
|
||
│ ├── Category/ ← دستهبندی فروشگاه عادی
|
||
│ ├── Products/ ← محصولات فروشگاه عادی
|
||
│ ├── UserOrder/ ← سفارشات + گزارش فروش (Hub)
|
||
│ ├── DiscountShop/ ← فروشگاه تخفیفی (محصولات + دستهبندی + سفارشات)
|
||
│ │ └── Components/ ← دیالوگها و کامپوننتهای اختصاصی
|
||
│ ├── Inventory/ ← انبارداری (4 صفحه)
|
||
│ ├── Package/ ← پکیجها
|
||
│ ├── Commission/ ← کمیسیون (5 صفحه)
|
||
│ ├── Network/ ← شبکه (4 صفحه)
|
||
│ ├── Club/ ← باشگاه مشتریان (Hub: اعضا + آمار + فیچرها)
|
||
│ ├── Blog/ ← بلاگ (Hub: پست + دستهبندی + تگ)
|
||
│ ├── Content/ ← صفحات سایت
|
||
│ ├── Wallet/ ← کیفپول (تبها: لیست + تاریخچه)
|
||
│ ├── Contract/ ← قراردادها
|
||
│ ├── SystemManagement/ ← سیستم (Hub: تنظیمات + Worker + Health)
|
||
│ └── ...
|
||
├── Services/
|
||
│ ├── DiscountProduct/ ← IDiscountProductService + implementation
|
||
│ ├── DiscountCategory/ ← IDiscountCategoryService + implementation
|
||
│ ├── DiscountOrder/ ← IDiscountOrderService + implementation
|
||
│ └── Authorization/ ← IAuthorizationService
|
||
├── Shared/
|
||
│ ├── MainLayout.razor ← لایوت اصلی (AppBar + NavMenu + MudContainer)
|
||
│ ├── NavMenu.razor ← منوی ناوبری
|
||
│ ├── GlobalSearch.razor ← جستجوی سراسری
|
||
│ └── AppBreadcrumb.razor ← Breadcrumb فارسی
|
||
└── wwwroot/
|
||
├── js/main.js ← jsSaveAsFile (Excel export)
|
||
└── appsettings.json ← تنظیمات endpoints
|
||
```
|
||
|
||
---
|
||
|
||
## ۴. الگوهای اصلی
|
||
|
||
### ۴.۱ BasePageComponent — پترن صفحات لیست
|
||
|
||
**هر صفحه لیست** از `BasePageComponent` استفاده میکند:
|
||
|
||
```
|
||
┌──────────────────────────────────────┐
|
||
│ BasePageComponent │
|
||
│ ┌────────────────────────────────┐ │
|
||
│ │ 📋 Filter Panel (collapsible) │ │
|
||
│ │ [فیلد ۱] [فیلد ۲] [فیلد ۳] │ │
|
||
│ │ [پاک کردن فیلتر] [جستجو] │ │
|
||
│ └────────────────────────────────┘ │
|
||
│ ┌────────────────────────────────┐ │
|
||
│ │ 📊 Content (DataGrid) │ │
|
||
│ │ ToolBar: [عنوان] [Excel] [+] │ │
|
||
│ │ Columns: ... │ │
|
||
│ │ Pager: 20/50/100 │ │
|
||
│ └────────────────────────────────┘ │
|
||
└──────────────────────────────────────┘
|
||
```
|
||
|
||
**فایل:** `Common/BaseComponents/BasePageComponent.razor`
|
||
|
||
**پراپرتیها:**
|
||
- `RenderFragment Filters` — محتوای فیلتر
|
||
- `RenderFragment Content` — محتوای اصلی
|
||
- `EventCallback OnSubmitClick` — کلیک جستجو
|
||
- `EventCallback OnClearFilterClick` — کلیک پاک کردن
|
||
- `bool IsFiltered` — آیا فیلتر فعال است (نشاندهنده badge «فعال»)
|
||
|
||
---
|
||
|
||
### ۴.۲ Hub Pages — پترن ادغام صفحات
|
||
|
||
صفحات مرتبط در یک Hub با `MudTabs` ادغام میشوند:
|
||
|
||
| Hub | Routeها | تبها |
|
||
|-----|---------|-------|
|
||
| `OrdersHub` | `/OrdersPage/`, `/OrdersSalesReportsPage/` | سفارشات + گزارش فروش |
|
||
| `DiscountShopHub` | `/discount-shop`, `/discount-orders`, `/discount-sales-reports` | سفارشات + گزارش فروش |
|
||
| `ClubHub` | `/club`, `/club/members`, `/club/statistics` | اعضا + آمار |
|
||
| `BlogHub` | `/blog`, `/blog/posts`, `/blog/categories`, `/tags` | پست + دستهبندی + تگ |
|
||
| `SystemHub` | `/system`, `/system/configuration`, `/system/worker-control`, `/system/health` | تنظیمات + Worker + Health |
|
||
|
||
---
|
||
|
||
### ۴.۳ Code-Behind — پترن جداسازی markup/logic
|
||
|
||
```
|
||
MyPage.razor → فقط HTML/Razor markup
|
||
MyPage.razor.cs → partial class + [Inject] + methods
|
||
```
|
||
|
||
**قوانین:**
|
||
1. فایلهایی که سرویس inject دارند **باید** code-behind داشته باشند (محدودیت Razor source generator)
|
||
2. سرویسهای global (`_Imports.razor`) **نباید** دوباره `[Inject]` شوند
|
||
3. `namespace` باید با مسیر فایل match کند
|
||
|
||
**سرویسهای Global (از `_Imports.razor`):**
|
||
|
||
| سرویس | نام متغیر | توضیح |
|
||
|--------|-----------|-------|
|
||
| `IDialogService` | `DialogService` | دیالوگ MudBlazor |
|
||
| `ISnackbar` | `Snackbar` | نوتیفیکیشن MudBlazor |
|
||
| `IJSRuntime` | `jsRuntime` | ⚠️ حرف کوچک `j` |
|
||
| `NavigationManager` | `Navigation` | ناوبری |
|
||
| `ILocalStorageService` | `LocalStorageService` | ذخیره محلی |
|
||
| `AuthenticationStateProvider` | `AuthenticationStateProvider` | احراز هویت |
|
||
|
||
---
|
||
|
||
### ۴.۴ Excel Export — پترن خروجی CSV
|
||
|
||
```csharp
|
||
private async Task ExportToExcel()
|
||
{
|
||
var sb = new StringBuilder();
|
||
sb.AppendLine("ستون ۱,ستون ۲,ستون ۳"); // هدر فارسی
|
||
foreach (var item in items)
|
||
{
|
||
sb.AppendLine($"{EscapeCsv(item.Col1)},{item.Col2},{item.Col3}");
|
||
}
|
||
var bytes = Encoding.UTF8.GetPreamble() // UTF-8 BOM
|
||
.Concat(Encoding.UTF8.GetBytes(sb.ToString())).ToArray();
|
||
var base64 = Convert.ToBase64String(bytes);
|
||
await jsRuntime.InvokeVoidAsync("jsSaveAsFile", "filename.csv", base64);
|
||
}
|
||
|
||
private string EscapeCsv(string? value)
|
||
{
|
||
if (string.IsNullOrEmpty(value)) return "";
|
||
if (value.Contains(',') || value.Contains('"') || value.Contains('\n'))
|
||
return $"\"{value.Replace("\"", "\"\"")}\"";
|
||
return value;
|
||
}
|
||
```
|
||
|
||
**صفحات دارای Excel:** Products, UserOrders, ClubMembers, WithdrawalRequests, WeeklyReports, StockMovements, Users, DiscountOrders, ManualPayments, Inventory, DiscountProducts
|
||
|
||
---
|
||
|
||
### ۴.۵ Server-Side DataGrid — پترن بارگذاری صفحهای
|
||
|
||
```razor
|
||
<MudDataGrid T="MyDto"
|
||
ServerData="LoadServerData"
|
||
Height="calc(100vh - 240px)"
|
||
FixedHeader="true"
|
||
Hover="true" Dense="true">
|
||
```
|
||
|
||
```csharp
|
||
private async Task<GridData<MyDto>> LoadServerData(GridState<MyDto> state)
|
||
{
|
||
var filter = new MyFilter
|
||
{
|
||
PageNumber = state.Page + 1, // MudDataGrid is 0-based
|
||
PageSize = state.PageSize
|
||
};
|
||
var (items, totalCount, _) = await MyService.GetAsync(filter);
|
||
return new GridData<MyDto> { Items = items, TotalItems = totalCount };
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### ۴.۶ Permission System
|
||
|
||
NavMenu از `IAuthorizationService.HasPermissionAsync()` برای نمایش/مخفی کردن آیتمها استفاده میکند:
|
||
|
||
| Permission | صفحه(ها) |
|
||
|-----------|----------|
|
||
| `dashboard.view` | داشبورد |
|
||
| `packages.manage` | پکیجها |
|
||
| `products.manage` | محصولات + دستهبندی + ویرایش دستهجمعی |
|
||
| `orders.view` | سفارشات |
|
||
| `inventory.manage` | انبارداری (4 صفحه) |
|
||
| `discountshop.manage` | فروشگاه تخفیفی |
|
||
| `users.view` | کاربران |
|
||
| `roles.manage` | نقشها |
|
||
| `manualpayments.create` | پرداخت دستی |
|
||
| `blog.manage` | بلاگ |
|
||
| `sitepages.manage` | صفحات سایت |
|
||
| `publicmessages.view` | پیامهای عمومی |
|
||
| `settings.manage_configuration` | تنظیمات سیستم |
|
||
|
||
---
|
||
|
||
## ۵. مسیرهای (Routing)
|
||
|
||
### مسیرهای ثابت (`RouteConstance.cs`)
|
||
```
|
||
/ → Dashboard
|
||
/PackagePage/ → Packages
|
||
/ProductsPage/ → Products
|
||
/CategoryPage/ → Categories
|
||
/OrdersPage/ → Orders Hub
|
||
/OrdersSalesReportsPage/ → Orders Sales Reports
|
||
/InventoryPage/ → Inventory
|
||
/InventoryLowStockPage/ → Low Stock
|
||
/InventoryWarehousesPage/ → Warehouses
|
||
/InventoryMovementsPage/ → Stock Movements
|
||
/UserPage/ → Users
|
||
/RolePage/ → Roles
|
||
/ProductsBulkEditPage/ → Bulk Edit
|
||
/ProductCategoriesPage/ → Product-Category DragDrop
|
||
/CategoryProductsPage/ → Category-Product DragDrop
|
||
```
|
||
|
||
### مسیرهای hardcode (فروشگاه تخفیفی + سایر)
|
||
```
|
||
/discount-products → Discount Products
|
||
/discount-categories → Discount Categories
|
||
/discount-shop → Discount Orders Hub
|
||
/discount-orders → Discount Orders
|
||
/discount-sales-reports → Discount Sales Reports
|
||
/commission/* → Commission pages
|
||
/network/* → Network pages
|
||
/club/* → Club pages
|
||
/blog/* → Blog pages
|
||
/wallets → Wallets
|
||
/contracts → Contracts
|
||
/payment/manual-payments → Manual Payments
|
||
/system/* → System pages
|
||
/settings → Settings
|
||
/content/pages → Content Pages
|
||
/public-messages → Public Messages
|
||
```
|
||
|
||
---
|
||
|
||
## ۶. ارتباط فروشگاه عادی vs تخفیفی
|
||
|
||
| جنبه | فروشگاه عادی | فروشگاه تخفیفی |
|
||
|------|-------------|---------------|
|
||
| **سرویس محصولات** | gRPC `ProductsContractClient` | HTTP `IDiscountProductService` |
|
||
| **سرویس دستهبندی** | gRPC `CategoryContractClient` | HTTP `IDiscountCategoryService` |
|
||
| **سرویس سفارشات** | gRPC `UserOrderContractClient` | HTTP `IDiscountOrderService` |
|
||
| **Entity بکند** | `Product` | `DiscountProduct` |
|
||
| **پرداخت** | فقط درگاه | ترکیبی (کیف تخفیفی + درگاه) |
|
||
| **فیلد اختصاصی** | — | `MaxDiscountPercent` |
|
||
| **UI Pattern** | BasePageComponent | BasePageComponent (یکسان) |
|
||
| **ستونها** | یکسان | یکسان + ستون تخفیف |
|
||
|
||
---
|
||
|
||
## ۷. نقشه NavMenu
|
||
|
||
```
|
||
داشبورد
|
||
─────────────────────
|
||
کمیسیون و شبکه
|
||
├── کمیسیون (NavGroup)
|
||
│ ├── داشبورد کمیسیون
|
||
│ ├── گزارشهای هفتگی
|
||
│ ├── پرداخت کاربران
|
||
│ ├── درخواستهای برداشت [Badge]
|
||
│ └── گزارش برداشتها
|
||
├── شبکه (NavGroup)
|
||
│ ├── درخت شبکه
|
||
│ ├── گزارش موجودیها
|
||
│ └── آمار شبکه
|
||
└── باشگاه مشتریان (NavGroup)
|
||
├── اعضا و آمار
|
||
└── فیچرهای باشگاه
|
||
─────────────────────
|
||
فروشگاه [AuthorizeView: Administrator]
|
||
├── پکیجها
|
||
├── فروشگاه عادی (NavGroup)
|
||
│ ├── محصولات
|
||
│ ├── دستهبندیها
|
||
│ └── سفارشات و گزارش
|
||
├── انبارداری (NavGroup)
|
||
│ ├── موجودی انبار
|
||
│ ├── محصولات کمموجود
|
||
│ ├── مدیریت انبارها
|
||
│ └── تاریخچه تغییرات
|
||
└── فروشگاه تخفیفی (NavGroup)
|
||
├── محصولات
|
||
├── دستهبندیها
|
||
└── سفارشات و گزارش
|
||
─────────────────────
|
||
مدیریت [AuthorizeView: Administrator]
|
||
├── کاربران
|
||
├── نقشها
|
||
├── پرداخت دستی
|
||
├── کیفپول
|
||
└── قراردادها
|
||
─────────────────────
|
||
مدیریت محتوا
|
||
├── بلاگ
|
||
├── صفحات سایت
|
||
└── پیامهای عمومی
|
||
─────────────────────
|
||
سیستم [AuthorizeView: Administrator]
|
||
├── مدیریت سیستم
|
||
└── نسخه اپلیکیشنها
|
||
─────────────────────
|
||
تنظیمات
|
||
```
|