Files
BackOffice/docs/BACKOFFICE-CHANGELOG.md
T

43 KiB
Raw Blame History

📝 BackOffice — Changelog

آخرین بروزرسانی: اسفند ۱۴۰۴ (February 17, 2026)


🏷 فاز ۱۵ — Production Deploy + فیکس CI/CD Cross-Deploy (اسفند ۱۴۰۴)

هدف: دیپلوی به سرور Production و رفع باگ cross-deploy

۱۵.۱ — Merge به برنچ production

  • کامیت: 4454b8d — merge kub-stageproduction
  • ریموت: kub-stage (Gitea)

۱۵.۲ — فیکس باگ Cross-Deploy

  • مشکل: Gitea Act Runner همه workflowهای .gitea/workflows/ را اجرا می‌کرد — بدون توجه به branches: filter
  • عارضه: push به production باعث دیپلوی همزمان به staging و production می‌شد
  • رفع: حذف فایل‌های workflow staging از برنچ production
  • فایل حذف شده: .gitea/workflows/deploy.yml (staging) از برنچ production

۱۵.۳ — بروزرسانی Proto به v0.0.179

  • تغییر: Foursat.CMSMicroservice.Protobuf0.0.179
  • فایل: BackOffice.csproj

🏷 فاز ۱۴ — فیکس Docker Build + Deployment (بهمن ۱۴۰۴)

هدف: رفع مشکلات Docker build و CI/CD pipeline

۱۴.۱ — تغییر به NuGet Package

  • مشکل: ProjectReference به ../../../CMS/src/CMSMicroservice.Protobuf/ خارج از Docker build context بود
  • رفع: تغییر به PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.178"
  • فایل: BackOffice.csproj

۱۴.۲ — حذف COPY libs/ از Dockerfile

  • مشکل: COPY ["libs/", "libs/"] فیل می‌شد — libs/ خارج از build context
  • رفع: حذف خط — دیگه نیازی به DLLهای BFF نیست
  • فایل: Dockerfile

۱۴.۳ — تغییر nginx:alpine به رجیستری لوکال

  • مشکل: FROM nginx:alpine از Docker Hub → TLS handshake timeout
  • رفع: FROM 194.5.195.53:32082/nginx:alpine
  • فایل: Dockerfile

۱۴.۴ — اضافه شدن SERVER_PASSWORD secret

  • مشکل: مرحله Deploy to Kubernetes با Permission denied فیل می‌شد
  • رفع: سکرت SERVER_PASSWORD به ریپو Gitea اضافه شد (BackOffice + FrontOffice)

🏷 فاز ۱۳ — بهبودهای UI بک‌آفیس (بهمن ۱۴۰۴)

هدف: رفع مشکلات بصری، بهبود UX فرم‌ها و ناوبری

۱۳.۱ — فیکس کامپوننت Image (پیشوند /uploads/)

  • مشکل: تصاویر آپلود‌شده (بلاگ، صفحات سایت، سکشن‌ها) در بک‌آفیس نمایش داده نمی‌شدند — مسیر GwUrl + Src با مسیر UploadsController هماهنگ نبود
  • رفع: اضافه شدن /uploads/ بین FileBaseUrl و مسیر نسبی تصویر
  • فایل: BackOffice/Common/BaseComponents/Image.razor.cs

۱۳.۲ — فیکس فیلتر هفته در گزارش‌های هفتگی

  • مشکل: فیلتر هفته از MudTextField (ورودی متنی) استفاده می‌کرد — کاربر باید عدد حدس می‌زد
  • رفع: جایگزینی با WeekNumberPicker — انتخاب هفته از لیست با بایندینگ WeekDefinitionId
  • فایل‌ها:
    • CMS/src/CMSMicroservice.Protobuf/Protos/commission.proto — تغییر فیلدها از StringValue به Int64Value
    • CMS/.../CommissionCQ/Queries/GetAllWeeklyPools/GetAllWeeklyPoolsQuery.cs + Handler.cs
    • BackOffice/Pages/Commission/WeeklyReports.razor

۱۳.۳ — فیکس دانلود PDF قراردادها

  • مشکل: فیلد SignedPdfFile محتوای HTML کامل دارد (نه URL فایل PDF) — دکمه دانلود کار نمی‌کرد
  • رفع: تابع JS جدید jsHtmlToPdf() برای باز کردن HTML در پنجره جدید و چاپ/ذخیره به‌عنوان PDF
  • فایل‌ها:
    • BackOffice/wwwroot/js/main.js — تابع jsHtmlToPdf
    • BackOffice/Pages/Contract/UserContractPage.razor
    • BackOffice/Pages/Contract/ContractDetailsDialog.razor

۱۳.۴ — یکسان‌سازی ارتفاع ویرایشگر HTML

  • مشکل: ارتفاع MudHtmlEditor در صفحات مختلف متفاوت بود — برخی خیلی کوتاه
  • رفع: اضافه شدن MinHeight="300px" به تمام ۷ ویرایشگر HTML
  • فایل‌ها: BlogPostEditDialog, SitePageSectionEditDialog, DiscountShop/ProductFormDialog, Package/CreateDialog, Package/UpdateDialog, Products/CreateDialog, Products/UpdateDialog

۱۳.۵ — تولید خودکار اسلاگ بلاگ

  • مشکل: کاربر باید اسلاگ URL را دستی وارد می‌کرد — غیرضروری و مستعد خطا
  • رفع: حذف فیلد اسلاگ از فرم، تولید خودکار post-{GUID} در بک‌اند (حداکثر ۲۰ کاراکتر)
  • فایل‌ها:
    • CMS/.../BlogPostCQ/Commands/CreateBlogPost/CreateBlogPostCommandHandler.cs
    • CMS/.../BlogPostCQ/Commands/UpdateBlogPost/UpdateBlogPostCommandHandler.cs
    • BackOffice/Pages/Blog/Components/BlogPostEditDialog.razor

۱۳.۶ — انتقال تگ‌ها به منوی جداگانه

  • مشکل: تگ‌ها فقط از تب سوم بلاگ قابل دسترسی بودند — ولی تگ‌ها بین محصولات و بلاگ مشترکند
  • رفع: اضافه شدن مسیر /tags به TagManagementPage، لینک جدید «مدیریت تگ‌ها» در منوی ناوبری، حذف تب تگ‌ها از BlogHub
  • فایل‌ها:
    • BackOffice/Pages/Tag/TagManagementPage.razor
    • BackOffice/Shared/NavMenu.razor
    • BackOffice/Pages/Blog/BlogHub.razor

۱۳.۷ — تولید خودکار کلید سکشن

  • مشکل: کاربر باید کلید سکشن صفحه سایت را دستی وارد می‌کرد (مثلاً about-us-section)
  • رفع: فیلد اختیاری شد، تولید خودکار section-{GUID} (حداکثر ۲۰ کاراکتر) در هندلر CMS
  • فایل‌ها:
    • CMS/.../SitePageCQ/Commands/CreateSitePageSection/CreateSitePageSectionCommandHandler.cs
    • CMS/.../SitePageCQ/Commands/CreateSitePageSection/CreateSitePageSectionCommandValidator.cs
    • BackOffice/Pages/Content/Components/SitePageSectionEditDialog.razor

🏷 فاز ۱۲ — فیکس فلوی ثبت‌نام / ورود FrontOffice (بهمن ۱۴۰۴)

هدف: رفع ۳ باگ بحرانی در فلوی ثبت‌نام و ورود FrontOffice مستند کامل: totalDoc/cms/REGISTRATION-FLOW-FIXES.md

۱۲.۱ — رفع ایجاد کاربر جدید در VerifyOtpToken 🔴

  • مشکل: UserCQ/VerifyOtpTokenCommandHandler کاربران جدید ایجاد نمی‌کرد — فقط خطای «کاربر یافت نشد»
  • رفع: اضافه شدن لاجیک کامل: اعتبارسنجی کد معرف، بررسی ظرفیت درخت باینری (حداکثر ۲ فرزند)، تعیین شاخه (چپ/راست)، ایجاد User + UserRole + UserWallet، رویدادهای دامنه
  • فایل: CMS/src/CMSMicroservice.Application/UserCQ/Commands/VerifyOtpToken/VerifyOtpTokenCommandHandler.cs

۱۲.۲ — رفع جستجوی موبایل در AcceptContract 🔴

  • مشکل: _currentUserService.Username = "{FirstName} {LastName}" — نه شماره موبایل! در نتیجه OTP و کاربر هیچوقت پیدا نمی‌شد
  • رفع: ابتدا کاربر از UserId پیدا شود، سپس user.Mobile برای جستجوی OTP استفاده شود
  • فایل: CMS/src/CMSMicroservice.Application/UserCQ/Commands/AcceptContract/AcceptContractCommandHandler.cs

۱۲.۳ — رفع IsCompleteRegister() در FrontOffice 🟡

  • مشکل: InitUserAuthInfo().GetAwaiter() بدون .GetResult() — عملیات async اجرا نمی‌شود، منوی کناری وضعیت نادرست
  • رفع: تغییر به InitUserAuthInfo().GetAwaiter().GetResult()
  • فایل: FrontOffice/src/FrontOffice.Main/Utilities/AuthService.cs

🏷 فاز ۱۱ — رفع خطای صفحات + سرویس عمومی تصاویر (بهمن ۱۴۰۴)

هدف: رفع خطای ۳ صفحه BackOffice + ایجاد اندپوینت HTTP عمومی برای سرو تصاویر

۱۱.۱ — سرویس عمومی سرو تصاویر (CMS)

  • UploadsController — اندپوینت GET /uploads/{path} برای سرو مستقیم فایل‌ها
  • [AllowAnonymous] — بدون نیاز به احراز هویت
  • کش مرورگر ۲۴ ساعته (ResponseCache)
  • پشتیبانی از Range Requests
  • FMS Fallback: اگر فایل محلی نباشد، از dl.afrino.co دانلود و کش می‌شود
  • IHttpClientFactory با named client "FMS" (timeout: 30s)
  • فایل‌ها: CMS/WebApi/Controllers/UploadsController.cs, CMS/WebApi/Program.cs

۱۱.۲ — رفع صفحه «صفحات سایت»

  • اضافه شدن دکمه «افزودن صفحه جدید» به بالای صفحه
  • اضافه شدن دکمه «حذف» (آیکون قرمز) برای هر ردیف
  • ایجاد SitePageCreateDialog — دیالوگ ایجاد صفحه جدید با فیلدها:
    • کلید صفحه (PageKey)، عنوان، توضیحات متا، عنوان هیرو، زیرعنوان هیرو، تصویر هیرو، وضعیت
  • Proto: اضافه شدن CreateSitePage و DeleteSitePage RPC
  • CQRS: CreateSitePageCommand/Handler و DeleteSitePageCommand/Handler
  • فایل‌ها:
    • sitepage.proto — 2 RPC جدید + پیام‌های Request/Response
    • SitePageCQ/Commands/CreateSitePage/ — Command + Handler
    • SitePageCQ/Commands/DeleteSitePage/ — Command + Handler
    • CMS/WebApi/Services/SitePageService.cs — 2 override جدید
    • BackOffice/Services/Content/ISitePageService.csCreateAsync + DeleteAsync + SitePageCreateDto
    • BackOffice/Services/Content/SitePageService.cs — پیاده‌سازی Create/Delete
    • BackOffice/Pages/Content/SitePageManagementPage.razor — دکمه‌های Add/Delete
    • BackOffice/Pages/Content/SitePageManagementPage.razor.cs — متدهای CreatePage/DeletePage
    • BackOffice/Pages/Content/Components/SitePageCreateDialog.razor + .razor.cs

۱۱.۳ — رفع صفحه «قراردادها» (Contracts)

  • مشکل: صفحه /contracts اصلاً بارگذاری نمی‌شد — crash در DI
  • علت: UserContractContract.UserContractContractClient در DI ثبت نشده بود
  • رفع: اضافه شدن using CMSMicroservice.Protobuf.Protos.UserContract و ثبت gRPC client
  • فایل: BackOffice/Common/Configure/ConfigureService.cs

۱۱.۴ — رفع صفحه «کیف پول کاربران» (Wallets)

  • مشکل: صفحه /wallets اصلاً بارگذاری نمی‌شد — crash در DI
  • علت: دو سرویس ثبت نشده بود:
    • UserWalletContract.UserWalletContractClient
    • UserWalletChangeLogContract.UserWalletChangeLogContractClient
  • رفع: اضافه شدن using‌ها و ثبت هر دو gRPC client
  • فایل: BackOffice/Common/Configure/ConfigureService.cs

🏷 فاز ۱۰ — بهبود مدیریت محتوا: بلاگ + صفحات سایت (بهمن ۱۴۰۴)

هدف: فعال‌سازی آپلود تصویر باینری و ادیتور HTML در صفحات بلاگ و صفحات سایت

۱۰.۱ — بهبود ادیتور پست بلاگ

  • MudTextField Lines="10"MudHtmlEditor برای ویرایش محتوای HTML
  • فیلد متنی مسیر تصویرMudFileUpload با پیش‌نمایش تصویر (Image component)
  • حذف فیلد FeaturedImageThumbnailPath (تولید خودکار توسط بک‌اند)
  • اضافه شدن MudForm با اعتبارسنجی + حالت بارگذاری (_loading)
  • مدیریت خطا: try-catch + Snackbar
  • فایل‌ها: Pages/Blog/Components/BlogPostEditDialog.razor + .razor.cs

۱۰.۲ — بهبود ادیتور صفحه سایت

  • فیلد متنی Hero ImageMudFileUpload با پیش‌نمایش تصویر
  • اضافه شدن MudForm + حالت آپلود + مدیریت خطا
  • فایل‌ها: Pages/Content/Components/SitePageEditDialog.razor + .razor.cs

۱۰.۳ — بهبود ادیتور بخش صفحه سایت (Section)

  • MudTextField Lines="8"MudHtmlEditor برای ویرایش محتوای HTML بخش‌ها
  • فیلدهای متنی تصویر/thumbnailMudFileUpload با پیش‌نمایش
  • اضافه شدن MudForm + حالت آپلود + مدیریت خطا
  • فایل‌ها: Pages/Content/Components/SitePageSectionEditDialog.razor + .razor.cs

۱۰.۴ — تغییرات Proto

Proto تغییر
blogpost.proto اضافه شدن BlogImageFileModel + فیلد image_file در Create/Update
sitepage.proto اضافه شدن SitePageImageFileModel + فیلد image_file در Update/CreateSection/UpdateSection

۱۰.۵ — تغییرات CQRS (بک‌اند CMS)

  • Commands: اضافه شدن ImageFileBytes, ImageMime, ImageFileName به:
    • CreateBlogPostCommand, UpdateBlogPostCommand
    • UpdateSitePageCommand, CreateSitePageSectionCommand, UpdateSitePageSectionCommand
  • Handlers: تزریق IFileManager + فراخوانی UploadImageAsync:
    • BlogPost → Images/BlogPosts/
    • SitePage → Images/SitePages/
    • SitePageSection → Images/SitePageSections/

۱۰.۶ — تغییرات سرویس‌های BackOffice

  • BlogPostService.cs — ارسال BlogImageFileModel با ByteString.CopyFrom(dto.ImageFile)
  • SitePageService.cs — ارسال SitePageImageFileModel در Update/CreateSection/UpdateSection
  • DTOs: اضافه شدن ImageFile, ImageMime, ImageFileName به BlogPostEditDto, SitePageEditDto, SitePageSectionEditDto

خلاصه آمار فاز ۱۰

معیار تعداد
فایل‌های proto تغییریافته 2
Command‌های بروزشده 5
Handler‌های بروزشده 5
سرویس‌های gRPC تغییریافته 2 (BlogPostService + SitePageService)
دیالوگ‌های UI بازنویسی‌شده 3 (BlogPost, SitePage, SitePageSection)
سرویس‌های BackOffice بروزشده 2
DTO‌های بروزشده 3
Build 0 Error (هر ۳ پروژه)

🏷 فاز ۹ — معماری مدیریت فایل + رفع سفارشات + مهاجرت DB (بهمن ۱۴۰۴)

مستند کامل معماری فایل: totalDoc/cms/FILE-MANAGEMENT-ARCHITECTURE.md

۹.۱ — حذف کد مرده FMS

  • حذف ۳ فایل غیرقابل استفاده مرتبط با FMS خارجی (https://dl.afrino.co):
فایل حذف‌شده شرح
Infrastructure/Services/FmsFileManager.cs پیاده‌سازی HTTP upload به FMS
Application/Common/FileManager/FileManagementService.cs سرویس قدیمی مدیریت فایل
Application/Common/FileManager/IFileManagementService.cs اینترفیس قدیمی

۹.۲ — رفع صفحه سفارشات (Orders)

مشکل ۱ — صفحه خالی (بدون پیغام خطا)

  • علت: ServerReload بدون try-catch — exception‌های gRPC ساکت می‌شدند
  • رفع: اضافه شدن try-catch + نمایش خطا با Snackbar
  • فایل: Pages/UserOrder/UserOrderMainPage.razor.cs

مشکل ۲ — Shadow FK تکراری در OrderVAT

  • علت: .WithOne() بدون inverse navigation → EF Core یک shadow FK اضافی می‌ساخت
  • رفع: .WithOne().WithOne(x => x.OrderVAT)
  • فایل: Persistence/Configurations/OrderVATConfiguration.cs

مشکل ۳ — فیلترهای oneof همیشه فعال

  • علت: فیلدهای proto oneof مقدار پیش‌فرض enum دارند (هیچ‌وقت null نیستند)، پس PaymentStatus != null همیشه true بود
  • رفع: PaymentStatus != nullHasPaymentStatus == true (و مشابه برای DeliveryStatus و PaymentMethod)
  • فایل‌ها: UserOrderService.cs — هر دو متد GetAllUserOrderByFilter و GetCustomerOrders

۹.۳ — مهاجرت DB: حذف محدودیت طول ستون‌های تصویر

  • علت: data URI‌های base64 بزرگ‌تر از nvarchar(500) بودند → truncation خاموش
  • رفع: حذف HasMaxLength(500) از تمام ستون‌های image path
  • Migration: RemoveImagePathMaxLength
Entity ستون‌ها
Product ImagePath, ImageThumbnailPath
DiscountProduct ImagePath, ImageThumbnailPath
Category ImagePath
DiscountCategory ImagePath
BlogPost FeaturedImagePath, FeaturedImageThumbnailPath
SitePage HeroImagePath
SitePageSection ImagePath, ImageThumbnailPath

۹.۴ — بازنویسی کامل مدیریت فایل: ذخیره دیسکی

معماری قبلی: ذخیره data URI مستقیم در DB (ناکارآمد + حجم بالا)

معماری جدید:

  1. فایل‌ها در دیسک ذخیره می‌شوند: Uploads/Images/{folder}/{guid}.jpg
  2. مسیر نسبی در DB ذخیره می‌شود
  3. ImagePathResolverInterceptor هنگام serve تبدیل به base64 می‌کند

فایل‌های اصلی:

فایل شرح
Application/Common/FileManager/IFileManager.cs اینترفیس: Upload, UploadImage, Delete, ResolveImageUrl
Infrastructure/Services/LocalFileManager.cs پیاده‌سازی: ImageSharp, main 1200×1200 + thumb 300×300, JPEG Q75
WebApi/Interceptors/ImagePathResolverInterceptor.cs gRPC Interceptor: walk بازگشتی response → تبدیل path به data URI

تنظیمات:

  • FileStorage:UploadPath → پوشه ریشه آپلود (پیش‌فرض: AppContext.BaseDirectory/Uploads)
  • gRPC MaxReceiveMessageSize: 50MB

۹.۵ — پاکسازی LoggingBehaviour

  • قبل: فیلدهای باینری (byte[] تصاویر) کامل در لاگ چاپ می‌شدند → لاگ‌های چند مگابایتی
  • بعد:
    • فرمت: JsonFormatter.Default.Format() به جای {@Request}
    • Regex: حذف فیلدهای باینری (File, ImageFile, image_file, file)
    • محدودیت: حداکثر 2000 کاراکتر
  • فایل: WebApi/Common/Behaviours/LoggingBehaviour.cs

خلاصه آمار فاز ۹

معیار تعداد
فایل‌های حذف‌شده (کد مرده) 3
فایل‌های جدید 2 (LocalFileManager بازنویسی + ImagePathResolverInterceptor)
فایل‌های ویرایش‌شده ~12
باگ‌های رفع‌شده 4 (Orders page ×3 + DB truncation)
Migration‌های جدید 1 (RemoveImagePathMaxLength)
ستون‌های DB تغییریافته 9 (nvarchar(500) → nvarchar(max))
Build 0 Error (هر ۳ پروژه)

🏷 فاز ۸ — یکسان‌سازی فروشگاه عادی و تخفیفی (بهمن ۱۴۰۴)

مستند کامل: totalDoc/ui-modernization/BACKOFFICE-STORE-UNIFICATION.md

۸.۱ — بازسازی NavMenu

  • ایجاد دو NavGroup مجزا: «فروشگاه عادی» و «فروشگاه تخفیفی»
  • حذف «ویرایش دسته‌جمعی» از منو
  • انبارداری → گروه مستقل | پکیج‌ها → آیتم مستقل
  • فایل: Shared/NavMenu.razor

۸.۲ — حذف گزارش‌های کوچک از سفارشات

  • حذف کارت‌های آماری (TotalOrders + TotalAmount) و نمودار Bar ارسال
  • حذف فیلدها: _stats, _statusChartLabels, _statusChartSeries
  • حذف متد UpdateStats() و کلاس OrderStatsViewModel
  • عنوان: «سفارش‌های کاربر» → «لیست سفارشات»
  • فایل‌ها: Pages/UserOrder/UserOrderMainPage.razor + .razor.cs

۸.۳ — رفع باگ لیست خالی سفارشات

  • علت: PaymentDate.ToDateTime() بدون null check → exception ساکت در WASM
  • رفع: @if (context.Item.PaymentDate != null) + fallback "-"
  • فایل: Pages/UserOrder/UserOrderMainPage.razor

۸.۴ — بازنویسی صفحه محصولات تخفیفی

  • تبدیل به BasePageComponent (مطابق فروشگاه عادی)
  • فیلترهای جدید: وضعیت + موجودی
  • ستون‌های جدید: تصویر inline + عنوان truncate + چیپ رنگی موجودی + چیپ وضعیت
  • فایل‌ها: Pages/DiscountShop/DiscountProductsMainPage.razor + .razor.cs (بازنویسی کامل)

۸.۵ — بازنویسی صفحه دسته‌بندی‌های تخفیفی

  • تبدیل به BasePageComponent (مطابق فروشگاه عادی)
  • ستون‌های جدید: نام لاتین، دسته‌بندی والد (resolve شده)، تعداد محصولات، ترتیب
  • code-behind جدید (@code درون‌خطی → .razor.cs)
  • فایل‌ها: Pages/DiscountShop/DiscountCategoriesMainPage.razor + .razor.cs (بازنویسی کامل)

خلاصه آمار فاز ۸

معیار تعداد
فایل‌های بازنویسی‌شده 4
فایل‌های ویرایش‌شده 3
باگ‌های رفع‌شده 2 (PaymentDate null + لیست خالی)
Build 0 Error

🏷 فاز ۷ — پس از اجرای Audit v7.0 (تیر ۱۴۰۴)

خلاصه تغییرات

  • ۵۷ مورد از ۵۸ یافته audit اجرا شد (≈98%)
  • تمام ۱۶ مورد بحرانی 🔴 حل شد
  • تمام ۱۸ مورد جزئی 🟢 حل شد
  • فازهای ۱ تا ۶ تکمیل شدند (به‌جز DayaLoan و Audit Trail که نیاز به بک‌اند دارند)
  • فاز ۷ — Global Search, Notification Bell, NavMenu Badge, Export Excel 4 صفحه جدید
  • ۱۳+ فایل جدید ساخته شد
  • ۹ صفحه ادغام شدند (۱۴ صفحه → ۵ صفحه)
  • Build: 0 error

فاز ۷ — Global Search + Notifications + Export All + NavMenu Badge (v7.0)

6.5 — Badge Pending در NavMenu —

  • NavMenu.razor: اضافه شدن MudBadge روی لینک «درخواست‌های برداشت»
  • نمایش تعداد درخواست‌های Pending بصورت real-time از gRPC (CommissionContract.GetWithdrawalRequestsAsync با Status=0)
  • fire-and-forget در OnInitializedAsync با try/catch silent

6.2 — Global Search در AppBar —

  • فایل جدید: Shared/GlobalSearch.razor
  • MudAutocomplete<SearchResultItem> با Debounce 400ms
  • دو نوع جستجو: ۱) نام صفحات (۱۵ صفحه اصلی) ۲) کاربران از gRPC (UserContract.GetAllUserByFilterAsync)
  • Template سفارشی با آیکون + عنوان + زیرنویس
  • ناوبری خودکار با Navigation.NavigateTo
  • اضافه شده در MainLayout.razor داخل <AuthorizeView>
  • CSS در app.css — rounded border-radius 24px, compact padding

6.1 — Notification Bell (placeholder) —

  • MainLayout.razor: اضافه شدن MudMenu + MudBadge (Dot) + آیکون Notifications
  • Dropdown با هدر «اعلان‌ها» + placeholder «اعلان جدیدی وجود ندارد»
  • آماده اتصال به بک‌اند — فقط Visible=true و populate items

6.3 — Export Excel صفحات جدید — (۱۰ صفحه کامل)

  • ۴ صفحه جدید اضافه شدند به ۶ صفحه قبلی:
    1. UserMainPage — خروجی CSV: شناسه, موبایل, نام, نام خانوادگی, کدملی
    2. DiscountOrdersMainPage — خروجی CSV: شماره سفارش, تاریخ, مبلغ کل, تخفیف, قابل پرداخت, تعداد, وضعیت, پرداخت
    3. ManualPayments — خروجی CSV: شناسه, شناسه کاربر, نام کاربر, مبلغ, نوع, وضعیت, تاریخ
    4. InventoryMainPage — خروجی CSV: شناسه, محصول, انبار, موجودی, رزرو, قابل فروش, حد هشدار, وضعیت
  • هر ۴ صفحه: دکمه «خروجی Excel» + ExportToExcel() + EscapeCsv() + UTF-8 BOM + jsSaveAsFile
  • فایل‌های code-behind جدید: ManualPayments.razor.cs, DiscountOrdersMainPage.razor.cs

فاز ۶ — تاریخ شمسی + تاریخچه‌ها + Export Excel (v6.0)

تاریخ شمسی یکپارچه (3.6) — کامل

  • ۱۹+ فایل آپدیت شدند: تمام تاریخ‌ها از فرمت میلادی (yyyy/MM/dd) به شمسی تبدیل شدند
  • از extension method‌های DateTimeConverterCL استفاده شد:
    • .MiladiToJalali() — فرمت تاریخ فقط (مثال: ۱۴۰۴/۰۴/۱۲)
    • .MiladiToJalaliWithTime() — فرمت تاریخ و ساعت
  • صفحات اصلاح‌شده شامل: Club (Members, Statistics, Features, MemberDetailsDialog)، Commission (Dashboard, WeeklyReports, WithdrawalRequests, Payouts, WithdrawalReports)، Network (UserNetworkInfo, BalancesReport, Statistics, NetworkTreeViewer)، UserOrder, Products, Package, Inventory, DiscountShop, Blog, Content, و غیره
  • PropertyColumn Format="yyyy/MM/dd"TemplateColumn با .MiladiToJalali()
  • MudDatePicker DateFormat تغییر نکرد (قابلیت تقویم شمسی نیاز به کتابخانه جداگانه دارد)

تاریخچه عضویت باشگاه (5.7) —

  • MemberDetailsDialog.razor: تب تاریخچه با فیلدهای صحیح proto:
    • ستون‌ها: Action, Created, PackageName, Reason, PerformedBy
    • Request: PageIndex = 0 (نه PageNumber)

تاریخچه تغییرات شبکه (5.8) —

  • UserNetworkInfo.razor: تب تاریخچه با فیلدهای تخصصی:
    • ستون‌ها: Action, Created, OldParentId → NewParentId, OldNetworkLeg → NewNetworkLeg (چپ/راست)
    • ستون Reason و PerformedBy اضافه شد
    • Request: PageIndex = 0

لاگ اجرای Worker‌ها (5.6) —

  • در تب WorkerControl از SystemHub قبلاً پیاده‌سازی شده بود

Export Excel / CSV (6.3) — ۶ صفحه

قابلیت خروجی CSV (سازگار با Excel) به ۶ صفحه اصلی اضافه شد:

صفحه فایل(ها) ستون‌های خروجی
Products (قبلاً موجود) ProductsMainPage.razor.cs
Club Members ClubMembers.razor + .razor.cs شناسه,کاربر,نام,پکیج,کد فعال‌سازی,تاریخ فعال‌سازی,تاریخ انقضا,فعال,منقضی
Withdrawal Requests WithdrawalRequests.razor + .razor.cs شناسه,کاربر,نام,مبلغ,وضعیت,روش,شبا,تاریخ درخواست,تاریخ پردازش,مرجع بانکی
Weekly Reports WeeklyReports.razor + .razor.cs هفته,مبلغ استخر,موجودی‌ها,ارزش,وضعیت,تاریخ محاسبه
User Orders UserOrderMainPage.razor + .razor.cs شناسه,کاربر,نام,مبلغ,وضعیت پرداخت,وضعیت ارسال,روش پرداخت,تاریخ
Stock Movements MovementsPage.razor + .razor.cs شناسه,محصول,نوع,تعداد,قبل,بعد,مرجع,یادداشت,تاریخ

الگوی پیاده‌سازی:

  • دکمه <MudButton> با آیکون FileDownload در ToolBarContent
  • StringBuilder → CSV با هدرهای فارسی
  • UTF-8 BOM (Encoding.UTF8.GetPreamble()) برای نمایش صحیح فارسی در Excel
  • jsSaveAsFile(filename, base64) از wwwroot/js/main.js
  • متد EscapeCsv() برای مقادیر حاوی کاما/کوتیشن
  • تاریخ‌ها در خروجی نیز شمسی هستند

فایل‌های جدید (این نسخه)

فایل عملکرد
Pages/Commission/WeeklyReports.razor.cs Code-behind برای export (به‌دلیل محدودیت Razor parser با escaped quotes)

نسخه قبلی — Audit v5.0 (خرداد ۱۴۰۴)

تم رنگی یکپارچه

  • CustomMudTheme.cs: تم Primary از #0380C0 به #6366f1 (Indigo) تغییر کرد — هماهنگ با FrontOffice
  • PaletteDark اضافه شد: Surface #1a1a2e, Background #16213e, AppbarBackground #0f3460
  • app.css: رنگ loading از #1b6ec2 به var(--mud-palette-primary) تغییر کرد
  • NavMenu.razor.css: رنگ active از #0380C0 هاردکد به CSS variable تغییر کرد
  • MainLayout.razor: حذف inline style border: 1px solid #5e4df9

Dark Mode Toggle

  • آیکون ماه/آفتاب در AppBar اضافه شد
  • _isDarkMode state با MudThemeProvider اتصال دارد
  • تعویض بین PaletteLight و PaletteDark در CustomMudTheme

عنوان اپلیکیشن

  • "پنل مدیریت فرصت" → "پنل مدیریت کارا بازار سلامت"

فاز ۲ — بازطراحی لایوت صفحات

BasePageComponent بازنویسی کامل

  • قبل: فیلتر ثابت سمت راست (20%) + جدول (80%)، ارتفاع 85vh هاردکد
  • بعد: فیلتر collapsible بالای جدول، فیلدها در MudGrid با MudItem، responsive
  • ۱۳ صفحه آپدیت شدند: User, Products, Package, Category, UserOrder, UserAddress, UserRole, Role, BlogPost, BlogCategory, Tag, Transactions, Content

DataGrid Height یکسان‌سازی

  • همه DataGrid‌ها: Height="calc(100vh - 240px)"
  • صفحات اصلاح‌شده: تمام ~33 صفحه دارای DataGrid

Pager یکسان‌سازی

  • PageSize: همه 20, 50, 100
  • متن فارسی: RowsPerPageString="تعداد در صفحه" و InfoFormat="سطر {first_item} تا {last_item} از {all_items}"

MaxWidth یکسان‌سازی

  • MainLayout.razor MudContainer wrapper اضافه شد → MaxWidth یکسان برای همه صفحات
  • ۳۱ صفحه: حذف MudContainer تکراری (double nesting)

Breadcrumb

  • Shared/AppBreadcrumb.razor ساخته شد
  • جداکننده چپ‌به‌راست (ChevronLeft)
  • نقشه فارسی URL segments (60+ مسیر)
  • آخرین آیتم disabled (صفحه فعلی)

Login + VerifyCode بازطراحی

  • عرض ثابت 35% → responsive MaxWidth.Small
  • لوگو + برندینگ "کارا بازار سلامت" اضافه شد
  • طراحی gradient background

فاز ۲.۵ — پاکسازی ساختاری

NavMenu بازسازی کامل

  • لینک مرده categories-dragdrop: حذف شد
  • Transactions: حذف از NavMenu (صفحه stub خالی)
  • AlertsMonitoring: حذف از NavMenu (100% mock)
  • WorkerControl: به SystemHub منتقل شد (قبلاً لینک نداشت)
  • «پیام‌های عمومی»: از بخش فروشگاه تخفیفی به «مدیریت محتوا» منتقل شد
  • ساختار گروه‌بندی اصلاح شد:
    • کمیسیون و شبکه: NavGroup واضح
    • باشگاه مشتریان: اعضا و آمار + فیچرها
    • فروشگاه: پکیج‌ها، محصولات (group)، سفارش‌ها، فروشگاه تخفیفی (group)
    • مدیریت: کاربران، نقش‌ها، پرداخت دستی، کیف‌پول (جدید)، قراردادها (جدید)
    • محتوا: بلاگ، صفحات سایت، پیام‌های عمومی
    • سیستم: مدیریت سیستم، نسخه اپ‌ها

فاز ۳ — UX بهبودها

NoRecordsContent (Empty State)

  • ۳۳ DataGrid آپدیت شدند
  • پیام: <MudAlert Severity="Info">موردی یافت نشد.</MudAlert>

Delete Confirmation با نام آیتم

  • ۱۱ صفحه اصلاح شدند:
    • Role → «{model.Title}»
    • User → «{model.FirstName} {model.LastName}»
    • Package → «{model.Title}»
    • UserAddress → «{model.Title}»
    • UserRole → شناسه «{model.Id}»
    • UserOrder → شماره «{model.Id}»
    • Category → «{model.Title}»
    • Products → «{model.Title}»
    • DiscountCategories → «{category?.Title}» (lookup اضافه شد)
    • DiscountProducts → «{product?.Title}» (lookup اضافه شد)
    • PublicMessages → «{message?.Title}» (lookup اضافه شد)

User Menu در AppBar

  • MudMenu جایگزین متن ساده شماره موبایل شد
  • آیتم‌ها: نام کاربر (غیرفعال) + خروج
  • آیکون AccountCircle
  • خروج (signout) از NavMenu به AppBar منتقل شد

فاز ۳.۵ — ادغام صفحات

Dashboard Merge ← Pages/Index.razor

  • Index.razor + SystemOverview.razor ادغام شدند
  • Routes: / + /dashboard/overview
  • بخش‌ها:
    • 6 کارت آمار CMS (کاربران، محصولات، پکیج‌ها، دسته‌بندی‌ها، سفارش‌ها، مبلغ پرداخت‌شده)
    • آمار کمیسیون (هفته جاری، استخر، موجودی‌ها، وضعیت محاسبه)
    • آمار باشگاه (کل/فعال/غیرفعال)
    • جدول آخرین ۵ سفارش پرداخت‌شده
    • ۶ دکمه Quick Action
  • بارگذاری موازی با Task.WhenAll + .ResponseAsync
  • SystemOverview.razor حذف شد

DiscountShopHub ← Pages/DiscountShop/DiscountShopHub.razor

  • Routes: /discount-shop, /discount-orders, /discount-sales-reports
  • ۲ تب: DiscountOrdersMainPage + SalesReports
  • انتخاب تب از URL

ClubHub ← Pages/Club/ClubHub.razor

  • Routes: /club, /club/members, /club/statistics
  • ۲ تب: ClubMembers + Statistics

BlogHub ← Pages/Blog/BlogHub.razor

  • Routes: /blog, /blog/posts, /blog/categories, /tags
  • ۳ تب: BlogPostManagementPage + BlogCategoryManagementPage + TagManagementPage

SystemHub ← Pages/SystemManagement/SystemHub.razor

  • Routes: /system, /system/configuration, /system/worker-control, /system/health
  • ۳ تب: Configuration + WorkerControl + HealthDashboard

۱۰ صفحه — @page directive حذف شد

صفحاتی که به hub منتقل شدند دیگر route مستقل ندارند: DiscountOrdersMainPage, SalesReports, ClubMembers, Statistics, BlogPostManagementPage, BlogCategoryManagementPage, TagManagementPage, Configuration, WorkerControl, HealthDashboard


فاز ۴ — فیکس‌های بیزینسی

Dashboard آمار اصلاح شد

  • قبل: آمار از ۱۰ رکورد اول محاسبه می‌شد (نادرست)
  • بعد: از metadata.TotalCount و API‌های جداگانه استفاده می‌شود

ManualPayments — تأیید/رد

  • دکمه‌های Approve/Reject وقتی Status==0 (در انتظار) نمایش داده می‌شوند
  • Confirmation dialog قبل از اجرا
  • از ManualPaymentId (نه Id) استفاده می‌شود

UserOrder — فیلتر Cancelled

  • <MudSelectItem Value="@(5)">لغو شده</MudSelectItem> اضافه شد

WithdrawalRequests — بهبود کامل

  • Pager: 10/25/50/100 → 20/50/100
  • WithdrawalDetailsDialog.razor (جدید): نمایش کامل اطلاعات کاربر، درخواست، و بانکی
  • RejectReasonDialog.razor (جدید): ورود دلیل رد با اعتبارسنجی
  • ViewDetails: از Snackbar TODO به دیالوگ واقعی تغییر کرد
  • RejectRequest: از دلیل هاردکد به دیالوگ custom تغییر کرد

فاز ۵ — صفحات مفقود (CMS-Derived)

WalletManagementPage ← Pages/Wallet/WalletManagementPage.razor

  • Route: /wallets
  • تب ۱ — کیف‌پول‌ها: DataGrid با ServerData، فیلتر UserAutoComplete
    • ستون‌ها: شناسه، کاربر، موجودی اصلی، موجودی شبکه، مشاهده تغییرات
    • نوع: GetAllUserWalletByFilterResponseModel
  • تب ۲ — تاریخچه تغییرات: DataGrid با ServerData، فیلتر کاربر + نوع (افزایش/کاهش)
    • ستون‌ها: شناسه، کیف‌پول، نوع (چیپ رنگی)، تغییر موجودی، موجودی فعلی، تغییر شبکه، موجودی شبکه فعلی، شناسه مرجع، تاریخ
    • نوع: GetAllUserWalletChangeLogByFilterResponseModel
    • فیلدهای proto با typo: ChangeNerworkValue, RefrenceId

UserContractPage ← Pages/Contract/UserContractPage.razor

  • Route: /contracts
  • DataGrid با ServerData، فیلتر UserAutoComplete
  • ستون‌ها: شناسه، کاربر، قرارداد، کد امضا، لینک PDF، جزئیات
  • نوع: GetAllUserContractByFilterResponseModel

ContractDetailsDialog ← Pages/Contract/ContractDetailsDialog.razor

  • جدول ساده: شناسه، کاربر، قالب قرارداد، کد امضا، لینک دانلود PDF

ClubFeaturesPage ← Pages/Club/ClubFeaturesPage.razor

  • Route: /club/features
  • تب ۱ — فیچرهای تعریف‌شده: کارت‌های MudPaper با عنوان، توضیحات، وضعیت (فعال/غیرفعال)، ترتیب
    • از ConfigClient.GetClubFeaturesAsync
  • تب ۲ — فیچرهای کاربران: DataGrid با فیلتر کاربر، سوئیچ فعال/غیرفعال
    • از ClubClient.GetUserClubFeaturesAsync + ToggleUserClubFeatureAsync

⚠️ نکات فنی مهم

الگوهای Proto

  • فیلتر: new GetAllXxxByFilterFilter() (سطح بالا، بدون .Types.)
  • پاسخ لیست: GetAllXxxByFilterResponseModel (نه GetXxxResponse)
  • Typo‌ها در proto: ChangeNerworkValue و RefrenceId — باید دقیقاً همین‌ها استفاده شوند

_Imports.razor — سرویس‌های Global

سرویس‌های زیر از _Imports.razor تزریق می‌شوند و نباید در code-behind با [Inject] دوباره تعریف شوند:

  • NavigationManager Navigation
  • ILocalStorageService LocalStorageService
  • ISnackbar Snackbar
  • IJSRuntime jsRuntime
  • IDialogService DialogService
  • AuthenticationStateProvider

MudBlazor محدودیت‌ها

  • Variant.Flat وجود ندارد → از Variant.Text استفاده شود
  • GutterSize روی MudGrid deprecated است

فاز ۴ (ادامه) — تکمیل فیکس‌های بیزینسی

UserSettings — حذف تب‌های جعلی (2.5.5)

  • UserSettings.razor: تب Notifications (۷ تاگل جعلی بدون بک‌اند) → placeholder «به‌زودی فعال می‌شود» با آیکون NotificationsActive
  • UserSettings.razor: تب Security (فرم تغییر رمز + 2FA بدون بک‌اند) → placeholder «به‌زودی فعال می‌شود» با آیکون Lock
  • حذف کد مرده: ~۱۵ متغیر notification/security + متدهای SaveNotificationSettings(), SaveSecuritySettings(), ChangePassword()

HealthDashboard — حذف متریک‌های Mock (2.5.6)

  • HealthDashboard.razor: بخش System Resources (۴ کارت CPU=45.2%, Memory=62.8%, Disk=73.5%, Network) → یک کارت با پیام «مانیتورینگ منابع سیستم در نسخه‌های آینده با اتصال به Prometheus/Grafana فعال خواهد شد»
  • حذف کد مرده: ۹ متغیر mock (_cpuUsage, _memoryUsage, etc.) + متد GetResourceColor()

حذف cursor:pointer زائد (4.10)

  • Style="cursor:pointer;" از ۱۷ فایل حذف شد (MudButton/MudIconButton خودشان cursor:pointer دارند)
  • شامل: ProductsMainPage, GalleryDialog, Image.razor (base component), RoleMainPage, UserOrderMainPage, PackageMainPage, etc.

حذف Console.WriteLine (4.11)

  • از ۱۱ فایل حذف شد: DiscountProductService, DiscountCategoryService, NetworkTreeViewer, UserSettings, CategoryMainPage, UserOrderMainPage, Commission/Dashboard, DiscountProductsMainPage, DiscountCategoryMultiSelectCombo, UserRole/CreateDialog
  • Commission/Dashboard.razor.cs: using System.Text.Json هم حذف شد (دیگر استفاده نمی‌شد)

DiscountProducts — فیلتر دسته‌بندی (4.7)

  • DiscountProductsMainPage.razor: @inject IDiscountCategoryService اضافه شد
  • دسته‌بندی‌های فعال از سرویس بارگذاری و در MudSelect نمایش داده می‌شوند
  • جایگزینی @* TODO: Load categories *@ با @foreach واقعی

DiscountProducts — Items → ServerData (4.8)

  • DiscountProductsMainPage.razor: تبدیل از Items="@_products" به ServerData="LoadServerData"
  • متد LoadServerData(GridState<T>) اضافه شد با PageNumber و PageSize از state
  • Height="calc(100vh - 300px)" + FixedHeader="true" اضافه شد
  • Snackbar اطلاع‌رسانی اضافی در هر بارگذاری حذف شد (redundant)

UserOrder — فعال‌سازی آمار (4.6)

  • UserOrderMainPage.razor: بخش آمار (MudCard + MudChart) از حالت comment خارج شد
  • نمایش تعداد سفارش‌ها + مجموع مبلغ + نمودار Bar وضعیت ارسال

UserSettings — persist با localStorage (4.9)

  • تب General از قبل با localStorage کار می‌کرد (فقط تب‌های جعلی حذف شدند)

فاز ۴.۵ — Cross-Navigation

لینک نام کاربر → پروفایل (4.5.1, 4.5.2)

  • UserOrderMainPage.razor: ستون UserFullName از PropertyColumn به TemplateColumn تبدیل شد — MudLink به /network/user-info/{UserId}
  • UserPayouts.razor: نام/شناسه کاربر به MudLink تبدیل شد → /network/user-info/{UserId}
  • WithdrawalRequests.razor: نام کاربر به MudLink تبدیل شد → /network/user-info/{UserId}

لینک محصول ↔ انبار (4.5.3, 4.5.4) — Skip

  • صفحه جزئیات محصول وجود ندارد (فقط لیست + دیالوگ ویرایش)
  • لینک cross-navigation بدون صفحه مقصد معنادار نیست

Extract shared status helpers (3.5.6) — Skip

  • بررسی نشان داد هر context مقادیر متفاوتی دارد:
    • UserPayouts: status 1 = Success/پرداخت شده
    • WithdrawalRequests: status 1 = Info/واریز شده
    • PayoutDetailsDialog: فقط ۳ وضعیت (نه ۶)
  • استخراج به helper مشترک باعث از دست رفتن معنای domain-specific می‌شود

📈 آمار تغییرات

معیار تعداد
فایل‌های جدید 11
فایل‌های حذف‌شده 1 (SystemOverview.razor)
فایل‌های ویرایش‌شده ~65+
DataGrid‌های آپدیت‌شده 33
Delete confirmation اصلاح‌شده 11
صفحات ادغام‌شده 14 → 5
خطاهای build حل‌شده 9+
Console.WriteLine حذف‌شده 22+ (از ۱۱ فایل)
cursor:pointer حذف‌شده 17 فایل
Cross-link اضافه‌شده 3 صفحه (UserOrder, UserPayouts, WithdrawalRequests)