# برنامه پیاده‌سازی باشگاه مشتریان

## خلاصه

این سند، برنامه پیاده‌سازی MVP باشگاه مشتریان را بر اساس `club.md` مشخص می‌کند.  
در فاز اول، همه قواعد امتیازدهی سند جدید پیاده‌سازی می‌شوند:

- امتیاز معرفی
- امتیاز اولین سرمایه‌گذاری
- امتیاز روزانه سرمایه‌گذاری
- امتیاز نگهداری بیش از ۳ ماه
- امتیاز نگهداری بیش از ۶ ماه
- داشبورد باشگاه در یک صفحه
- تبدیل امتیاز به کارت هدیه از طریق سیستم فعلی کارت هدیه

طراحی باید `ledger-first` و `idempotent` باشد.

---

## مدل‌های داده

مدل‌های جدید:

### 1. ClubPointTransaction

منبع اصلی تمام تغییرات امتیاز:

- earned
- spent
- expired
- reversed
- adjusted

فیلدهای اصلی:

- `user`
- `type`
- `points`
- `source`
- `sourceId`
- `eventKey`
- `meta`
- `expiresAt`

### 2. ClubReferral

برای نگهداری ارتباط معرف و کاربر دعوت‌شده:

- `inviter`
- `invitee`
- `referralCode`
- `status`
- `qualifiedAt`

### 3. ClubReward

برای تعریف جوایز قابل دریافت:

- `title`
- `description`
- `pointsCost`
- `status`
- `rewardType`
- `meta`

### 4. ClubRewardRedemption

برای ثبت درخواست دریافت جایزه:

- `user`
- `reward`
- `pointsSpent`
- `status`
- `paymentCard`
- `fulfilledAt`

### 5. User fields

افزودن فیلدهای جدید به `User`:

- `clubReferralCode`
- `clubInviter`

در صورت نیاز:

- `clubSuccessfulReferralCount` فقط به عنوان فیلد کمکی، نه منبع اصلی داده

---

## جریان معرفی و ثبت‌نام

در زمان ثبت‌نام کاربر جدید:

- امکان ورود `referralCode` وجود داشته باشد
- فقط در اولین ثبت‌نام معتبر باشد
- بعد از ایجاد کاربر، امکان تغییر معرف وجود نداشته باشد
- self-referral مجاز نباشد
- اگر کد معتبر بود، یک `ClubReferral` با وضعیت pending ساخته شود

زمان موفق شدن معرفی:

- در اولین تکمیل موفق ثبت‌نام/احراز هویت از مسیر OTP

در زمان موفق شدن معرفی:

- `10000` امتیاز برای معرف
- `5000` امتیاز خوش‌آمدگویی برای کاربر جدید

این امتیازها باید فقط یک بار ثبت شوند.

---

## موتور امتیازدهی

### 1. امتیاز اولین سرمایه‌گذاری

وقتی اولین درخواست صدور کاربر به وضعیت `approved` برسد:

- `10000` امتیاز به کاربر تعلق بگیرد

### 2. سهم معرف از سرمایه‌گذاری

اگر کاربر معرفی‌شده سرمایه‌گذاری داشته باشد:

- `10%` از امتیاز سرمایه‌گذاری او به معرف تعلق بگیرد

### 3. امتیاز روزانه و نگهداری

به دلیل اینکه اطلاعات نگهداری سرمایه از `Request` به تنهایی کافی نیست، یک Job زمان‌بندی‌شده لازم است که بر اساس داده‌های Tadbir محاسبه کند:

- امتیاز روزانه: `x/365*0.004`
- بیشتر از ۳ ماه: `x/365*0.005`
- بیشتر از ۶ ماه: `x/365*0.006`

قاعده اعمال نرخ:

- کمتر از ۹۰ روز: فقط نرخ روزانه
- بین ۹۰ تا ۱۷۹ روز: نرخ ۳ ماهه
- ۱۸۰ روز به بالا: نرخ ۶ ماهه

### 4. انقضای امتیاز

امتیازها بعد از ۱۲ ماه منقضی شوند.
انقضا باید با ثبت تراکنش منفی جدید انجام شود، نه ویرایش رکورد قبلی.

### 5. idempotency

همه تخصیص‌های امتیاز باید `eventKey` یکتا داشته باشند تا با retry یا sync مجدد، امتیاز تکراری ایجاد نشود.

---

## جوایز و بازخرید

در MVP از سیستم فعلی کارت هدیه استفاده شود.

فرآیند:

1. کاربر جایزه را انتخاب می‌کند
2. اگر موجودی امتیاز کافی داشت:
   - یک `ClubRewardRedemption` ساخته شود
   - یک تراکنش منفی امتیاز ثبت شود
3. سیستم از زیرساخت فعلی `payment card` برای تحویل جایزه استفاده کند
4. شناسه کارت هدیه در رکورد redemption ذخیره شود

اگر تحویل جایزه ناموفق بود:

- redemption باید failed شود
- کسر امتیاز باید rollback شود یا نهایی نشود

---

## داشبورد باشگاه

داشبورد باشگاه باید فقط **یک صفحه** باشد و همه اطلاعات اصلی به صورت **widget style** نمایش داده شوند.

### اطلاعات روی همین یک صفحه

- امتیاز فعلی
- تاریخچه امتیازها
- لیست جوایز قابل دریافت
- تعداد معرفی‌های موفق

### چیدمان پیشنهادی

- ردیف اول:
  - ویجت امتیاز فعلی
  - ویجت تعداد معرفی‌های موفق
- ردیف دوم:
  - ویجت کد/لینک معرفی
  - ویجت لیست جوایز قابل دریافت
- ردیف سوم:
  - ویجت تاریخچه امتیازها

### رفتار موبایل

- همه ویجت‌ها به صورت تک‌ستونه نمایش داده شوند
- هیچ صفحه جداگانه‌ای برای history یا rewards در MVP وجود نداشته باشد

---

## API های مورد نیاز

### API های کاربر

- `GET /club/me`
- `GET /club/history`
- `GET /club/referrals`
- `GET /club/rewards`
- `POST /club/rewards/:id/redeem`

### API های ادمین

- `GET /club/admin/ledger`
- `GET /club/admin/referrals`
- `GET /club/admin/redemptions`
- `POST /club/admin/rewards`
- `PUT /club/admin/rewards/:id`
- `POST /club/admin/adjustments`

---

## Permission های مورد نیاز

این permission ها باید در `init-database.js` به سیستم اضافه شوند:

### Member

- `club:view`
  - دسترسی کاربر به صفحه باشگاه و API های کاربری

### Admin / Operator

- `clubRewards:view`
- `clubRewards:create`
- `clubRewards:update`
- `clubRewards:delete`

- `clubLedger:view`
- `clubReferrals:view`
- `clubRedemptions:view`
- `clubAdjustments:create`

### معنی هر permission

- `club:view`
  - مشاهده داشبورد باشگاه برای خود کاربر
- `clubRewards:view`
  - مشاهده لیست جوایز در پنل مدیریتی
- `clubRewards:create`
  - ایجاد جایزه جدید
- `clubRewards:update`
  - ویرایش جایزه
- `clubRewards:delete`
  - حذف/غیرفعال‌سازی جایزه
- `clubLedger:view`
  - مشاهده تراکنش‌های امتیاز
- `clubReferrals:view`
  - مشاهده معرفی‌ها و وضعیت آن‌ها
- `clubRedemptions:view`
  - مشاهده درخواست‌های دریافت جایزه
- `clubAdjustments:create`
  - ثبت اصلاح دستی امتیاز مثبت/منفی

---

## تست‌ها

### Referral

- ثبت‌نام با کد معرفی معتبر
- رد self-referral
- عدم امکان تغییر معرف بعد از ثبت‌نام
- عدم ثبت دوباره پاداش معرفی در retry

### Points

- ثبت یک‌باره امتیاز اولین سرمایه‌گذاری
- ثبت سهم ۱۰٪ معرف فقط یک بار
- عدم ثبت امتیاز تکراری در sync/retry

### Accrual job

- ثبت امتیاز روزانه فقط یک بار در هر روز
- اعمال درست مرز ۹۰ روز و ۱۸۰ روز
- اجرای مجدد job در همان روز باعث تکرار نشود

### Rewards

- جلوگیری از redeem بدون امتیاز کافی
- ایجاد کارت هدیه بعد از redeem موفق
- مدیریت failure در fulfillment

### UI

- نمایش همه اطلاعات باشگاه در یک صفحه
- نمایش ویجتی در دسکتاپ
- چیدمان تک‌ستونه در موبایل

---

## فرض‌های نهایی

- MVP شامل همه قواعد امتیازدهی سند جدید است
- امتیاز سرمایه‌گذاری بر اساس `approved` شدن درخواست محاسبه می‌شود
- امتیازهای روزانه و نگهداری از طریق job شبانه محاسبه می‌شوند
- بازخرید جایزه از سیستم فعلی کارت هدیه استفاده می‌کند
- سهم `10%` معرف فقط روی امتیاز سرمایه‌گذاری اعمال می‌شود
- تاریخچه امتیازها منبع اصلی audit است و نباید با update مستقیم تغییر کند
