3c729304db
Corrections verified against actual CMS/BackOffice/FrontOffice source code: - ClubActivationFee: 25,200,000 (not 25,000,000) - Tree depth: no limit (15 is commission calculation depth only) - IPG wallet charge: Balance=56M + Discount=56M - DayaLoan wallet charge: Balance=56M + Discount=112M (2×) - Discount: per-product MaxDiscountPercent (not fixed 30%) - VAT: 10% (ShopVAT) vs 9% (discount store PlaceOrder) - Kavenegar template: 'Afrino' only (not verify-foursat) - SMS sender: 1000001110100 - DayaLoan job: every 20min (not 15min) - Commission job: Sunday 00:05 (not Saturday) - Network tree: on User entity (not separate NetworkNode table) - UserWallets entity (not UserWalletBalances) - OTP: 6 digits, 5 attempts, 2min TTL, 60s cooldown - Removed non-existent constants (ClubJoiningPercentage, ClubActivationThreshold) - Fixed Hangfire Chatika interval: every 5min - Removed InventorySync from recurring jobs list
7.3 KiB
7.3 KiB
👤 سفر کاربر، ثبتنام و چرخه عضویت
منابع ادغامشده:
club-membership-contract-system.md,REGISTRATION-FLOW-FIXES.md,chatika-integration.md,club-feature-management-services.md,ADMIN-CUSTOMER-SEPARATION-FIX.md,ICURRENTUSERSERVICE-IMPLEMENTATION.md
آخرین بروزرسانی: اسفند ۱۴۰۴
۱. فلوی کامل چرخه کاربر
ورود به سایت
│
▼
ثبتنام (موبایل + OTP)
│
▼
تکمیل پروفایل
│
▼
┌─────────────────────┬────────────────────────┐
│ مسیر عادی │ مسیر باشگاه │
├─────────────────────┼────────────────────────┤
│ خرید از فروشگاه │ خرید پکیج طلایی (56M) │
│ مشاهده بلاگ │ امضای قرارداد (OTP) │
│ استفاده از خدمات │ فعالسازی (25M) │
│ │ عضویت در درخت باینری │
│ │ دسترسی فروشگاه تخفیفی │
│ │ دسترسی فیچرهای باشگاه │
│ │ کسب کمیسیون هفتگی │
└─────────────────────┴────────────────────────┘
۲. ثبتنام و احراز هویت
۲.۱ فلوی ثبتنام
صفحه ثبتنام
│
▼
ورود شماره موبایل
│
▼
ارسال OTP (Kavenegar SMS API)
│
▼
تأیید کد OTP
│
├─→ کاربر جدید: ساخت User + JWT Token
└─→ کاربر موجود: ورود + JWT Token
JWT Claims:
• UserId
• PhoneNumber
• IsClubMember (bool)
• Roles[] (Admin, Customer)
• ReferralCode
۲.۲ اصلاحات ثبتنام
| مشکل | راهحل | وضعیت |
|---|---|---|
| OTP تکراری | Cooldown: ۶۰ ثانیه بین درخواستها | ✅ |
| شماره نامعتبر | Regex validation ایران ^09\d{9}$ |
✅ |
| حمله brute-force | MaxAttempts: ۵ تلاش برای تأیید کد | ✅ |
| انقضای کد | TTL: ۲ دقیقه | ✅ |
| طول کد | ۶ رقم | ✅ |
| قالب SMS | Kavenegar template: Afrino |
✅ |
۳. جداسازی Admin/Customer
۳.۱ مشکل قبلی
قبل:
Admin و Customer هر دو از یک DbContext و Identity استفاده میکردند
یک ادمین میتوانست به صورت Customer هم ظاهر شود ← تداخل Claims
بعد (اصلاحشده):
✅ ICurrentUserService → تشخیص دقیق نقش فعلی
✅ جداسازی Authorization Policy
✅ Admin claims فقط در BackOffice
✅ Customer claims فقط در FrontOffice
۳.۲ ICurrentUserService
public interface ICurrentUserService {
Guid UserId { get; }
string PhoneNumber { get; }
bool IsClubMember { get; }
bool IsAdmin { get; }
string[] Roles { get; }
Guid? ReferrerId { get; }
}
// پیادهسازی: از HttpContext.User.Claims خوانده میشود
// ثبت: services.AddScoped<ICurrentUserService, CurrentUserService>()
۴. قرارداد عضویت باشگاه
۴.۱ فلوی امضای قرارداد
خرید پکیج طلایی → Redirect به صفحه قرارداد
│
▼
نمایش Modal غیرقابلبستهشدن
│
▼
ReadContract RPC → نمایش متن قرارداد (Markdown/HTML)
│
▼
کاربر باید تا انتهای متن اسکرول کند
│
▼
فعال شدن دکمه "ارسال کد تأیید"
│
▼
RequestContractOtp → ارسال SMS
│
▼
ورود کد ← VerifyContractOtp
│
├─→ معتبر: AcceptContract → فعالسازی عضویت
└─→ نامعتبر: پیام خطا (حداکثر ۵ تلاش)
۴.۲ ذخیرهسازی قرارداد
// از کد: UserContract : BaseAuditableEntity
public class UserContract {
public long UserId { get; set; }
public virtual User User { get; set; }
public long ContractId { get; set; } // FK → Contract
public virtual Contract Contract { get; set; }
public string SignGuid { get; set; } // GUID یکتای امضا
public string SignedPdfFile { get; set; } // فایل PDF امضاشده
// فیلدهای BaseAuditableEntity: CreatedAt, ModifiedAt, ...
}
۵. فیچرهای باشگاه (Club Features)
۵.۱ سرویس مدیریت
public interface IClubFeatureService {
Task<List<ClubFeature>> GetUserFeaturesAsync(Guid userId);
Task ActivateFeatureAsync(Guid userId, string featureCode);
Task DeactivateFeatureAsync(Guid userId, string featureCode);
Task<bool> HasFeatureAsync(Guid userId, string featureCode);
}
۵.۲ فیچرهای موجود
| کد فیچر | نام | توضیح | وضعیت |
|---|---|---|---|
DISCOUNT_STORE |
فروشگاه تخفیفی | دسترسی به فروشگاه ۳۰% تخفیف | ✅ فعال |
CHATIKA_AI |
چاتیکا | مشاوره هوش مصنوعی | ✅ فعال |
COMMISSION |
کمیسیون | دریافت کمیسیون هفتگی | ✅ فعال |
NETWORK_VIEW |
نمای شبکه | مشاهده درخت باینری | ✅ فعال |
DAYA_LOAN |
وام دایا | درخواست وام | ⚠️ بلاکشده |
۵.۳ UserClubFeature Entity
public class UserClubFeature {
public Guid Id { get; set; }
public Guid UserId { get; set; }
public string FeatureCode { get; set; }
public bool IsActive { get; set; }
public DateTime ActivatedAt { get; set; }
public DateTime? DeactivatedAt { get; set; }
}
۶. ناوبری Auth-Aware
// صفحه اصلی — مسیردهی هوشمند
if (IsAuthenticated && IsClubMember)
→ نمایش داشبورد باشگاه + فروشگاه تخفیفی
else if (IsAuthenticated)
→ نمایش فروشگاه عادی + پروفایل
else
→ نمایش Landing Page + ثبتنام
۷. کدهای معرف (Referral)
هر عضو باشگاه → یک ReferralCode یکتا
لینک: https://foursat.ir/register?ref={ReferralCode}
ثبتنام با لینک:
│
▼
ذخیره ReferrerId در پروفایل کاربر جدید
│
▼
هنگام خرید پکیج → زیرمجموعه Referrer در درخت باینری
│
▼
Referrer → دریافت bonus (طبق شرایط باشگاه)
۸. خلاصه وضعیت
| ماژول | وضعیت | درصد |
|---|---|---|
| ثبتنام OTP | ✅ | 100% |
| جداسازی Admin/Customer | ✅ | 100% |
| ICurrentUserService | ✅ | 100% |
| قرارداد باشگاه + OTP | ✅ | 100% |
| فیچرهای باشگاه | ✅ | 100% |
| Referral System | ✅ | 100% |
| ناوبری Auth-Aware | ✅ | 100% |
| مشاهده درخت شبکه (FrontOffice) | ✅ | 100% |