Files
docs/ui-modernization/UI-MODERNIZATION-PLAN.md
T

1419 lines
60 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🎨 طرح نوسازی رابط کاربری فرانت‌آفیس + سیستم بلاگ
> **تاریخ شروع:** تیر ۱۴۰۴
> **آخرین بروزرسانی:** بهمن ۱۴۰۴
> **وضعیت:** فازهای ۱ تا ۶ تکمیل ✅ — فاز ۷ در حال اجرا
> **اولویت:** بالا
---
## فهرست مطالب
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<BlogPostCategory> BlogPostCategories
- ICollection<BlogPostTag> BlogPostTags
- ICollection<BlogPostImage> 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<BlogPostCategory> 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<SitePageSection> 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<BlogPost> BlogPosts
+ DbSet<BlogCategory> BlogCategories
+ DbSet<BlogPostCategory> BlogPostCategories
+ DbSet<BlogPostTag> BlogPostTags
+ DbSet<BlogPostImage> BlogPostImages
+ DbSet<SitePage> SitePages
+ DbSet<SitePageSection> 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
<MudText Class="nav-menu__title" Typo="Typo.subtitle2">مدیریت محتوا</MudText>
<AuthorizeView Roles="Administrator">
<Authorized>
@if (CanManageBlog)
{
<MudNavGroup Title="بلاگ" Icon="@Icons.Material.Filled.Article" Expanded="false">
<MudNavLink Href="/blog/posts" Icon="@Icons.Material.Filled.PostAdd">پست‌ها</MudNavLink>
<MudNavLink Href="/blog/categories" Icon="@Icons.Material.Filled.Category">دسته‌بندی‌ها</MudNavLink>
</MudNavGroup>
}
@if (CanManageSitePages)
{
<MudNavLink Href="/content/pages" Icon="@Icons.Material.Filled.WebAsset">صفحات سایت</MudNavLink>
}
</Authorized>
</AuthorizeView>
```
مجوزهای جدید: `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
<!-- در CreateBlogPostDialog -->
<MudHtmlEditor @bind-Value="_post.HtmlContent"
Placeholder="محتوای مقاله را بنویسید..."
MinHeight="400px" />
```
### 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
<!-- Latest Blog Posts Section -->
<section class="py-16">
<MudContainer MaxWidth="MaxWidth.Large">
<MudText Typo="Typo.h4" Align="Align.Center">آخرین مقالات</MudText>
<MudGrid Spacing="4">
@foreach (var post in _latestPosts.Take(3))
{
<MudItem xs="12" md="4">
<BlogPostCard Post="post" />
</MudItem>
}
</MudGrid>
<MudButton Href="/blog" Variant="Variant.Outlined">مشاهده همه</MudButton>
</MudContainer>
</section>
```
#### د) CTA Banner نهایی (جدید)
```razor
<!-- Final CTA -->
<section class="cta-banner py-16">
<MudContainer MaxWidth="MaxWidth.Medium">
<MudStack AlignItems="AlignItems.Center" Spacing="4">
<MudText Typo="Typo.h3">آماده شروع هستید؟</MudText>
<MudText>همین الان ثبت‌نام کنید و از مزایای کارا بازار سلامت بهره‌مند شوید.</MudText>
<MudButton Variant="Variant.Filled" Color="Color.Primary" Size="Size.Large">
شروع رایگان
</MudButton>
</MudStack>
</MudContainer>
</section>
```
### 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: '<integer>';
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<BlogCategoryService>();
// gRPC clients:
services.AddScoped(CreateAuthenticatedClient<BlogCategoryContract.BlogCategoryContractClient>);
```
---
## 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<DashTile> _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** | نداشت | `<meta name="theme-color" content="#7c4dff">` |
### 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<BlogPostCategory> BlogPostCategories { get; set; } = new List<BlogPostCategory>();
public ICollection<BlogPostTag> BlogPostTags { get; set; } = new List<BlogPostTag>();
public ICollection<BlogPostImage> BlogPostImages { get; set; } = new List<BlogPostImage>();
}
```
### 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<CreateBlogPostCommand, long>
{
private readonly IApplicationDbContext _context;
private readonly IFileManagerService _fileManager;
public CreateBlogPostCommandHandler(
IApplicationDbContext context,
IFileManagerService fileManager)
{
_context = context;
_fileManager = fileManager;
}
public async Task<long> 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<BlogPostResponse> CreateBlogPost(
CreateBlogPostRequest request, ServerCallContext context)
{
var command = _mapper.Map<CreateBlogPostCommand>(request);
var id = await _mediator.Send(command);
// Get and return the created post...
}
}
```
---
> **یادداشت:** این سند یک نقشه‌راه جامع است. هر فاز به صورت مستقل قابل پیاده‌سازی است و وابستگی‌ها در بخش ۱۳ مشخص شده‌اند. بعد از تأیید این طرح، پیاده‌سازی فاز به فاز شروع می‌شود.