diff --git a/business/BIZ-PACKAGE-BASED-SYSTEM.md b/business/BIZ-PACKAGE-BASED-SYSTEM.md
new file mode 100644
index 0000000..549dd4a
--- /dev/null
+++ b/business/BIZ-PACKAGE-BASED-SYSTEM.md
@@ -0,0 +1,554 @@
+# 📦 سیستم مبتنی بر پکیج (Package-Based System)
+
+> **وضعیت:** تحلیل و بررسی — منتظر تایید
+> **تاریخ:** اسفند ۱۴۰۴
+> **تاثیرگذاری:** زیاد — بخشهای متعدد سیستم تحت تاثیر قرار میگیرد
+
+---
+
+## ۱. خلاصه فیچر
+
+**وضعیت فعلی:** سیستم فقط یک پکیج پایه (۵۶ میلیون تومان) دارد و همه چیز حول آن میچرخد.
+
+**وضعیت هدف:** سیستم چندین پکیج با قیمتها و ویژگیهای متفاوت پشتیبانی میکند. هر پکیج روشهای پرداخت، محاسبه پورسانت، شارژ کیف پول و فیچرهای مختص خود را دارد.
+
+```
+مثال پکیجها:
+┌──────────────┬──────────────┬──────────────┬──────────────┐
+│ 🥈 نقرهای │ 🥇 طلایی │ 💎 الماسی │ ⭐ ویژه │
+│ ۵.۶M تومان │ ۵۶M تومان │ ؟؟ تومان │ ؟؟ تومان │
+│ │ (پکیج پایه) │ │ │
+│ فقط مستقیم │ دایا+مستقیم │ فقط مستقیم │ فقط مستقیم │
+│ فیچر محدود │ همه فیچرها │ همه فیچرها │ همه+اختصاصی │
+└──────────────┴──────────────┴──────────────┴──────────────┘
+```
+
+---
+
+## ۲. وضعیت فعلی سیستم (AS-IS)
+
+### ۲.۱ فلوی فعلی فعالسازی
+
+```mermaid
+flowchart TD
+ A["کاربر وارد سیستم میشود"] --> B{"روش پرداخت"}
+ B -->|"خرید الماس دایا"| C["DayaLoan — ۵۶M"]
+ B -->|"پرداخت مستقیم"| D["درگاه بانکی — ۵۶M"]
+ C --> E["بررسی موفقیت پرداخت"]
+ D --> E
+ E --> F["شارژ کیف پول"]
+ F --> G["مدال قرارداد باشگاه مشتریان"]
+ G --> H["تایید OTP + امضا"]
+ H --> I["فعالسازی عضویت باشگاه"]
+ I --> J["اختصاص فیچرها"]
+ I --> K["ایجاد Cycle"]
+ I --> L["اضافه به Commission Pool"]
+ J --> M["✅ کاربر فعال — لینک معرف"]
+```
+
+### ۲.۲ جریان پول فعلی
+
+```
+کاربر ۵۶M پرداخت میکند
+ │
+ ├── Balance (کیف پول عادی) += ۵۶,۰۰۰,۰۰۰ ریال
+ ├── DiscountBalance (اعتباری) += ۱۱۲,۰۰۰,۰۰۰ ریال (×۲)
+ │
+ └── Club Activation:
+ ├── CommissionPool += ۲۵,۲۰۰,۰۰۰ ریال (ClubActivationFee)
+ └── GiftValue = ۲۵,۲۰۰,۰۰۰ ریال (اطلاعرسانی)
+```
+
+### ۲.۳ مقادیر Hardcoded فعلی (`SystemConstants.cs`)
+
+| ثابت | مقدار | کاربرد |
+|------|-------|--------|
+| `BasePackageAmount` | ۵۶,۰۰۰,۰۰۰ | قیمت پکیج |
+| `DayaLoanAmount` | ۵۶,۰۰۰,۰۰۰ | مبلغ وام دایا |
+| `ClubActivationFee` | ۲۵,۲۰۰,۰۰۰ | سهم هفتگی Commission Pool |
+| `ClubMembershipGiftValue` | ۲۵,۲۰۰,۰۰۰ | ارزش هدیه حق عضویت |
+| `MagicWalletMultiplier` | ×۲.۵ | ضریب کیف پول جادویی |
+
+### ۲.۴ مشکلات فعلی
+
+| # | مشکل | فایل |
+|---|------|------|
+| ۱ | پکیج ID=4 **hardcoded** در `InitiateBasePackagePaymentCommandHandler` | Application/Commands |
+| ۲ | مبلغ ۵۶M **hardcoded** در `SystemConstants` و چندین handler | Domain/Common |
+| ۳ | فیچرها **همه یکجا** assign میشن (۴ فیچر ثابت: چتیکا، بیمه، تریپ، لرن) | ActivateClubMembershipHandler |
+| ۴ | Commission Pool فقط با `ClubActivationFee` ثابت پر میشه | ActivateClubMembershipHandler |
+| ۵ | `DiscountBalance = Amount × 2` — ضریب hardcoded | VerifyPayment handlers |
+| ۶ | فرانتاند فقط یک مسیر خرید نشون میده | FrontOffice pages |
+
+---
+
+## ۳. طراحی پیشنهادی (TO-BE)
+
+### ۳.۱ فلوی جدید فعالسازی
+
+```mermaid
+flowchart TD
+ A["کاربر وارد سیستم"] --> B["صفحه پکیجها
(کاشیهای نقرهای/طلایی/الماسی/...)"]
+
+ B -->|"کلیک روی پکیج"| C{"نوع پکیج"}
+
+ C -->|"پکیج پایه (طلایی)"| D["مدال با دو گزینه:
۱. خرید الماس دایا
۲. پرداخت مستقیم"]
+ C -->|"پکیجهای دیگر"| E["مدال با یک گزینه:
فقط پرداخت مستقیم
+ توضیحات + قیمت"]
+
+ D -->|"دایا"| F["فلوی دایا"]
+ D -->|"مستقیم"| G["درگاه پرداخت"]
+ E --> G
+
+ F --> H["پرداخت موفق"]
+ G --> H
+
+ H --> I["شارژ کیف پول
(متناسب با قیمت پکیج)"]
+ I --> J["مدال قرارداد باشگاه"]
+ J --> K["OTP + امضا"]
+ K --> L["فعالسازی
+ اختصاص فیچرهای پکیج"]
+ L --> M["✅ کاربر فعال"]
+```
+
+### ۳.۲ تغییرات Entity — Package
+
+**فعلی:**
+```csharp
+public class Package : BaseAuditableEntity
+{
+ public string Title { get; set; }
+ public string Description { get; set; }
+ public string ImagePath { get; set; }
+ public long Price { get; set; }
+}
+```
+
+**پیشنهادی:**
+```csharp
+public class Package : BaseAuditableEntity
+{
+ public string Title { get; set; }
+ public string Description { get; set; }
+ public string ImagePath { get; set; }
+ public long Price { get; set; } // قیمت پکیج (ریال)
+
+ // === فیلدهای جدید ===
+ public int SortOrder { get; set; } // ترتیب نمایش
+ public bool IsActive { get; set; } = true; // فعال/غیرفعال
+ public bool IsBasePackage { get; set; } // آیا پکیج پایه است؟
+ public bool SupportsDayaPurchase { get; set; } // پشتیبانی از خرید دایا
+ public bool SupportsDirectPurchase { get; set; } = true; // پشتیبانی از پرداخت مستقیم
+
+ // === محاسبات مالی ===
+ public long ActivationFee { get; set; } // سهم Commission Pool
+ public long GiftValue { get; set; } // ارزش هدیه
+ public decimal DiscountMultiplier { get; set; } = 2.0m; // ضریب شارژ DiscountBalance
+
+ // === Navigation ===
+ public virtual ICollection PackageFeatures { get; set; }
+ public virtual ICollection Purchases { get; set; }
+}
+```
+
+### ۳.۳ Entity جدید — PackageFeature (پل بین پکیج و فیچر)
+
+```csharp
+///
+/// مشخص میکند هر پکیج چه فیچرهایی را فعال میکند
+///
+public class PackageFeature : BaseAuditableEntity
+{
+ public long PackageId { get; set; }
+ public virtual Package Package { get; set; }
+
+ public long ClubFeatureId { get; set; }
+ public virtual ClubFeature ClubFeature { get; set; }
+
+ public bool IsIncluded { get; set; } = true; // آیا این فیچر در پکیج هست؟
+}
+```
+
+### ۳.۴ تغییرات Entity — ClubMembership
+
+```csharp
+public class ClubMembership : BaseAuditableEntity
+{
+ // ... فیلدهای فعلی حفظ میشوند ...
+
+ // === فیلد جدید ===
+ public long PackageId { get; set; } // کدام پکیج خریداری شده
+ public virtual Package Package { get; set; }
+}
+```
+
+### ۳.۵ تغییرات Entity — ClubMembershipCycle
+
+```csharp
+public class ClubMembershipCycle : BaseAuditableEntity
+{
+ // ... فیلدهای فعلی حفظ میشوند ...
+
+ // === فیلد جدید ===
+ public long PackageId { get; set; } // پکیج این سایکل
+ public virtual Package Package { get; set; }
+ // PackageAmount قبلاً وجود دارد — از Package.Price پر میشود
+}
+```
+
+### ۳.۶ تغییرات Entity — WeeklyCommissionPool
+
+```csharp
+public class WeeklyCommissionPool : BaseAuditableEntity
+{
+ // ... فیلدهای فعلی حفظ میشوند ...
+
+ // === فیلد جدید ===
+ public long PackageId { get; set; } // Pool جداگانه برای هر پکیج
+ public virtual Package Package { get; set; }
+}
+```
+
+### ۳.۷ جریان پول جدید
+
+```
+پکیج نقرهای (۵.۶M):
+ ├── Balance += ۵,۶۰۰,۰۰۰
+ ├── DiscountBalance += ۱۱,۲۰۰,۰۰۰ (×۲)
+ └── CommissionPool += ActivationFee مخصوص نقرهای
+
+پکیج طلایی/پایه (۵۶M):
+ ├── Balance += ۵۶,۰۰۰,۰۰۰
+ ├── DiscountBalance += ۱۱۲,۰۰۰,۰۰۰ (×۲)
+ └── CommissionPool += ۲۵,۲۰۰,۰۰۰
+
+پکیج الماسی (??M):
+ ├── Balance += ??
+ ├── DiscountBalance += ?? (×۲)
+ └── CommissionPool += ActivationFee مخصوص الماسی
+```
+
+---
+
+## ۴. محاسبه پورسانت — تغییرات
+
+### ۴.۱ وضعیت فعلی
+
+```
+یک WeeklyCommissionPool برای کل هفته
+ ↓
+TotalAmount = مجموع ActivationFee همه فعالسازیها
+ ↓
+ValuePerBalance = TotalAmount ÷ مجموع Balanceها
+ ↓
+همه یکسان محاسبه میشوند
+```
+
+### ۴.۲ وضعیت هدف
+
+```
+برای هر پکیج، یک WeeklyCommissionPool جداگانه:
+
+Pool_نقرهای:
+ TotalAmount = مجموع ActivationFee خریداران نقرهای این هفته
+ Balanceها = فقط از شبکه خریداران نقرهای
+ ValuePerBalance = Pool_نقرهای ÷ Balance_نقرهای
+
+Pool_طلایی:
+ TotalAmount = مجموع ActivationFee خریداران طلایی این هفته
+ Balanceها = فقط از شبکه خریداران طلایی
+ ValuePerBalance = Pool_طلایی ÷ Balance_طلایی
+```
+
+### ۴.۳ نکته مهم: ساختار شبکه یکی است
+
+```
+ [Ali]
+ / \
+ [Sara] [Reza] ← شبکه باینری یکیست
+ / \ / \
+ [M1] [M2] [M3] [M4]
+
+ولی محاسبات جدا:
+ - Ali با پکیج طلایی → پورسانت از Pool طلایی
+ - Sara با پکیج نقرهای → پورسانت از Pool نقرهای
+ - Reza با پکیج طلایی → پورسانت از Pool طلایی
+```
+
+### ۴.۴ تغییرات Stored Procedure
+
+**`sp_CalculateWeeklyBalances`** باید:
+- پارامتر `@PackageId` بگیرد
+- فقط کاربرانی که این پکیج را خریدهاند فیلتر کند
+- برای هر پکیج جداگانه اجرا شود
+
+**`sp_CalculateWeeklyCommissionPool`** باید:
+- پارامتر `@PackageId` بگیرد
+- Pool مخصوص آن پکیج را بخواند
+- پرداختها فقط به خریداران آن پکیج اختصاص یابد
+
+---
+
+## ۵. فیچرهای باشگاه مشتریان بر اساس پکیج
+
+### ۵.۱ وضعیت فعلی
+
+وقتی کاربر فعال میشود، **همه ۴ فیچر** یکجا assign میشوند:
+```csharp
+// ActivateClubMembershipCommandHandler — خط ~350
+var allFeatureIds = ClubFeatureTypeExtensions.GetAllFeatureIds();
+foreach (var featureId in allFeatureIds)
+{
+ userClubFeatures.Add(new UserClubFeature { ... });
+}
+```
+
+### ۵.۲ وضعیت هدف
+
+فیچرها بر اساس جدول `PackageFeature` تعیین میشوند:
+
+| فیچر | نقرهای | طلایی (پایه) | الماسی |
+|------|---------|-------------|--------|
+| چتیکا | ❌ | ✅ | ✅ |
+| بیمه | ❌ | ✅ | ✅ |
+| تریپ | ✅ | ✅ | ✅ |
+| لرن | ✅ | ✅ | ✅ |
+| فیچر VIP | ❌ | ❌ | ✅ |
+
+*مقادیر بالا نمونهای هستند — قابل تنظیم از BackOffice*
+
+### ۵.۳ تغییر در ActivateClubMembershipHandler
+
+```
+قبلی:
+ GetAllFeatureIds() → assign all
+
+جدید:
+ Package.PackageFeatures
+ .Where(pf => pf.IsIncluded)
+ .Select(pf => pf.ClubFeatureId)
+ → assign only included features
+```
+
+---
+
+## ۶. تغییرات UI — FrontOffice
+
+### ۶.۱ صفحه پکیجها (کاشیها)
+
+```
+┌─────────────────────────────────────────────────────┐
+│ انتخاب پکیج باشگاه مشتریان │
+├─────────────┬──────────────┬──────────────┬─────────┤
+│ │ │ │ │
+│ 🥈 نقرهای │ 🥇 طلایی │ 💎 الماسی │ ⭐ ویژه │
+│ ۵.۶M │ ۵۶M │ ؟؟M │ ؟؟M │
+│ │ │ │ │
+│ ● لرن │ ● چتیکا │ ● همه │ ● همه │
+│ ● تریپ │ ● بیمه │ ● + VIP │ ● +... │
+│ │ ● تریپ │ │ │
+│ │ ● لرن │ │ │
+│ │ │ │ │
+│ [انتخاب] │ [انتخاب] │ [انتخاب] │[انتخاب]│
+└─────────────┴──────────────┴──────────────┴─────────┘
+```
+
+### ۶.۲ مدال پرداخت — پکیج پایه (طلایی)
+
+```
+┌─────────────────────────────────────────┐
+│ خرید پکیج طلایی — ۵۶M تومان │
+│ │
+│ توضیحات: ... │
+│ │
+│ روشهای پرداخت: │
+│ ┌─────────────────────────────────┐ │
+│ │ 💎 خرید از طریق الماس دایا │ │
+│ └─────────────────────────────────┘ │
+│ ┌─────────────────────────────────┐ │
+│ │ 💳 پرداخت مستقیم (درگاه بانکی) │ │
+│ └─────────────────────────────────┘ │
+└─────────────────────────────────────────┘
+```
+
+### ۶.۳ مدال پرداخت — پکیجهای دیگر (نقرهای و بالاتر)
+
+```
+┌─────────────────────────────────────────┐
+│ خرید پکیج نقرهای — ۵.۶M تومان │
+│ │
+│ توضیحات: ... │
+│ ویژگیها: لرن، تریپ │
+│ │
+│ ┌─────────────────────────────────┐ │
+│ │ 💳 پرداخت و فعالسازی │ │
+│ └─────────────────────────────────┘ │
+└─────────────────────────────────────────┘
+```
+
+---
+
+## ۷. بخشهای تحت تاثیر (Impact Analysis)
+
+### ۷.۱ جدول تاثیرپذیری
+
+| # | لایه | فایل/بخش | نوع تغییر | شدت |
+|---|------|----------|-----------|-----|
+| ۱ | **Domain** | `Package.cs` | اضافه فیلد | 🟡 متوسط |
+| ۲ | **Domain** | `PackageFeature.cs` — **جدید** | Entity جدید | 🔴 زیاد |
+| ۳ | **Domain** | `ClubMembership.cs` | اضافه `PackageId` | 🟡 متوسط |
+| ۴ | **Domain** | `ClubMembershipCycle.cs` | اضافه `PackageId` | 🟡 متوسط |
+| ۵ | **Domain** | `WeeklyCommissionPool.cs` | اضافه `PackageId` | 🔴 زیاد |
+| ۶ | **Domain** | `SystemConstants.cs` | حذف hardcodeها → خوانش از Package | 🟡 متوسط |
+| ۷ | **Application** | `ActivateClubMembershipCommandHandler` | فیچر بر اساس پکیج | 🔴 زیاد |
+| ۸ | **Application** | `InitiateBasePackagePaymentCommandHandler` | حذف ID=4 hardcoded | 🟡 متوسط |
+| ۹ | **Application** | `VerifyBasePackagePaymentCommandHandler` | شارژ متناسب با پکیج | 🔴 زیاد |
+| ۱۰ | **Application** | `VerifyPackagePurchasePaymentCommandHandler` | شارژ متناسب با پکیج | 🔴 زیاد |
+| ۱۱ | **Application** | `ManualPaymentCommandHandler` | شارژ متناسب با پکیج | 🟡 متوسط |
+| ۱۲ | **Application** | `CustomerPurchasePackageCommandHandler` | پشتیبانی روشهای پرداخت پکیج | 🟡 متوسط |
+| ۱۳ | **Infra** | `sp_CalculateWeeklyBalances` | پارامتر PackageId | 🔴 زیاد |
+| ۱۴ | **Infra** | `sp_CalculateWeeklyCommissionPool` | Pool جداگانه هر پکیج | 🔴 زیاد |
+| ۱۵ | **Infra** | `WeeklyCommissionCalculationService` | Loop روی پکیجها | 🟡 متوسط |
+| ۱۶ | **Infra** | EF Configurations | جدول جدید + FKها | 🟡 متوسط |
+| ۱۷ | **Infra** | Database Migration | schema changes | 🟡 متوسط |
+| ۱۸ | **Proto** | `package.proto` | فیلدهای جدید پکیج | 🟢 کم |
+| ۱۹ | **Proto** | `clubmembership.proto` | PackageId در response | 🟢 کم |
+| ۲۰ | **Proto** | `commission.proto` | PackageId در pool/payout | 🟢 کم |
+| ۲۱ | **FrontOffice** | صفحه انتخاب پکیج | UI جدید (کاشیها) | 🔴 زیاد |
+| ۲۲ | **FrontOffice** | مدال پرداخت | دو مدال متفاوت | 🔴 زیاد |
+| ۲۳ | **FrontOffice** | `MyPackages.razor` | نمایش نوع پکیج | 🟡 متوسط |
+| ۲۴ | **FrontOffice** | `ActivateClubDialog.razor` | ارتباط با پکیج | 🟡 متوسط |
+| ۲۵ | **BackOffice** | صفحه مدیریت پکیجها | CRUD فیلدهای جدید | 🟡 متوسط |
+| ۲۶ | **BackOffice** | صفحه فیچر پکیجها — **جدید** | ماتریس پکیج×فیچر | 🔴 زیاد |
+| ۲۷ | **BackOffice** | `ActivateClubDialog.razor` | انتخاب پکیج | 🟡 متوسط |
+
+### ۷.۲ ریسکها
+
+| ریسک | احتمال | شدت | راهحل |
+|------|--------|-----|--------|
+| دادههای فعلی — کاربران بدون PackageId | قطعی | زیاد | Migration: کاربران فعلی → PackageId = پکیج پایه |
+| Commission Pool فعلی بدون PackageId | قطعی | زیاد | Migration: Poolهای موجود → PackageId = پکیج پایه |
+| SP تغییر → محاسبات اشتباه | متوسط | بحرانی | تست جامع + محیط staging |
+| مبالغ hardcoded در جاهای پراکنده | زیاد | متوسط | Audit کامل کدبیس |
+| عدم سازگاری FrontOffice/BackOffice | متوسط | متوسط | تست end-to-end |
+
+---
+
+## ۸. فازبندی پیادهسازی
+
+### فاز ۱ — زیرساخت (Domain + DB) ≈ ۳-۴ روز
+
+| تسک | شرح |
+|-----|------|
+| T1.1 | بروزرسانی `Package` entity (فیلدهای جدید) |
+| T1.2 | ایجاد `PackageFeature` entity + EF Configuration |
+| T1.3 | اضافه کردن `PackageId` به `ClubMembership` |
+| T1.4 | اضافه کردن `PackageId` به `ClubMembershipCycle` |
+| T1.5 | اضافه کردن `PackageId` به `WeeklyCommissionPool` |
+| T1.6 | Database Migration + Seed data (پکیج پایه + فیچرها) |
+| T1.7 | Migration: کاربران/Poolهای فعلی → PackageId = پکیج پایه |
+| T1.8 | بروزرسانی Protoها |
+
+### فاز ۲ — منطق کسبوکار (Application) ≈ ۴-۵ روز
+
+| تسک | شرح |
+|-----|------|
+| T2.1 | بروزرسانی `ActivateClubMembershipCommandHandler` — فیچر بر اساس پکیج |
+| T2.2 | بروزرسانی Verify handlers — شارژ کیف پول متناسب با پکیج |
+| T2.3 | حذف مقادیر hardcoded از `SystemConstants` → خوانش از Package |
+| T2.4 | بروزرسانی `InitiateBasePackagePayment` → Generic `InitiatePackagePayment` |
+| T2.5 | بروزرسانی `ManualPaymentCommandHandler` — پشتیبانی پکیج متغیر |
+| T2.6 | CRUD پکیج با فیلدهای جدید (gRPC handlers) |
+| T2.7 | CRUD `PackageFeature` (ماتریس پکیج×فیچر) |
+
+### فاز ۳ — محاسبه پورسانت ≈ ۳-۴ روز
+
+| تسک | شرح |
+|-----|------|
+| T3.1 | بروزرسانی `sp_CalculateWeeklyBalances` — فیلتر بر اساس PackageId |
+| T3.2 | بروزرسانی `sp_CalculateWeeklyCommissionPool` — Pool جداگانه |
+| T3.3 | بروزرسانی `WeeklyCommissionCalculationService` — Loop روی پکیجها |
+| T3.4 | تست محاسبات با داده واقعی |
+
+### فاز ۴ — UI (FrontOffice + BackOffice) ≈ ۴-۵ روز
+
+| تسک | شرح |
+|-----|------|
+| T4.1 | صفحه کاشیهای پکیج (FrontOffice) |
+| T4.2 | مدال پرداخت پکیج پایه (دایا + مستقیم) |
+| T4.3 | مدال پرداخت پکیجهای دیگر (فقط مستقیم) |
+| T4.4 | بروزرسانی `MyPackages.razor` — نمایش نوع پکیج |
+| T4.5 | بروزرسانی `ActivateClubDialog.razor` — ارتباط با پکیج |
+| T4.6 | BackOffice: CRUD پکیج با فیلدهای جدید |
+| T4.7 | BackOffice: صفحه ماتریس فیچرهای پکیج |
+| T4.8 | BackOffice: `ActivateClubDialog` — انتخاب پکیج |
+
+### فاز ۵ — تست و استقرار ≈ ۲-۳ روز
+
+| تسک | شرح |
+|-----|------|
+| T5.1 | تست end-to-end فلوی خرید هر پکیج |
+| T5.2 | تست محاسبه پورسانت جداگانه |
+| T5.3 | تست migration دادههای فعلی |
+| T5.4 | Deploy به staging + تست |
+| T5.5 | Deploy به production |
+
+---
+
+## ۹. Seed Data — پکیجهای اولیه
+
+```sql
+-- Migration: Seed packages
+INSERT INTO Packages (Title, Description, Price, IsActive, IsBasePackage,
+ SupportsDayaPurchase, SupportsDirectPurchase, ActivationFee, GiftValue,
+ DiscountMultiplier, SortOrder)
+VALUES
+ ('نقرهای', 'پکیج نقرهای باشگاه مشتریان', 5600000, 1, 0,
+ 0, 1, ???, ???, 2.0, 1),
+ ('طلایی', 'پکیج طلایی باشگاه مشتریان (پایه)', 56000000, 1, 1,
+ 1, 1, 25200000, 25200000, 2.0, 2);
+
+-- Migration: ربط فیچرها به پکیجها
+INSERT INTO PackageFeatures (PackageId, ClubFeatureId, IsIncluded) VALUES
+ -- نقرهای: فقط تریپ و لرن
+ (@silverId, @tripId, 1),
+ (@silverId, @learnId, 1),
+ -- طلایی: همه فیچرها
+ (@goldId, @chatikaId, 1),
+ (@goldId, @bimeId, 1),
+ (@goldId, @tripId, 1),
+ (@goldId, @learnId, 1);
+
+-- Migration: کاربران فعلی → پکیج پایه
+UPDATE ClubMemberships SET PackageId = @goldId WHERE PackageId IS NULL;
+UPDATE ClubMembershipCycles SET PackageId = @goldId WHERE PackageId IS NULL;
+UPDATE WeeklyCommissionPools SET PackageId = @goldId WHERE PackageId IS NULL;
+```
+
+---
+
+## ۱۰. سوالات باز (نیاز به تصمیمگیری)
+
+| # | سوال | گزینهها |
+|---|------|---------|
+| ۱ | `ActivationFee` و `GiftValue` پکیج نقرهای چقدر باشد؟ | نسبت به قیمت؟ مقدار ثابت؟ |
+| ۲ | آیا کاربر میتواند بعداً پکیج خود را ارتقا دهد (upgrade)؟ | بله → فقط مابهالتفاوت / خیر |
+| ۳ | `DiscountMultiplier` برای همه پکیجها ×۲ باشد؟ | یکسان / متفاوت به ازای هر پکیج |
+| ۴ | ضریب `MagicWallet` (×۲.۵) برای پکیجهای کوچکتر هم همان باشد؟ | بله / خیر |
+| ۵ | فیچرهای پکیج نقرهای دقیقاً کدامها هستند؟ | لرن+تریپ؟ فقط لرن؟ |
+| ۶ | آیا یک کاربر میتواند چند پکیج همزمان داشته باشد؟ | فقط یکی / امکان خرید چندتا |
+| ۷ | نام و تعداد دقیق پکیجها چیست؟ | نقرهای+طلایی؟ بیشتر؟ |
+| ۸ | کاربرانی که با دایا فعال شدن، چه پکیجی دارند؟ | طلایی (پایه) |
+
+---
+
+## ۱۱. تخمین زمانی
+
+| فاز | مدت | وابستگی |
+|-----|------|---------|
+| فاز ۱ — زیرساخت | ۳-۴ روز | — |
+| فاز ۲ — منطق | ۴-۵ روز | فاز ۱ |
+| فاز ۳ — پورسانت | ۳-۴ روز | فاز ۱ |
+| فاز ۴ — UI | ۴-۵ روز | فاز ۲ |
+| فاز ۵ — تست | ۲-۳ روز | فاز ۳, ۴ |
+| **مجموع** | **~۱۶-۲۱ روز کاری** | |
+
+> فازهای ۲ و ۳ قابل موازیسازی هستند.
diff --git a/business/BUSINESS-02-PAYMENT-FINANCE.md b/business/BUSINESS-02-PAYMENT-FINANCE.md
index cbfd905..12ee42f 100644
--- a/business/BUSINESS-02-PAYMENT-FINANCE.md
+++ b/business/BUSINESS-02-PAYMENT-FINANCE.md
@@ -1,7 +1,7 @@
# 💰 سیستم مالی، پرداخت و درگاهها
> **منابع ادغامشده:** `payment-gateway.md`, `payment-architecture-pyms.md`, `daya-loan-integration.md`, `manual-payment-system.md`, `discount-shop-business.md`
-> **آخرین بروزرسانی:** اسفند ۱۴۰۴ (بروزرسانی: فعالسازی درگاه ZarinPal + تنظیمات محیطی)
+> **آخرین بروزرسانی:** اسفند ۱۴۰۴ (بروزرسانی: فیکس WalletChangeLog + validation کیفپول اعتباری + نامگذاری جدید کیفپولها)
---
@@ -24,9 +24,9 @@ flowchart TD
PYMS --> WALLETS
subgraph WALLETS["3 Wallet System"]
- W1["💰 Balance\nنقدی"]
- W2["🌟 NetworkBalance\nشبکه"]
- W3["🏷️ DiscountBalance\nاعتباری"]
+ W1["💰 Balance\nکیف پول اصلی"]
+ W2["🌟 NetworkBalance\nپاداش تیمی"]
+ W3["🏷️ DiscountBalance\nکیف پول اعتباری"]
end
```
@@ -137,7 +137,11 @@ flowchart TD
قیمت محصول = 1,000,000 ریال
MaxDiscountPercent محصول = 40% (هر محصول درصد تخفیف مخصوص خود را دارد)
-سهم تخفیف = MIN(1,000,000 × 40%, DiscountBalanceکاربر) = 400,000
+سهم تخفیف = قیمت × MaxDiscountPercent% = 400,000
+
+⚠️ اگر DiscountBalance < سهم تخفیف → خطا: «موجودی کیف پول اعتباری کافی نیست»
+ (دیگر MIN استفاده نمیشود — کاربر باید موجودی کافی داشته باشد)
+
باقیمانده → ZarinPal IPG = 1,000,000 - 400,000 = 600,000
─────────
مجموع = 1,000,000
@@ -151,11 +155,15 @@ MaxDiscountPercent محصول = 40% (هر محصول درصد تخفیف مخص
flowchart TD
A["کاربر عضو باشگاه\nمشاهده محصول"] --> B["قیمت تخفیفخورده نمایش داده میشود"]
B --> C["افزودن به سبد\nمحاسبه MaxDiscount% هر محصول"]
- C --> D["سهم تخفیف = MIN(قیمت×MaxDiscount%, DiscountBalance)"]
- D --> E["باقیمانده = مجموع - سهم تخفیف"]
+ C --> D["سهم تخفیف = قیمت × MaxDiscount%"]
+ D --> V{"DiscountBalance >= سهم تخفیف?"}
+ V -->|خیر| X["❌ خطا: موجودی کیف پول اعتباری کافی نیست"]
+ V -->|بله| E["باقیمانده = مجموع - سهم تخفیف"]
E --> F{"باقیمانده > 0?"}
F -->|بله| G["کسر DiscountBalance\n+ Redirect → ZarinPal IPG\nباقیمانده + 10% VAT"]
F -->|خیر| H["فقط کسر از DiscountBalance\nبدون درگاه → ثبت مستقیم"]
+ G --> LOG["ثبت UserWalletChangeLog"]
+ H --> LOG
```
### ۵.۳ دسترسی فروشگاه اعتباری
@@ -164,8 +172,21 @@ flowchart TD
|------|--------|
| `IsClubMember = true` | دسترسی به Discount Store |
| `IsClubMember = false` | فقط Regular Store |
-| `DiscountBalance > 0` | میتواند از تخفیف استفاده کند |
-| `DiscountBalance = 0` | پرداخت ۱۰۰% از طریق ZarinPal IPG |
+| `DiscountBalance >= سهم تخفیف` | خرید مجاز |
+| `DiscountBalance < سهم تخفیف` | ❌ خطا: موجودی کیف پول اعتباری کافی نیست |
+
+### ۵.۴ UserWalletChangeLog (اسفند ۱۴۰۴ — فیکس)
+
+> **باگ:** هنگام خرید از فروشگاه اعتباری، `DiscountBalance` در دیتابیس کم میشد ولی هیچ
+> `UserWalletChangeLog` ثبت نمیشد → کاربر در تاریخچه کیفپول چیزی نمیدید.
+
+فیکس در ۳ هندلر:
+
+| هندلر | سناریو | فیکس |
+|--------|---------|------|
+| `PlaceOrderCommandHandler` | پرداخت کامل با DiscountBalance (بدون درگاه) | ✅ ثبت log با `ChangeDiscountValue = -amount` |
+| `CompleteOrderPaymentCommandHandler` | پرداخت ترکیبی (درگاه + DiscountBalance) | ✅ ثبت log بعد از verify موفق درگاه |
+| `VerifyDiscountWalletChargeCommandHandler` | شارژ کیفپول اعتباری | ✅ ثبت log با `ChangeDiscountValue = +amount` |
---
@@ -221,6 +242,18 @@ service PaymentService {
| وام دایا | ✅ کامل | Mock mode فعال در staging |
| پرداخت ترکیبی | ✅ کامل | Discount + IPG |
| Pool هفتگی | ✅ کامل | SP + Hangfire |
+| WalletChangeLog | ✅ فیکس شده | لاگ تغییرات کیفپول در ۳ هندلر اضافه شد |
+| Validation کیفپول اعتباری | ✅ فیکس شده | ارور اگر موجودی کافی نباشد |
| پرداخت دستی | ⬜ طراحی | نیاز به تصمیم مدیریت |
| Refund | ⬜ طراحی | فقط در PYMS تعریفشده |
| کیفپول جادویی (Magic) | ✅ کامل | فاز 1-6 پیادهسازی شده — Production فعال |
+
+### ۸.۱ نامگذاری استاندارد کیفپولها (اسفند ۱۴۰۴)
+
+| فیلد دیتابیس | نام قدیم (UI) | نام جدید (UI) |
+|-------------|--------------|---------------|
+| `Balance` | عادی / اعتباری / نقدی | **کیف پول اصلی** |
+| `DiscountBalance` | تخفیفی / تخفیف | **کیف پول اعتباری** |
+| `NetworkBalance` | شبکه / طلایی / پورسانت | **پاداش تیمی** |
+
+> تغییرات UI در ۱۲ فایل (FrontOffice: 5, BackOffice: 7) اعمال شد.
diff --git a/business/BUSINESS-03-ECOMMERCE-STORES.md b/business/BUSINESS-03-ECOMMERCE-STORES.md
index 1b4a7d0..31ba937 100644
--- a/business/BUSINESS-03-ECOMMERCE-STORES.md
+++ b/business/BUSINESS-03-ECOMMERCE-STORES.md
@@ -1,7 +1,7 @@
# 🛒 فروشگاه، موجودی و محصولات
> **منابع ادغامشده:** `discount-shop-business.md`, `DISCOUNT-STORE-STATUS.md`, `package-purchase-system.md`, `INVENTORY-IMPROVEMENTS.md`, `INVENTORY-REFACTORING-STATUS.md`, `PRODUCT-BUNDLE-FEATURE.md`, `SHOP-UNIFICATION.md`
-> **آخرین بروزرسانی:** اسفند ۱۴۰۴ (بروزرسانی: VAT 10%)
+> **آخرین بروزرسانی:** اسفند ۱۴۰۴ (بروزرسانی: ExpirePendingOrders ۱۵ دقیقه + فروشگاه اعتباری نامگذاری)
---
@@ -226,5 +226,44 @@ graph TD
| Lazy Loading | ✅ کامل | 100% |
| موجودی خودکار | ✅ کامل | 100% |
| تصاویر مربعی | ✅ کامل | 100% |
+| انقضای سفارشات Pending | ✅ کامل | 100% |
| باندل محصولات | ⬜ طراحی | 30% |
| مقایسه محصول | ⬜ ایده | 0% |
+
+---
+
+## ۹. انقضای خودکار سفارشات Pending (ExpirePendingOrdersService)
+
+> سرویس پسزمینهای که سفارشات فروشگاه اعتباری را بعد از ۱۵ دقیقه منقضی میکند.
+
+### ۹.۱ پارامترها
+
+| پارامتر | مقدار | توضیح |
+|---------|-------|-------|
+| `ExpirationTime` | **۱۵ دقیقه** | مدت زمان مجاز برای پرداخت |
+| `CheckInterval` | ۵ دقیقه | فاصله بررسی |
+
+### ۹.۲ عملکرد
+
+```mermaid
+flowchart TD
+ A["هر ۵ دقیقه\nExpirePendingOrdersService"] --> B["جستجوی DiscountOrders\nPaymentStatus=Pending\nCreated < (now - 15 min)"]
+ B --> C{"سفارشی یافت شد?"}
+ C -->|خیر| A
+ C -->|بله| D["آزادسازی رزرو موجودی\nReleaseReservationAsync"]
+ D --> E["PaymentStatus → Reject\nDeliveryStatus → Cancelled"]
+ E --> F["Transaction.PaymentStatus → Reject"]
+ F --> G["Log: Expired order #X"]
+ G --> A
+```
+
+### ۹.۳ فایل
+
+```
+CMS/src/CMSMicroservice.Infrastructure/BackgroundServices/ExpirePendingOrdersService.cs
+```
+
+رجیستر شده در `ConfigureServices.cs`:
+```csharp
+services.AddHostedService();
+```
diff --git a/technical/TECH-03-DEPLOYMENT-INFRA.md b/technical/TECH-03-DEPLOYMENT-INFRA.md
index 887fea8..5ad1aa8 100644
--- a/technical/TECH-03-DEPLOYMENT-INFRA.md
+++ b/technical/TECH-03-DEPLOYMENT-INFRA.md
@@ -1,7 +1,7 @@
# 🚀 استقرار، CI/CD و زیرساخت
> **منابع ادغامشده:** `CICD-PIPELINE-GUIDE.md`, `DEPLOYMENT-README.md`, `INFRASTRUCTURE-GUIDE.md`, `INGRESS-NGINX-WARNING.md`, `OFFLINE-DEPLOYMENT-GUIDE.md`, `SERVER-MIRRORS-CONFIG.md`
-> **آخرین بروزرسانی:** اسفند ۱۴۰۴ (بروزرسانی: PVC آپلود + K8s Secret برای config دائمی + جدا کردن appsettings هر برنچ)
+> **آخرین بروزرسانی:** اسفند ۱۴۰۴ (بروزرسانی: فیکس URL پروداکشن + چریپیک فیکسهای WalletChangeLog/Validation/Expiry)
---
@@ -473,21 +473,55 @@ flowchart TD
| `9288d06` | feat: externalize appsettings to K8s Secret — config persists independently |
| `e72673c` | chore(staging): remove appsettings.Production.json (فقط kub-stage) |
| `3ebe0f9` | chore(production): remove appsettings.Staging.json (فقط production) |
+| `f3ac5ad` | fix: add missing UserWalletChangeLog for discount shop purchases |
+| `0457ef6` | fix: validate discount wallet balance before applying discount |
+| `e206b71` | fix: reduce discount order expiry from 30 to 15 minutes |
+| `2620a24` | fix: correct production URLs from kbs1 to kbs2 in cms-config |
> کامیتهای PVC و Secret به هر دو شاخه push شدهاند.
> ⚠️ کامیتهای حذف appsettings فقط به برنچ مربوطه push شده — cherry-pick نکنید!
+### ۹.۳ فیکس URL پروداکشن (اسفند ۱۴۰۴)
+
+> **مشکل:** در `cms-config.yaml` پروداکشن، URLها به اشتباه `kbs1.ir` (استیج) بودند.
+> زرینپال callback را به سرور استیج میفرستاد → خطای 401 → `Code=-1` (خطای ناشناخته).
+
+| فیلد | مقدار اشتباه | مقدار صحیح |
+|------|-------------|------------|
+| `CmsBaseUrl` | `https://cms.kbs1.ir` | `https://cms.kbs2.ir` |
+| `FrontOfficeBaseUrl` | `https://kbs1.ir` | `https://kbs2.ir` |
+
+```bash
+# فیکس مستقیم روی سرور (بدون نیاز به rebuild)
+kubectl apply -f cms-config.yaml
+kubectl rollout restart deployment/cms
+```
+
+### ۹.۴ نامگذاری کیفپولها (اسفند ۱۴۰۴)
+
+> تغییر عنوان کیفپولها در تمام UI (FrontOffice: 5 فایل، BackOffice: 7 فایل):
+
+| فیلد | نام قدیم | نام جدید |
+|------|---------|----------|
+| `Balance` | عادی / نقدی | **کیف پول اصلی** |
+| `DiscountBalance` | تخفیفی / تخفیف | **کیف پول اعتباری** |
+| `NetworkBalance` | شبکه / طلایی | **پاداش تیمی** |
+
**تنظیمات محیطی Production (`appsettings.Production.json`):**
| تنظیم | مقدار |
|--------|-------|
| `ZarinPal.MerchantId` | `4225d555-5fa9-4df0-9b61-1ce152cbbba8` |
| `ZarinPal.UseSandbox` | `false` |
+| `CmsBaseUrl` | `https://cms.kbs2.ir` |
+| `FrontOfficeBaseUrl` | `https://kbs2.ir` |
| `SeedWorkers.MagicWalletCycleSeed.Enabled` | `true` |
| `Kestrel.Endpoints.Grpc.Protocols` | `Http2` |
| `Seq.ServerUrl` | `http://seq-svc:5341` |
| `ConnectionStrings.Default` | `Server=mssql-svc;Database=KBS` |
+> ⚠️ **مهم:** URLها باید `kbs2.ir` باشند نه `kbs1.ir` — اشتباه در URL باعث خطای 401 زرینپال میشود.
+
```bash
# k8s-health-check.sh (namespace = default)
kubectl get pods