# 📄 Dynamic Content Pages System - Implementation Plan

## نگاه کلی

یک سیستم **مدیریت محتوای پویا (Dynamic CMS)** برای مدیریت صفحات استاتیک مانند:
- درباره ما (About Us)
- تماس با ما (Contact Us)
- قوانین و مقررات (Terms & Conditions)
- حریم خصوصی (Privacy Policy)
- سوالات متداول (FAQ)
- و هر صفحه دلخواه دیگر

### ویژگی‌های کلیدی
- ✅ **Flexible Structure**: هر صفحه می‌تواند چندین بخش (Section) داشته باشد
- ✅ **Multi-Section Types**: Hero, TextBlock, ImageGallery, ContactForm, TeamMembers, FAQ, etc.
- ✅ **JSON-Based Content**: محتوای هر Section به صورت JSON ذخیره می‌شود
- ✅ **Reorderable**: امکان تغییر ترتیب Sections با Drag & Drop
- ✅ **SEO-Friendly**: Meta Tags, Structured Data, Sitemap
- ✅ **Multi-Language Ready**: آماده برای چند زبانه (فارسی/انگلیسی)
- ✅ **BackOffice Management**: مدیریت کامل از پنل ادمین

---

## معماری سیستم

```
┌─────────────────────────────────────────────────────────────┐
│                     ContentPage Table                        │
├─────────────────────────────────────────────────────────────┤
│ Id, Slug (about-us), Title, MetaDescription,                │
│ IsActive, IsPublic, SortOrder, Created, CreatedBy           │
└────────────────────┬────────────────────────────────────────┘
                     │ 1-to-Many
                     ▼
┌─────────────────────────────────────────────────────────────┐
│                   ContentSection Table                       │
├─────────────────────────────────────────────────────────────┤
│ Id, PageId (FK), SectionType (Enum), Title,                 │
│ Content (JSON), SortOrder, IsActive, Created                │
└─────────────────────────────────────────────────────────────┘

SectionType Enum:
- Hero
- TextBlock
- ImageGallery
- ContactForm
- TeamMembers
- FAQ
- Map
- SocialMedia
```

---

## مراحل پیاده‌سازی (7 مرحله)

### ✅ Phase 1: Domain Layer - Entities

**مسیر**: `CMS/src/CMSMicroservice.Domain/Entities/Content/`

#### 1.1 Create `ContentPage.cs`
```csharp
namespace CMSMicroservice.Domain.Entities.Content;

public class ContentPage : BaseAuditableEntity
{
    public long Id { get; set; }
    
    // Core Properties
    public string Slug { get; set; } = string.Empty;         // "about-us", "contact-us"
    public string Title { get; set; } = string.Empty;        // "درباره ما"
    public string? Subtitle { get; set; }                    // اختیاری
    
    // SEO Properties
    public string? MetaDescription { get; set; }
    public string? MetaKeywords { get; set; }
    public string? OgImage { get; set; }                     // Open Graph Image
    
    // Display Properties
    public bool IsActive { get; set; } = true;
    public bool IsPublic { get; set; } = true;               // نمایش در منو/سایت
    public int SortOrder { get; set; } = 0;                  // ترتیب نمایش در منو
    
    // Navigation Property
    public virtual ICollection<ContentSection> Sections { get; set; } = new List<ContentSection>();
}
```

#### 1.2 Create `ContentSection.cs`
```csharp
namespace CMSMicroservice.Domain.Entities.Content;

public class ContentSection : BaseAuditableEntity
{
    public long Id { get; set; }
    
    // Foreign Key
    public long PageId { get; set; }
    public virtual ContentPage Page { get; set; } = null!;
    
    // Section Properties
    public SectionType SectionType { get; set; }
    public string Title { get; set; } = string.Empty;
    public string Content { get; set; } = "{}";              // JSON Content
    
    // Display Properties
    public int SortOrder { get; set; } = 0;
    public bool IsActive { get; set; } = true;
}
```

#### 1.3 Create `SectionType.cs` (Enum)
```csharp
namespace CMSMicroservice.Domain.Entities.Content;

public enum SectionType
{
    Hero = 0,              // بنر بزرگ با عکس و متن
    TextBlock = 1,         // بلوک متنی ساده (HTML)
    ImageGallery = 2,      // گالری تصاویر
    ContactForm = 3,       // فرم تماس
    TeamMembers = 4,       // اعضای تیم
    FAQ = 5,               // سوالات متداول
    Map = 6,               // نقشه (Google Maps)
    SocialMedia = 7,       // لینک‌های شبکه‌های اجتماعی
    VideoEmbed = 8,        // ویدیو Embed
    Testimonials = 9,      // نظرات مشتریان
    Features = 10,         // ویژگی‌ها (با آیکون)
    Statistics = 11,       // آمار (عدد + توضیح)
    Timeline = 12,         // تایم‌لاین (تاریخچه)
    CallToAction = 13      // دکمه Call-to-Action
}
```

**فایل‌های ایجاد شده**:
- ✅ `ContentPage.cs`
- ✅ `ContentSection.cs`
- ✅ `SectionType.cs`

---

### ✅ Phase 2: Infrastructure Layer - EF Core Configurations

**مسیر**: `CMS/src/CMSMicroservice.Infrastructure/Persistence/Configurations/Content/`

#### 2.1 Create `ContentPageConfiguration.cs`
```csharp
using CMSMicroservice.Domain.Entities.Content;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace CMSMicroservice.Infrastructure.Persistence.Configurations.Content;

public class ContentPageConfiguration : IEntityTypeConfiguration<ContentPage>
{
    public void Configure(EntityTypeBuilder<ContentPage> builder)
    {
        builder.ToTable("ContentPages", "CMS");
        
        builder.HasKey(x => x.Id);
        
        builder.Property(x => x.Slug)
            .IsRequired()
            .HasMaxLength(100);
        
        builder.Property(x => x.Title)
            .IsRequired()
            .HasMaxLength(200);
        
        builder.Property(x => x.Subtitle)
            .HasMaxLength(500);
        
        builder.Property(x => x.MetaDescription)
            .HasMaxLength(500);
        
        builder.Property(x => x.MetaKeywords)
            .HasMaxLength(300);
        
        builder.Property(x => x.OgImage)
            .HasMaxLength(500);
        
        // Unique constraint on Slug
        builder.HasIndex(x => x.Slug)
            .IsUnique();
        
        // Index for active pages
        builder.HasIndex(x => new { x.IsActive, x.IsPublic, x.SortOrder });
        
        // Relationship
        builder.HasMany(x => x.Sections)
            .WithOne(x => x.Page)
            .HasForeignKey(x => x.PageId)
            .OnDelete(DeleteBehavior.Cascade);
    }
}
```

#### 2.2 Create `ContentSectionConfiguration.cs`
```csharp
using CMSMicroservice.Domain.Entities.Content;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace CMSMicroservice.Infrastructure.Persistence.Configurations.Content;

public class ContentSectionConfiguration : IEntityTypeConfiguration<ContentSection>
{
    public void Configure(EntityTypeBuilder<ContentSection> builder)
    {
        builder.ToTable("ContentSections", "CMS");
        
        builder.HasKey(x => x.Id);
        
        builder.Property(x => x.PageId)
            .IsRequired();
        
        builder.Property(x => x.SectionType)
            .IsRequired();
        
        builder.Property(x => x.Title)
            .IsRequired()
            .HasMaxLength(200);
        
        builder.Property(x => x.Content)
            .IsRequired()
            .HasColumnType("nvarchar(max)"); // JSON Storage
        
        builder.Property(x => x.SortOrder)
            .IsRequired();
        
        // Index for querying sections by page
        builder.HasIndex(x => new { x.PageId, x.SortOrder });
        
        // Index for section type filtering
        builder.HasIndex(x => x.SectionType);
    }
}
```

**فایل‌های ایجاد شده**:
- ✅ `ContentPageConfiguration.cs`
- ✅ `ContentSectionConfiguration.cs`

---

### ✅ Phase 3: Update ApplicationDbContext

**مسیر**: `CMS/src/CMSMicroservice.Infrastructure/Persistence/ApplicationDbContext.cs`

#### 3.1 Add DbSets
```csharp
// در بخش DbSets اضافه شود (بعد از خط 85):

// ============= Content Management System DbSets =============
public DbSet<ContentPage> ContentPages => Set<ContentPage>();
public DbSet<ContentSection> ContentSections => Set<ContentSection>();
```

#### 3.2 Configuration Auto-Discovery
Configuration ها به صورت خودکار از Assembly کشف می‌شوند (قبلاً پیاده‌سازی شده):
```csharp
protected override void OnModelCreating(ModelBuilder builder)
{
    builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
    // ...
}
```

**تغییرات**:
- ✅ 2 DbSet جدید اضافه شد

---

### ✅ Phase 4: Database Migration

**مسیر**: `CMS/src/CMSMicroservice.Infrastructure/`

#### 4.1 Create Migration
```bash
cd /home/masoud/Apps/project/FourSat/CMS/src/CMSMicroservice.Infrastructure
dotnet ef migrations add AddDynamicContentSystem --startup-project ../CMSMicroservice.WebApi
```

#### 4.2 Review Migration
بررسی فایل Migration ایجاد شده:
- `Migrations/YYYYMMDD_AddDynamicContentSystem.cs`

#### 4.3 Apply Migration
```bash
dotnet ef database update --startup-project ../CMSMicroservice.WebApi
```

**نتیجه**:
- ✅ جدول `[CMS].[ContentPages]` ایجاد شد
- ✅ جدول `[CMS].[ContentSections]` ایجاد شد
- ✅ Indexes و Constraints اعمال شدند

---

### ✅ Phase 5: Application Layer - CQRS

**مسیر**: `CMS/src/CMSMicroservice.Application/ContentCQ/`

#### 5.1 Queries

##### 5.1.1 GetContentPageBySlug
```
ContentCQ/
├── Queries/
│   └── GetContentPageBySlug/
│       ├── GetContentPageBySlugQuery.cs
│       ├── GetContentPageBySlugQueryHandler.cs
│       ├── GetContentPageBySlugQueryValidator.cs
│       └── GetContentPageBySlugResponseDto.cs
```

**Query**:
```csharp
public record GetContentPageBySlugQuery(string Slug) : IRequest<GetContentPageBySlugResponseDto>;
```

**Handler**:
```csharp
public class GetContentPageBySlugQueryHandler : IRequestHandler<GetContentPageBySlugQuery, GetContentPageBySlugResponseDto>
{
    private readonly IApplicationDbContext _context;

    public async Task<GetContentPageBySlugResponseDto> Handle(...)
    {
        var page = await _context.ContentPages
            .Include(x => x.Sections.Where(s => s.IsActive))
            .FirstOrDefaultAsync(x => x.Slug == request.Slug && x.IsActive);
        
        // Map to DTO
    }
}
```

##### 5.1.2 GetAllContentPages (for BackOffice)
```
ContentCQ/
├── Queries/
│   └── GetAllContentPages/
│       ├── GetAllContentPagesQuery.cs
│       ├── GetAllContentPagesQueryHandler.cs
│       └── GetAllContentPagesResponseDto.cs
```

#### 5.2 Commands

##### 5.2.1 CreateContentPage
```
ContentCQ/
├── Commands/
│   └── CreateContentPage/
│       ├── CreateContentPageCommand.cs
│       ├── CreateContentPageCommandHandler.cs
│       ├── CreateContentPageCommandValidator.cs
│       └── CreateContentPageResponseDto.cs
```

##### 5.2.2 UpdateContentPage
```
ContentCQ/
├── Commands/
│   └── UpdateContentPage/
│       ├── UpdateContentPageCommand.cs
│       ├── UpdateContentPageCommandHandler.cs
│       ├── UpdateContentPageCommandValidator.cs
│       └── UpdateContentPageResponseDto.cs
```

##### 5.2.3 DeleteContentPage
```
ContentCQ/
├── Commands/
│   └── DeleteContentPage/
│       ├── DeleteContentPageCommand.cs
│       └── DeleteContentPageCommandHandler.cs
```

##### 5.2.4 AddContentSection
```
ContentCQ/
├── Commands/
│   └── AddContentSection/
│       ├── AddContentSectionCommand.cs
│       ├── AddContentSectionCommandHandler.cs
│       ├── AddContentSectionCommandValidator.cs
│       └── AddContentSectionResponseDto.cs
```

##### 5.2.5 UpdateContentSection
```
ContentCQ/
├── Commands/
│   └── UpdateContentSection/
│       ├── UpdateContentSectionCommand.cs
│       ├── UpdateContentSectionCommandHandler.cs
│       ├── UpdateContentSectionCommandValidator.cs
│       └── UpdateContentSectionResponseDto.cs
```

##### 5.2.6 DeleteContentSection
```
ContentCQ/
├── Commands/
│   └── DeleteContentSection/
│       ├── DeleteContentSectionCommand.cs
│       └── DeleteContentSectionCommandHandler.cs
```

##### 5.2.7 ReorderContentSections
```
ContentCQ/
├── Commands/
│   └── ReorderContentSections/
│       ├── ReorderContentSectionsCommand.cs
│       └── ReorderContentSectionsCommandHandler.cs
```

**کل فایل‌های Application Layer**: ~21 فایل

---

### ✅ Phase 6: API Layer - Protobuf & gRPC

**مسیر**: `CMS/src/CMSMicroservice.Protobuf/Protos/`

#### 6.1 Create `content.proto`
```protobuf
syntax = "proto3";

option csharp_namespace = "CMSMicroservice.Protobuf.Protos.Content";

package content;

import "google/protobuf/timestamp.proto";

// ============= Services =============

service ContentService {
  rpc GetContentPageBySlug(GetContentPageBySlugRequest) returns (GetContentPageBySlugResponse);
  rpc GetAllContentPages(GetAllContentPagesRequest) returns (GetAllContentPagesResponse);
  rpc CreateContentPage(CreateContentPageRequest) returns (CreateContentPageResponse);
  rpc UpdateContentPage(UpdateContentPageRequest) returns (UpdateContentPageResponse);
  rpc DeleteContentPage(DeleteContentPageRequest) returns (DeleteContentPageResponse);
  rpc AddContentSection(AddContentSectionRequest) returns (AddContentSectionResponse);
  rpc UpdateContentSection(UpdateContentSectionRequest) returns (UpdateContentSectionResponse);
  rpc DeleteContentSection(DeleteContentSectionRequest) returns (DeleteContentSectionResponse);
  rpc ReorderContentSections(ReorderContentSectionsRequest) returns (ReorderContentSectionsResponse);
}

// ============= Messages =============

// GetContentPageBySlug
message GetContentPageBySlugRequest {
  string slug = 1;
}

message GetContentPageBySlugResponse {
  int64 id = 1;
  string slug = 2;
  string title = 3;
  string subtitle = 4;
  string meta_description = 5;
  string meta_keywords = 6;
  string og_image = 7;
  repeated ContentSectionModel sections = 8;
}

message ContentSectionModel {
  int64 id = 1;
  string section_type = 2;  // "Hero", "TextBlock", etc.
  string title = 3;
  string content = 4;       // JSON string
  int32 sort_order = 5;
  bool is_active = 6;
}

// GetAllContentPages
message GetAllContentPagesRequest {
  bool include_inactive = 1;
}

message GetAllContentPagesResponse {
  repeated ContentPageSummary pages = 1;
}

message ContentPageSummary {
  int64 id = 1;
  string slug = 2;
  string title = 3;
  bool is_active = 4;
  bool is_public = 5;
  int32 sections_count = 6;
  google.protobuf.Timestamp created = 7;
}

// CreateContentPage
message CreateContentPageRequest {
  string slug = 1;
  string title = 2;
  string subtitle = 3;
  string meta_description = 4;
  string meta_keywords = 5;
  string og_image = 6;
  bool is_active = 7;
  bool is_public = 8;
  int32 sort_order = 9;
}

message CreateContentPageResponse {
  bool success = 1;
  string message = 2;
  int64 page_id = 3;
}

// UpdateContentPage
message UpdateContentPageRequest {
  int64 page_id = 1;
  string slug = 2;
  string title = 3;
  string subtitle = 4;
  string meta_description = 5;
  string meta_keywords = 6;
  string og_image = 7;
  bool is_active = 8;
  bool is_public = 9;
  int32 sort_order = 10;
}

message UpdateContentPageResponse {
  bool success = 1;
  string message = 2;
}

// DeleteContentPage
message DeleteContentPageRequest {
  int64 page_id = 1;
}

message DeleteContentPageResponse {
  bool success = 1;
  string message = 2;
}

// AddContentSection
message AddContentSectionRequest {
  int64 page_id = 1;
  string section_type = 2;
  string title = 3;
  string content = 4;      // JSON string
  int32 sort_order = 5;
  bool is_active = 6;
}

message AddContentSectionResponse {
  bool success = 1;
  string message = 2;
  int64 section_id = 3;
}

// UpdateContentSection
message UpdateContentSectionRequest {
  int64 section_id = 1;
  string section_type = 2;
  string title = 3;
  string content = 4;
  int32 sort_order = 5;
  bool is_active = 6;
}

message UpdateContentSectionResponse {
  bool success = 1;
  string message = 2;
}

// DeleteContentSection
message DeleteContentSectionRequest {
  int64 section_id = 1;
}

message DeleteContentSectionResponse {
  bool success = 1;
  string message = 2;
}

// ReorderContentSections
message ReorderContentSectionsRequest {
  int64 page_id = 1;
  repeated SectionOrder orders = 2;
}

message SectionOrder {
  int64 section_id = 1;
  int32 new_sort_order = 2;
}

message ReorderContentSectionsResponse {
  bool success = 1;
  string message = 2;
}
```

#### 6.2 Update `.csproj`
```xml
<!-- در CMSMicroservice.Protobuf.csproj -->
<ItemGroup>
  <Protobuf Include="Protos\content.proto" GrpcServices="Server" />
</ItemGroup>
```

#### 6.3 Generate Protobuf Code
```bash
cd /home/masoud/Apps/project/FourSat/CMS/src/CMSMicroservice.Protobuf
dotnet build
```

**فایل‌های ایجاد شده**:
- ✅ `content.proto`
- ✅ Auto-generated C# classes

---

### ✅ Phase 7: WebApi Layer - gRPC Service

**مسیر**: `CMS/src/CMSMicroservice.WebApi/Services/`

#### 7.1 Create `ContentGrpcService.cs`
```csharp
using CMSMicroservice.Application.ContentCQ.Commands.*;
using CMSMicroservice.Application.ContentCQ.Queries.*;
using CMSMicroservice.Protobuf.Protos.Content;
using Grpc.Core;
using Mapster;
using MediatR;

namespace CMSMicroservice.WebApi.Services;

public class ContentGrpcService : ContentService.ContentServiceBase
{
    private readonly IMediator _mediator;
    private readonly ILogger<ContentGrpcService> _logger;

    public ContentGrpcService(IMediator mediator, ILogger<ContentGrpcService> logger)
    {
        _mediator = mediator;
        _logger = logger;
    }

    public override async Task<GetContentPageBySlugResponse> GetContentPageBySlug(
        GetContentPageBySlugRequest request, 
        ServerCallContext context)
    {
        var query = new GetContentPageBySlugQuery(request.Slug);
        var result = await _mediator.Send(query);
        
        return result.Adapt<GetContentPageBySlugResponse>();
    }

    public override async Task<GetAllContentPagesResponse> GetAllContentPages(
        GetAllContentPagesRequest request, 
        ServerCallContext context)
    {
        var query = new GetAllContentPagesQuery(request.IncludeInactive);
        var result = await _mediator.Send(query);
        
        return result.Adapt<GetAllContentPagesResponse>();
    }

    // ... سایر متدها
}
```

#### 7.2 Register Service در `Program.cs`
```csharp
// در WebApi/Program.cs اضافه شود:
app.MapGrpcService<ContentGrpcService>();
```

**فایل‌های ایجاد شده**:
- ✅ `ContentGrpcService.cs`
- ✅ تغییرات در `Program.cs`

---

## JSON Schema Examples

### 1. Hero Section
```json
{
  "backgroundImage": "/images/hero-bg.jpg",
  "title": "به شرکت فورست خوش آمدید",
  "subtitle": "راهکارهای نوین دیجیتال مارکتینگ",
  "buttonText": "شروع کنید",
  "buttonLink": "/contact",
  "alignment": "center",
  "overlayOpacity": 0.5
}
```

### 2. TextBlock Section
```json
{
  "title": "درباره شرکت",
  "body": "<p>شرکت فورست از سال 1395...</p>",
  "backgroundColor": "#f5f5f5",
  "textAlign": "justify",
  "padding": "40px 20px",
  "hasReadMore": false
}
```

### 3. ContactForm Section
```json
{
  "title": "تماس با ما",
  "description": "لطفاً فرم زیر را پر کنید",
  "fields": [
    {
      "name": "fullName",
      "label": "نام و نام خانوادگی",
      "type": "text",
      "required": true,
      "placeholder": "نام خود را وارد کنید"
    },
    {
      "name": "email",
      "label": "ایمیل",
      "type": "email",
      "required": true,
      "placeholder": "example@email.com"
    },
    {
      "name": "phone",
      "label": "شماره تماس",
      "type": "tel",
      "required": false,
      "placeholder": "09123456789"
    },
    {
      "name": "message",
      "label": "پیام",
      "type": "textarea",
      "required": true,
      "placeholder": "پیام خود را بنویسید...",
      "rows": 5
    }
  ],
  "submitButton": "ارسال پیام",
  "successMessage": "پیام شما با موفقیت ارسال شد",
  "errorMessage": "خطا در ارسال پیام",
  "emailTo": "info@foursat.com"
}
```

### 4. TeamMembers Section
```json
{
  "title": "تیم ما",
  "members": [
    {
      "name": "علی احمدی",
      "position": "مدیر عامل",
      "image": "/images/team/ali.jpg",
      "bio": "بیش از 15 سال تجربه در...",
      "linkedin": "https://linkedin.com/in/ali",
      "email": "ali@foursat.com"
    },
    {
      "name": "سارا محمدی",
      "position": "مدیر فنی",
      "image": "/images/team/sara.jpg",
      "bio": "متخصص در زمینه...",
      "linkedin": "https://linkedin.com/in/sara",
      "email": "sara@foursat.com"
    }
  ],
  "layout": "grid",
  "columns": 3
}
```

### 5. FAQ Section
```json
{
  "title": "سوالات متداول",
  "questions": [
    {
      "question": "چگونه می‌توانم ثبت نام کنم؟",
      "answer": "برای ثبت نام کافیست به صفحه...",
      "isExpanded": false
    },
    {
      "question": "روش‌های پرداخت چیست؟",
      "answer": "شما می‌توانید از طریق...",
      "isExpanded": false
    }
  ],
  "layout": "accordion"
}
```

### 6. Map Section
```json
{
  "title": "موقعیت ما",
  "latitude": 35.6892,
  "longitude": 51.3890,
  "zoom": 15,
  "markerTitle": "شرکت فورست",
  "address": "تهران، خیابان ولیعصر، پلاک 123",
  "height": "400px",
  "showControls": true
}
```

### 7. SocialMedia Section
```json
{
  "title": "ما را دنبال کنید",
  "platforms": [
    {
      "name": "Instagram",
      "icon": "instagram",
      "url": "https://instagram.com/foursat",
      "color": "#E4405F"
    },
    {
      "name": "Telegram",
      "icon": "telegram",
      "url": "https://t.me/foursat",
      "color": "#0088cc"
    },
    {
      "name": "LinkedIn",
      "icon": "linkedin",
      "url": "https://linkedin.com/company/foursat",
      "color": "#0077b5"
    }
  ],
  "layout": "horizontal",
  "iconSize": "large"
}
```

### 8. Features Section
```json
{
  "title": "ویژگی‌های ما",
  "features": [
    {
      "icon": "shield-check",
      "title": "امنیت بالا",
      "description": "تمام اطلاعات شما با استانداردهای..."
    },
    {
      "icon": "clock",
      "title": "پشتیبانی 24/7",
      "description": "تیم پشتیبانی ما همیشه آماده..."
    },
    {
      "icon": "globe",
      "title": "دسترسی جهانی",
      "description": "از هر جای دنیا می‌توانید..."
    }
  ],
  "layout": "grid",
  "columns": 3
}
```

### 9. Statistics Section
```json
{
  "title": "اعداد و ارقام",
  "stats": [
    {
      "number": 10000,
      "suffix": "+",
      "label": "کاربر فعال",
      "icon": "users",
      "animateOnView": true
    },
    {
      "number": 500,
      "suffix": "+",
      "label": "پروژه موفق",
      "icon": "briefcase",
      "animateOnView": true
    },
    {
      "number": 98,
      "suffix": "%",
      "label": "رضایت مشتریان",
      "icon": "heart",
      "animateOnView": true
    }
  ],
  "layout": "horizontal",
  "backgroundColor": "#f8f9fa"
}
```

### 10. Timeline Section
```json
{
  "title": "تاریخچه شرکت",
  "events": [
    {
      "year": "1395",
      "title": "تأسیس شرکت",
      "description": "شرکت فورست با هدف...",
      "image": "/images/timeline/2016.jpg"
    },
    {
      "year": "1397",
      "title": "توسعه محصول اول",
      "description": "راه‌اندازی اولین محصول...",
      "image": "/images/timeline/2018.jpg"
    },
    {
      "year": "1400",
      "title": "جایزه بهترین استارتاپ",
      "description": "دریافت جایزه ملی...",
      "image": "/images/timeline/2021.jpg"
    }
  ],
  "layout": "vertical",
  "alternateLayout": true
}
```

---

## BackOffice UI Design

### صفحه لیست (ContentPagesMainPage.razor)
```
┌─────────────────────────────────────────────────────────────┐
│ 📄 مدیریت صفحات محتوا                    [+ صفحه جدید]     │
├─────────────────────────────────────────────────────────────┤
│ 🔍 جستجو: [_____________]  🔧 فیلتر: [همه ▼]              │
├─────┬──────────────┬────────┬────────┬──────────┬──────────┤
│ ID  │ عنوان صفحه   │ Slug   │ وضعیت  │ Sections │ عملیات   │
├─────┼──────────────┼────────┼────────┼──────────┼──────────┤
│ 1   │ درباره ما    │about-us│ ✅ فعال│    5     │[✏️][🗑️][👁️]│
│ 2   │ تماس با ما   │contact │ ✅ فعال│    3     │[✏️][🗑️][👁️]│
│ 3   │ قوانین      │terms   │ ❌ غیرف│    2     │[✏️][🗑️][👁️]│
└─────┴──────────────┴────────┴────────┴──────────┴──────────┘
```

### صفحه ویرایش (ContentPageEditor.razor)
```
┌─────────────────────────────────────────────────────────────┐
│ ✏️ ویرایش صفحه: درباره ما                 [💾 ذخیره] [❌]  │
├─────────────────────────────────────────────────────────────┤
│ Tab: [📝 اطلاعات پایه] [🧩 بخش‌ها] [🔍 SEO]               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│ عنوان: [______________________________________]             │
│ Slug:  [about-us________________] (منحصر به فرد)           │
│ زیرعنوان: [________________________________]              │
│                                                             │
│ ☑ فعال   ☑ نمایش عمومی   ترتیب: [0___]                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

### Tab بخش‌ها (Sections)
```
┌─────────────────────────────────────────────────────────────┐
│ 🧩 بخش‌های صفحه                         [+ افزودن بخش]     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│ ┌─────────────────────────────────────┐                     │
│ │ ☰ 1. Hero Section       [↑][↓][✏️][🗑️]│                   │
│ │ نوع: Hero | فعال: ✅                │                     │
│ │ محتوا: بنر خوش آمد گویی...          │                     │
│ └─────────────────────────────────────┘                     │
│                                                             │
│ ┌─────────────────────────────────────┐                     │
│ │ ☰ 2. TextBlock          [↑][↓][✏️][🗑️]│                   │
│ │ نوع: TextBlock | فعال: ✅           │                     │
│ │ محتوا: درباره شرکت...               │                     │
│ └─────────────────────────────────────┘                     │
│                                                             │
│ ┌─────────────────────────────────────┐                     │
│ │ ☰ 3. TeamMembers        [↑][↓][✏️][🗑️]│                   │
│ │ نوع: TeamMembers | فعال: ✅         │                     │
│ │ محتوا: 4 عضو تیم                    │                     │
│ └─────────────────────────────────────┘                     │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

### ویرایشگر Section (SectionEditor.razor)
```
┌─────────────────────────────────────────────────────────────┐
│ ✏️ ویرایش بخش: Hero Section              [💾 ذخیره] [❌]  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│ نوع بخش: [Hero ▼]                                          │
│ عنوان: [بنر خوش آمد گویی_________________]                │
│ فعال: ☑                                                    │
│                                                             │
│ ─── تنظیمات Hero Section ───                               │
│                                                             │
│ تصویر پس‌زمینه: [انتخاب فایل] /images/hero-bg.jpg         │
│ عنوان اصلی: [به شرکت فورست خوش آمدید____]                │
│ زیرعنوان: [راهکارهای نوین دیجیتال مارکتینگ__]            │
│ متن دکمه: [شروع کنید_________]                            │
│ لینک دکمه: [/contact__________]                           │
│ موقعیت متن: [○ چپ  ●  وسط  ○ راست]                       │
│ شفافیت لایه: [▓▓▓▓▓▓░░░░] 50%                             │
│                                                             │
│ 👁️ [پیش‌نمایش]                                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

---

## Validation Rules

### ContentPage Validation
- ✅ `Slug`: 
  - الزامی
  - فقط حروف کوچک، اعداد، و خط تیره (-)
  - طول: 3-100 کاراکتر
  - منحصر به فرد
  - مثال: `about-us`, `contact-us`, `terms-conditions`

- ✅ `Title`:
  - الزامی
  - طول: 3-200 کاراکتر

- ✅ `MetaDescription`:
  - اختیاری
  - طول: حداکثر 500 کاراکتر

### ContentSection Validation
- ✅ `SectionType`:
  - الزامی
  - باید یکی از مقادیر Enum باشد

- ✅ `Title`:
  - الزامی
  - طول: 3-200 کاراکتر

- ✅ `Content`:
  - الزامی
  - باید JSON معتبر باشد
  - Schema validation بر اساس `SectionType`

---

## SEO Optimization

### 1. Meta Tags
```html
<!-- در صفحه About Us -->
<title>درباره ما - شرکت فورست</title>
<meta name="description" content="شرکت فورست از سال 1395 فعالیت خود را...">
<meta name="keywords" content="فورست، درباره ما، تاریخچه شرکت">

<!-- Open Graph -->
<meta property="og:title" content="درباره ما - شرکت فورست">
<meta property="og:description" content="شرکت فورست از سال 1395...">
<meta property="og:image" content="https://foursat.com/og-about.jpg">
<meta property="og:type" content="website">
```

### 2. Structured Data (JSON-LD)
```json
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "شرکت فورست",
  "url": "https://foursat.com",
  "logo": "https://foursat.com/logo.png",
  "contactPoint": {
    "@type": "ContactPoint",
    "telephone": "+98-21-12345678",
    "contactType": "Customer Service",
    "areaServed": "IR",
    "availableLanguage": ["fa", "en"]
  },
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "خیابان ولیعصر، پلاک 123",
    "addressLocality": "تهران",
    "postalCode": "1234567890",
    "addressCountry": "IR"
  }
}
```

### 3. Sitemap.xml
```xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://foursat.com/about-us</loc>
    <lastmod>2025-12-06</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
  </url>
  <url>
    <loc>https://foursat.com/contact-us</loc>
    <lastmod>2025-12-06</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.7</priority>
  </url>
</urlset>
```

---

## Multi-Language Support (آینده)

### Approach 1: Separate Tables
```
ContentPage (fa) ──┐
ContentPage (en) ──┼─→ ContentPageTranslation
ContentPage (ar) ──┘
```

### Approach 2: JSON Field
```csharp
public class ContentPage
{
    public string Title { get; set; }              // فارسی (پیشفرض)
    public string TitleTranslations { get; set; }  // JSON: {"en": "About Us", "ar": "معلومات عنا"}
}
```

### Approach 3: Separate Content Column
```csharp
public class ContentSection
{
    public string Content { get; set; }      // فارسی
    public string ContentEn { get; set; }    // انگلیسی
    public string ContentAr { get; set; }    // عربی
}
```

**توصیه**: Approach 2 (JSON Field) - flexible و مقیاس‌پذیر

---

## Performance Optimization

### 1. Caching Strategy
```csharp
// Cache صفحات برای 30 دقیقه
services.AddMemoryCache();

public class GetContentPageBySlugQueryHandler
{
    private readonly IMemoryCache _cache;
    
    public async Task<...> Handle(...)
    {
        var cacheKey = $"content-page-{request.Slug}";
        
        if (!_cache.TryGetValue(cacheKey, out GetContentPageBySlugResponseDto result))
        {
            result = await GetFromDatabase(...);
            
            _cache.Set(cacheKey, result, TimeSpan.FromMinutes(30));
        }
        
        return result;
    }
}
```

### 2. Database Indexes
```sql
-- Index برای Slug (Unique)
CREATE UNIQUE INDEX IX_ContentPages_Slug ON ContentPages(Slug);

-- Index برای فیلتر صفحات فعال
CREATE INDEX IX_ContentPages_Active ON ContentPages(IsActive, IsPublic, SortOrder);

-- Index برای Sections
CREATE INDEX IX_ContentSections_PageId ON ContentSections(PageId, SortOrder);
```

### 3. Lazy Loading
```csharp
// فقط Sections فعال را بارگذاری کن
var page = await _context.ContentPages
    .Include(x => x.Sections.Where(s => s.IsActive).OrderBy(s => s.SortOrder))
    .FirstOrDefaultAsync(x => x.Slug == slug);
```

---

## Security Considerations

### 1. Authorization
```csharp
// فقط Admin می‌تواند صفحات را مدیریت کند
[Authorize(Roles = "Admin")]
public class ContentGrpcService : ContentService.ContentServiceBase
{
    // ...
}
```

### 2. Input Validation
```csharp
public class CreateContentPageCommandValidator : AbstractValidator<CreateContentPageCommand>
{
    public CreateContentPageCommandValidator()
    {
        RuleFor(x => x.Slug)
            .NotEmpty()
            .Matches("^[a-z0-9-]+$") // فقط حروف کوچک، اعداد، و خط تیره
            .Length(3, 100);
        
        RuleFor(x => x.Title)
            .NotEmpty()
            .Length(3, 200);
    }
}
```

### 3. XSS Prevention
```csharp
// Sanitize HTML content در TextBlock
using HtmlAgilityPack;

public class ContentSanitizer
{
    public string SanitizeHtml(string html)
    {
        var doc = new HtmlDocument();
        doc.LoadHtml(html);
        
        // حذف تگ‌های خطرناک
        doc.DocumentNode.Descendants()
            .Where(n => n.Name == "script" || n.Name == "iframe")
            .ToList()
            .ForEach(n => n.Remove());
        
        return doc.DocumentNode.OuterHtml;
    }
}
```

---

## Testing Strategy

### 1. Unit Tests
```csharp
// Test: GetContentPageBySlug با Slug نامعتبر
[Fact]
public async Task GetContentPageBySlug_WithInvalidSlug_ReturnsNull()
{
    // Arrange
    var handler = new GetContentPageBySlugQueryHandler(_context);
    var query = new GetContentPageBySlugQuery("invalid-slug");
    
    // Act
    var result = await handler.Handle(query, CancellationToken.None);
    
    // Assert
    Assert.Null(result);
}
```

### 2. Integration Tests
```csharp
// Test: ایجاد صفحه با Slug تکراری
[Fact]
public async Task CreateContentPage_WithDuplicateSlug_ThrowsException()
{
    // Arrange
    await CreatePage("about-us");
    
    // Act & Assert
    await Assert.ThrowsAsync<DbUpdateException>(
        () => CreatePage("about-us")
    );
}
```

### 3. E2E Tests
```csharp
// Test: BackOffice - ایجاد و ویرایش صفحه
[Fact]
public async Task BackOffice_CreateAndEditPage_Success()
{
    // 1. Navigate to ContentPages
    await Page.GotoAsync("/content-pages");
    
    // 2. Click "New Page"
    await Page.ClickAsync("button:has-text('صفحه جدید')");
    
    // 3. Fill form
    await Page.FillAsync("input[name='title']", "تست صفحه");
    await Page.FillAsync("input[name='slug']", "test-page");
    
    // 4. Submit
    await Page.ClickAsync("button:has-text('ذخیره')");
    
    // 5. Verify
    await Expect(Page.Locator("text=تست صفحه")).ToBeVisibleAsync();
}
```

---

## Deployment Checklist

### Pre-Deployment
- [ ] همه Unit Tests پاس شوند
- [ ] Integration Tests پاس شوند
- [ ] Migration در Staging اجرا شود
- [ ] Performance Testing انجام شود
- [ ] Security Audit انجام شود
- [ ] Documentation کامل باشد

### Deployment Steps
1. [ ] Backup دیتابیس Production
2. [ ] اجرای Migration در Production
3. [ ] Deploy کد جدید
4. [ ] Smoke Testing
5. [ ] Cache را Clear کنید
6. [ ] Monitor logs برای 24 ساعت

### Post-Deployment
- [ ] Verify صفحات About Us و Contact Us
- [ ] بررسی Performance Metrics
- [ ] بررسی Error Logs
- [ ] User Acceptance Testing (UAT)

---

## Monitoring & Analytics

### 1. Application Insights
```csharp
// Log Page Views
_telemetry.TrackPageView(new PageViewTelemetry
{
    Name = $"ContentPage-{slug}",
    Url = new Uri($"https://foursat.com/{slug}")
});
```

### 2. Custom Metrics
```csharp
// Track Section Rendering Time
using (_telemetry.StartOperation<RequestTelemetry>("RenderSection"))
{
    await RenderSection(section);
}
```

### 3. Alerts
- ⚠️ اگر Page Load Time > 3 ثانیه
- ⚠️ اگر Error Rate > 1%
- ⚠️ اگر Cache Miss Rate > 20%

---

## Future Enhancements

### Phase 8: Advanced Features (آینده)
- [ ] **Versioning**: نگهداری تاریخچه تغییرات
- [ ] **Scheduling**: زمان‌بندی انتشار محتوا
- [ ] **A/B Testing**: تست نسخه‌های مختلف
- [ ] **Analytics Dashboard**: آمار بازدید صفحات
- [ ] **SEO Score**: امتیاز SEO برای هر صفحه
- [ ] **Content Templates**: قالب‌های آماده برای صفحات
- [ ] **Workflow**: تایید چند مرحله‌ای (Draft → Review → Published)
- [ ] **Media Library**: مدیریت تصاویر و فایل‌ها
- [ ] **Comments System**: سیستم نظرات برای صفحات
- [ ] **Related Pages**: پیشنهاد صفحات مرتبط

---

## خلاصه آمار پیاده‌سازی

| Phase | فایل‌ها | خطوط کد تقریبی | زمان تخمینی |
|-------|---------|----------------|-------------|
| 1. Domain Entities | 3 | ~150 | 1 ساعت |
| 2. EF Configurations | 2 | ~100 | 1 ساعت |
| 3. DbContext Update | 1 | ~10 | 15 دقیقه |
| 4. Migration | 1 | Auto | 30 دقیقه |
| 5. Application (CQRS) | ~21 | ~800 | 4 ساعت |
| 6. Protobuf | 1 | ~200 | 1 ساعت |
| 7. WebApi (gRPC) | 1 | ~150 | 1 ساعت |
| **Total** | **~30** | **~1,410** | **~9 ساعت** |

### BackOffice UI (اختیاری)
| Phase | فایل‌ها | خطوط کد تقریبی | زمان تخمینی |
|-------|---------|----------------|-------------|
| 8. Razor Pages | ~5 | ~800 | 4 ساعت |
| 9. Services | ~2 | ~200 | 1 ساعت |
| 10. Components | ~10 | ~500 | 3 ساعت |
| **Total** | **~17** | **~1,500** | **~8 ساعت** |

**جمع کل**: ~47 فایل، ~2,910 خط کد، ~17 ساعت توسعه

---

## نتیجه‌گیری

این سیستم یک **راهکار کامل و انعطاف‌پذیر** برای مدیریت صفحات محتوایی ارائه می‌دهد که:

✅ **Scalable**: امکان افزودن هر تعداد صفحه و بخش  
✅ **Flexible**: ساختار JSON برای محتوای پویا  
✅ **Maintainable**: معماری Clean Architecture و CQRS  
✅ **User-Friendly**: رابط کاربری BackOffice ساده و کاربردی  
✅ **SEO-Optimized**: Meta Tags و Structured Data  
✅ **Production-Ready**: Caching، Validation، Security  

**زمان شروع پیاده‌سازی**: هر زمان که آماده باشید! 🚀

---

**نسخه:** 1.0  
**تاریخ:** December 6, 2025  
**وضعیت:** ✅ آماده برای پیاده‌سازی  
**اولویت:** متوسط (بعد از فیچرهای اصلی)

