# 🎨 طرح نوسازی رابط کاربری فرانت‌آفیس + سیستم بلاگ > **تاریخ شروع:** تیر ۱۴۰۴ > **آخرین بروزرسانی:** بهمن ۱۴۰۴ > **وضعیت:** فازهای ۱ تا ۶ تکمیل ✅ — فاز ۷ در حال اجرا > **اولویت:** بالا --- ## فهرست مطالب 1. [خلاصه اجرایی](#1-خلاصه-اجرایی) 2. [وضعیت فعلی](#2-وضعیت-فعلی) 3. [اهداف پروژه](#3-اهداف-پروژه) 4. [معماری فنی](#4-معماری-فنی) 5. [فاز ۱ — موجودیت‌های بکند (CMS)](#5-فاز-۱--موجودیتهای-بکند-cms) 6. [فاز ۲ — پنل مدیریت بلاگ (BackOffice)](#6-فاز-۲--پنل-مدیریت-بلاگ-backoffice) 7. [فاز ۳ — صفحات محتوای دینامیک (درباره ما / تماس با ما)](#7-فاز-۳--صفحات-محتوای-دینامیک-درباره-ما--تماس-با-ما) 8. [فاز ۴ — نوسازی لندینگ پیج](#8-فاز-۴--نوسازی-لندینگ-پیج) 9. [فاز ۵ — صفحات بلاگ فرانت‌آفیس](#9-فاز-۵--صفحات-بلاگ-فرانتآفیس) 10. [فاز ۶ — بهبود داشبورد کاربر](#10-فاز-۶--بهبود-داشبورد-کاربر) 11. [فاز ۷ — بهینه‌سازی موبایل](#11-فاز-۷--بهینهسازی-موبایل) 12. [فایل‌های تغییریافته (نقشه فایل‌ها)](#12-فایلهای-تغییریافته-نقشه-فایلها) 13. [جدول زمانی](#13-جدول-زمانی) 14. [ریسک‌ها و وابستگی‌ها](#14-ریسکها-و-وابستگیها) --- ## 1. خلاصه اجرایی این سند طرح جامع نوسازی رابط کاربری **فرانت‌آفیس** (سمت مشتری) و ایجاد **سیستم بلاگ/مدیریت محتوا** را شامل می‌شود. اهداف اصلی: - ✅ ایجاد **سیستم بلاگ** با قابلیت انتشار مقالات، مجوزها، گواهینامه‌ها با تصاویر - ✅ **صفحات دینامیک** درباره ما و تماس با ما (قابل مدیریت از پنل ادمین) - ✅ **نوسازی لندینگ پیج** با طراحی حرفه‌ای و حس زنده بودن سامانه - ✅ **صفحات بلاگ فرانت‌آفیس** — لیست مقالات با جستجو/فیلتر + صفحه جزئیات مقاله - ✅ **بهبود داشبورد** کاربر با طراحی مدرن و اطلاعات پویا - 🔄 **طراحی Mobile-First** (اولویت موبایل) — فاز ۷ - ⛔ بدون تغییر UI سمت ادمین (فقط افزودن صفحات مدیریت بلاگ/محتوا) --- ## 2. وضعیت فعلی ### 2.1 پشته فنی | لایه | تکنولوژی | |------|----------| | FrontOffice | Blazor Server (.NET 9) + MudBlazor 8.14.0 | | BackOffice | Blazor WebAssembly (.NET 9) + MudBlazor 8.14.0 | | CMS (Backend) | .NET 9 gRPC + MediatR CQRS + EF Core | | دیتابیس | SQL Server | | فایل‌ها | FMS (File Management Service) via gRPC | | زبان UI | فارسی (RTL) + فونت Vazir | | تم | Light/Dark toggle | ### 2.2 صفحات فعلی فرانت‌آفیس | صفحه | مسیر | وضعیت | |------|------|-------| | لندینگ | `/` | ✅ Hero گرادیان + Features + Timeline + Stats + بلاگ + Testimonials + FAQ + CTA | | درباره ما | `/about` | ✅ محتوای دینامیک از CMS (با fallback) | | تماس با ما | `/contact` | ✅ محتوای دینامیک از CMS + فرم تماس | | بلاگ | `/blog` | ✅ لیست مقالات + جستجو + فیلتر دسته‌بندی + صفحه‌بندی | | مقاله | `/blog/{slug}` | ✅ صفحه جزئیات مقاله + breadcrumb + تگ‌ها + شمارنده بازدید | | سوالات متداول | `/faq` | ✅ فعال | | پروفایل | `/profile/*` | ✅ ۱۰ صفحه (هدر گرادیانی + والت‌کارت‌ها + تایل‌های مدرن) | | فروشگاه | `/products/*` | ✅ ۸ صفحه (محصولات، سبد، سفارشات، ...) | | باشگاه | `/club/*` | ✅ ۲ صفحه | | کمیسیون | `/commission/*` | ✅ ۳ صفحه | | شبکه | `/network/*` | ✅ ۲ صفحه | | پکیج | `/packages/*` | ✅ ۴ صفحه | ### 2.3 مشکلات فعلی (رفع شده ✅) 1. ~~**احساس ایستا بودن** — لندینگ پیج بدون انیمیشن و محتوای پویا~~ → ✅ فاز ۴ حل شد 2. ~~**بدون بلاگ** — امکان انتشار مقاله/خبر/مجوز وجود ندارد~~ → ✅ فازهای ۱، ۲، ۵ حل شد 3. ~~**صفحات استاتیک** — درباره ما و تماس با ما هاردکد هستند~~ → ✅ فاز ۳ حل شد 4. ~~**طراحی ساده** — فاقد عناصر بصری جذاب~~ → ✅ فازهای ۴ و ۶ حل شد 5. **موبایل‌محور نبودن** — ریسپانسیو هست اما اولویت با دسکتاپ → 🔄 فاز ۷ --- ## 3. اهداف پروژه ### 3.1 اهداف عملیاتی | هدف | شاخص موفقیت | |-----|-------------| | سیستم بلاگ | ادمین بتواند مقاله بنویسد، دسته‌بندی کند، تصویر آپلود کند، منتشر/آرشیو کند | | محتوای دینامیک | ادمین بتواند درباره ما و تماس با ما را از پنل ویرایش کند | | لندینگ حرفه‌ای | اولین بازدید حس «پلتفرم زنده و فعال» بدهد | | Mobile-First | تمام صفحات در موبایل عالی نمایش داده شوند | | عملکرد | زمان بارگذاری صفحه اول < ۳ ثانیه | ### 3.2 محدوده (Scope) ``` ✅ در محدوده: - سیستم بلاگ کامل (CMS → BackOffice → FrontOffice) - صفحات محتوای دینامیک (About, Contact) - نوسازی لندینگ پیج - بهبود داشبورد/پروفایل - بهینه‌سازی موبایل - افزودن صفحات مدیریت بلاگ به BackOffice ⛔ خارج از محدوده: - تغییرات UI سایر بخش‌های BackOffice - سیستم کامنت‌گذاری (فاز بعدی) - سیستم جستجوی پیشرفته (فاز بعدی) - اپلیکیشن موبایل (PWA یا Native) ``` --- ## 4. معماری فنی ### 4.1 جریان داده بلاگ ``` ┌──────────────┐ gRPC ┌───────────┐ EF Core ┌──────────┐ │ BackOffice │ ──────────► │ CMS │ ────────────► │ SQL Server│ │ (Admin CRUD) │ ◄────────── │ (gRPC) │ ◄──────────── │ │ └──────────────┘ └───────────┘ └──────────┘ │ ▲ gRPC │ │ ▼ │ ┌──────────────┐ │ FrontOffice │ │ (مشاهده بلاگ)│ └──────────────┘ │ FMS │ (آپلود تصاویر) ▼ ┌──────────┐ │ FMS │ │ (فایل‌ها) │ └──────────┘ ``` ### 4.2 موجودیت‌های جدید (Entity Relationship) ``` BlogPost (1) ──────── (N) BlogPostCategory ──────── (1) BlogCategory │ │ (1:N) ▼ BlogPostImage BlogPost.Tags → از Tag موجود استفاده می‌شود (BlogPostTag join table) SitePage → صفحات دینامیک (About, Contact, Custom) │ │ (1:N) ▼ SitePageSection → بخش‌های هر صفحه ``` ### 4.3 الگوی CQRS موجود (برای مرجع) ``` Proto (gRPC Definition) ↓ WebApi/Services/{Feature}Service.cs (extends generated gRPC base) ↓ Mapster (Proto → Command/Query) Application/{Feature}CQ/Commands/ or Queries/ ↓ MediatR Handler → Repository (DbContext) ↓ Domain/Entities/{Entity}.cs ``` --- ## 5. فاز ۱ — موجودیت‌های بکند (CMS) ✅ تکمیل شد > **وضعیت:** ✅ تکمیل | **اولویت:** بالا | **پیش‌نیاز:** ندارد ### 5.1 موجودیت‌های جدید Domain #### `BlogPost.cs` ``` Location: CMS/src/CMSMicroservice.Domain/Entities/Blog/BlogPost.cs Base: BaseAuditableEntity Properties: - string Title (required, max 200) - string Slug (required, unique, max 200) - string Summary (max 500) — خلاصه برای کارت‌ها - string HtmlContent (required) — محتوای HTML کامل - string? FeaturedImagePath — تصویر شاخص - string? FeaturedImageThumbnailPath — تامبنیل تصویر شاخص - BlogPostStatus Status (enum: Draft, Published, Scheduled, Archived) - DateTime? PublishedAt — زمان انتشار - DateTime? ScheduledPublishAt — زمانبندی انتشار - int ViewCount — تعداد بازدید - long AuthorUserId — نویسنده - bool IsFeatured — نمایش در صفحه اول - int SortOrder — ترتیب نمایش Relations: - ICollection BlogPostCategories - ICollection BlogPostTags - ICollection BlogPostImages ``` #### `BlogCategory.cs` ``` Location: CMS/src/CMSMicroservice.Domain/Entities/Blog/BlogCategory.cs Base: BaseAuditableEntity Properties: - string Title (required, max 100) - string Slug (required, unique, max 100) - string? Description (max 500) - string? IconName — آیکون Material - int SortOrder - bool IsActive Relations: - ICollection BlogPostCategories ``` #### `BlogPostCategory.cs` (Join Table) ``` Location: CMS/src/CMSMicroservice.Domain/Entities/Blog/BlogPostCategory.cs Base: BaseEntity Properties: - long BlogPostId - long BlogCategoryId Relations: - BlogPost BlogPost - BlogCategory BlogCategory ``` #### `BlogPostTag.cs` (Join Table) ``` Location: CMS/src/CMSMicroservice.Domain/Entities/Blog/BlogPostTag.cs Base: BaseEntity Properties: - long BlogPostId - long TagId Relations: - BlogPost BlogPost - Tag Tag (موجود — استفاده مجدد) ``` #### `BlogPostImage.cs` ``` Location: CMS/src/CMSMicroservice.Domain/Entities/Blog/BlogPostImage.cs Base: BaseAuditableEntity Properties: - long BlogPostId - string ImagePath - string ThumbnailPath - string? AltText (max 200) - string? Caption (max 300) - int SortOrder Relations: - BlogPost BlogPost ``` #### `SitePage.cs` (صفحات دینامیک) ``` Location: CMS/src/CMSMicroservice.Domain/Entities/Content/SitePage.cs Base: BaseAuditableEntity Properties: - string PageKey (unique, e.g. "about", "contact") — کلید شناسایی - string Title (max 200) - string? MetaDescription (max 300) — SEO - string? HeroTitle — عنوان Hero - string? HeroSubtitle — زیرعنوان Hero - string? HeroImagePath — تصویر Hero - bool IsActive Relations: - ICollection Sections ``` #### `SitePageSection.cs` (بخش‌های صفحه) ``` Location: CMS/src/CMSMicroservice.Domain/Entities/Content/SitePageSection.cs Base: BaseAuditableEntity Properties: - long SitePageId - string SectionKey (e.g. "mission", "vision", "team-member-1") - string Title (max 200) - string? Subtitle (max 300) - string? HtmlContent — محتوای HTML - string? IconName — آیکون Material - string? ImagePath - string? ImageThumbnailPath - int SortOrder - bool IsActive - string? ExtraData — JSON blob for flexible data Relations: - SitePage SitePage ``` #### Enum: `BlogPostStatus.cs` ``` Location: CMS/src/CMSMicroservice.Domain/Enums/BlogPostStatus.cs Values: Draft = 0 Published = 1 Scheduled = 2 Archived = 3 ``` ### 5.2 Entity Configurations (Infrastructure) ``` فایل‌های جدید: CMS/src/CMSMicroservice.Infrastructure/Configurations/Blog/ ├── BlogPostConfiguration.cs ├── BlogCategoryConfiguration.cs ├── BlogPostCategoryConfiguration.cs ├── BlogPostTagConfiguration.cs └── BlogPostImageConfiguration.cs CMS/src/CMSMicroservice.Infrastructure/Configurations/Content/ ├── SitePageConfiguration.cs └── SitePageSectionConfiguration.cs فایل‌های ویرایشی: CMS/src/CMSMicroservice.Infrastructure/ApplicationDbContext.cs + DbSet BlogPosts + DbSet BlogCategories + DbSet BlogPostCategories + DbSet BlogPostTags + DbSet BlogPostImages + DbSet SitePages + DbSet SitePageSections ``` ### 5.3 Proto Definitions #### `blogpost.proto` ``` Location: CMS/src/CMSMicroservice.Protobuf/Protos/blogpost.proto service BlogPostContract { rpc CreateBlogPost (CreateBlogPostRequest) returns (BlogPostResponse); rpc UpdateBlogPost (UpdateBlogPostRequest) returns (BlogPostResponse); rpc DeleteBlogPost (DeleteBlogPostRequest) returns (BoolResponse); rpc GetBlogPost (GetBlogPostRequest) returns (BlogPostResponse); rpc GetBlogPostBySlug (GetBlogPostBySlugRequest) returns (BlogPostResponse); rpc GetAllBlogPosts (GetAllBlogPostsRequest) returns (BlogPostListResponse); rpc GetPublishedBlogPosts (GetPublishedBlogPostsRequest) returns (BlogPostListResponse); rpc GetFeaturedBlogPosts (GetFeaturedBlogPostsRequest) returns (BlogPostListResponse); rpc PublishBlogPost (PublishBlogPostRequest) returns (BoolResponse); rpc ArchiveBlogPost (ArchiveBlogPostRequest) returns (BoolResponse); rpc IncrementViewCount (IncrementViewCountRequest) returns (BoolResponse); } ``` #### `blogcategory.proto` ``` Location: CMS/src/CMSMicroservice.Protobuf/Protos/blogcategory.proto service BlogCategoryContract { rpc CreateBlogCategory (CreateBlogCategoryRequest) returns (BlogCategoryResponse); rpc UpdateBlogCategory (UpdateBlogCategoryRequest) returns (BlogCategoryResponse); rpc DeleteBlogCategory (DeleteBlogCategoryRequest) returns (BoolResponse); rpc GetBlogCategory (GetBlogCategoryRequest) returns (BlogCategoryResponse); rpc GetAllBlogCategories (GetAllBlogCategoriesRequest) returns (BlogCategoryListResponse); } ``` #### `blogpostimage.proto` ``` Location: CMS/src/CMSMicroservice.Protobuf/Protos/blogpostimage.proto service BlogPostImageContract { rpc AddBlogPostImage (AddBlogPostImageRequest) returns (BlogPostImageResponse); rpc DeleteBlogPostImage (DeleteBlogPostImageRequest) returns (BoolResponse); rpc GetBlogPostImages (GetBlogPostImagesRequest) returns (BlogPostImageListResponse); rpc ReorderBlogPostImages (ReorderBlogPostImagesRequest) returns (BoolResponse); } ``` #### `sitepage.proto` ``` Location: CMS/src/CMSMicroservice.Protobuf/Protos/sitepage.proto service SitePageContract { rpc GetSitePage (GetSitePageRequest) returns (SitePageResponse); rpc GetSitePageByKey (GetSitePageByKeyRequest) returns (SitePageResponse); rpc UpdateSitePage (UpdateSitePageRequest) returns (SitePageResponse); rpc GetAllSitePages (GetAllSitePagesRequest) returns (SitePageListResponse); rpc CreateSitePageSection (CreateSitePageSectionRequest) returns (SitePageSectionResponse); rpc UpdateSitePageSection (UpdateSitePageSectionRequest) returns (SitePageSectionResponse); rpc DeleteSitePageSection (DeleteSitePageSectionRequest) returns (BoolResponse); rpc ReorderSitePageSections (ReorderSitePageSectionsRequest) returns (BoolResponse); } ``` ### 5.4 Application Layer (CQRS) ``` CMS/src/CMSMicroservice.Application/ BlogPostCQ/ Commands/ CreateBlogPost/ CreateBlogPostCommand.cs CreateBlogPostCommandHandler.cs CreateBlogPostCommandValidator.cs UpdateBlogPost/ UpdateBlogPostCommand.cs UpdateBlogPostCommandHandler.cs UpdateBlogPostCommandValidator.cs DeleteBlogPost/ DeleteBlogPostCommand.cs DeleteBlogPostCommandHandler.cs PublishBlogPost/ PublishBlogPostCommand.cs PublishBlogPostCommandHandler.cs ArchiveBlogPost/ ArchiveBlogPostCommand.cs ArchiveBlogPostCommandHandler.cs Queries/ GetBlogPost/ GetBlogPostQuery.cs GetBlogPostQueryHandler.cs GetBlogPostBySlug/ GetBlogPostBySlugQuery.cs GetBlogPostBySlugQueryHandler.cs GetAllBlogPosts/ GetAllBlogPostsQuery.cs GetAllBlogPostsQueryHandler.cs GetPublishedBlogPosts/ GetPublishedBlogPostsQuery.cs GetPublishedBlogPostsQueryHandler.cs GetFeaturedBlogPosts/ GetFeaturedBlogPostsQuery.cs GetFeaturedBlogPostsQueryHandler.cs BlogCategoryCQ/ Commands/ CreateBlogCategory/ (3 files) UpdateBlogCategory/ (3 files) DeleteBlogCategory/ (2 files) Queries/ GetBlogCategory/ (2 files) GetAllBlogCategories/ (2 files) BlogPostImageCQ/ Commands/ AddBlogPostImage/ (3 files) DeleteBlogPostImage/ (2 files) ReorderBlogPostImages/ (2 files) Queries/ GetBlogPostImages/ (2 files) SitePageCQ/ Commands/ UpdateSitePage/ (3 files) CreateSitePageSection/ (3 files) UpdateSitePageSection/ (3 files) DeleteSitePageSection/ (2 files) ReorderSitePageSections/ (2 files) Queries/ GetSitePage/ (2 files) GetSitePageByKey/ (2 files) GetAllSitePages/ (2 files) ``` ### 5.5 WebApi Services & Mappings ``` CMS/src/CMSMicroservice.WebApi/ Services/ BlogPostService.cs — extends BlogPostContractBase BlogCategoryService.cs — extends BlogCategoryContractBase BlogPostImageService.cs — extends BlogPostImageContractBase SitePageService.cs — extends SitePageContractBase Common/Mappings/ BlogPostProfile.cs BlogCategoryProfile.cs BlogPostImageProfile.cs SitePageProfile.cs ``` ### 5.6 Migration ```bash # ساخت Migration جدید cd CMS/src/CMSMicroservice.Infrastructure dotnet ef migrations add AddBlogAndSitePages \ --startup-project ../CMSMicroservice.WebApi \ --context ApplicationDbContext ``` --- ## 6. فاز ۲ — پنل مدیریت بلاگ (BackOffice) ✅ تکمیل شد > **تخمین:** ۲-۳ روز | **اولویت:** بالا | **پیش‌نیاز:** فاز ۱ | **وضعیت: تکمیل ✅** ### 6.1 صفحات ایجاد شده BackOffice ``` BackOffice/src/BackOffice/Pages/ Blog/ BlogPostManagementPage.razor — لیست پست‌ها + فیلتر وضعیت/دسته‌بندی + جستجو BlogPostManagementPage.razor.cs — کدبیهایند: LoadServerData، CRUD، Publish، Archive BlogCategoryManagementPage.razor — مدیریت دسته‌بندی‌ها (MudDataGrid) BlogCategoryManagementPage.razor.cs Components/ BlogPostEditDialog.razor — ایجاد/ویرایش پست (عنوان، اسلاگ، خلاصه، HTML، دسته‌بندی‌ها) BlogPostEditDialog.razor.cs — Multi-select دسته‌بندی + ویژه/ترتیب BlogCategoryEditDialog.razor — ایجاد/ویرایش دسته‌بندی BlogCategoryEditDialog.razor.cs Content/ SitePageManagementPage.razor — لیست صفحات سایت SitePageManagementPage.razor.cs — ویرایش صفحه + مدیریت بخش‌ها Components/ SitePageEditDialog.razor — ویرایش اطلاعات صفحه (Hero, Meta, وضعیت) SitePageEditDialog.razor.cs SitePageSectionsDialog.razor — مدیریت بخش‌های صفحه (CRUD + لیست) SitePageSectionsDialog.razor.cs SitePageSectionEditDialog.razor — ایجاد/ویرایش بخش (کلید، عنوان، HTML، تصاویر) SitePageSectionEditDialog.razor.cs ``` ### 6.2 ناوبری BackOffice (NavMenu) ✅ بخش «مدیریت محتوا» به `NavMenu.razor` اضافه شد (قبل از بخش سیستم): ```razor مدیریت محتوا @if (CanManageBlog) { پست‌ها دسته‌بندی‌ها } @if (CanManageSitePages) { صفحات سایت } ``` مجوزهای جدید: `blog.manage`، `sitepages.manage` ### 6.3 سرویس‌های BackOffice ✅ ``` BackOffice/src/BackOffice/Services/ Blog/ IBlogCategoryService.cs — اینترفیس + DTOs (Filter, ListResult, Item, Edit) BlogCategoryService.cs — پیاده‌سازی با gRPC client (GetAll, GetActive, GetById, Create, Update, Delete) IBlogPostService.cs — اینترفیس + DTOs (Filter, ListResult, ListItem, Details, Edit, PublishResult, ArchiveResult) BlogPostService.cs — پیاده‌سازی (CRUD + Publish + Archive) IBlogPostImageService.cs — اینترفیس + DTOs (ImageItem, ImageAdd, ImageSort) BlogPostImageService.cs — پیاده‌سازی (GetByPostId, Add, Delete, Reorder) Content/ ISitePageService.cs — اینترفیس + DTOs (Summary, Details, SectionItem, Edit, SectionEdit, SectionSort) SitePageService.cs — پیاده‌سازی (GetAll, GetById, Update, CRUD Section, Reorder) ``` ثبت DI در `ConfigureService.cs`: - ۴ gRPC Client: `BlogPostContractClient`، `BlogCategoryContractClient`، `BlogPostImageContractClient`، `SitePageContractClient` - ۴ Application Service: `IBlogPostService`، `IBlogCategoryService`، `IBlogPostImageService`، `ISitePageService` ### 6.4 ویرایشگر محتوا از پکیج موجود `Tizzani.MudBlazor.HtmlEditor` (قبلاً نصب شده) استفاده می‌شود: ```razor ``` ### 6.5 آپلود تصویر شاخص از سرویس موجود `IFileManagerService` استفاده: ```csharp // الگوی موجود از ProductService var imagePath = await _fileManagerService.UploadFileAsync(imageBytes, fileName); ``` ### 6.6 مشخصات صفحه مدیریت مقالات | ویژگی | شرح | |-------|------| | جدول مقالات | MudDataGrid با ستون‌های: عنوان، دسته‌بندی، وضعیت، تاریخ انتشار، بازدید | | فیلتر | وضعیت (همه/پیش‌نویس/منتشر/آرشیو) + جستجوی عنوان | | عملیات | ایجاد، ویرایش، حذف، انتشار، آرشیو، پیش‌نمایش | | تصویر شاخص | Drag & Drop آپلود + پیش‌نمایش | | دسته‌بندی | Multi-select از دسته‌بندی‌های موجود | | تگ | Multi-select با autocomplete از تگ‌های موجود | | ویرایشگر | WYSIWYG HTML editor (MudBlazor.HtmlEditor) | --- ## 7. فاز ۳ — صفحات محتوای دینامیک (درباره ما / تماس با ما) ✅ تکمیل شد > **وضعیت:** ✅ تکمیل | **اولویت:** متوسط | **پیش‌نیاز:** فاز ۱ ### 7.1 تغییرات About.razor **قبل (فعلی):** محتوا هاردکد — عنوان‌ها، تصاویر، متون همه در Razor مستقیم نوشته شده **بعد (جدید):** ``` OnInitializedAsync: 1. صدا زدن SitePageContract.GetSitePageByKey("about") 2. دریافت SitePage + Sections 3. نمایش دینامیک با loop روی Sections Fallback: - اگر سرویس خطا داد → نمایش محتوای پیش‌فرض (هاردکد فعلی به عنوان fallback) ``` ساختار بخش‌های صفحه درباره ما: | SectionKey | نوع | داده | |-----------|-----|------| | `hero` | Hero | HeroTitle, HeroSubtitle, HeroImagePath | | `mission` | Card | Title, HtmlContent, IconName | | `vision` | Card | Title, HtmlContent, IconName | | `value-1` ... `value-N` | Cards Grid | Title, Subtitle, IconName, HtmlContent | | `team-1` ... `team-N` | Team Cards | Title (نام), Subtitle (سمت), HtmlContent (توضیح), ImagePath | ### 7.2 تغییرات Contact.razor | SectionKey | نوع | داده | |-----------|-----|------| | `hero` | Hero | HeroTitle, HeroSubtitle | | `contact-info` | Info | ExtraData (JSON: address, phone, email, hours) | | `social-media` | Links | ExtraData (JSON: telegram, instagram, linkedin, whatsapp urls) | | `map` | Map | ExtraData (JSON: lat, lng, address text) | ### 7.3 Seed Data اجرای اولیه Migration با داده پیش‌فرض (محتوای هاردکد فعلی): ```csharp // در SitePageConfiguration یا Seed Migration var aboutPage = new SitePage { PageKey = "about", Title = "درباره ما", HeroTitle = "پلتفرم هوشمند تیم‌سازی و مدیریت فروش", HeroSubtitle = "ما با ارائه ابزارهای نوآورانه...", IsActive = true }; // + Sections با محتوای فعلی ``` --- ## 8. فاز ۴ — نوسازی لندینگ پیج ✅ تکمیل شد > **وضعیت:** ✅ تکمیل | **اولویت:** بالا | **پیش‌نیاز:** فاز ۱ (بخش بلاگ برای "آخرین مقالات") ### 8.1 ساختار جدید لندینگ پیج ``` ┌─────────────────────────────────────────┐ │ 🔝 HERO SECTION │ │ • Gradient animated background │ │ • عنوان بزرگ + زیرعنوان │ │ • Badge‌های انیمیشنی │ │ • CTA buttons با hover effects │ │ • تصویر/ایلاستریشن سمت چپ │ │ • اعداد زنده (تعداد کاربران، ...) │ └─────────────────────────────────────────┘ ↓ Scroll indicator ↓ ┌─────────────────────────────────────────┐ │ ✨ FEATURES (چرا ما؟) │ │ • 6 کارت با آیکون + عنوان + توضیح │ │ • Hover effect (scale + shadow) │ │ • انیمیشن fade-in on scroll │ └─────────────────────────────────────────┘ ┌─────────────────────────────────────────┐ │ 📊 LIVE STATS (آمار زنده) │ │ • Counter animation (شمارش تعداد) │ │ • تعداد کاربران فعال │ │ • تعداد محصولات │ │ • حجم معاملات │ │ • Intersection Observer trigger │ └─────────────────────────────────────────┘ ┌─────────────────────────────────────────┐ │ 🔄 HOW IT WORKS (چطور کار می‌کند) │ │ • Timeline بهبودیافته │ │ • آیکون‌های مرحله‌ای بزرگ‌تر │ │ • انیمیشن step-by-step │ └─────────────────────────────────────────┘ ┌─────────────────────────────────────────┐ │ 📝 LATEST BLOG (آخرین مقالات) │ ← جدید! │ • ۳ کارت آخرین مقالات منتشرشده │ │ • تصویر شاخص + عنوان + خلاصه │ │ • دکمه "مشاهده همه مقالات" │ │ • Loading skeleton │ └─────────────────────────────────────────┘ ┌─────────────────────────────────────────┐ │ 🏆 TESTIMONIALS (اعتماد مشتریان) │ │ • Carousel/Swiper اسلایدر │ │ • Avatar + نام + سمت + نقل قول │ │ • Auto-play + دکمه‌های ناوبری │ └─────────────────────────────────────────┘ ┌─────────────────────────────────────────┐ │ ❓ FAQ (سوالات متداول) │ │ • بدون تغییر اساسی (فقط پولیش) │ └─────────────────────────────────────────┘ ┌─────────────────────────────────────────┐ │ 📞 CTA BANNER (دعوت نهایی) │ ← جدید! │ • Gradient background │ │ • عنوان جذاب + دکمه ثبت‌نام │ │ • طرح ساده و تأثیرگذار │ └─────────────────────────────────────────┘ ┌─────────────────────────────────────────┐ │ 🦶 FOOTER │ │ • بدون تغییر اساسی + لینک بلاگ │ └─────────────────────────────────────────┘ ``` ### 8.2 تغییرات فنی لندینگ #### الف) Hero Section بهبودیافته ``` تغییرات: 1. Animated gradient background (CSS keyframes) 2. اعداد واقعی از API (تعداد کاربران، محصولات، ...) 3. Badge‌ها با انیمیشن pulse 4. Scroll-down indicator (chevron انیمیشنی) 5. تصویر/SVG illustration سمت چپ ``` #### ب) آمار زنده (Live Stats) ``` سرویس جدید — یک Query ساده در CMS: GetPlatformStats → { UserCount, ProductCount, OrderCount, ... } فرانت: - Counter animation (JS interop یا CSS counter) - Intersection Observer: فقط وقتی اسکرول به این بخش رسید شمارش شروع شود ``` #### ج) بخش آخرین مقالات (جدید) ```razor
آخرین مقالات @foreach (var post in _latestPosts.Take(3)) { } مشاهده همه
``` #### د) CTA Banner نهایی (جدید) ```razor
آماده شروع هستید؟ همین الان ثبت‌نام کنید و از مزایای کارا بازار سلامت بهره‌مند شوید. شروع رایگان
``` ### 8.3 CSS جدید / بهبودیافته ```css /* فایل: wwwroot/css/app.css — بخش‌های جدید */ /* Animated gradient hero */ .hero-section { background: linear-gradient(-45deg, #6366f1, #8b5cf6, #a855f7, #6366f1); background-size: 400% 400%; animation: gradientShift 8s ease infinite; } @keyframes gradientShift { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } } /* Scroll-triggered fade-in */ .fade-in-up { opacity: 0; transform: translateY(30px); transition: opacity 0.6s ease, transform 0.6s ease; } .fade-in-up.visible { opacity: 1; transform: translateY(0); } /* Counter animation */ @property --num { syntax: ''; initial-value: 0; inherits: false; } .counter { animation: counter 2s ease-out forwards; counter-reset: num var(--num); } /* Pulse badge */ .pulse-badge { animation: pulse 2s infinite; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(99,102,241,0.4); } 70% { box-shadow: 0 0 0 10px rgba(99,102,241,0); } 100% { box-shadow: 0 0 0 0 rgba(99,102,241,0); } } /* CTA Banner */ .cta-banner { background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); color: white; border-radius: 24px; margin: 2rem; } /* Card hover effects */ .feature-card-v2 { transition: transform 0.3s, box-shadow 0.3s; } .feature-card-v2:hover { transform: translateY(-8px); box-shadow: 0 12px 40px rgba(0,0,0,0.12); } /* Blog post card */ .blog-card { transition: transform 0.3s ease; overflow: hidden; } .blog-card:hover { transform: translateY(-4px); } .blog-card .blog-card-image { transition: transform 0.5s ease; } .blog-card:hover .blog-card-image { transform: scale(1.05); } ``` ### 8.4 JS Interop (حداقل) ```javascript // فایل: wwwroot/js/landing.js // Intersection Observer for fade-in animations window.initScrollAnimations = () => { const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('visible'); observer.unobserve(entry.target); } }); }, { threshold: 0.1 }); document.querySelectorAll('.fade-in-up').forEach(el => observer.observe(el)); }; // Counter animation window.animateCounter = (elementId, target, duration) => { const el = document.getElementById(elementId); if (!el) return; let start = 0; const step = target / (duration / 16); const timer = setInterval(() => { start += step; if (start >= target) { start = target; clearInterval(timer); } el.textContent = Math.floor(start).toLocaleString('fa-IR'); }, 16); }; ``` --- ## 9. فاز ۵ — صفحات بلاگ فرانت‌آفیس ✅ تکمیل شد > **وضعیت:** ✅ تکمیل | **اولویت:** بالا | **پیش‌نیاز:** فاز ۱ ### 9.1 صفحات ایجاد شده (واقعی) ``` FrontOffice/src/FrontOffice.Main/Pages/Blog/ Index.razor — لیست مقالات با جستجو + فیلتر دسته‌بندی + صفحه‌بندی Index.razor.cs — LoadPostsAsync، OnCategoryChanged، OnPageChanged، NavigateToPost Post.razor — صفحه جزئیات مقاله (تصویر شاخص، breadcrumb، HTML، تگ‌ها) Post.razor.cs — OnParametersSetAsync (لود slug)، IncrementViewCount خودکار ``` ### 9.2 سرویس‌های جدید فرانت‌آفیس ``` FrontOffice/src/FrontOffice.Main/Utilities/ BlogPostService.cs — (قبلاً فاز ۴ ایجاد شد) GetFeatured, GetPublished, GetBySlug, IncrementView BlogCategoryService.cs — GetActiveCategoriesAsync (فیلتر سایدبار بلاگ) ``` **DTOs تعریف شده در `BlogPostService.cs`:** - `BlogPostCardDto` — Id, Title, Slug, Summary, ThumbnailUrl, PublishedAt, ViewCount, IsFeatured, Categories - `BlogPostDetailDto` — همه فیلدهای کارت + HtmlContent, FeaturedImagePath, Tags - `BlogPostListResult` — Posts, TotalCount, TotalPages, CurrentPage - `BlogCategoryInfo` — Id, Title, Slug - `BlogTagInfo` — Id, Title, Name **DTO تعریف شده در `BlogCategoryService.cs`:** - `BlogCategoryDto` — Id, Title, Slug, Description, IconName, PostCount ### 9.3 مسیرها (Routes) — پیاده‌سازی شده ```csharp // RouteConstants.cs public static class Blog { public const string Index = "/blog"; public const string Post = "/blog/"; // usage: /blog/{slug} } ``` ### 9.4 طراحی صفحه لیست بلاگ — پیاده‌سازی شده ``` ┌─────────────────────────────────────────┐ │ Blog Hero (گرادیان بنفش) │ │ "بلاگ" │ │ "آخرین مطالب، آموزش‌ها و اخبار" │ └─────────────────────────────────────────┘ ┌─────────────────────────────────────────┐ │ [جستجو...] [دسته‌بندی ▼] [جستجو 🔍] │ ← فیلتر + MudSelect └─────────────────────────────────────────┘ ┌────────┐ ┌────────┐ ┌────────┐ │ Card 1 │ │ Card 2 │ │ Card 3 │ ← blog-card-v2 │ thumb │ │ thumb │ │ thumb │ ← تصویر شاخص │ cat │ │ cat │ │ cat │ ← chip دسته‌بندی │ title │ │ title │ │ title │ ← ۲ خط clamp │ desc │ │ desc │ │ desc │ ← ۲ خط clamp │ 📅 👁 │ │ 📅 👁 │ │ 📅 👁 │ ← تاریخ + بازدید └────────┘ └────────┘ └────────┘ ← ← ← [1] [2] [3] → → → ← MudPagination ``` ### 9.5 طراحی صفحه مقاله — پیاده‌سازی شده ``` ┌─────────────────────────────────────────┐ │ [تصویر شاخص full-width] + overlay │ └─────────────────────────────────────────┘ ┌─────────────────────────────────────────┐ │ خانه > بلاگ > عنوان مقاله │ ← Breadcrumb │ │ │ [دسته‌بندی ۱] [دسته‌بندی ۲] │ ← Chips (کلیک → فیلتر) │ │ │ عنوان مقاله (H4, bold) │ │ خلاصه مقاله (subtitle) │ │ │ │ 📅 تاریخ 👁 ۱,۲۳۴ بازدید │ │ ───────────────────────── │ │ │ │ [محتوای HTML مقاله] │ ← blog-content (styled) │ ... │ │ │ │ ───────────────────────── │ │ 🏷️ [تگ ۱] [تگ ۲] [تگ ۳] │ ← Outlined chips │ │ │ [← بازگشت به بلاگ] │ └─────────────────────────────────────────┘ ``` ### 9.6 CSS اضافه شده (بخش Blog Pages در site.css) ```css /* Blog Pages region — اضافه شده به site.css */ .blog-hero — گرادیان بنفش (مشابه CTA) .blog-title-clamp — -webkit-line-clamp: 2 .blog-summary-clamp — -webkit-line-clamp: 2 .cursor-pointer — cursor: pointer .blog-detail-hero — تصویر شاخص 340px + overlay .blog-content — تایپوگرافی مقاله (h1-h3, p, img, blockquote, code, pre, ul/ol, a) /* + mobile overrides + dark mode */ ``` ### 9.7 ناوبری — لینک بلاگ اضافه شد ✅ ``` تغییرات واقعی: - MainLayout.razor → لینک "بلاگ" در navbar دسکتاپ (بین FAQ و Contact) - MainLayout.razor → لینک "بلاگ" در Mobile Drawer - Index.razor (لندینگ) → کارت‌های بلاگ کلیک‌پذیر شدند (onclick) - Index.razor (لندینگ) → دکمه "مشاهده همه مقالات" فعال شد (uncomment) ``` ### 9.8 ثبت DI (ConfigureServices.cs) ```csharp // اضافه شده: using CMSMicroservice.Protobuf.Protos.BlogCategory; // Common services: services.AddScoped(); // gRPC clients: services.AddScoped(CreateAuthenticatedClient); ``` --- ## 10. فاز ۶ — بهبود داشبورد کاربر ✅ تکمیل شد > **وضعیت:** ✅ تکمیل | **اولویت:** متوسط | **پیش‌نیاز:** ندارد ### 10.1 بازطراحی کامل Profile/Index.razor صفحه `/profile` به طور کامل با طراحی مدرن بازنویسی شد: ``` ┌─────────────────────────────────────────┐ │ ████ GRADIENT HEADER CARD ████ │ ← .dash-header-card │ 🧑 آواتار شیشه‌ای | نام + موبایل │ ← .dash-avatar │ عضو از ... | [💎 سامانه دایا] │ ← دکمه glass-morphism └─────────────────────────────────────────┘ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ 💳 اعتباری│ │ 🏷 تخفیف │ │ 👥 تیمی │ ← .dash-wallet-card │ ۲.۵M تومان│ │ ۵۰۰K │ │ ۸۵۰K │ (hover lift) └──────────┘ └──────────┘ └──────────┘ ┌─────────────────────────────────────────┐ │ 📎 کد دعوت شما | [اشتراک‌گذاری] │ ← فعال اگر پکیج + باشگاه │ یا │ │ 🔒 لینک دعوت فعال نشده (dashed border)│ ← حالت قفل │ [شروع فرآیند تامین اعتبار] │ └─────────────────────────────────────────┘ ┌─────────────────────────────────────────┐ │ دسترسی سریع │ ← .dash-tile (10 تایل) │ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │ │ │شخصی│ │آدرس│ │شجره│ │تنظیم│ │ هر تایل: │ └────┘ └────┘ └────┘ └────┘ │ - آواتار رنگی │ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │ - عنوان + زیرعنوان │ │فروش│ │کیف │ │برداشت│ │باشگا│ │ - hover: lift + primary border │ └────┘ └────┘ └────┘ └────┘ │ │ ┌────┐ ┌────┐ │ │ │آمار│ │پاداش│ │ │ └────┘ └────┘ │ └─────────────────────────────────────────┘ ``` ### 10.2 تغییرات فایل‌ها **`Profile/Index.razor`** — بازنویسی کامل: - هدر گرادیانی (`dash-header-card`) با آواتار شیشه‌ای - ۳ کارت والت جداگانه (اعتباری/تخفیف/تیمی) با رنگ‌های مختلف - بخش رفرال تمیزتر (فعال با TextField + دکمه | قفل با dashed border) - ۱۰ تایل مدرن با `DashTile` record + آواتار رنگی **`Profile/Index.razor.cs`** — اضافه شده: ```csharp private readonly List _dashTiles = new() { new(RouteConstants.Profile.Personal, Icons.Material.Filled.Person, "اطلاعات شخصی", ...), new(RouteConstants.Profile.Addresses, Icons.Material.Filled.LocationOn, "آدرس‌ها", ...), // ... 10 تایل با رنگ‌بندی اختصاصی }; private record DashTile(string Href, string Icon, string Title, string Subtitle, string AvatarStyle); ``` ### 10.3 CSS اضافه شده (بخش Dashboard v2 در site.css) ```css /* Dashboard v2 region */ .dash-header-card — گرادیان بنفش + دایره تزئینی .dash-avatar — شیشه‌ای (rgba + border سفید) .dash-wallet-card — border + hover lift .dash-tile — border + hover lift + primary border on hover /* + dark mode + mobile overrides */ ``` --- ## 11. فاز ۷ — بهینه‌سازی موبایل ✅ تکمیل شد > **وضعیت:** ✅ تکمیل | **اولویت:** بالا | **پیش‌نیاز:** فازهای ۴-۶ ### 11.1 مشکلات شناسایی و رفع شده | مشکل | وضعیت قبل | راه‌حل | |------|----------|--------| | **Dead Zone ناوبری (600-959px)** | همبرگر فقط زیر 600px، لینک‌ها فقط بالای 960px | تغییر Breakpoint از `SmAndUp` به `MdAndUp` | | **فوتر پنهان در موبایل** | `DeviceDetector.IsDesktop()` فوتر را حذف می‌کرد | حذف شرط — فوتر همیشه نمایش داده شود | | **عدم وجود Bottom Nav** | فقط Drawer برای ناوبری موبایل | اضافه شدن bottom-nav ثابت (5 لینک) | | **تایپوگرافی بزرگ** | h1=2rem, h2=1.875rem ثابت | responsive: h1→1.5rem, h2→1.35rem در موبایل | | **Touch targets کوچک** | Dense AppBar، لینک‌های Drawer بدون padding | min-height: 44px برای لینک‌ها، 40px برای آیکون‌ها | | **نقشه تماس بلند** | 400px ثابت | 240px در موبایل با کلاس `contact-map-placeholder` | | **دکمه‌های About تنگ** | Row بدون flex-wrap | اضافه flex-wrap + full-width در موبایل | | **محتوای بلاگ overflow** | بدون guard | `overflow-x: auto` + table/iframe responsive | | **هاور در تاچ** | جلوه‌های هاور در صفحه لمسی | `@media (hover: none)` — غیرفعال | | **Safe area** | بدون padding | `env(safe-area-inset-*)` برای notched phones | | **theme-color** | نداشت | `` | ### 11.2 Bottom Navigation — پیاده‌سازی ``` ┌──────────────────────────────────────┐ │ 🏠 🏬 📰 🛒 👤 │ ← .bottom-nav (fixed) │ خانه فروش بلاگ سبد پروفایل │ backdrop-filter blur └──────────────────────────────────────┘ ``` - فقط در زیر `Breakpoint.MdAndUp` نمایش داده شود (`MudHidden`) - اگر لاگین نباشد: دکمه "ورود" بجای "سبد خرید" و "پروفایل" - `padding-bottom: 68px` روی `.main-content-wrapper` برای جلوگیری از overlap - `env(safe-area-inset-bottom)` برای گوشی‌های notched ### 11.3 CSS اضافه شده (بخش Phase 7 در site.css ~120 خط) ``` .bottom-nav — fixed, z-1100, rounded top, glass blur .bottom-nav-item — flex column, min 48px touch, transition color .main-content-wrapper — padding-bottom 68px (≤960px) responsive typography — h1-h5 smaller ≤600px touch targets — drawer links 44px, appbar icons 40px footer mobile — compact padding, smaller text landing mobile — smaller chips, timeline text blog mobile — shorter thumbnails, scaled pagination, overflow guard dashboard mobile — compact wallets + tiles about mobile — hero button wrap, reduced padding contact mobile — shorter map, full-width submit global mobile — tighter container padding, safe-area @media (hover: none) — disable hover transforms on touch ``` ### 11.4 فایل‌های تغییریافته ``` MainLayout.razor — Breakpoint fix + Bottom Nav + Footer gate removed site.css — +120 خط CSS موبایل (Phase 7 region) _Host.cshtml — +theme-color + apple-mobile-web-app meta tags Contact.razor — +class contact-map-placeholder About.razor — +flex-wrap روی دکمه‌های hero ``` --- ## 12. فایل‌های تغییریافته (نقشه فایل‌ها) ### فایل‌های جدید | پروژه | مسیر | تعداد فایل | |--------|------|-----------| | **CMS Domain** | `Entities/Blog/` (BlogPost, BlogCategory, BlogTag, BlogPostCategory, BlogPostTag, BlogPostImage) + `Entities/Content/` (SitePage, SitePageAttachment) + `Enums/` (BlogPostStatus) | **9** | | **CMS Infrastructure** | `Configurations/Blog/` (5) + `Configurations/Content/` (2) + EF Migration | **8** | | **CMS Application** | `BlogPostCQ/` (~25) + `BlogCategoryCQ/` (~12) + `BlogPostImageCQ/` (~9) + `SitePageCQ/` (~18) | **~64** | | **CMS Protobuf** | `public_messages.proto` + `blogpost.proto` + `blogcategory.proto` + `sitepage.proto` | **4** | | **CMS WebApi** | `Services/` (BlogPostService, BlogCategoryService, SitePageService, BlogPostImageService) + `Mappings/` (4 profiles) | **8** | | **BackOffice Pages** | `Pages/Blog/` (BlogPosts.razor, BlogCategories.razor + ۲ dialog) + `Pages/Content/` (SitePages.razor + ۳ dialog) | **10** | | **BackOffice Services** | `Services/Blog/` (BlogPostService, BlogCategoryService, BlogTagService + ۳ model) + `Services/Content/` (SitePageService + model) | **8** | | **FrontOffice Pages** | `Pages/Blog/Index.razor` + `Index.razor.cs` + `Post.razor` + `Post.razor.cs` | **4** | | **FrontOffice Services** | `Utilities/BlogPostService.cs` + `Utilities/BlogCategoryService.cs` + `Utilities/SitePageService.cs` | **3** | | **FrontOffice Assets** | `wwwroot/js/landing.js` | **1** | | | | **~119 فایل جدید** | ### فایل‌های ویرایشی | پروژه | فایل | تغییر | |--------|------|-------| | CMS Infrastructure | `ApplicationDbContext.cs` | +7 DbSets (BlogPost, BlogCategory, BlogTag, BlogPostCategory, BlogPostTag, BlogPostImage, SitePage) | | CMS WebApi | `Program.cs` | +4 gRPC service registrations | | BackOffice | `Shared/NavMenu.razor` | +بخش مدیریت محتوا (بلاگ + صفحات) + ۲ مجوز جدید | | BackOffice | `Common/Configure/ConfigureService.cs` | +4 gRPC clients + 4 services + using statements | | FrontOffice | `Pages/Index.razor` | بازنویسی کامل (Hero + Features + Timeline + Stats + Blog + Testimonials + FAQ + CTA) | | FrontOffice | `Pages/Index.razor.cs` | +LoadFeaturedPosts + NavigateToPost | | FrontOffice | `Pages/About.razor` | تبدیل به دینامیک (CMS + fallback) | | FrontOffice | `Pages/Contact.razor` | تبدیل به دینامیک (CMS + fallback) | | FrontOffice | `Pages/Profile/Index.razor` | بازنویسی کامل (header card + wallets + tiles) | | FrontOffice | `Pages/Profile/Index.razor.cs` | +DashTile record + _dashTiles لیست | | FrontOffice | `Shared/MainLayout.razor` | +لینک بلاگ (desktop + mobile drawer) | | FrontOffice | `Common/Configure/ConfigureServices.cs` | +BlogCategoryService + BlogCategoryContract gRPC | | FrontOffice | `Utilities/RouteConstants.cs` | +Blog.Index + Blog.Post routes | | FrontOffice | `wwwroot/css/site.css` | +Landing v2 + Blog Pages + Dashboard v2 (~300 خط CSS) | | FrontOffice | `Pages/_Host.cshtml` | +landing.js script reference | | | | **~15 فایل ویرایشی** | --- ## 13. جدول زمانی ``` هفته ۱: ├─ فاز ۱: موجودیت‌های بکند (Entities + Protos + CQRS) [۲-۳ روز] ✅ تکمیل └─ فاز ۲: پنل مدیریت بلاگ BackOffice [۲-۳ روز] ✅ تکمیل هفته ۲: ├─ فاز ۳: صفحات دینامیک (About + Contact) [۱-۲ روز] ✅ تکمیل ├─ فاز ۴: نوسازی لندینگ پیج [۲-۳ روز] ✅ تکمیل └─ فاز ۵: صفحات بلاگ FrontOffice [۲-۳ روز] ✅ تکمیل هفته ۳: ├─ فاز ۶: بهبود داشبورد کاربر [۱-۲ روز] ✅ تکمیل ├─ فاز ۷: بهینه‌سازی موبایل [۱-۲ روز] ✅ تکمیل └─ تست + رفع باگ + دیپلوی [۱-۲ روز] ``` **مجموع تخمین: ۱۲-۲۰ روز کاری (۲.۵ تا ۴ هفته)** ### ترتیب وابستگی ``` فاز ۱ (Backend) ──► فاز ۲ (Admin Blog) │ ├──────────► فاز ۳ (Dynamic Pages) │ ├──────────► فاز ۵ (FrontOffice Blog) │ │ │ ▼ └──────────► فاز ۴ (Landing) ──► فاز ۷ (Mobile) ▲ فاز ۶ (Dashboard) ───────┘ ``` --- ## 14. ریسک‌ها و وابستگی‌ها | ریسک | احتمال | تأثیر | راه‌حل | |------|--------|-------|--------| | WYSIWYG Editor محدودیت RTL | متوسط | متوسط | تست اولیه MudBlazor.HtmlEditor با فارسی، fallback به textarea + markdown | | حجم Migration بزرگ | کم | بالا | Migration را تکه‌تکه اجرا کن (Blog اول، SitePage بعد) | | عملکرد لندینگ با انیمیشن‌ها | متوسط | متوسط | Lazy load + Intersection Observer + حداقل JS | | FMS قطعی هنگام آپلود تصویر | کم | بالا | Retry policy + پیام خطای مناسب | | Slug فارسی در URL | متوسط | کم | استفاده از ID-based URLs با slug فقط برای SEO | | سازگاری Dark Mode | متوسط | کم | تست هر بخش در هر دو حالت | --- ## ضمیمه: نمونه کد الگوهای کلیدی ### A. الگوی Entity (مطابق پروژه) ```csharp // Domain/Entities/Blog/BlogPost.cs public class BlogPost : BaseAuditableEntity { public string Title { get; set; } = default!; public string Slug { get; set; } = default!; public string? Summary { get; set; } public string HtmlContent { get; set; } = default!; public string? FeaturedImagePath { get; set; } public string? FeaturedImageThumbnailPath { get; set; } public BlogPostStatus Status { get; set; } = BlogPostStatus.Draft; public DateTime? PublishedAt { get; set; } public int ViewCount { get; set; } public long AuthorUserId { get; set; } public bool IsFeatured { get; set; } public int SortOrder { get; set; } public ICollection BlogPostCategories { get; set; } = new List(); public ICollection BlogPostTags { get; set; } = new List(); public ICollection BlogPostImages { get; set; } = new List(); } ``` ### B. الگوی Proto (مطابق پروژه) ```protobuf // blogpost.proto syntax = "proto3"; option csharp_namespace = "CMSMicroservice.Protobuf"; import "google/protobuf/timestamp.proto"; import "google/protobuf/wrappers.proto"; service BlogPostContract { rpc CreateBlogPost (CreateBlogPostRequest) returns (BlogPostResponse); rpc GetPublishedBlogPosts (GetPublishedBlogPostsRequest) returns (BlogPostListResponse); // ... } message CreateBlogPostRequest { string title = 1; string slug = 2; string summary = 3; string html_content = 4; bytes featured_image = 5; string featured_image_file_name = 6; repeated int64 category_ids = 7; repeated int64 tag_ids = 8; bool is_featured = 9; } message BlogPostResponse { int64 id = 1; string title = 2; string slug = 3; string summary = 4; string html_content = 5; string featured_image_path = 6; string featured_image_thumbnail_path = 7; int32 status = 8; google.protobuf.Timestamp published_at = 9; int32 view_count = 10; bool is_featured = 11; repeated BlogCategoryInfo categories = 12; repeated TagInfo tags = 13; } ``` ### C. الگوی CQRS Handler (مطابق پروژه) ```csharp // Application/BlogPostCQ/Commands/CreateBlogPost/CreateBlogPostCommandHandler.cs public class CreateBlogPostCommandHandler : IRequestHandler { private readonly IApplicationDbContext _context; private readonly IFileManagerService _fileManager; public CreateBlogPostCommandHandler( IApplicationDbContext context, IFileManagerService fileManager) { _context = context; _fileManager = fileManager; } public async Task Handle(CreateBlogPostCommand request, CancellationToken ct) { var post = new BlogPost { Title = request.Title, Slug = request.Slug, Summary = request.Summary, HtmlContent = request.HtmlContent, Status = BlogPostStatus.Draft, AuthorUserId = request.AuthorUserId, }; if (request.FeaturedImage?.Length > 0) { var (path, thumb) = await _fileManager.UploadFileAsync( request.FeaturedImage, request.FeaturedImageFileName); post.FeaturedImagePath = path; post.FeaturedImageThumbnailPath = thumb; } _context.BlogPosts.Add(post); await _context.SaveChangesAsync(ct); // Add categories & tags... return post.Id; } } ``` ### D. الگوی gRPC Service (مطابق پروژه) ```csharp // WebApi/Services/BlogPostService.cs public class BlogPostService : BlogPostContract.BlogPostContractBase { private readonly IMediator _mediator; private readonly IMapper _mapper; public BlogPostService(IMediator mediator, IMapper mapper) { _mediator = mediator; _mapper = mapper; } public override async Task CreateBlogPost( CreateBlogPostRequest request, ServerCallContext context) { var command = _mapper.Map(request); var id = await _mediator.Send(command); // Get and return the created post... } } ``` --- > **یادداشت:** این سند یک نقشه‌راه جامع است. هر فاز به صورت مستقل قابل پیاده‌سازی است و وابستگی‌ها در بخش ۱۳ مشخص شده‌اند. بعد از تأیید این طرح، پیاده‌سازی فاز به فاز شروع می‌شود.