- F1-F7 از 🟡 به ✅ تغییر کردند - NuGet: v0.0.188 → v0.0.189 - R8 (validator hardcoded 1B): فیکس شد - کامیت هشهای جدید اضافه شد - آمار کامیتها و تاریخ بروز شد
42 KiB
📦 راهنمای مهاجرت سیستم پکیجبیس — خلاصه تغییرات و پلن استقرار
وضعیت: آماده تست و استقرار — Q1-Q30 تکمیلشده ✅ | F1-F11 تکمیلشده ✅
تاریخ: ۸ اسفند ۱۴۰۴ (27 Feb 2026) — آپدیت ۱۰ اسفند
نسخه NuGet: v0.0.189
تعداد کامیتها: ۵۱+ کامیت در ۴ ریپازیتوری (۲۱ CMS + ۹ FO + ۷ BO + ۱۴+ docs)
مدت پیادهسازی: ۶ روز (۲۴ فوریه – ۱ مارس ۲۰۲۶)
ریپوها: CMS (gitea/kub-stage) · FrontOffice (kub-stage) · BackOffice (kub-stage) · totalDoc (foursatDocs/main)
فهرست مطالب
- خلاصه اجرایی
- چه چیزی تغییر کرده؟ — نمای بیزینسی
- بخشهای تحت تاثیر سیستم
- جزئیات تغییرات هر ریپو
- پلن مهاجرت مرحلهبهمرحله
- Rollback Plan
- چکلیست تست قبل از Production
- ریسکها و نکات بحرانی
1. خلاصه اجرایی
قبل (سیستم تکپکیج):
- فقط یک پکیج پایه (۵۶ میلیون تومان) وجود داشت
- تمام مقادیر مالی (قیمت، هزینه فعالسازی، ضرایب، سقفها) hardcoded در کد بودند
- خرید مجدد پکیج غیرممکن بود (حتی بعد تکمیل چرخه)
- پورسانت فقط از یک Pool واحد محاسبه میشد
- همه کاربران همه فیچرها را دریافت میکردند
بعد (سیستم چندپکیجی):
- سیستم N پکیج با قیمت و ویژگیهای متفاوت پشتیبانی میکند
- تمام مقادیر مالی از دیتابیس (Package entity) خوانده میشوند
- خرید مجدد بعد تکمیل چرخه Magic Wallet فعال شده
- هر پکیج Commission Pool مستقل خود را دارد
- فیچرها per-package هستند و با الگوریتم DIFF مدیریت میشوند
- قرارداد باشگاه فقط یک بار (اولین خرید) امضا میشود
آمار تغییرات:
| شاخص | مقدار |
|---|---|
| فایلهای تغییریافته | ۲۲۷+ فایل |
| خطوط اضافهشده | +۱۷,۰۰۰+ |
| خطوط حذفشده | −۲,۶۶۰+ |
| تصمیمات بیزینسی پیادهشده | ۳۰ تصمیم (Q1–Q30) |
| باگهای فیکسشده | ۶ باگ بحرانی |
| مقادیر hardcoded حذفشده | ۱۵+ مورد |
| Handlerهای deprecated حذفشده | ۴ handler (۱۲ فایل) |
| RPCهای deprecated حذفشده | ۴ RPC + ۸ message type |
| فایلهای rename شده | ۳۴ فایل + ۱۱ دایرکتوری (UserWalletChangeLog → UserWalletHistory) |
| History Tables جدید | ۳ جدول (PackageHistories, ClubMembershipCycleHistories, UserWalletHistories) |
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-downline-package — بر اساس پکیج زیرمجموعهها (تغییر پکیج خود کاربر تاثیری ندارد) |
| 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 + Commission + Proto + History + Rename + Interceptor |
| FrontOffice | ۸ | ۲۹ | +۵۵۰ | −۱۳۶ | Dynamic UI + Customer RPCs + Per-package Reports + UI Guidance |
| BackOffice | ۶ | ۲۴ | +۵۸۰ | −۳۱ | Package CRUD + Feature Matrix + Per-package Reports + UI Guidance |
| totalDoc | ۱۴ | ۱۳ | +۲,۷۰۰ | −۱۹۴ | مستندات بیزینسی + تکنیکال + Phase 9 |
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 |
| Phase 9a | a1024a3 |
Q24: آستانه موجودی ≤1M ریال + Q26: SP Worker auto-deploy (IHostedService + checksum) |
| Phase 9b | fdbb91d |
Q27: PackageHistory + ClubMembershipCycleHistory entities + enums + EF configs |
| Phase 9d | 10d2ca2 |
Rename UserWalletChangeLog→UserWalletHistory (86 فایل) + IHasHistory + Interceptor + Migration |
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 — قیمتگذاری داینامیک |
| Phase 9c | 474d364 |
Q28: UI Guidance alerts (G1-G7) — ۷ صفحه MudAlert آموزشی |
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 |
| Phase 9c | 6939780 |
Q28: UI Guidance alerts (G8-G13) — ۶ صفحه MudAlert |
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.5b اجرای Migration دوم: Q27_HistoryTables_And_RenameWalletHistory
└── این migration شامل:
• RenameTable: UserWalletChangeLogs → UserWalletHistories (حفظ دادهها!)
• RenameIndex × 2 + sp_rename PK + FK × 2
• CreateTable: PackageHistories (فیلدهای Old*/New*)
• CreateTable: ClubMembershipCycleHistories (فیلدهای Old*/New*)
⚠️ دادههای قبلی UserWalletChangeLogs حفظ میشوند (RenameTable نه DropTable)
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 دیتابیس
# 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 موفق)
# ⚠️ نکته: migration undo ممکن نیست (ستونهای جدید اضافه شدهاند)
# اما کد قدیمی با ستونهای nullable مشکلی ندارد
# Rollback فقط CMS image
kubectl set image deployment/cms cms=cms:rollback-point
سناریو ۳: مشکل در FO/BO
# 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-downline-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.189 ✅ |
| R7 | JWT claims — cache invalidation | کاربران باید re-login کنند |
| R8 | ✅ فیکس شد — SystemConstants.WalletMaxSafeAmount (10B) حصار ایمنی |
⚠️ تغییرات آینده (هنوز پیادهنشده — Phase بعدی)
این موارد در BIZ spec شناسایی شدهاند ولی هنوز پیاده نشدهاند:
| # | مورد | شدت | شرح |
|---|---|---|---|
| ✅ انجامشده | CMS:e5bc3a9 — PackageId در UserWalletHistory |
||
| ✅ انجامشده | CMS:61b7e4f — SmsTemplates+IUserNotificationService+UserNotificationService با packageName |
||
| ✅ بررسیشده | بدون تغییر — هر ۳ worker از قبل per-package صحیح کار میکنند | ||
| ✅ انجامشده | CMS:61b7e4f BO:92c9922 — proto+handler+CSV برای ManualPayments/WithdrawalRequests |
||
| ✅ بررسیشده | بدون تغییر — مقادیر per-package قبلاً به Package entity منتقل شدهاند | ||
| ✅ انجامشده | CMS:61b7e4f FO:ecc4f44 — magic_multiplier+magic_max_credit از API، داشبورد "شارژ چندبرابری" |
||
| ✅ انجامشده | CMS:61b7e4f FO:ecc4f44 — SystemConstants.WalletMaxSafeAmount (10B) حصار ایمنی، سقف واقعی per-package در هندلر |
||
| ✅ انجامشده | CMS:a1024a3 — Balance <= 1_000_000 |
||
| ✅ انجامشده | CMS:a1024a3 — StoredProcedureDeploymentService |
||
| ✅ انجامشده | CMS:fdbb91d+10d2ca2 — IHasHistory + Interceptor + RenameTable migration |
||
| ✅ انجامشده | FO:474d364 BO:6939780 — ۱۳ صفحه MudAlert |
✅ F1-F11 همه پیادهسازی شدند.
ضمیمه: ۳۰ تصمیم بیزینسی (Q1–Q30)
پیادهشده (Q1–Q23):
| # | تصمیم | وضعیت |
|---|---|---|
| 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 |
تصمیمات v6 (Q24–Q30) — ✅ تکمیلشده:
| # | تصمیم | وضعیت | کامیت |
|---|---|---|---|
| Q24 | آستانه موجودی ≤ ۱,۰۰۰,۰۰۰ ریال (ورود Magic + خرید مجدد) | ✅ | CMS:a1024a3 |
| Q25 | DayaLoans فقط پکیج پایه — تایید (بدون تغییر کد) | ✅ تایید | — |
| Q26 | SP Worker — auto-deploy با checksum (IHostedService) | ✅ | CMS:a1024a3 |
| Q27 | History Tables — PackageHistory + CycleHistory + IHasHistory + Interceptor + Rename UserWalletChangeLog→UserWalletHistory | ✅ | CMS:fdbb91d+10d2ca2 |
| Q28 | UI Guidance — ۱۳ صفحه MudAlert آموزشی/هشداری در FO/BO | ✅ | FO:474d364 BO:6939780 |
| Q29 | شرط EXIT Magic — تایید: آخرین پکیج فعال (بدون تغییر کد) | ✅ تایید | — |
| Q30 | Carryover — تایید: توضیح مستند شد (بدون تغییر کد) | ✅ تایید | — |
آخرین بروزرسانی: ۱۰ اسفند ۱۴۰۴ — v7: F1-F7 همه تکمیلشده ✅ | ۵۱+ کامیت (۲۱ CMS + ۹ FO + ۷ BO + ۱۴+ docs) | NuGet v0.0.189 | Notifications+PackageName, CSV ستون پکیج, Dynamic MagicWallet, SystemConstants validators