Files
docs/roadmap/MAGIC-WALLET-PLAN.md
T
masoodafar-web a94d0dbe95 docs: add Magic Wallet spec & implementation plan
- New folder: roadmap/ for upcoming features
- MAGIC-WALLET-SPEC: full business rules, state machine, x2.5 multiplier,
  100M deposit cap, API flow, data model changes, transaction logging
- MAGIC-WALLET-PLAN: 6-phase implementation, checklist, time estimates
- Note: ChargeDiscountWallet completion is independent (not Magic Wallet)
- Note: WalletChangeLog is mandatory (not optional)
- Updated master index with roadmap section
2026-02-19 02:08:28 +03:30

206 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🪄 پلن پیاده‌سازی کیف‌پول جادویی
> **مرجع:** [MAGIC-WALLET-SPEC](./MAGIC-WALLET-SPEC.md)
> **تخمین کل:** ~۷ روز کاری
> **وابستگی مستقل:** تکمیل ChargeDiscountWallet (ربطی به جادویی ندارد)
---
## فازبندی
### فاز ۱ — مدل داده و Migration (روز ۱)
**هدف:** زیرساخت دیتابیس و enum‌ها
```
فایل‌های تغییری:
├── UserWallet.cs → + WalletMode, MagicTotalDeposited, MagicTotalCredited, MagicActivatedAt, MagicCompletedAt
├── WalletMode.cs → enum جدید (Normal=0, Magic=1)
├── TransactionType.cs → + MagicWalletDeposit=14, MagicWalletBonus=15
├── SystemConstants.cs → + MagicWalletMultiplier, MagicWalletMaxDeposit, MagicWalletMaxCredit
├── UserWalletConfiguration.cs → EF config برای فیلدهای جدید
└── Migration: AddMagicWalletFields → dotnet ef migrations add
```
**تست:** Migration اجرا بشه، فیلدها در DB ایجاد بشن، default‌ها درست باشن.
---
### فاز ۲ — Trigger ورود/خروج Magic (روز ۲)
**هدف:** State Machine خودکار
```
فایل‌های تغییری:
├── SubmitShopBuyOrderCommandHandler.cs
│ ├── بعد از کسر Balance: check ورود به Magic
│ └── بعد از کسر Balance: check خروج از Magic
├── (Optional) Domain Event: WalletModeChangedEvent
│ └── برای لاگ و نوتیفیکیشن
└── User.cs (یا UserWallet)
└── + PurchaseCycleCount (int) — تعداد دور خرید پکیج
```
**تست:**
- سناریو ۱: Balance=0 بعد از خرید → WalletMode=Magic ✅
- سناریو ۲: بدون پکیج + Balance=0 → نباید Magic بشه ❌
- سناریو ۳: Magic + Balance=0 + TotalDeposited>0 → خروج ✅
---
### فاز ۳ — API شارژ جادویی (روز ۳-۴)
**هدف:** مسیر کامل شارژ از درگاه با ضریب ×2.5
```
فایل‌های جدید:
├── InitiateMagicChargeCommand.cs
├── InitiateMagicChargeCommandHandler.cs
├── InitiateMagicChargeCommandValidator.cs
├── VerifyMagicChargeCommand.cs
├── VerifyMagicChargeCommandHandler.cs
├── MagicWalletController.cs → GET /api/wallet/verify-magic-charge
├── userwallet.proto → + InitiateMagicCharge, GetMagicWalletStatus RPCs
└── UserWalletService.cs → implement new RPCs
نکات مهم:
├── هر شارژ = ۲ تراکنش (Deposit + Bonus)
├── هر شارژ = ۱ WalletChangeLog (اجباری)
├── Validation: WalletMode==Magic && TotalDeposited+Amount <= Cap
└── Callback: /api/wallet/verify-magic-charge → redirect FrontOffice
```
**تست:**
- واریز 10M → Balance += 25M, TotalDeposited += 10M ✅
- واریز بیشتر از سقف → خطا ❌
- واریز در Normal Mode → خطا ❌
- ۲ تراکنش + ۱ لاگ ثبت شده ✅
---
### فاز ۴ — غیرفعال‌سازی کمیسیون (روز ۴.۵)
**هدف:** کاربرهای Magic از کمیسیون خارج بشن
```
فایل‌های تغییری:
├── CalculateWeeklyBalancesCommandHandler.cs
│ └── فیلتر: WHERE wallet.WalletMode != Magic
└── (یا SP اگه از Stored Procedure استفاده میکنه)
└── sp_CalculateWeeklyBalances → + JOIN UserWallets WHERE WalletMode = 0
```
**تست:** کاربر Magic در محاسبات هفتگی شرکت نکنه ✅
---
### فاز ۵ — صفحات FrontOffice (روز ۵-۶)
**هدف:** UI شارژ جادویی + نمایش وضعیت
```
فایل‌های جدید:
├── Pages/Profile/MagicWallet.razor → فرم شارژ + پروگرس‌بار سقف
├── Pages/Profile/MagicWallet.razor.cs → code-behind
├── Pages/Profile/MagicPaymentCallback.razor → نتیجه پرداخت
└── Pages/Profile/MagicPaymentCallback.razor.cs
فایل‌های تغییری:
├── WalletService.cs → + InitiateMagicChargeAsync, GetMagicWalletStatusAsync
├── RouteConstants.cs → + MagicWallet, MagicPaymentCallback
├── Pages/Profile/Index.razor → بنر Magic Mode
├── Pages/Profile/Wallet.razor → پروگرس سقف + لینک شارژ
└── NavMenu / Sidebar → لینک شرطی به صفحه جادویی
```
**UI شارژ جادویی:**
```
┌──────────────────────────────────────────────┐
│ 🪄 کیف‌پول جادویی │
│ │
│ وضعیت: فعال ✅ │
│ مجموع واریزی: 30M / 100M تومان │
│ ██████████░░░░░░░░░░░░░░░░░░░░ 30% │
│ مجموع اعتبار دریافتی: 75M تومان │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ مبلغ واریز: [________] تومان │ │
│ │ اعتبار دریافتی: 0 × 2.5 = 0 تومان │ │
│ │ باقیمانده سقف: 70M تومان │ │
│ │ │ │
│ │ [ 🔒 پرداخت از درگاه ] │ │
│ └──────────────────────────────────────┘ │
└──────────────────────────────────────────────┘
```
---
### فاز ۶ — محدودیت خرید مجدد پکیج (روز ۷)
**هدف:** بعد از Magic فقط IPG مجاز باشه
```
فایل‌های تغییری:
├── CheckAndProcessDayaLoansCommandHandler.cs
│ └── if PurchaseCycleCount > 0 → reject
├── Package Purchase UI (FrontOffice)
│ └── if PurchaseCycleCount > 0 → hide Daya button
└── ActivateClubMembershipCommandHandler.cs
└── if WalletMode == Magic → "ابتدا جادویی تمام شود"
```
---
## Checklist پیاده‌سازی
- [ ] **فاز ۱:** WalletMode enum
- [ ] **فاز ۱:** UserWallet entity + 5 فیلد جدید
- [ ] **فاز ۱:** TransactionType + 2 مقدار
- [ ] **فاز ۱:** SystemConstants + 3 ثابت
- [ ] **فاز ۱:** EF Configuration
- [ ] **فاز ۱:** Migration
- [ ] **فاز ۲:** Trigger ورود Magic (SubmitShopBuyOrder)
- [ ] **فاز ۲:** Trigger خروج Magic
- [ ] **فاز ۲:** PurchaseCycleCount
- [ ] **فاز ۳:** InitiateMagicChargeCommand + Handler
- [ ] **فاز ۳:** VerifyMagicChargeCommand + Handler
- [ ] **فاز ۳:** MagicWalletController (HTTP callback)
- [ ] **فاز ۳:** gRPC Proto + Service
- [ ] **فاز ۳:** ۲ تراکنش + ۱ لاگ (اجباری)
- [ ] **فاز ۴:** فیلتر کمیسیون (C# یا SP)
- [ ] **فاز ۵:** MagicWallet.razor
- [ ] **فاز ۵:** MagicPaymentCallback.razor
- [ ] **فاز ۵:** WalletService gRPC client
- [ ] **فاز ۵:** Profile + Wallet page updates
- [ ] **فاز ۶:** Daya restriction
- [ ] **فاز ۶:** Club activation restriction
---
## وابستگی مستقل: تکمیل ChargeDiscountWallet
> ⚠️ **این کار ربطی به کیف‌پول جادویی ندارد** و باید مستقل انجام شود.
```
مشکل فعلی:
├── ChargeDiscountWalletCommandHandler — CQRS handler موجوده ✅
├── VerifyDiscountWalletChargeCommandHandler — موجوده ✅
├── Callback URL = "/api/wallet/verify-discount-charge" — ست شده
├── HTTP Controller endpoint — ❌ وجود ندارد
├── gRPC RPC — ❌ در proto تعریف نشده
└── FrontOffice page — ❌ صفحه شارژ وجود ندارد
کار لازم:
├── WalletController.cs → GET /api/wallet/verify-discount-charge
├── userwallet.proto → rpc ChargeDiscountWallet
├── UserWalletService.cs → implement RPC
├── FrontOffice → صفحه شارژ DiscountBalance + callback
└── تست end-to-end
```