# 🏗️ 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 ``` ```csharp private async Task> LoadServerData(GridState 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 { 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] ├── مدیریت سیستم └── نسخه اپلیکیشن‌ها ───────────────────── تنظیمات ```