# FourSat Data Migration Tool

## نگاه کلی

این ابزار برای مهاجرت داده‌های دیتابیس از ساختار قدیمی (Production) به ساختار جدید (Stage) طراحی شده است.

**ویژگی‌ها:**
- ✅ Queue-based processing با retry logic
- ✅ Error handling - آیتم‌های ناموفق به صف retry می‌روند
- ✅ Logging کامل با Serilog (Console + File)
- ✅ قابلیت توقف/ادامه (Pause/Resume)
- ✅ Table name mapping (مثل Categorys → Categories)
- ✅ Batch processing برای کارایی بهتر
- ✅ Retry با Exponential Backoff
- ✅ Progress tracking

---

## ساختار پروژه

```
FourSat.DataMigration/
├── Program.cs                 # Entry point با Hosting
├── appsettings.json           # تنظیمات (ConnectionStrings, Mappings)
├── Models/
│   ├── MigrationSettings.cs   # تنظیمات migration
│   ├── TableMapping.cs        # نگاشت table ها
│   └── MigrationQueueItem.cs  # آیتم صف
├── Services/
│   ├── IMigrationService.cs   # Interface
│   ├── MigrationService.cs    # سرویس اصلی migration
│   ├── QueueManager.cs        # مدیریت صف و retry
│   └── TableMigrator.cs       # مهاجرت یک table
└── Logs/                      # لاگ فایل‌ها (auto-created)
```

---

## تنظیمات (`appsettings.json`)

### 1. ConnectionStrings
```json
{
  "SourceDatabase": "Server=185.252.31.42,2019;Database=Foursat;...",
  "TargetDatabase": "Server=194.5.195.53,31433;Database=Foursat;..."
}
```

**⚠️ توجه**: حتماً Username و Password را وارد کنید!

### 2. MigrationSettings
- **BatchSize**: تعداد رکوردهای هر batch (پیشنهاد: 1000)
- **MaxRetryAttempts**: حداکثر تلاش مجدد (5 بار)
- **RetryDelaySeconds**: تأخیر بین retry ها (5 ثانیه)
- **MaxConcurrentTables**: تعداد table های همزمان (3 عدد)
- **EnableDetailedLogging**: لاگ جزئیات (true)
- **SkipEmptyTables**: نادیده گرفتن table های خالی (true)

### 3. TableMappings
نگاشت نام table قدیمی به جدید (33 جدول):

```json
{
  "Categorys": "Categories",
  "ClubFeatures": "ClubFeatures",
  "ClubMembershipHistories": "ClubMembershipHistories",
  "ClubMemberships": "ClubMemberships",
  "CommissionPayoutHistories": "CommissionPayoutHistories",
  "Contracts": "Contracts",
  "FactorDetailss": "FactorDetails",
  "NetworkMembershipHistories": "NetworkMembershipHistories",
  "NetworkWeeklyBalances": "NetworkWeeklyBalances",
  "OtpTokens": "OtpTokens",
  "Packages": "Packages",
  "ProductGalleryss": "ProductGalleries",
  "ProductImagess": "ProductImages",
  "Productss": "Products",
  "PruductCategorys": "ProductCategories",
  "PruductTags": "ProductTags",
  "Roles": "Roles",
  "SystemConfigurationHistories": "SystemConfigurationHistories",
  "SystemConfigurations": "SystemConfigurations",
  "Tags": "Tags",
  "Transactionss": "Transactions",
  "UserAddresss": "UserAddresses",
  "UserCartss": "UserCarts",
  "UserClubFeatures": "UserClubFeatures",
  "UserCommissionPayouts": "UserCommissionPayouts",
  "UserContracts": "UserContracts",
  "UserOrders": "UserOrders",
  "UserRoles": "UserRoles",
  "Users": "Users",
  "UserWalletChangeLogs": "UserWalletChangeLogs",
  "UserWallets": "UserWallets",
  "WeeklyCommissionPools": "WeeklyCommissionPools",
  "WorkerExecutionLogs": "WorkerExecutionLogs"
}
```

**چگونه کار می‌کند:**
- اگر table در mapping باشد → از نام جدید استفاده می‌کند
- اگر در mapping نباشد → همان نام را استفاده می‌کند
- اگر table در target نباشد → Log می‌کند و skip می‌کند

---

## نحوه اجرا

### 1. ویرایش appsettings.json
```bash
cd /home/masoud/Apps/project/FourSat/DataMigration/FourSat.DataMigration
nano appsettings.json
```

**تغییرات لازم:**
- ✅ `SourceDatabase`: Username و Password را وارد کنید
- ✅ `TargetDatabase`: Username و Password را وارد کنید
- ✅ `TableMappings`: اگر mapping جدید دارید اضافه کنید

### 2. Build پروژه
```bash
dotnet build
```

### 3. اجرای Migration
```bash
dotnet run
```

### 4. مشاهده Logs
```bash
# Real-time console output
# یا
tail -f Logs/migration-20251206.txt
```

---

## جریان کار (Workflow)

```
1. خواندن تنظیمات از appsettings.json
   ↓
2. اتصال به Source و Target databases
   ↓
3. کشف تمام table های Source (CMS schema)
   ↓
4. برای هر table:
   ├─ بررسی mapping (قدیمی → جدید)
   ├─ تعداد رکوردها را بخواند
   ├─ اگر خالی → skip (با log)
   ├─ اگر پر → افزودن به Queue
   └─ Log: "Table X → Y: N records"
   ↓
5. پردازش Queue:
   ├─ تا MaxConcurrentTables همزمان
   ├─ هر table در batch ها (BatchSize)
   ├─ اگر error → Retry (MaxRetryAttempts)
   ├─ اگر بعد از retry fail → Log + Skip
   └─ پیشرفت را نمایش بده
   ↓
6. گزارش نهایی:
   ├─ تعداد table های موفق
   ├─ تعداد table های ناموفق
   ├─ جمع رکوردهای migrate شده
   └─ مدت زمان کل
```

---

## Retry Logic

### استراتژی:
1. **اولین تلاش**: بلافاصله
2. **تلاش 2**: بعد از 5 ثانیه
3. **تلاش 3**: بعد از 10 ثانیه (exponential backoff)
4. **تلاش 4**: بعد از 20 ثانیه
5. **تلاش 5**: بعد از 40 ثانیه

**اگر همه fail شوند:**
- Log error با جزئیات کامل
- Table را از queue حذف کن
- به table بعدی برو (متوقف نمی‌شود!)

---

## Error Handling

### خطاهای رایج:

| خطا | دلیل | راه حل |
|-----|------|--------|
| **Login failed** | Username/Password اشتباه | appsettings.json را بررسی کنید |
| **Table not found** | Table در target وجود ندارد | Migration بزنید یا از mapping صحیح استفاده کنید |
| **Timeout** | Network کند یا batch زیاد | BatchSize را کاهش دهید |
| **Deadlock** | همزمانی بالا | MaxConcurrentTables را کم کنید |
| **Permission denied** | User دسترسی ندارد | سطح دسترسی SQL را بررسی کنید |

---

## مثال خروجی

```
[12:30:15 INF] Starting migration...
[12:30:16 INF] Source: 30 tables found
[12:30:16 INF] Mapping: Categorys → Categories
[12:30:16 INF] Mapping: Productss → Products
[12:30:17 INF] Queue: 28 tables added (2 empty skipped)
[12:30:18 INF] Migrating: Categories (6 records)
[12:30:18 INF] Success: Categories (6/6) - 100%
[12:30:19 INF] Migrating: Products (150 records)
[12:30:21 INF] Success: Products (150/150) - 100%
...
[12:35:42 INF] === Migration Complete ===
[12:35:42 INF] Success: 28 tables, 45,320 records
[12:35:42 INF] Failed: 0 tables
[12:35:42 INF] Duration: 5 minutes 27 seconds
```

---

## فایل‌های باقی مانده برای پیاده‌سازی

### Models/MigrationSettings.cs
```csharp
public class MigrationSettings
{
    public int BatchSize { get; set; } = 1000;
    public int MaxRetryAttempts { get; set; } = 5;
    public int RetryDelaySeconds { get; set; } = 5;
    public int MaxConcurrentTables { get; set; } = 3;
    public bool EnableDetailedLogging { get; set; } = true;
    public bool SkipEmptyTables { get; set; } = true;
}
```

### Models/TableMapping.cs
```csharp
public class TableMapping
{
    public string SourceTable { get; set; } = string.Empty;
    public string TargetTable { get; set; } = string.Empty;
    public long TotalRecords { get; set; }
    public long MigratedRecords { get; set; }
    public MigrationStatus Status { get; set; }
}

public enum MigrationStatus
{
    Pending,
    InProgress,
    Completed,
    Failed,
    Retrying
}
```

### Models/MigrationQueueItem.cs
```csharp
public class MigrationQueueItem
{
    public string SourceTable { get; set; } = string.Empty;
    public string TargetTable { get; set; } = string.Empty;
    public long TotalRecords { get; set; }
    public int RetryCount { get; set; }
    public DateTime? LastAttempt { get; set; }
    public string? LastError { get; set; }
}
```

### Services/IMigrationService.cs
```csharp
public interface IMigrationService
{
    Task RunAsync(CancellationToken cancellationToken);
}
```

### Services/MigrationService.cs
```csharp
public class MigrationService : IMigrationService
{
    // کلاس اصلی که:
    // 1. لیست table ها را از source می‌خواند
    // 2. QueueManager را راه‌اندازی می‌کند
    // 3. TableMigrator ها را همزمان اجرا می‌کند
    // 4. Progress و statistics را نمایش می‌دهد
}
```

### Program.cs
```csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;

var host = Host.CreateDefaultBuilder(args)
    .UseSerilog((context, config) => config.ReadFrom.Configuration(context.Configuration))
    .ConfigureServices((context, services) =>
    {
        services.Configure<MigrationSettings>(context.Configuration.GetSection("MigrationSettings"));
        services.AddSingleton<IMigrationService, MigrationService>();
        // Register other services...
    })
    .Build();

await host.Services.GetRequiredService<IMigrationService>().RunAsync(CancellationToken.None);
```

---

## توقف و ادامه (Pause/Resume)

**نحوه توقف:**
```bash
Ctrl+C  # Graceful shutdown
```

**نحوه ادامه:**
- هیچ state ذخیره نمی‌شود (stateless)
- دوباره `dotnet run` کنید
- چون `INSERT` استفاده می‌شود، رکوردهای duplicate ایجاد می‌شود
- **پیشنهاد**: قبل از اجرای مجدد، Target را TRUNCATE کنید

**برای Production:**
- از `MERGE` یا `INSERT IF NOT EXISTS` استفاده کنید
- یک جدول `MigrationState` برای ذخیره پیشرفت ایجاد کنید

---

## نکات امنیتی

1. **Credentials**:
   - ❌ هرگز appsettings.json را commit نکنید
   - ✅ از Environment Variables یا User Secrets استفاده کنید

2. **Network**:
   - ✅ از VPN برای اتصال به Production استفاده کنید
   - ✅ IP شما در Firewall مجاز باشد

3. **Permissions**:
   - Source: فقط `SELECT` کافی است
   - Target: نیاز به `INSERT` دارد

---

## بهینه‌سازی عملکرد

### برای دیتابیس کوچک (<100K records):
```json
{
  "BatchSize": 5000,
  "MaxConcurrentTables": 5
}
```

### برای دیتابیس متوسط (100K-1M):
```json
{
  "BatchSize": 2000,
  "MaxConcurrentTables": 3
}
```

### برای دیتابیس بزرگ (>1M):
```json
{
  "BatchSize": 500,
  "MaxConcurrentTables": 2
}
```

---

## حذف یا خاموش کردن

### خاموش کردن موقت:
```bash
# فقط اجرا نکنید!
```

### حذف کامل:
```bash
cd /home/masoud/Apps/project/FourSat
rm -rf DataMigration/
```

---

## لایسنس

این ابزار موقت برای استفاده داخلی FourSat است. بعد از sync کامل، حذف شود.

---

## سوالات متداول (FAQ)

**Q: چرا بعضی table ها migrate نمی‌شوند؟**
A: چک کنید:
1. Table در Target وجود دارد؟
2. Schema match می‌کند؟
3. Mapping صحیح است؟

**Q: چگونه فقط یک table خاص را migrate کنم؟**
A: در کد `MigrationService.cs`، فیلتر اضافه کنید:
```csharp
var tablesToMigrate = allTables.Where(t => t == "Users").ToList();
```

**Q: چگونه از duplicate جلوگیری کنم؟**
A: قبل از اجرا، Target را خالی کنید:
```sql
TRUNCATE TABLE [CMS].[Categories];
TRUNCATE TABLE [CMS].[Products];
-- ...
```

**Q: آیا می‌توانم بدون توقف سرور اجرا کنم؟**
A: بله، فقط `SELECT` روی Source اجرا می‌شود (ReadOnly).

---

**آخرین بروزرسانی**: December 6, 2025  
**نسخه**: 1.0  
**وضعیت**: آماده برای پیاده‌سازی نهایی
