34 KiB
📊 تحلیل جامع FrontOffice - وضعیت فعلی و نقشه راه
تاریخ تحلیل: ۱۴ آذر ۱۴۰۴ (بروزرسانی شده)
وضعیت کلی: ⚠️ پیادهسازی BFF (60%) - هسته مرکزی آماده، نیاز به UI
اولویت: 🟡 متوسط - BFF Skeleton آماده، فقط UI باقی مانده
🎯 خلاصه اجرایی
وضعیت موجود:
- ✅ 24 صفحه UI موجود (Store, Profile, Root pages)
- ✅ 12 ماژول CQ در BFF (9 قدیمی + 3 جدید: Club, Network, Commission)
- ✅ هسته مرکزی BFF کامل (ClubMembership, NetworkMembership, Commission)
- ✅ معماری gRPC پیادهسازی شده + Infrastructure آماده
- ⚠️ UI Pages برای Club/Network/Commission غایب (فقط اسکلت BFF)
نیازمندیهای کاربر (7 دسته) - بروزرسانی شده:
- 🟡 باشگاه مشتریان - BFF آماده ✅ | UI غایب ❌
- 🟡 صفحه داشبورد باشگاه - BFF آماده ✅ | UI غایب ❌
- ⚠️ دیدن اطلاعات در یک نگاه - Dashboard جامع (نیمهکاره)
- ⚠️ فروشگاه معمولی - نیاز به بهبود UI/UX
- ❌ پرداخت دستی پکیج طلایی - فرآیند ناقص
- 🟡 گزارش شبکه و کمیسیون - BFF آماده ✅ | UI غایب ❌
- ❓ موارد اضافی - نیازمند تحلیل
📁 ساختار فعلی پروژه
1️⃣ FrontOffice UI (Blazor Server)
مسیر: /FrontOffice/src/FrontOffice.Main/Pages/
صفحات موجود (24 صفحه):
الف. Root Level (7 صفحه):
✅ Index.razor - صفحه اصلی (Hero, Features, Stats)
✅ About.razor - درباره ما
✅ Contact.razor - تماس با ما
✅ FAQ.razor - سوالات متداول
✅ Checkout.razor - صفحه پرداخت
✅ RegisterWizard.razor - ثبتنام کاربر
✅ PackageDetail.razor - جزئیات پکیج
ب. Profile Section (6 صفحه):
✅ Profile/Index.razor - داشبورد پروفایل (نمایش _walletNetwork)
✅ Profile/Personal.razor - اطلاعات شخصی
✅ Profile/Settings.razor - تنظیمات
✅ Profile/Wallet.razor - کیف پول (3 موجودی: Credit, Discount, Network)
⚠️ Profile/Addresses.razor - آدرسها (کامل)
⚠️ Profile/Tree.razor - شجرهنامه (Mock data - OrganizationChart component)
ج. Store Section (7 صفحه):
✅ Store/Products.razor - لیست محصولات
✅ Store/ProductDetail.razor - جزئیات محصول
✅ Store/Cart.razor - سبد خرید
✅ Store/Categories.razor - دستهبندیها
✅ Store/Orders.razor - سفارشات
✅ Store/OrderDetail.razor - جزئیات سفارش
✅ Store/CheckoutSummary.razor - خلاصه پرداخت
د. Shared Components:
✅ Shared/MainLayout.razor
✅ Shared/Footer.razor
✅ Shared/AuthDialog.razor
✅ Shared/SimpleOtpDialog.razor
2️⃣ FrontOffice.BFF (Backend For Frontend)
مسیر: /FrontOffice.BFF/src/
معماری (Clean Architecture):
FrontOffice.BFF/
├── Application/ # CQRS Handlers + DTOs
│ ├── CategoryCQ/ ✅ قدیمی
│ ├── PackageCQ/ ✅ قدیمی
│ ├── ProductsCQ/ ✅ قدیمی
│ ├── ShopingCartCQ/ ✅ قدیمی
│ ├── TransactionCQ/ ✅ قدیمی
│ ├── UserAddressCQ/ ✅ قدیمی
│ ├── UserCQ/ ✅ قدیمی
│ ├── UserOrderCQ/ ✅ قدیمی
│ ├── UserWalletCQ/ ✅ قدیمی (DiscountBalance موجود)
│ ├── ClubMembershipCQ/ 🆕 جدید (امروز)
│ ├── NetworkMembershipCQ/ 🆕 جدید (امروز)
│ └── CommissionCQ/ 🆕 جدید (امروز)
├── Domain/ # Entities (minimal)
├── Infrastructure/ # gRPC clients, DB context
│ ├── Services/
│ │ └── ApplicationContractContext.cs ✅ بروز (ClubMemberships, NetworkMemberships)
│ └── ConfigureGrpcServices.cs ✅ Auto-register
└── WebApi/
├── Services/ # gRPC Service Implementations
│ ├── CategoriesService.cs
│ ├── PackageService.cs
│ ├── ProductsService.cs
│ ├── ShopingCartService.cs
│ ├── TransactionService.cs
│ ├── UserAddressService.cs
│ ├── UserOrderService.cs
│ ├── UserService.cs
│ └── UserWalletService.cs
└── Protobufs/ # gRPC Proto definitions
12 ماژول موجود (9 قدیمی + 3 جدید):
| ماژول | وضعیت | توضیحات |
|---|---|---|
| CategoryCQ | ✅ کامل | دریافت دستهبندیها |
| PackageCQ | ✅ کامل | دریافت پکیجها |
| ProductsCQ | ✅ کامل | محصولات و گالری |
| ShopingCartCQ | ⚠️ ناقص | Add/Update موجود، Delete/Clear غایب |
| TransactionCQ | ✅ کامل | پرداخت و تأیید |
| UserAddressCQ | ✅ کامل | CRUD آدرسها |
| UserCQ | ✅ کامل | OTP, Login, Profile |
| UserOrderCQ | ✅ کامل | CRUD سفارشات |
| UserWalletCQ | ✅ کامل | GetWallet + DiscountBalance موجود ✅ |
| 🆕 ClubMembershipCQ | ✅ اسکلت | GetMyClubMembership, ActivateMyClubMembership |
| 🆕 NetworkMembershipCQ | ✅ اسکلت | GetMyNetworkTree, GetMyNetworkStatistics |
| 🆕 CommissionCQ | ✅ اسکلت | GetMyCommissionPayouts, GetMyWeeklyBalances |
🔴 تحلیل شکافهای بحرانی (Gap Analysis)
دسته A: ماژولهای BFF آماده (اسکلت کامل ✅) - نیاز به UI
1️⃣ ClubMembershipCQ - باشگاه مشتریان
✅ در FrontOffice.BFF: اسکلت کامل شده (امروز ۱۴ آذر)
❌ در FrontOffice UI: هیچ صفحهای برای باشگاه وجود ندارد
✅ در CMS موجود:
- Commands:
ActivateClubMembership,DeactivateClubMembership,AssignClubFeature - Queries:
GetClubMembership,GetClubMembershipHistory,GetClubStatistics
✅ کارهای انجام شده در BFF:
الف. BFF Module (FrontOffice.BFF/Application/):
✅ ClubMembershipCQ/
✅ Commands/
✅ ActivateMyClubMembership/ # پرداخت 56M
- ActivateMyClubMembershipCommand.cs
- ActivateMyClubMembershipCommandHandler.cs
- ActivateMyClubMembershipResponseDto.cs
✅ Queries/
✅ GetMyClubMembership/ # وضعیت عضویت (Active/Inactive/Trial)
- GetMyClubMembershipQuery.cs
- GetMyClubMembershipQueryHandler.cs
- GetMyClubMembershipResponseDto.cs
✅ Infrastructure Updates:
✅ IApplicationContractContext + Implementation:
- ClubMemberships property اضافه شد
- NetworkMemberships property اضافه شد
ج. UI Pages (FrontOffice/Pages/):
[ ] Club/
[ ] MembershipPage.razor
- Badge وضعیت (Active/Inactive/Trial)
- دکمه فعالسازی (56M تومان)
- نمایش تاریخ انقضا
- لیست مزایا
[ ] FeaturesPage.razor
- کارت هر فیچر (Trial vs VIP)
- امتیاز لازم (RequiredPoints)
- Badge فیچرهای فعال
[ ] Components/
[ ] ActivationButton.razor # فرم پرداخت
[ ] FeatureCard.razor # کارت تک فیچر
💰 اثر بیزینسی:
- ❌ کاربر نمیتواند عضو باشگاه شود
- ❌ 56M شارژ Balance/Discount انجام نمیشود
- ❌ دسترسی به فروشگاه تخفیف وجود ندارد
2️⃣ NetworkMembershipCQ - شبکه باینری
❌ در FrontOffice.BFF: هیچ چیز موجود نیست
⚠️ در FrontOffice UI: فقط Profile/Tree.razor با داده Mock
✅ در CMS موجود:
- Commands:
JoinNetwork,MoveInNetwork,RemoveFromNetwork - Queries:
GetNetworkTree,GetUserNetworkPosition,GetNetworkMembershipHistory,GetNetworkStatistics
📋 کارهای مورد نیاز:
الف. BFF Module:
[ ] NetworkMembershipCQ/
[ ] Commands/
[ ] JoinNetwork/ # عضویت در شبکه
[ ] Queries/
[ ] GetMyNetworkTree/ # درخت باینری (MaxDepth: 1-10)
[ ] GetMyNetworkPosition/ # موقعیت من (Parent, Left, Right)
[ ] GetMyNetworkStatistics/ # آمار (تعداد چپ/راست/کل)
[ ] GetNetworkHistory/ # تاریخچه جابجایی
ب. BFF Service:
[ ] NetworkMembershipService.cs
- GetMyNetworkTree(maxDepth) → CMS.GetNetworkTreeAsync(userId, maxDepth)
- GetMyNetworkPosition() → CMS.GetUserNetworkPositionAsync(userId)
- GetMyNetworkStatistics() → CMS.GetNetworkStatisticsAsync(userId)
- JoinNetwork(parentId, position) → CMS.JoinNetworkAsync()
ج. UI Updates:
[ ] Profile/Tree.razor
✅ Component موجود: OrganizationChart
[ ] حذف Mock data
[ ] فراخوانی GetMyNetworkTree از BFF
[ ] Selector عمق درخت (1-10)
[ ] Lazy loading برای زیرشاخهها
[ ] دکمه Expand/Collapse
[ ] Pages/Network/
[ ] StatsPage.razor # صفحه آمار شبکه
- کارت تعداد چپ/راست
- کارت کل اعضا
- عمق درخت
- آخرین عضو جدید
- نمودار رشد
[ ] JoinPage.razor # فرم عضویت
- انتخاب Parent (جستجو)
- انتخاب Position (Left/Right)
- پیشنمایش موقعیت
💰 اثر بیزینسی:
- ❌ کاربر نمیتواند زیرمجموعه بگیرد
- ❌ درخت شبکه واقعی نمایش داده نمیشود
- ❌ محاسبه کمیسیون باینری کار نمیکند
3️⃣ CommissionCQ - کمیسیون و برداشت
⚠️ در FrontOffice.BFF: فقط WithdrawBalance (کامل - در UserWalletCQ)
❌ در FrontOffice UI: هیچ صفحه کمیسیون موجود نیست
✅ در CMS موجود:
- Commands:
RequestWithdrawal,ApproveWithdrawal,ProcessWithdrawal,CalculateWeekly* - Queries:
GetUserCommissionPayouts,GetUserWeeklyBalances,GetWeeklyCommissionPool,GetWithdrawalRequests
📋 کارهای مورد نیاز:
الف. BFF Module:
[ ] CommissionCQ/
[ ] Queries/
[ ] GetMyCommissionPayouts/ # لیست پرداختهای کمیسیون
- GetMyCommissionPayoutsQuery.cs
- GetMyCommissionPayoutsQueryHandler.cs
- CommissionPayoutDto.cs (Week, Amount, Status, Date)
[ ] GetMyWeeklyBalances/ # تعادل هفتگی
- GetMyWeeklyBalancesQuery.cs
- GetMyWeeklyBalancesQueryHandler.cs
- WeeklyBalanceDto.cs (Left, Right, Weaker, Carryover)
[ ] GetWeeklyPoolInfo/ # اطلاعات استخر هفته
- GetWeeklyPoolInfoQuery.cs
- GetWeeklyPoolInfoQueryHandler.cs
- WeeklyPoolDto.cs (TotalPool, BalanceValue)
[ ] GetMyWithdrawalHistory/ # تاریخچه برداشتها
- GetMyWithdrawalHistoryQuery.cs
- GetMyWithdrawalHistoryQueryHandler.cs
- WithdrawalHistoryDto.cs
ب. BFF Service:
[ ] CommissionService.cs
- GetMyCommissionPayouts(weekNumber?, status?) → CMS.GetUserCommissionPayoutsAsync(userId)
- GetMyWeeklyBalances(weekNumber?) → CMS.GetUserWeeklyBalancesAsync(userId)
- GetWeeklyPoolInfo(weekNumber?) → CMS.GetWeeklyCommissionPoolAsync(weekNumber)
- GetMyWithdrawalHistory() → CMS.GetWithdrawalRequestsAsync(userId)
توجه: WithdrawBalance در UserWalletService قبلاً پیادهسازی شده ✅
ج. UI Pages:
[ ] Pages/Commission/
[ ] DashboardPage.razor # داشبورد کمیسیون
- کارت استخر هفته (TotalPool, BalanceValue)
- کارت امتیازات من (LesserLegPoints)
- پیشبینی کمیسیون این هفته
- نمودار روند 4 هفته اخیر
[ ] HistoryPage.razor # تاریخچه پرداختها
- جدول پرداختهای گذشته
- فیلتر Status (Pending/Calculated/Paid/Withdrawn)
- فیلتر هفته
- نمودار خطی روند
[ ] WithdrawPage.razor # صفحه برداشت
✅ قسمتی در Profile/Wallet.razor موجود است
[ ] جداسازی به صفحه مستقل
- فرم برداشت (PayoutId, Method, IBAN)
- نمایش MinWithdrawalAmount
- نمایش موجودی قابل برداشت
- تاریخچه برداشتها
[ ] WeeklyBalancePage.razor # تعادل هفتگی
- تعادل چپ/راست
- Carryover از هفته قبل
- سقف 300 Balance
- نمودار میلهای هفتهها
💰 اثر بیزینسی:
- ❌ کاربر نمیتواند کمیسیون خود را ببیند
- ✅ برداشت از NetworkBalance کار میکند (در Wallet.razor)
- ❌ تعادل هفتگی و Carryover نامشخص است
4️⃣ DayaLoanCQ - وام دایا
❌ در FrontOffice.BFF: هیچ چیز موجود نیست
❌ در FrontOffice UI: هیچ چیز موجود نیست
✅ در CMS موجود:
- Commands:
CheckDayaLoanStatus,ProcessDayaLoanApproval - Background Worker: Daily check for loan status
📋 کارهای مورد نیاز:
الف. BFF Module:
[ ] DayaLoanCQ/
[ ] Queries/
[ ] GetMyDayaLoanStatus/
- GetMyDayaLoanStatusQuery.cs
- GetMyDayaLoanStatusQueryHandler.cs
- DayaLoanStatusDto.cs (Status, ContractNumber, LastCheckDate, ApprovalDate)
ب. BFF Service:
[ ] DayaLoanService.cs
- GetMyDayaLoanStatus() → CMS.GetDayaLoanStatusAsync(userId)
ج. UI Pages:
[ ] Pages/DayaLoan/
[ ] StatusPage.razor
- Badge وضعیت (PendingReceive/Received/Rejected)
- نمایش شماره قرارداد
- تاریخ آخرین بررسی
- توضیحات وام (168M = 56M×3)
[ ] Components/
[ ] StatusBadge.razor
- رنگبندی (Warning/Success/Error)
💰 اثر بیزینسی:
- ❌ کاربر نمیتواند وضعیت وام دایا را ببیند
- ❌ 168M شارژ (56M×3) نامشخص است
- ⚠️ Worker پسزمینه فعال است اما UI ندارد
دسته B: ماژولهای کاملشده (100% BFF)
5️⃣ UserWalletCQ - کیفپول
✅ موجود در BFF (کامل):
GetUserWallet- دریافت موجودی (✅ DiscountBalance موجود است)GetAllUserWalletChangeLog- تاریخچه تراکنشهاWithdrawBalance- برداشت (✅ کار میکند)GetUserWithdrawals- لیست برداشتهاGetWithdrawalSettings- تنظیمات برداشت (MinAmount)
✅ Response DTO:
public class GetUserWalletResponseDto
{
✅ public long Balance { get; set; }
✅ public long NetworkBalance { get; set; }
✅ public long DiscountBalance { get; set; } // موجود است
}
⚠️ مشکلات جزئی:
- فیلترهای ناقص:
GetAllUserWalletChangeLogفیلتر ندارد- نیاز: Type (Deposit/Withdraw/Purchase), DateRange, ReferenceId
ب. UI Updates:
[ ] Profile/Wallet.razor
✅ نمایش Balance
✅ نمایش NetworkBalance
❌ نمایش DiscountBalance (زرد/نارنجی)
[ ] حذف داده Mock (Discount: "در انتظار اتصال CMS...")
[ ] افزودن فیلترهای تراکنش:
- Select نوع (همه/ورودی/خروجی)
- DateRange picker
- TextField جستجو ReferenceId
[ ] نمایش ChangeValue به جای CurrentBalance
[ ] Pagination برای تراکنشها
💰 اثر بیزینسی:
- ⚠️ کاربر DiscountBalance خود را نمیبیند (باشگاه)
- ⚠️ فیلتر تراکنشها محدود است
6️⃣ ShopingCartCQ - سبد خرید
✅ موجود در BFF:
AddNewUserCart- افزودن به سبدUpdateUserCart- بهروزرسانی تعدادGetAllUserCart- دریافت سبد
❌ غایب:
ClearCart- پاک کردن کل سبدDeleteUserCarts- حذف یک آیتمMergeGuestCart- ادغام سبد مهمان→ورود
📋 کارهای مورد نیاز:
الف. BFF Commands:
[ ] ShopingCartCQ/Commands/
[ ] ClearCart/
- ClearCartCommand.cs
- ClearCartCommandHandler.cs → CMS.ClearUserCartAsync(userId)
[ ] DeleteCartItem/
- DeleteCartItemCommand.cs (CartId)
- DeleteCartItemCommandHandler.cs → CMS.DeleteUserCartsAsync(cartId)
[ ] MergeGuestCart/
- MergeGuestCartCommand.cs (SessionId)
- MergeGuestCartCommandHandler.cs:
1. Get guest cart by SessionId
2. Get user cart by UserId
3. Merge duplicates (sum quantities)
4. CMS.AddNewUserCart() for each
ب. UI Updates:
[ ] Store/Cart.razor
[ ] دکمه "پاک کردن سبد" (ClearCart)
[ ] دکمه حذف (DeleteCartItem) در هر سطر
[ ] SessionId handling:
- ذخیره در LocalStorage
- POST به MergeGuestCart بعد از Login
- نمایش پیام "x محصول از سبد قبلی شما اضافه شد"
7️⃣ DiscountShopCQ - فروشگاه تخفیف
❌ در FrontOffice.BFF: هیچ چیز موجود نیست
❌ در FrontOffice UI: هیچ صفحهای موجود نیست
✅ در CMS موجود:
- Full CRUD for
DiscountProduct,DiscountCategory,DiscountOrder - BackOffice UI: 3 pages (Products, Categories, Orders)
📋 کارهای مورد نیاز:
الف. BFF Module:
[ ] DiscountShopCQ/
[ ] Queries/
[ ] GetDiscountProducts/ # محصولات تخفیف
[ ] GetDiscountCategories/ # دستهبندیهای تخفیف
[ ] GetMyDiscountOrders/ # سفارشات تخفیف من
[ ] Commands/
[ ] AddToDiscountCart/ # افزودن به سبد تخفیف
[ ] PlaceDiscountOrder/ # ثبت سفارش با DiscountBalance
ب. BFF Service:
[ ] DiscountShopService.cs
- GetDiscountProducts() → CMS.GetAllDiscountProductsAsync()
- GetDiscountCategories() → CMS.GetAllDiscountCategoriesAsync()
- GetMyDiscountOrders() → CMS.GetAllDiscountOrdersAsync(userId)
- PlaceDiscountOrder(items) → CMS.CreateDiscountOrderAsync()
ج. UI Pages:
[ ] Pages/DiscountShop/
[ ] ProductsPage.razor # لیست محصولات تخفیف
- نمایش DiscountPercent (بادگ)
- نمایش MaxDiscountPercentage سقف
- فیلتر دستهبندی
- کارت محصول با قیمت اصلی/تخفیفیافته
[ ] CartPage.razor # سبد تخفیف
- نمایش DiscountBalance موجود
- محاسبه قیمت نهایی
- دکمه Checkout
[ ] OrdersPage.razor # سفارشات تخفیف
- لیست سفارشات با Badge "Club Discount"
- جزئیات تخفیف اعمالشده
💰 اثر بیزینسی:
- ❌ کاربر باشگاه نمیتواند از تخفیف استفاده کند
- ❌ DiscountBalance کاربرد ندارد
- ❌ 3 صفحه BackOffice بدون UI مشتری
دسته C: قابلیتهای جزئی (نیازهای اضافی)
8️⃣ PublicMessageCQ - پیامهای عمومی
✅ در BackOffice موجود: صفحه مدیریت پیامها
❌ در FrontOffice: هیچ چیز نیست
📋 کارهای مورد نیاز:
[ ] PublicMessageCQ/Queries/GetActivePublicMessages/
[ ] UI: Pages/Messages/ListPage.razor
- لیست پیامها با فیلتر Type (News/Announcement/Promotion)
- Badge اولویت
- نمایش تاریخ انتشار
9️⃣ NotificationCQ - نوتیفیکیشن
❌ در همه جا موجود نیست
پیشنهاد:
[ ] NotificationCQ/
[ ] Queries/GetMyNotifications/
[ ] Commands/MarkAsRead/
[ ] UI: Bell Icon در Navbar
- Badge تعداد جدید
- Dropdown لیست نوتیفیکیشن
🔟 ReferralLinkCQ - لینک دعوت
❌ در همه جا موجود نیست
پیشنهاد:
[ ] ReferralLinkCQ/Queries/GetMyReferralLink/
[ ] UI: Profile/ReferralPage.razor
- نمایش لینک دعوت
- دکمه Copy
- آمار دعوتشدهها (تعداد)
- QR Code
📊 خلاصه آماری شکافها (بروزرسانی شده)
| دسته | تعداد ماژول | وضعیت BFF | وضعیت UI | درصد کل |
|---|---|---|---|---|
| ✅ کامل (BFF+UI) | 6 | Category, Package, Products, Transaction, UserAddress, UserCQ | موجود | 35% |
| ✅ BFF آماده | 3 | ClubMembership, NetworkMembership, Commission | UI غایب | 20% |
| ✅ BFF کامل | 2 | UserWallet (DiscountBalance), UserOrder | UI موجود | 15% |
| ⚠️ نیمهکاره | 1 | ShopingCart (Delete/Clear غایب) | UI موجود | 5% |
| ❌ غایب بحرانی | 1 | DayaLoan | UI غایب | 5% |
| ❌ غایب اضافی | 4 | DiscountShop, PublicMessage, Notification, ReferralLink | UI غایب | 20% |
جمع: 17 ماژول وضعیت BFF: 60% کامل (12 از 17) وضعیت UI: 40% کامل (فقط 9 ماژول قدیمی)
🎯 اولویتهای باقیمانده (بروزرسانی شده)
فاز 1: UI برای ماژولهای BFF آماده (اولویت بالا 🔴)
هدف: اتصال UI به BFF موجود
[ ] Phase 1A: Club UI (2-3 روز)
[ ] Pages/Club/MembershipPage.razor
[ ] Pages/Club/FeaturesPage.razor (اختیاری)
[ ] Components/Club/ActivationButton.razor
[ ] Phase 1B: Network UI (2 روز)
[ ] Update Profile/Tree.razor (حذف Mock + اتصال به BFF)
[ ] Pages/Network/StatsPage.razor
[ ] Phase 1C: Commission UI (3 روز)
[ ] Pages/Commission/DashboardPage.razor
[ ] Pages/Commission/HistoryPage.razor
[ ] Pages/Commission/WeeklyBalancePage.razor
[ ] Phase 1D: Wallet UI Update (1 روز)
[ ] Update Profile/Wallet.razor (نمایش DiscountBalance - کارت زرد)
زمان تخمینی: 8-9 روز
فاز 2: ماژولهای ثانویه (اولویت متوسط 🟡)
Day 1-2: DiscountShopCQ
[ ] BFF Module
[ ] Pages/DiscountShop/ProductsPage.razor
[ ] Pages/DiscountShop/CartPage.razor
Day 3: ShopingCartCQ Completion
[ ] Add DeleteCartItem, ClearCart Commands
[ ] Update Store/Cart.razor
Day 4: DayaLoanCQ
[ ] BFF Module (Query only)
[ ] Pages/DayaLoan/StatusPage.razor
Day 5: PublicMessageCQ
[ ] BFF Module
[ ] Pages/Messages/ListPage.razor
مرحله 3: بهبودهای UI/UX (1 هفته)
Day 1-2: Store Improvements
[ ] Responsive design (mobile-first)
[ ] Skeleton loaders
[ ] Image lazy loading
[ ] Product filters enhancement
Day 3-4: Profile Enhancements
[ ] Avatar upload
[ ] Settings page completion
[ ] ReferralPage.razor (لینک دعوت)
Day 5: Notification System
[ ] Bell icon در Navbar
[ ] Notification dropdown
[ ] Mark as read
مرحله 4: قابلیتهای اضافی (اختیاری)
[ ] Referral System (لینک دعوت + آمار)
[ ] Achievement/Rewards System
[ ] Reports (Excel/PDF export)
[ ] Advanced Filters (تاریخ، نوع، مبلغ)
[ ] Mobile App (PWA)
🛠️ الگوی پیادهسازی استاندارد
الف. BFF Module Template
FrontOffice.BFF/Application/[ModuleName]CQ/
├── Commands/
│ └── [ActionName]/
│ ├── [ActionName]Command.cs
│ ├── [ActionName]CommandHandler.cs
│ ├── [ActionName]CommandValidator.cs
│ └── [ActionName]ResponseDto.cs (optional)
└── Queries/
└── [QueryName]/
├── [QueryName]Query.cs
├── [QueryName]QueryHandler.cs
└── [QueryName]ResponseDto.cs
مثال: GetMyClubMembership
// GetMyClubMembershipQuery.cs
public record GetMyClubMembershipQuery : IRequest<ClubMembershipDto>;
// GetMyClubMembershipQueryHandler.cs
public class GetMyClubMembershipQueryHandler : IRequestHandler<GetMyClubMembershipQuery, ClubMembershipDto>
{
private readonly IApplicationContractContext _context;
private readonly ICurrentUserService _currentUser;
public async Task<ClubMembershipDto> Handle(GetMyClubMembershipQuery request, CancellationToken ct)
{
var userId = _currentUser.UserId; // از JWT Token
var cmsRequest = new GetClubMembershipRequest { UserId = userId };
var result = await _context.ClubMemberships.GetClubMembershipAsync(cmsRequest, cancellationToken: ct);
return new ClubMembershipDto
{
UserId = result.UserId,
IsActive = result.IsActive,
ActivationDate = result.ActivationDate.ToDateTime(),
ExpirationDate = result.ExpirationDate.ToDateTime(),
Status = result.Status // Active/Inactive/Trial
};
}
}
ب. gRPC Service Template
// FrontOffice.BFF/WebApi/Services/ClubMembershipService.cs
public class ClubMembershipService : ClubMembershipContract.ClubMembershipContractBase
{
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
public ClubMembershipService(IDispatchRequestToCQRS dispatchRequestToCQRS)
{
_dispatchRequestToCQRS = dispatchRequestToCQRS;
}
public override async Task<GetMyClubMembershipResponse> GetMyClubMembership(Empty request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<GetMyClubMembershipQuery, GetMyClubMembershipResponse>(context);
}
public override async Task<Empty> ActivateClubMembership(ActivateClubMembershipRequest request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<ActivateClubMembershipRequest, ActivateClubMembershipCommand, Empty>(request, context);
}
}
ج. UI Page Template
@* Pages/Club/MembershipPage.razor *@
@page "/club/membership"
@inject ClubMembershipContract.ClubMembershipContractClient ClubService
<PageTitle>باشگاه مشتریان</PageTitle>
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
<MudStack Spacing="3">
<MudText Typo="Typo.h4">باشگاه مشتریان</MudText>
@if (_isLoading)
{
<MudProgressCircular Indeterminate="true" />
}
else if (_membership != null)
{
<MudPaper Elevation="2" Class="pa-4">
<MudStack Spacing="2">
<MudChip Color="@GetStatusColor()" Variant="Variant.Filled">
@GetStatusText()
</MudChip>
@if (!_membership.IsActive)
{
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
OnClick="ActivateMembership">
فعالسازی باشگاه (56,000,000 تومان)
</MudButton>
}
else
{
<MudText>تاریخ انقضا: @_membership.ExpirationDate.ToPersianDate()</MudText>
}
</MudStack>
</MudPaper>
}
</MudStack>
</MudContainer>
@code {
private ClubMembershipDto? _membership;
private bool _isLoading = true;
protected override async Task OnInitializedAsync()
{
try
{
var response = await ClubService.GetMyClubMembershipAsync(new Empty());
_membership = response; // Map to DTO
}
finally
{
_isLoading = false;
}
}
private async Task ActivateMembership()
{
// پرداخت 56M
}
private Color GetStatusColor() => _membership?.IsActive == true ? Color.Success : Color.Warning;
private string GetStatusText() => _membership?.IsActive == true ? "فعال" : "غیرفعال";
}
📋 چکلیست شروع توسعه
قبل از شروع هر ماژول:
[ ] CMS Commands/Queries را شناسایی کردم
[ ] Proto definitions را یافتم (CMS/Protobuf/*.proto)
[ ] نمونه Handler موجود در BFF را بررسی کردم
[ ] JWT Token و CurrentUserService را فهمیدم
[ ] ساختار DTO مشتریمحور را طراحی کردم
[ ] Mock data برای UI آماده کردم
🚨 نکات بحرانی
1. تفاوت CMS vs BFF
| جنبه | CMS | FrontOffice.BFF |
|---|---|---|
| مخاطب | Admin + System | Customer فقط |
| داده | همه کاربران | کاربر جاری (UserId از JWT) |
| Response | DTO کامل + Metadata | DTO ساده (فقط فیلدهای لازم) |
| Authorization | Role-based (Admin/User) | User-only (No Admin) |
| Input | UserId required |
UserId از Token (خودکار) |
2. احراز هویت
JWT Token Structure:
{
"sub": "123", // UserId
"email": "user@example.com",
"phone": "09123456789",
"IsSignMainContract": "True",
"exp": 1234567890
}
استخراج UserId:
public class GetMyDataQueryHandler
{
private readonly ICurrentUserService _currentUser;
public async Task<Response> Handle(Query request, CancellationToken ct)
{
var userId = _currentUser.UserId; // از JWT
// Call CMS with userId
}
}
3. DTO Mapping Pattern
CMS DTO (خام):
public class CommissionPayoutDto
{
public long Id { get; set; }
public long UserId { get; set; }
public int WeekNumber { get; set; }
public long TotalAmount { get; set; }
public CommissionPayoutStatus Status { get; set; }
// ... 10 فیلد دیگر
}
BFF Response DTO (مشتریمحور):
public class MyCommissionPayoutDto
{
public long Id { get; set; }
public string WeekLabel { get; set; } // "هفته 45 - آذر 1403"
public string AmountFormatted { get; set; } // "1,250,000 تومان"
public string StatusText { get; set; } // "پرداخت شده"
public string StatusBadgeColor { get; set; } // "success"
public string DatePersian { get; set; } // "25 آذر 1403"
}
📞 مسائل و سوالات
سوالات باز:
-
پرداخت دستی پکیج طلایی (نیازمندی #5):
- منظور چیست؟ آیا جدا از فعالسازی باشگاه (56M) است؟
- آیا در CMS Handler مربوطه وجود دارد؟
-
فروشگاه "معمولی" (نیازمندی #4):
- چه بهبودهای خاصی مدنظر است؟
- آیا Discount Shop جداست یا همان Store معمولی؟
-
Dashboard "در یک نگاه" (نیازمندی #3):
- آیا
Profile/Index.razorهمان Dashboard است؟ - یا نیاز به صفحه جداگانه
/dashboardداریم؟
- آیا
-
گزارش شبکه و کمیسیون (نیازمندی #6):
- چه گزارشهای دقیقی مدنظر است؟
- PDF/Excel export لازم است؟
📈 معیارهای موفقیت (Success Metrics)
مرحله 1 (بحرانی):
- کاربر بتواند عضو باشگاه شود (پرداخت 56M)
- کاربر 3 موجودی کیفپول را ببیند (Balance, Network, Discount)
- کاربر درخت شبکه واقعی خود را ببیند (نه Mock)
- کاربر کمیسیون هفتگی خود را ببیند
- کاربر بتواند برداشت کند (WithdrawBalance)
مرحله 2 (ثانویه):
- کاربر از فروشگاه تخفیف خرید کند
- کاربر وضعیت وام دایا را ببیند
- کاربر پیامهای عمومی را ببیند
- سبد خرید: Delete/Clear کار کند
مرحله 3 (UI/UX):
- تمام صفحات Responsive باشند
- Skeleton loaders در همه جا
- لینک دعوت (Referral) فعال باشد
- نوتیفیکیشن Bell icon در Navbar
🎉 نتیجهگیری
وضعیت فعلی: 40% تکمیل (9 ماژول پایه)
هدف: 95% تکمیل (17 ماژول کامل)
زمان تخمینی: 4 هفته (3 مرحله اصلی + 1 اختیاری)
اولویتهای کلیدی:
- 🔴 ClubMembership + Dashboard (هفته 1)
- 🔴 Network + Commission (هفته 2)
- 🟡 DiscountShop + Enhancements (هفته 3)
- 🟢 UI/UX Improvements (هفته 4)
نکته مهم: دقت کنیم که هیچ چیزی را جا نیندازیم و خارج از ساختار حرکت نکنیم ✅