Files
docs/business/BUSINESS-04-USER-MEMBERSHIP.md
T
masoodafar-web 3c729304db docs: fix all discrepancies based on comprehensive code audit
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
2026-02-18 22:58:40 +03:30

7.3 KiB
Raw Blame History

👤 سفر کاربر، ثبت‌نام و چرخه عضویت

منابع ادغام‌شده: 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%