# 🔄 Data Migration Guide

> **آخرین بروزرسانی**: January 3, 2026  
> **ابزار**: FourSat.DataMigration  
> **تعداد جداول**: 33  
> **وضعیت**: ✅ آماده برای Production

---

## 📋 نگاه اجمالی

این ابزار یک **ابزار یکبار مصرف** برای مهاجرت داده‌های دیتابیس از ساختار قدیمی (Production) به ساختار جدید (Stage) است.

**زمان تخمینی اجرا**: 5-10 دقیقه  
**تکنولوژی**: .NET 9.0 + Dapper + PostgreSQL

---

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

```
DataMigration/
├── FourSat.DataMigration/
│   ├── Program.cs                    # Entry point
│   ├── appsettings.json              # 33 table mappings
│   ├── Models/
│   │   └── MigrationModels.cs        # Settings, Mapping, QueueItem
│   ├── Services/
│   │   └── MigrationService.cs       # Migration + Post-Migration logic
│   └── Scripts/
│       └── PostMigration_DataTransformation.sql
└── FourSat.GeographySeeder/          # ابزار جداگانه برای Geography data
```

---

## 🚀 راهنمای سریع (3 قدم)

### قدم 1: ویرایش تنظیمات

```bash
cd DataMigration/FourSat.DataMigration
# ویرایش appsettings.json
```

```json
{
  "SourceConnectionString": "Host=OLD_SERVER;Database=OLD_DB;Username=xxx;Password=xxx",
  "DestinationConnectionString": "Host=NEW_SERVER;Database=NEW_DB;Username=xxx;Password=xxx"
}
```

### قدم 2: اجرای Migration

```bash
dotnet run
```

### قدم 3: بررسی Logs

```bash
# خروجی:
✅ [Users] Migrated 50000 rows in 12.5s
✅ [Products] Migrated 8500 rows in 3.2s
...
✅ Migration completed! Total: 33 tables, Time: 4m 32s
```

---

## 📋 لیست جداول (33 جدول)

### جداول با تغییر نام (10 جدول)

| نام قدیمی (Source) | نام جدید (Target) | دلیل تغییر |
|-------------------|-------------------|-----------|
| `Categorys` | `Categories` | جمع صحیح Category |
| `FactorDetailss` | `FactorDetails` | s اضافی |
| `ProductGalleryss` | `ProductGalleries` | Gallery → Galleries |
| `ProductImagess` | `ProductImages` | s اضافی |
| `Productss` | `Products` | s اضافی |
| `PruductCategorys` | `ProductCategories` | Pruduct → Product |
| `PruductTags` | `ProductTags` | Pruduct → Product |
| `Transactionss` | `Transactions` | s اضافی |
| `UserAddresss` | `UserAddresses` | s اضافی |
| `UserCartss` | `UserCarts` | s اضافی |

### جداول بدون تغییر نام (23 جدول)

| گروه | جداول |
|------|--------|
| Core | `Roles`, `Tags`, `SystemConfigurations`, `ClubFeatures`, `Packages` |
| Users | `Users`, `OtpTokens`, `UserRoles`, `UserWallets`, `UserAddresses`, `UserCarts` |
| Products | `Categories`, `Products`, `ProductImages`, `ProductGalleries`, `ProductCategories`, `ProductTags` |
| Club | `ClubMemberships`, `ClubMembershipHistories`, `UserClubFeatures` |
| Network | `NetworkWeeklyBalances`, `NetworkMembershipHistories` |
| Commission | `CommissionPayoutHistories`, `UserCommissionPayouts`, `WeeklyCommissionPools` |
| Orders | `UserOrders`, `Transactions`, `Contracts`, `UserContracts` |

---

## 🔄 Post-Migration Transformation

### Binary Tree User Conversion

پس از migrate کردن جدول `Users`، باید تبدیل داده‌های شبکه انجام شود:

**مشکل**: در دیتابیس قدیمی، ستون‌های `Left` و `Right` شامل username است. در جدید باید UserId باشد.

**Script**: `PostMigration_DataTransformation.sql`

```sql
-- Convert username to user_id for binary tree
UPDATE "Users" u
SET 
    "LeftId" = (SELECT "Id" FROM "Users" WHERE "Username" = u."LeftUsername"),
    "RightId" = (SELECT "Id" FROM "Users" WHERE "Username" = u."RightUsername")
WHERE "LeftUsername" IS NOT NULL OR "RightUsername" IS NOT NULL;
```

---

## ⚙️ تنظیمات پیشرفته

### appsettings.json

```json
{
  "SourceConnectionString": "Host=...;Database=...;Username=...;Password=...",
  "DestinationConnectionString": "Host=...;Database=...;Username=...;Password=...",
  
  "BatchSize": 5000,
  "MaxRetries": 3,
  "RetryDelaySeconds": 5,
  
  "TableMappings": [
    {
      "SourceTable": "Categorys",
      "DestinationTable": "Categories",
      "Priority": 1,
      "ColumnMappings": {
        "Id": "Id",
        "Name": "Name",
        "ParentId": "ParentId"
      }
    }
    // ... 32 more tables
  ]
}
```

### تنظیمات کلیدی:

| تنظیم | پیش‌فرض | توضیحات |
|-------|---------|---------|
| `BatchSize` | 5000 | تعداد rows در هر batch |
| `MaxRetries` | 3 | تلاش مجدد در صورت خطا |
| `RetryDelaySeconds` | 5 | تأخیر بین retries |
| `Priority` | 1-5 | ترتیب migration (1=اول) |

---

## 🔧 ترتیب Migration

### مرحله 1: جداول پایه (بدون FK)
```
Roles → Tags → SystemConfigurations → ClubFeatures → Packages
```

### مرحله 2: جداول کاربری
```
Users → OtpTokens → UserRoles → UserWallets → UserAddresses → UserCarts
```

### مرحله 3: جداول محصولات
```
Categories → Products → ProductImages → ProductGalleries → ProductCategories → ProductTags
```

### مرحله 4: جداول عضویت
```
ClubMemberships → ClubMembershipHistories → NetworkWeeklyBalances
```

### مرحله 5: جداول تراکنش
```
UserOrders → Transactions → Contracts
```

---

## 🛠️ عیب‌یابی

### مشکل: FK Constraint Violation

**علامت**:
```
ERROR: insert or update on table "UserRoles" violates foreign key constraint
```

**راه‌حل**: بررسی Priority در appsettings.json - جدول parent باید Priority کمتر داشته باشد

---

### مشکل: Duplicate Key

**علامت**:
```
ERROR: duplicate key value violates unique constraint
```

**راه‌حل**:
```sql
-- پاک کردن destination قبل از migration
TRUNCATE TABLE "TargetTable" CASCADE;
```

---

### مشکل: Connection Timeout

**علامت**:
```
Npgsql.NpgsqlException: Timeout during reading attempt
```

**راه‌حل**: کاهش `BatchSize` به 1000

---

## ✅ چک‌لیست قبل از اجرا

- [ ] دسترسی به هر دو دیتابیس تست شده
- [ ] Backup از destination database گرفته شده
- [ ] Connection strings صحیح است
- [ ] BatchSize مناسب تنظیم شده
- [ ] Priority ها بررسی شده
- [ ] Post-Migration script آماده است

---

## 📊 آمار نهایی

| معیار | مقدار |
|-------|-------|
| تعداد جداول | 33 |
| جداول با تغییر نام | 10 |
| زمان تخمینی | 5-10 دقیقه |
| BatchSize پیش‌فرض | 5000 |
| MaxRetries | 3 |

---

## 📚 فایل‌های مرتبط

| فایل | توضیحات |
|------|---------|
| `appsettings.json` | تنظیمات و mapping ها |
| `MigrationService.cs` | لاجیک اصلی migration |
| `PostMigration_DataTransformation.sql` | Binary tree conversion |
