consolidate: move all project-level docs to totalDoc
- BackOffice/docs → totalDoc/backoffice/ (AUDIT + CHANGELOG) - FrontOffice/docs → totalDoc/frontoffice/ (CHANGELOG + UI-UNIFICATION-PLAN) - CMS/README.md → totalDoc/cms/CMS-README.md - DataMigration/README.md → totalDoc/migration/DATAMIGRATION-README.md - deployment/README.md → totalDoc/deployment/DEPLOYMENT-README.md - Updated INDEX.md with new paths and sections
This commit is contained in:
@@ -0,0 +1,425 @@
|
||||
# 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
|
||||
**وضعیت**: آماده برای پیادهسازی نهایی
|
||||
Reference in New Issue
Block a user