docs: add comprehensive Package Migration Guide — business impact + step-by-step deployment plan
This commit is contained in:
@@ -0,0 +1,667 @@
|
||||
# 📦 راهنمای مهاجرت سیستم پکیجبیس — خلاصه تغییرات و پلن استقرار
|
||||
|
||||
> **وضعیت:** آماده تست و استقرار
|
||||
> **تاریخ:** ۸ اسفند ۱۴۰۴ (27 Feb 2026)
|
||||
> **نسخه NuGet:** v0.0.188
|
||||
> **تعداد کامیتها:** ۴۳ کامیت در ۴ ریپازیتوری (+ ۴ کامیت مرتبط)
|
||||
> **مدت پیادهسازی:** ۴ روز (۲۴–۲۷ فوریه ۲۰۲۶)
|
||||
> **ریپوها:** CMS (`gitea`/`kub-stage`) · FrontOffice (`kub-stage`) · BackOffice (`kub-stage`) · totalDoc (`foursatDocs`/`main`)
|
||||
|
||||
---
|
||||
|
||||
## فهرست مطالب
|
||||
|
||||
1. [خلاصه اجرایی](#1-خلاصه-اجرایی)
|
||||
2. [چه چیزی تغییر کرده؟ — نمای بیزینسی](#2-چه-چیزی-تغییر-کرده--نمای-بیزینسی)
|
||||
3. [بخشهای تحت تاثیر سیستم](#3-بخشهای-تحت-تاثیر-سیستم)
|
||||
4. [جزئیات تغییرات هر ریپو](#4-جزئیات-تغییرات-هر-ریپو)
|
||||
5. [پلن مهاجرت مرحلهبهمرحله](#5-پلن-مهاجرت-مرحلهبهمرحله)
|
||||
6. [Rollback Plan](#6-rollback-plan)
|
||||
7. [چکلیست تست قبل از Production](#7-چکلیست-تست-قبل-از-production)
|
||||
8. [ریسکها و نکات بحرانی](#8-ریسکها-و-نکات-بحرانی)
|
||||
|
||||
---
|
||||
|
||||
## 1. خلاصه اجرایی
|
||||
|
||||
### قبل (سیستم تکپکیج):
|
||||
- فقط **یک پکیج پایه** (۵۶ میلیون تومان) وجود داشت
|
||||
- تمام مقادیر مالی (قیمت، هزینه فعالسازی، ضرایب، سقفها) **hardcoded** در کد بودند
|
||||
- خرید مجدد پکیج **غیرممکن** بود (حتی بعد تکمیل چرخه)
|
||||
- پورسانت فقط از **یک Pool واحد** محاسبه میشد
|
||||
- همه کاربران **همه فیچرها** را دریافت میکردند
|
||||
|
||||
### بعد (سیستم چندپکیجی):
|
||||
- سیستم **N پکیج** با قیمت و ویژگیهای متفاوت پشتیبانی میکند
|
||||
- تمام مقادیر مالی از **دیتابیس (Package entity)** خوانده میشوند
|
||||
- خرید مجدد بعد تکمیل چرخه Magic Wallet **فعال** شده
|
||||
- هر پکیج **Commission Pool مستقل** خود را دارد
|
||||
- فیچرها **per-package** هستند و با الگوریتم **DIFF** مدیریت میشوند
|
||||
- قرارداد باشگاه **فقط یک بار** (اولین خرید) امضا میشود
|
||||
|
||||
### آمار تغییرات:
|
||||
|
||||
| شاخص | مقدار |
|
||||
|-------|-------|
|
||||
| فایلهای تغییریافته | **۱۴۱ فایل** |
|
||||
| خطوط اضافهشده | **+۱۰,۸۳۵** |
|
||||
| خطوط حذفشده | **−۲,۱۹۴** |
|
||||
| تصمیمات بیزینسی پیادهشده | **۲۳ تصمیم** (Q1–Q23) |
|
||||
| باگهای فیکسشده | **۶ باگ بحرانی** |
|
||||
| مقادیر hardcoded حذفشده | **۱۵+ مورد** |
|
||||
| Handlerهای deprecated حذفشده | **۴ handler** (۱۲ فایل) |
|
||||
| RPCهای deprecated حذفشده | **۴ RPC** + ۸ message type |
|
||||
|
||||
---
|
||||
|
||||
## 2. چه چیزی تغییر کرده؟ — نمای بیزینسی
|
||||
|
||||
### 2.1 🏪 مدل فروش پکیج
|
||||
|
||||
| قابلیت | قبل | بعد |
|
||||
|--------|-----|------|
|
||||
| تعداد پکیج | ۱ (پایه ۵۶M) | **N پکیج** (پایه ۵۶M + نقرهای ۵.۶M + ...) |
|
||||
| قیمتگذاری | hardcoded `56_000_000` | از `Package.Price` در دیتابیس |
|
||||
| هزینه فعالسازی | hardcoded `25_200_000` | از `Package.ActivationFee` |
|
||||
| ضریب تخفیف | hardcoded `× 2` | از `Package.DiscountMultiplier` |
|
||||
| پشتیبانی دایا | فقط پکیج پایه | بر اساس `Package.SupportsDayaPurchase` |
|
||||
| پرداخت مستقیم | همه | بر اساس `Package.SupportsDirectPurchase` |
|
||||
|
||||
### 2.2 🔄 چرخه خرید مجدد (Re-Purchase)
|
||||
|
||||
| مرحله | قبل | بعد |
|
||||
|-------|-----|------|
|
||||
| تکمیل چرخه Magic | کاربر در بنبست | `PackagePurchaseMethod = None` ریست میشود |
|
||||
| خرید مجدد | **مسدود** (guard G1-G3) | **مجاز** — بعد تکمیل چرخه Magic |
|
||||
| قرارداد باشگاه | هر بار | **فقط یک بار** — خرید مجدد Skip (Q19) |
|
||||
| فیچرها | همه فیچرها بدون توجه به پکیج | **DIFF/تفاضل** — فقط اختلاف اعمال میشود (Q20) |
|
||||
| تاریخچه | فقط `ActivatedAt` | `FirstActivationDate` + `LastActivationDate` (Q21) |
|
||||
|
||||
### 2.3 💰 پورسانت و تعادلها
|
||||
|
||||
| ویژگی | قبل | بعد |
|
||||
|-------|-----|------|
|
||||
| Commission Pool | ۱ Pool واحد | **Pool جداگانه هر پکیج** |
|
||||
| تعادل هفتگی | ۱ رکورد per user/week | **N رکورد** per user/week/package |
|
||||
| MaxBalancesPerLeg | hardcoded `300` | per-package (پایه=۳۰۰, نقرهای=۳۰) |
|
||||
| MaxNetworkLevel | hardcoded `15` | per-package از دیتابیس |
|
||||
| Carryover | یکپارچه | **per-package** — تغییر پکیج = ریست carryover (Q23) |
|
||||
| Stored Procedure | پارامترهای ثابت | پارامترهای داینامیک از Package entity |
|
||||
| گزارش مشتری | بدون تفکیک | **breakdown per-package** |
|
||||
| گزارش ادمین | بدون فیلتر | **فیلتر بر اساس پکیج** |
|
||||
|
||||
### 2.4 🪄 کیف پول جادویی (Magic Wallet)
|
||||
|
||||
| ویژگی | قبل | بعد |
|
||||
|-------|-----|------|
|
||||
| ضریب جادویی | hardcoded `× 2.5` | از `Package.MagicWalletMultiplier` |
|
||||
| سقف واریز | hardcoded `1,000,000,000` | از `Package.MagicWalletMaxDeposit` |
|
||||
| سقف اعتبار | hardcoded `2,500,000,000` | از `Package.MagicWalletMaxCredit` |
|
||||
| شرط EXIT | بررسی سقف global | بررسی سقف **per-package** |
|
||||
|
||||
### 2.5 📋 فیچرهای باشگاه
|
||||
|
||||
| ویژگی | قبل | بعد |
|
||||
|-------|-----|------|
|
||||
| تخصیص فیچر | `GetAllFeatureIds()` — همه فیچرها | از `Package.PackageFeatures` — per-package |
|
||||
| خرید مجدد | — | الگوریتم **DIFF**: مقایسه فیچرهای فعلی با پکیج جدید |
|
||||
| مدیریت ادمین | — | ماتریس checkbox پکیج × فیچر در BackOffice |
|
||||
|
||||
---
|
||||
|
||||
## 3. بخشهای تحت تاثیر سیستم
|
||||
|
||||
### 3.1 نقشه تاثیرگذاری
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 🏗️ سیستم پکیجبیس — Impact Map │
|
||||
├─────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─── CMS (Backend) ──────────────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ 📦 Domain Layer (Entity تغییرات) │ │
|
||||
│ │ ├── Package.cs ← +۱۱ فیلد جدید │ │
|
||||
│ │ ├── PackageFeature.cs ← Entity کاملاً جدید │ │
|
||||
│ │ ├── ClubMembership.cs ← ActivatedAt → ۴ فیلد First/Last │ │
|
||||
│ │ ├── ClubMembershipCycle.cs ← +PackageId │ │
|
||||
│ │ ├── WeeklyCommissionPool.cs ← +PackageId │ │
|
||||
│ │ ├── UserCommissionPayout.cs ← +PackageId │ │
|
||||
│ │ ├── NetworkWeeklyBalance.cs ← +PackageId │ │
|
||||
│ │ └── SystemConstants.cs ← حذف ۹ ثابت منسوخ │ │
|
||||
│ │ │ │
|
||||
│ │ ⚙️ Application Layer (Handler تغییرات) │ │
|
||||
│ │ ├── ActivateClubMembershipCommandHandler ← فیچر DIFF + re-activate│ │
|
||||
│ │ ├── AcceptClubMembershipContractCommandHandler ← فیچر DIFF │ │
|
||||
│ │ ├── VerifyPackagePurchaseCommandHandler ← حذف fallback 2.0m │ │
|
||||
│ │ ├── CustomerPurchasePackage/Verify ← Generic purchase flow │ │
|
||||
│ │ ├── ChargeMagicWalletCommandHandler ← سقف per-package │ │
|
||||
│ │ ├── VerifyMagicWalletChargeCommandHandler ← ضریب per-package │ │
|
||||
│ │ ├── UserOrderService (EXIT Magic) ← ریست + سقف per-package │ │
|
||||
│ │ ├── CreateManualPaymentCommandHandler ← ضریب از Package │ │
|
||||
│ │ └── CheckAndProcessDayaLoansCommandHandler ← حذف ID=4 │ │
|
||||
│ │ │ │
|
||||
│ │ 🔌 Infrastructure Layer │ │
|
||||
│ │ ├── sp_CalculateWeeklyBalances ← @PackageId + @Max params │ │
|
||||
│ │ ├── sp_CalculateWeeklyCommissionPool ← @PackageId │ │
|
||||
│ │ ├── WeeklyCommissionCalculationService ← Loop per-package │ │
|
||||
│ │ ├── OrmCommissionCalculationStrategy ← فیلتر PackageId │ │
|
||||
│ │ └── SpCommissionCalculationStrategy ← پارامترهای داینامیک │ │
|
||||
│ │ │ │
|
||||
│ │ 📡 Proto/gRPC Layer │ │
|
||||
│ │ ├── package.proto ← ۱۱ فیلد + PackageFeature CRUD │ │
|
||||
│ │ ├── commission.proto ← package_id/title در ۴ model + فیلتر │ │
|
||||
│ │ ├── حذف ۴ RPC deprecated (Golden/Base) │ │
|
||||
│ │ └── حذف ۸ message type deprecated │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─── FrontOffice (مشتری) ─────────────────────────────────────────────┐│
|
||||
│ │ ├── Packages.razor ← کاشیهای داینامیک (نه hardcoded) ││
|
||||
│ │ ├── PackageDetail.razor ← فیچرها از API (نه ثابت) ││
|
||||
│ │ ├── Checkout.razor ← پرداخت شرطی (دایا/مستقیم) ││
|
||||
│ │ ├── MyPackages.razor ← خرید مجدد + پیشرفت Magic ││
|
||||
│ │ ├── ActivationSection.razor ← قیمت داینامیک (نه ۵۶M hardcoded) ││
|
||||
│ │ ├── ClubMembershipContractDialog ← متن قرارداد داینامیک ││
|
||||
│ │ ├── CommissionDashboard ← فیلتر + ستون پکیج ││
|
||||
│ │ ├── WeeklyBalancePage ← فیلتر per-package ││
|
||||
│ │ ├── PaymentCallback ← مهاجرت به Customer* RPCs ││
|
||||
│ │ └── حذف "پکیج طلایی" hardcoded (۵+ جا) ││
|
||||
│ └─────────────────────────────────────────────────────────────────────┘│
|
||||
│ │
|
||||
│ ┌─── BackOffice (ادمین) ──────────────────────────────────────────────┐│
|
||||
│ │ ├── Package CRUD ← +۱۲ فیلد جدید در Create/Update ││
|
||||
│ │ ├── PackageFeature Matrix ← checkbox فیچرها ││
|
||||
│ │ ├── ManualPaymentDialog ← حذف ۵۶M hardcoded + Amount editable ││
|
||||
│ │ ├── ChangeParentDialog ← جابجایی در شبکه (جدید) ││
|
||||
│ │ ├── UserPayouts ← فیلتر + ستون پکیج ││
|
||||
│ │ ├── BalancesReport ← فیلتر + ستون پکیج ││
|
||||
│ │ ├── PackageSelect Component ← dropdown قابل استفاده مجدد ││
|
||||
│ │ └── حذف "پکیج طلایی" → "خرید پکیج" ││
|
||||
│ └─────────────────────────────────────────────────────────────────────┘│
|
||||
│ │
|
||||
│ ┌─── Database ────────────────────────────────────────────────────────┐│
|
||||
│ │ ├── Packages ← ۱۱ ستون جدید + Seed نقرهای ││
|
||||
│ │ ├── PackageFeatures ← جدول جدید ││
|
||||
│ │ ├── ClubMemberships ← ۴ ستون First/Last + حذف ActivatedAt ││
|
||||
│ │ ├── ClubMembershipCycles ← +PackageId ││
|
||||
│ │ ├── WeeklyCommissionPools ← +PackageId + Unique ││
|
||||
│ │ ├── UserCommissionPayouts ← +PackageId + Unique ││
|
||||
│ │ ├── NetworkWeeklyBalances ← +PackageId + Unique ││
|
||||
│ │ └── EF Migration + Data Backfill ││
|
||||
│ └─────────────────────────────────────────────────────────────────────┘│
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.2 خلاصه آماری per-repo
|
||||
|
||||
| ریپو | کامیت | فایل | اضافه | حذف | شرح اصلی |
|
||||
|-------|-------|------|-------|-----|-----------|
|
||||
| **CMS** | ۱۷ | ۹۳ | +۷,۳۳۱ | −۱,۸۵۵ | Domain + Business Logic + Commission + Proto + Cleanup |
|
||||
| **FrontOffice** | ۸ | ۲۲ | +۴۷۵ | −۱۳۶ | Dynamic UI + Customer RPCs + Per-package Reports |
|
||||
| **BackOffice** | ۶ | ۱۸ | +۴۹۷ | −۳۱ | Package CRUD + Feature Matrix + Per-package Reports |
|
||||
| **totalDoc** | ۱۲ | ۸ | +۲,۵۳۲ | −۱۷۲ | مستندات بیزینسی + تکنیکال |
|
||||
|
||||
---
|
||||
|
||||
## 4. جزئیات تغییرات هر ریپو
|
||||
|
||||
### 4.1 CMS — ۱۷ کامیت
|
||||
|
||||
| فاز | کامیت | شرح |
|
||||
|-----|--------|------|
|
||||
| **Phase 0** | `8b9c317` | فیکس ۴ باگ بحرانی: DiscountBalance + UserPackagePurchase |
|
||||
| **Phase 0** | `fe3edd1` | فیکس EXIT Magic Mode — ریست PackagePurchaseMethod + بستن چرخه |
|
||||
| **Phase 1** | `ae92ab8` | زیرساخت Domain: Package +۱۱ فیلد، PackageFeature entity، FKهای جدید |
|
||||
| **Phase 1.5** | `a9cd2fd` | EF Migration + Seed Data + Data Backfill |
|
||||
| **Phase 2** | `8e5c7c5` | جایگزینی همه SystemConstants با Package entity reads |
|
||||
| **Phase 3** | `ccb938e` | بازسازی لایه Package + Proto enhancement + باگفیکس |
|
||||
| **Phase 4** | `0002a5a` | CRUD DTOs + Legacy fixes |
|
||||
| **Phase 5** | `607f791` | پورسانت per-package + حذف ref طلایی |
|
||||
| **SP Fix** | `7176fe4` | فیکس SP: `cm.PackageId` → `cm.LastPackageId` |
|
||||
| **Phase 6** | `d19c569` | Deprecation cleanup + ConfigurationService MagicWallet |
|
||||
| **Phase 7a** | `469d97b` | Cosmetic cleanup + حذف orphan handler |
|
||||
| **Phase 7b** | `161f796` | Embed orderId در callback URL |
|
||||
| **Phase 7c** | `8446e0e` | حذف ۴ handler deprecated (۱۴ فایل، −۱,۱۲۵ خط) |
|
||||
| **Phase 8b** | `ce8e248` | NuGet bump → 0.0.185 |
|
||||
| **Phase 8d** | `7554d70` | حذف ۴ RPC + ۸ message deprecated از Proto |
|
||||
| **Phase 8e** | `aaaf7fc` | Per-package filtering در Commission queries |
|
||||
| **Phase 8f** | `dcd1135` | PackageFeature CRUD support |
|
||||
| **Audit** | `1ac2366` | Compliance audit — Feature DIFF + حذف fallbackهای hardcoded |
|
||||
|
||||
### 4.2 FrontOffice — ۸ کامیت
|
||||
|
||||
| فاز | کامیت | شرح |
|
||||
|-----|--------|------|
|
||||
| **Phase 7a** | `b82cac4` | حذف "پکیج طلایی" + PackageTitle در DTO |
|
||||
| **Phase 7b** | `71f391a` | مهاجرت به Customer* RPCs |
|
||||
| **Phase 8a** | `0bbc11e` | Checkout wire-up به Customer RPCs |
|
||||
| **Phase 8c** | `d71d463` | صفحات پکیج — فیچرهای داینامیک |
|
||||
| **Phase 8d** | `40882c8` | NuGet bump Proto cleanup |
|
||||
| **Phase 8e** | `a956cb9` | Per-package filtering در Commission pages |
|
||||
| **Phase 8f** | `3bffc13` | T4.2+T4.3+F3: پرداخت شرطی + خرید مجدد + PV |
|
||||
| **Audit** | `816dcb7` | حذف ۵۶M hardcoded — قیمتگذاری داینامیک |
|
||||
|
||||
### 4.3 BackOffice — ۶ کامیت
|
||||
|
||||
| فاز | کامیت | شرح |
|
||||
|-----|--------|------|
|
||||
| **Phase 7a** | `f1b0085` | تغییر label "پکیج طلایی" → "خرید پکیج" |
|
||||
| **Phase 8b** | `89f5241` | Package CRUD expansion — ۱۲ فیلد جدید |
|
||||
| **Phase 8d** | `c96377a` | NuGet bump Proto cleanup |
|
||||
| **Phase 8e** | `8be98ae` | Per-package commission filtering + PackageSelect component |
|
||||
| **Phase 8f** | `e020354` | ChangeParentDialog + PackageFeature checkbox matrix |
|
||||
| **Audit** | `e6cf90e` | ManualPaymentDialog — حذف ۵۶M + Amount editable |
|
||||
|
||||
---
|
||||
|
||||
## 5. پلن مهاجرت مرحلهبهمرحله
|
||||
|
||||
### 📋 پیشنیازها
|
||||
|
||||
- [ ] بکاپ کامل از دیتابیس Production
|
||||
- [ ] بکاپ از stateهای Kubernetes (Deployments, ConfigMaps)
|
||||
- [ ] اطمینان از دسترسی به Container Registry (تصاویر فعلی)
|
||||
- [ ] زمانبندی Maintenance Window (ترجیحاً شب یا آخر هفته)
|
||||
- [ ] اطلاعرسانی به کاربران (در صورت نیاز به downtime)
|
||||
|
||||
---
|
||||
|
||||
### مرحله ۱ از ۶: بکاپ و آمادهسازی محیط 🛡️
|
||||
|
||||
> ⏱️ تخمین: ۳۰ دقیقه
|
||||
|
||||
```
|
||||
1.1 بکاپ کامل دیتابیس
|
||||
└── pg_dump -Fc cms_db > cms_backup_pre_package_migration.dump
|
||||
|
||||
1.2 بکاپ دیتابیس BO (اگر جداست)
|
||||
└── pg_dump -Fc bo_db > bo_backup_pre_package_migration.dump
|
||||
|
||||
1.3 ثبت وضعیت فعلی
|
||||
└── تعداد رکوردها:
|
||||
• ClubMemberships: SELECT COUNT(*) ...
|
||||
• ClubMembershipCycles: SELECT COUNT(*) ...
|
||||
• WeeklyCommissionPools: SELECT COUNT(*) ...
|
||||
• UserCommissionPayouts: SELECT COUNT(*) ...
|
||||
• NetworkWeeklyBalances: SELECT COUNT(*) ...
|
||||
• Packages: SELECT COUNT(*) ...
|
||||
|
||||
1.4 ذخیره نسخه فعلی Docker images
|
||||
└── docker tag <current-cms> cms:rollback-point
|
||||
└── docker tag <current-fo> fo:rollback-point
|
||||
└── docker tag <current-bo> bo:rollback-point
|
||||
```
|
||||
|
||||
**✅ Checkpoint:** بکاپها ذخیره شدهاند و قابل restore هستند.
|
||||
|
||||
---
|
||||
|
||||
### مرحله ۲ از ۶: استقرار CMS (Backend) 🏗️
|
||||
|
||||
> ⏱️ تخمین: ۴۵ دقیقه
|
||||
> ⚠️ **ترتیب بحرانی:** CMS باید **اول** deploy شود چون FO و BO به آن وابستهاند.
|
||||
|
||||
```
|
||||
2.1 Build CMS Docker image
|
||||
└── cd CMS/src
|
||||
└── docker build -t cms:package-based .
|
||||
|
||||
2.2 اجرای EF Migration
|
||||
└── این migration شامل:
|
||||
• ۱۱ ستون جدید به جدول Packages
|
||||
• جدول جدید PackageFeatures
|
||||
• ستون PackageId به ۵ جدول (ClubMemberships, Cycles, Pools, Payouts, Balances)
|
||||
• ۴ ستون First/Last به ClubMemberships
|
||||
• Unique Indexها
|
||||
|
||||
⚠️ Migration خودکار اجرا میشود در startup اگر EF auto-migration فعال باشد.
|
||||
✅ اگر دستی: dotnet ef database update
|
||||
|
||||
2.3 Data Backfill — مقداردهی پکیج پایه
|
||||
└── اسکریپت SQL:
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ -- مشخص کردن ID پکیج پایه │
|
||||
│ DO $$ │
|
||||
│ DECLARE base_pkg_id BIGINT; │
|
||||
│ BEGIN │
|
||||
│ SELECT "Id" INTO base_pkg_id │
|
||||
│ FROM "CMS"."Packages" │
|
||||
│ WHERE "IsBasePackage" = true LIMIT 1; │
|
||||
│ │
|
||||
│ -- ClubMemberships │
|
||||
│ UPDATE "CMS"."ClubMemberships" │
|
||||
│ SET "FirstActivationDate" = "ActivatedAt", │
|
||||
│ "LastActivationDate" = "ActivatedAt", │
|
||||
│ "FirstPackageId" = base_pkg_id, │
|
||||
│ "LastPackageId" = base_pkg_id │
|
||||
│ WHERE "FirstActivationDate" IS NULL; │
|
||||
│ │
|
||||
│ -- ClubMembershipCycles │
|
||||
│ UPDATE "CMS"."ClubMembershipCycles" │
|
||||
│ SET "PackageId" = base_pkg_id │
|
||||
│ WHERE "PackageId" IS NULL; │
|
||||
│ │
|
||||
│ -- WeeklyCommissionPools │
|
||||
│ UPDATE "CMS"."WeeklyCommissionPools" │
|
||||
│ SET "PackageId" = base_pkg_id │
|
||||
│ WHERE "PackageId" IS NULL; │
|
||||
│ │
|
||||
│ -- UserCommissionPayouts │
|
||||
│ UPDATE "CMS"."UserCommissionPayouts" │
|
||||
│ SET "PackageId" = base_pkg_id │
|
||||
│ WHERE "PackageId" IS NULL; │
|
||||
│ │
|
||||
│ -- NetworkWeeklyBalances │
|
||||
│ UPDATE "CMS"."NetworkWeeklyBalances" │
|
||||
│ SET "PackageId" = base_pkg_id │
|
||||
│ WHERE "PackageId" IS NULL; │
|
||||
│ │
|
||||
│ RAISE NOTICE 'Migration done: PackageId=%', │
|
||||
│ base_pkg_id; │
|
||||
│ END $$; │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
|
||||
2.4 Verification — بررسی migration
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ SELECT 'ClubMemberships' AS tbl, COUNT(*) │
|
||||
│ FROM "CMS"."ClubMemberships" │
|
||||
│ WHERE "LastPackageId" IS NULL │
|
||||
│ UNION ALL │
|
||||
│ SELECT 'Cycles', COUNT(*) │
|
||||
│ FROM "CMS"."ClubMembershipCycles" │
|
||||
│ WHERE "PackageId" IS NULL │
|
||||
│ UNION ALL │
|
||||
│ SELECT 'Pools', COUNT(*) │
|
||||
│ FROM "CMS"."WeeklyCommissionPools" │
|
||||
│ WHERE "PackageId" IS NULL │
|
||||
│ UNION ALL │
|
||||
│ SELECT 'Payouts', COUNT(*) │
|
||||
│ FROM "CMS"."UserCommissionPayouts" │
|
||||
│ WHERE "PackageId" IS NULL │
|
||||
│ UNION ALL │
|
||||
│ SELECT 'Balances', COUNT(*) │
|
||||
│ FROM "CMS"."NetworkWeeklyBalances" │
|
||||
│ WHERE "PackageId" IS NULL; │
|
||||
│ │
|
||||
│ -- ✅ همه باید 0 باشند! │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
|
||||
2.5 Seed پکیج نقرهای (اگر توسط EF Seed انجام نشده)
|
||||
└── INSERT پکیج نقرهای + PackageFeatures
|
||||
|
||||
2.6 Deploy CMS به Kubernetes
|
||||
└── kubectl set image deployment/cms cms=cms:package-based
|
||||
└── kubectl rollout status deployment/cms
|
||||
|
||||
2.7 Health Check
|
||||
└── curl http://cms-service/health
|
||||
└── بررسی لاگها: kubectl logs deployment/cms --tail=100
|
||||
```
|
||||
|
||||
**✅ Checkpoint:** CMS جدید بالا آمده، migration اجرا شده، همه رکوردها PackageId دارند.
|
||||
|
||||
---
|
||||
|
||||
### مرحله ۳ از ۶: استقرار FrontOffice 🖥️
|
||||
|
||||
> ⏱️ تخمین: ۲۰ دقیقه
|
||||
> پیشنیاز: CMS باید بالا و سالم باشد
|
||||
|
||||
```
|
||||
3.1 Build FrontOffice Docker image
|
||||
└── cd FrontOffice/src
|
||||
└── docker build -t fo:package-based .
|
||||
|
||||
3.2 Deploy به Kubernetes
|
||||
└── kubectl set image deployment/frontoffice fo=fo:package-based
|
||||
└── kubectl rollout status deployment/frontoffice
|
||||
|
||||
3.3 Smoke Test
|
||||
└── ✅ صفحه پکیجها باز میشود (کاشیهای داینامیک)
|
||||
└── ✅ جزئیات پکیج — فیچرها نمایش داده میشود
|
||||
└── ✅ صفحه پاداشها — فیلتر پکیج کار میکند
|
||||
└── ✅ صفحه تعادلها — per-package نمایش داده میشود
|
||||
└── ✅ متن قرارداد — مبلغ داینامیک (نه ۵۶M hardcoded)
|
||||
```
|
||||
|
||||
**✅ Checkpoint:** FrontOffice جدید بالا آمده و صفحات اصلی کار میکنند.
|
||||
|
||||
---
|
||||
|
||||
### مرحله ۴ از ۶: استقرار BackOffice 🛠️
|
||||
|
||||
> ⏱️ تخمین: ۲۰ دقیقه
|
||||
> پیشنیاز: CMS باید بالا و سالم باشد
|
||||
|
||||
```
|
||||
4.1 Build BackOffice Docker image
|
||||
└── cd BackOffice/src
|
||||
└── docker build -t bo:package-based .
|
||||
|
||||
4.2 Deploy به Kubernetes
|
||||
└── kubectl set image deployment/backoffice bo=bo:package-based
|
||||
└── kubectl rollout status deployment/backoffice
|
||||
|
||||
4.3 Smoke Test
|
||||
└── ✅ CRUD پکیج — ۱۲ فیلد جدید نمایش داده میشود
|
||||
└── ✅ ماتریس فیچر — checkboxها load میشوند
|
||||
└── ✅ گزارش تعادلها — فیلتر پکیج کار میکند
|
||||
└── ✅ گزارش پرداختها — ستون پکیج نمایش داده میشود
|
||||
└── ✅ ManualPayment — مبلغ editable (نه ۵۶M disabled)
|
||||
```
|
||||
|
||||
**✅ Checkpoint:** BackOffice جدید بالا آمده و CRUD + گزارشات کار میکنند.
|
||||
|
||||
---
|
||||
|
||||
### مرحله ۵ از ۶: بررسی پورسانت (بحرانی!) 💰
|
||||
|
||||
> ⏱️ تخمین: ۳۰ دقیقه
|
||||
> ⚠️ پورسانت = پول واقعی — دقت مضاعف لازم است
|
||||
|
||||
```
|
||||
5.1 بررسی SP پارامترها
|
||||
└── محاسبه پورسانت هفته تستی (staging)
|
||||
└── بررسی: هر پکیج Pool جداگانه دارد
|
||||
└── بررسی: MaxBalancesPerLeg صحیح (پایه=۳۰۰, نقرهای=۳۰)
|
||||
└── بررسی: MaxNetworkLevel صحیح
|
||||
|
||||
5.2 مقایسه نتایج
|
||||
└── اجرای محاسبه در staging
|
||||
└── مقایسه Pool مبلغ با محاسبه دستی
|
||||
└── ✅ تفاوت < ۱% قابل قبول
|
||||
|
||||
5.3 بررسی carryover
|
||||
└── ✅ carryover فقط per-package
|
||||
└── ✅ تغییر پکیج → ریست carryover
|
||||
```
|
||||
|
||||
**✅ Checkpoint:** محاسبات پورسانت per-package صحیح هستند.
|
||||
|
||||
---
|
||||
|
||||
### مرحله ۶ از ۶: تنظیمات نهایی و بررسی سلامت ✅
|
||||
|
||||
> ⏱️ تخمین: ۱۵ دقیقه
|
||||
|
||||
```
|
||||
6.1 بررسی PackageFeatures seed شدهاند
|
||||
└── SELECT * FROM "CMS"."PackageFeatures";
|
||||
└── پکیج پایه: همه فیچرها ✅
|
||||
└── پکیج نقرهای: فیچرهای تعیینشده ✅
|
||||
|
||||
6.2 بررسی JWT Claims (اختیاری)
|
||||
└── لاگین یک کاربر تست → decode JWT
|
||||
└── ✅ PackageId وجود دارد
|
||||
└── ✅ CanRepurchase صحیح
|
||||
|
||||
6.3 غیرفعال کردن Maintenance Mode (اگر فعال بود)
|
||||
|
||||
6.4 مانیتورینگ ۲۴ ساعته
|
||||
└── بررسی لاگ خطاها
|
||||
└── بررسی response timeها
|
||||
└── بررسی پرداختهای جدید
|
||||
```
|
||||
|
||||
**✅ مهاجرت تکمیل شد!**
|
||||
|
||||
---
|
||||
|
||||
## 6. Rollback Plan
|
||||
|
||||
### سناریو ۱: مشکل در Migration دیتابیس
|
||||
|
||||
```bash
|
||||
# Restore از بکاپ
|
||||
pg_restore -d cms_db cms_backup_pre_package_migration.dump
|
||||
|
||||
# Rollback CMS image
|
||||
kubectl set image deployment/cms cms=cms:rollback-point
|
||||
```
|
||||
|
||||
### سناریو ۲: مشکل در CMS (بعد Migration موفق)
|
||||
|
||||
```bash
|
||||
# ⚠️ نکته: migration undo ممکن نیست (ستونهای جدید اضافه شدهاند)
|
||||
# اما کد قدیمی با ستونهای nullable مشکلی ندارد
|
||||
|
||||
# Rollback فقط CMS image
|
||||
kubectl set image deployment/cms cms=cms:rollback-point
|
||||
```
|
||||
|
||||
### سناریو ۳: مشکل در FO/BO
|
||||
|
||||
```bash
|
||||
# FO و BO مستقل از هم هستند — هرکدام جداگانه rollback
|
||||
kubectl set image deployment/frontoffice fo=fo:rollback-point
|
||||
kubectl set image deployment/backoffice bo=bo:rollback-point
|
||||
```
|
||||
|
||||
### نکته مهم Rollback:
|
||||
- ستونهای جدید **nullable** هستند → کد قدیمی بدون مشکل کار میکند
|
||||
- جدول `PackageFeatures` جدید است → کد قدیمی آن را ignore میکند
|
||||
- **فقط Data Backfill** غیرقابلبرگشت است (ولی ضرری ندارد — فقط NULL → مقدار)
|
||||
|
||||
---
|
||||
|
||||
## 7. چکلیست تست قبل از Production
|
||||
|
||||
### 🛒 خرید و فعالسازی
|
||||
|
||||
| # | تست | روش | نتیجه مورد انتظار |
|
||||
|---|------|------|-------------------|
|
||||
| 1 | خرید پکیج نقرهای (ZarinPal) | از FO → پکیجها → نقرهای → پرداخت | Balance = ۵.۶M, Discount = ۱۱.۲M |
|
||||
| 2 | خرید پکیج پایه (ZarinPal) | از FO → پکیجها → پایه → پرداخت | Balance = ۵۶M, Discount = ۱۱۲M |
|
||||
| 3 | خرید پکیج پایه (Daya Loan) | از FO → پکیجها → پایه → دایا | Balance = ۵۶M + loan created |
|
||||
| 4 | پرداخت دستی (BO) | از BO → ManualPayment → مبلغ دلخواه | Amount editable, not hardcoded |
|
||||
| 5 | فعالسازی با نقرهای | فعالسازی باشگاه بعد خرید نقرهای | فقط فیچرهای نقرهای فعال (نه همه) |
|
||||
| 6 | فعالسازی با پایه | فعالسازی باشگاه بعد خرید پایه | همه فیچرها فعال |
|
||||
|
||||
### 🔄 چرخه Magic + خرید مجدد
|
||||
|
||||
| # | تست | نتیجه مورد انتظار |
|
||||
|---|------|-------------------|
|
||||
| 7 | تکمیل چرخه Magic → ریست | PackagePurchaseMethod = None |
|
||||
| 8 | خرید مجدد همان پکیج | بدون قرارداد مجدد، فقط شارژ wallet |
|
||||
| 9 | خرید مجدد پکیج متفاوت (پایه → نقرهای) | DIFF اجرا: فیچرهای اضافی غیرفعال |
|
||||
|
||||
### 💰 پورسانت per-package
|
||||
|
||||
| # | تست | نتیجه مورد انتظار |
|
||||
|---|------|-------------------|
|
||||
| 10 | Pool جداگانه هر پکیج | WeeklyCommissionPool با PackageId متفاوت |
|
||||
| 11 | MaxBalancesPerLeg متفاوت | پایه=۳۰۰, نقرهای=۳۰ |
|
||||
| 12 | Carryover per-package | تغییر پکیج → ریست carryover |
|
||||
| 13 | SP پارامترها از Package | بدون hardcoded ۳۰۰/۱۵ |
|
||||
|
||||
### 📊 گزارشات per-package
|
||||
|
||||
| # | تست | نتیجه مورد انتظار |
|
||||
|---|------|-------------------|
|
||||
| 14 | FO — فیلتر dropdown پکیج | فیلتر عملکرد صحیح |
|
||||
| 15 | FO — breakdown پاداش per-package | مبالغ صحیح به تفکیک |
|
||||
| 16 | BO — فیلتر پکیج در تعادلها | فیلتر عملکرد صحیح |
|
||||
| 17 | BO — ستون پکیج در پرداختها | نام پکیج نمایش داده میشود |
|
||||
|
||||
### 📋 UI / قرارداد
|
||||
|
||||
| # | تست | نتیجه مورد انتظار |
|
||||
|---|------|-------------------|
|
||||
| 18 | متن قرارداد — مبلغ داینامیک | مبلغ و نام پکیج صحیح (نه ۵۶M hardcoded) |
|
||||
| 19 | ActivationSection — قیمت | از API خوانده میشود |
|
||||
| 20 | BO — ManualPayment editable | مبلغ قابل ویرایش با validation |
|
||||
| 21 | BO — Package CRUD ۱۲ فیلد | همه فیلدهای جدید ذخیره/بارگذاری |
|
||||
| 22 | BO — Feature Matrix | checkboxها sync با DB |
|
||||
|
||||
---
|
||||
|
||||
## 8. ریسکها و نکات بحرانی
|
||||
|
||||
### 🔴 ریسکهای بحرانی
|
||||
|
||||
| # | ریسک | احتمال | تاثیر | کاهشدهنده |
|
||||
|---|-------|--------|-------|------------|
|
||||
| R1 | Migration دیتابیس — PackageId اشتباه | کم | **فاجعه** | Verification query (مرحله 2.4) + بکاپ |
|
||||
| R2 | SP تغییریافته → محاسبات مالی اشتباه | متوسط | **فاجعه** | تست staging + مقایسه دستی |
|
||||
| R3 | Magic Wallet EXIT — سقف global بهجای per-package | متوسط | **بالا** | بررسی MW1-MW3 در CMS handlers |
|
||||
| R4 | قرارداد حقوقی — مبلغ اشتباه | کم | **حقوقی** | متن قرارداد داینامیک ✅ فیکس شده |
|
||||
|
||||
### 🟡 ریسکهای متوسط
|
||||
|
||||
| # | ریسک | کاهشدهنده |
|
||||
|---|-------|------------|
|
||||
| R5 | Proto breaking change | Field numberها backward compatible (فقط اضافه) |
|
||||
| R6 | NuGet version mismatch بین repos | همه روی v0.0.188 ✅ |
|
||||
| R7 | JWT claims — cache invalidation | کاربران باید re-login کنند |
|
||||
| R8 | Validator hardcoded 1B | فعلاً anti-abuse cap — قابل قبول |
|
||||
|
||||
### ⚠️ تغییرات آینده (هنوز پیادهنشده — Phase بعدی)
|
||||
|
||||
این موارد در BIZ spec شناسایی شدهاند ولی **هنوز پیاده نشدهاند**:
|
||||
|
||||
| # | مورد | شدت | شرح |
|
||||
|---|------|------|------|
|
||||
| F1 | WalletChangeLog + PackageId | 🟡 | ۲۱ محل ساخت باید PackageId بگیرند |
|
||||
| F2 | Notification + PackageId | 🟡 | ۴ notification بدون نام پکیج |
|
||||
| F3 | Background Services + PackageId | 🟡 | ۳ worker بدون فیلتر پکیج |
|
||||
| F4 | CSV exports + ستون پکیج | 🟡 | ۳ export بدون ستون |
|
||||
| F5 | SystemConfiguration per-package | 🟡 | تنظیمات global vs per-package |
|
||||
| F6 | MagicWalletChargePage hardcoded | 🟡 | ×۲.۵ و سقف در ۶ جا FO |
|
||||
| F7 | Validators async per-package | 🟢 | سقف 1B → مقدار واقعی |
|
||||
|
||||
> **این موارد ریسک عملیاتی ندارند** و میتوانند در فاز بعدی انجام شوند. سیستم فعلی با fallback مناسب کار میکند.
|
||||
|
||||
---
|
||||
|
||||
## ضمیمه: ۲۳ تصمیم بیزینسی پیادهشده
|
||||
|
||||
| # | تصمیم | وضعیت |
|
||||
|---|-------|-------|
|
||||
| Q1 | باگ DiscountBalance → فیکس | ✅ `8b9c317` |
|
||||
| Q2 | ادغام ۳ مسیر پرداخت → Generic | ✅ `ccb938e` + `8446e0e` |
|
||||
| Q3 | پکیج نقرهای + پایه — داینامیک | ✅ `ae92ab8` + `a9cd2fd` |
|
||||
| Q4 | ActivationFee یک فیلد (حذف GiftValue) | ✅ `ae92ab8` |
|
||||
| Q5 | DiscountMultiplier داینامیک | ✅ `8e5c7c5` |
|
||||
| Q6 | Migration کاربران فعلی → پکیج پایه | ✅ `a9cd2fd` |
|
||||
| Q7 | خرید N بار بعد تکمیل چرخه | ✅ `fe3edd1` + `8e5c7c5` |
|
||||
| Q8 | Commission Pool جدا per-package | ✅ `607f791` |
|
||||
| Q9 | MagicWallet Multiplier داینامیک | ✅ `8e5c7c5` |
|
||||
| Q10 | دایا = پکیج پایه (نه طلایی) | ✅ `ccb938e` |
|
||||
| Q11 | فیچرها داینامیک per-package | ✅ `dcd1135` |
|
||||
| Q12 | MaxBalancesPerLeg per-package | ✅ `607f791` |
|
||||
| Q13 | MaxNetworkLevel per-package | ✅ `607f791` |
|
||||
| Q14 | MagicWalletMaxDeposit per-package | ✅ `ae92ab8` |
|
||||
| Q15 | MagicWalletMaxCredit per-package | ✅ `ae92ab8` |
|
||||
| Q16 | NetworkWeeklyBalance + PackageId | ✅ `ae92ab8` |
|
||||
| Q17 | گزارش FO breakdown per-package | ✅ `a956cb9` |
|
||||
| Q18 | گزارش BO فیلتر per-package | ✅ `8be98ae` |
|
||||
| Q19 | قرارداد فقط یک بار | ✅ `1ac2366` |
|
||||
| Q20 | فیچر DIFF/تفاضل | ✅ `1ac2366` |
|
||||
| Q21 | First/Last ActivationDate | ✅ `ae92ab8` |
|
||||
| Q22 | تشخیص هفته از LastActivationDate | ✅ `607f791` |
|
||||
| Q23 | Carryover strictly per-package | ✅ `607f791` |
|
||||
|
||||
---
|
||||
|
||||
*آخرین بروزرسانی: ۸ اسفند ۱۴۰۴ — آماده تست و استقرار*
|
||||
Reference in New Issue
Block a user