341 lines
12 KiB
Markdown
341 lines
12 KiB
Markdown
# 🎁 Club Features System
|
|
|
|
> **آخرین بروزرسانی**: ۳ دی ۱۴۰۴ (23 December 2025)
|
|
> **وضعیت**: ✅ Production Ready
|
|
|
|
---
|
|
|
|
## 📋 فهرست
|
|
|
|
1. [معرفی](#معرفی)
|
|
2. [فیچرهای باشگاه](#فیچرهای-باشگاه)
|
|
3. [Entity ها](#entity-ها)
|
|
4. [Enum ClubFeatureType](#enum-clubfeaturetype)
|
|
5. [فرآیند فعالسازی](#فرآیند-فعالسازی)
|
|
6. [API ها](#api-ها)
|
|
|
|
---
|
|
|
|
## معرفی
|
|
|
|
سیستم فیچرهای باشگاه مشتریان، امکانات ویژهای را برای اعضای باشگاه فراهم میکند. هر کاربر با فعالسازی باشگاه، به تمام 4 فیچر دسترسی پیدا میکند.
|
|
|
|
---
|
|
|
|
## فیچرهای باشگاه
|
|
|
|
| Id | نام | عنوان فارسی | توضیح |
|
|
|----|-----|-------------|-------|
|
|
| 1 | **Chatika** | چتیکا | دستیار هوش مصنوعی - حساب خودکار ایجاد میشود |
|
|
| 2 | **Bime** | بیمه | خدمات بیمهای |
|
|
| 3 | **Trip** | تریپ | خدمات سفر و گردشگری |
|
|
| 4 | **Learn** | لرن | آموزش و یادگیری |
|
|
|
|
---
|
|
|
|
## Entity ها
|
|
|
|
### ClubFeature (تعریف فیچرها)
|
|
|
|
```csharp
|
|
public class ClubFeature : BaseAuditableEntity
|
|
{
|
|
public string Title { get; set; }
|
|
public string? Description { get; set; }
|
|
public bool IsActive { get; set; }
|
|
public int SortOrder { get; set; }
|
|
|
|
public virtual ICollection<UserClubFeature>? UserClubFeatures { get; set; }
|
|
}
|
|
```
|
|
|
|
### UserClubFeature (فیچرهای کاربر)
|
|
|
|
```csharp
|
|
public class UserClubFeature : BaseAuditableEntity
|
|
{
|
|
public long UserId { get; set; }
|
|
public virtual User User { get; set; }
|
|
|
|
public long ClubMembershipId { get; set; }
|
|
public virtual ClubMembership ClubMembership { get; set; }
|
|
|
|
public long ClubFeatureId { get; set; }
|
|
public virtual ClubFeature ClubFeature { get; set; }
|
|
|
|
public DateTime GrantedAt { get; set; }
|
|
public bool IsActive { get; set; } = true;
|
|
public string? Notes { get; set; } // توضیحات اختیاری یا وضعیت فعالسازی
|
|
}
|
|
```
|
|
|
|
### Database Schema
|
|
|
|
```sql
|
|
CREATE TABLE ClubFeatures (
|
|
Id BIGINT PRIMARY KEY IDENTITY,
|
|
Title NVARCHAR(200) NOT NULL,
|
|
Description NVARCHAR(MAX),
|
|
IsActive BIT DEFAULT 1,
|
|
SortOrder INT DEFAULT 0,
|
|
-- BaseAuditableEntity fields
|
|
Created DATETIME2,
|
|
CreatedBy NVARCHAR(100),
|
|
LastModified DATETIME2,
|
|
LastModifiedBy NVARCHAR(100),
|
|
IsDeleted BIT DEFAULT 0
|
|
);
|
|
|
|
CREATE TABLE UserClubFeatures (
|
|
Id BIGINT PRIMARY KEY IDENTITY,
|
|
UserId BIGINT NOT NULL FOREIGN KEY REFERENCES Users(Id),
|
|
ClubMembershipId BIGINT NOT NULL FOREIGN KEY REFERENCES ClubMemberships(Id),
|
|
ClubFeatureId BIGINT NOT NULL FOREIGN KEY REFERENCES ClubFeatures(Id),
|
|
GrantedAt DATETIME2 NOT NULL,
|
|
IsActive BIT DEFAULT 1,
|
|
Notes NVARCHAR(MAX),
|
|
-- BaseAuditableEntity fields
|
|
Created DATETIME2,
|
|
CreatedBy NVARCHAR(100),
|
|
LastModified DATETIME2,
|
|
LastModifiedBy NVARCHAR(100),
|
|
IsDeleted BIT DEFAULT 0
|
|
);
|
|
|
|
-- Seed Data
|
|
INSERT INTO ClubFeatures (Id, Title, Description, IsActive, SortOrder)
|
|
VALUES
|
|
(1, N'چتیکا', N'دستیار هوش مصنوعی', 1, 1),
|
|
(2, N'بیمه', N'خدمات بیمهای', 1, 2),
|
|
(3, N'تریپ', N'خدمات سفر و گردشگری', 1, 3),
|
|
(4, N'لرن', N'آموزش و یادگیری', 1, 4);
|
|
```
|
|
|
|
---
|
|
|
|
## Enum ClubFeatureType
|
|
|
|
برای جلوگیری از hardcoded IDs، از Enum استفاده میشود:
|
|
|
|
**فایل**: `CMSMicroservice.Domain/Enums/ClubFeatureType.cs`
|
|
|
|
```csharp
|
|
namespace CMSMicroservice.Domain.Enums;
|
|
|
|
/// <summary>
|
|
/// انواع ویژگیهای باشگاه مشتریان
|
|
/// </summary>
|
|
public enum ClubFeatureType
|
|
{
|
|
/// <summary>
|
|
/// چتیکا - دستیار هوش مصنوعی
|
|
/// </summary>
|
|
Chatika = 1,
|
|
|
|
/// <summary>
|
|
/// بیمه - خدمات بیمهای
|
|
/// </summary>
|
|
Bime = 2,
|
|
|
|
/// <summary>
|
|
/// تریپ - خدمات سفر و گردشگری
|
|
/// </summary>
|
|
Trip = 3,
|
|
|
|
/// <summary>
|
|
/// لرن - آموزش و یادگیری
|
|
/// </summary>
|
|
Learn = 4
|
|
}
|
|
|
|
/// <summary>
|
|
/// Extension methods برای ClubFeatureType
|
|
/// </summary>
|
|
public static class ClubFeatureTypeExtensions
|
|
{
|
|
/// <summary>
|
|
/// دریافت تمام مقادیر ClubFeatureType به صورت آرایه long
|
|
/// </summary>
|
|
public static long[] GetAllFeatureIds()
|
|
{
|
|
return Enum.GetValues<ClubFeatureType>()
|
|
.Select(f => (long)f)
|
|
.ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// دریافت عنوان فارسی ویژگی
|
|
/// </summary>
|
|
public static string GetPersianTitle(this ClubFeatureType featureType)
|
|
{
|
|
return featureType switch
|
|
{
|
|
ClubFeatureType.Chatika => "چتیکا",
|
|
ClubFeatureType.Bime => "بیمه",
|
|
ClubFeatureType.Trip => "تور و سفر",
|
|
ClubFeatureType.Learn => "آموزش",
|
|
_ => featureType.ToString()
|
|
};
|
|
}
|
|
}
|
|
```
|
|
|
|
### استفاده در کد
|
|
|
|
```csharp
|
|
// ❌ قبل - Hardcoded
|
|
var featureIds = new long[] { 1, 2, 3, 4 };
|
|
|
|
// ✅ بعد - با Enum
|
|
var featureIds = ClubFeatureTypeExtensions.GetAllFeatureIds();
|
|
|
|
// دسترسی به یک فیچر خاص
|
|
var chatikaId = (long)ClubFeatureType.Chatika; // = 1
|
|
var title = ClubFeatureType.Bime.GetPersianTitle(); // = "بیمه"
|
|
```
|
|
|
|
---
|
|
|
|
## فرآیند فعالسازی
|
|
|
|
هنگام فعالسازی باشگاه مشتریان، فیچرها به این ترتیب اختصاص داده میشوند:
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ ActivateClubMembershipCommandHandler │
|
|
│ یا │
|
|
│ AcceptClubMembershipContractCommandHandler │
|
|
└─────────────────────────────┬───────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ // 8. اختصاص فیچرهای باشگاه │
|
|
│ var featureIds = ClubFeatureTypeExtensions.GetAllFeatureIds(); │
|
|
│ foreach (var featureId in featureIds) │
|
|
│ { │
|
|
│ _context.UserClubFeatures.Add(new UserClubFeature │
|
|
│ { │
|
|
│ UserId = user.Id, │
|
|
│ ClubMembershipId = membership.Id, │
|
|
│ ClubFeatureId = featureId, │
|
|
│ GrantedAt = DateTime.Now, │
|
|
│ IsActive = true, │
|
|
│ Notes = null // برای چتیکا بعداً توسط Worker پر میشود │
|
|
│ }); │
|
|
│ } │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ 4 UserClubFeature Records │
|
|
│ ┌─────────────┬──────────────┬────────────┬─────────────┐ │
|
|
│ │ ClubFeatureId │ GrantedAt │ IsActive │ Notes │ │
|
|
│ ├─────────────┼──────────────┼────────────┼─────────────┤ │
|
|
│ │ 1 (Chatika) │ 2025-12-23 │ true │ NULL → پر │ │
|
|
│ │ 2 (Bime) │ 2025-12-23 │ true │ NULL │ │
|
|
│ │ 3 (Trip) │ 2025-12-23 │ true │ NULL │ │
|
|
│ │ 4 (Learn) │ 2025-12-23 │ true │ NULL │ │
|
|
│ └─────────────┴──────────────┴────────────┴─────────────┘ │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
│
|
|
▼ (برای چتیکا)
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ ChatikaAccountActivationJob (Worker) │
|
|
│ - هر 5 دقیقه اجرا میشود │
|
|
│ - کاربران با Notes = NULL و ClubFeatureId = 1 را پیدا میکند │
|
|
│ - API چتیکا را کال میکند │
|
|
│ - Notes را با توضیحات فارسی پر میکند │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## API ها
|
|
|
|
### GetUserClubFeatures
|
|
|
|
دریافت لیست فیچرهای فعال کاربر:
|
|
|
|
```protobuf
|
|
rpc GetUserClubFeatures (GetUserClubFeaturesRequest) returns (GetUserClubFeaturesResponse);
|
|
|
|
message GetUserClubFeaturesRequest {
|
|
int64 user_id = 1;
|
|
}
|
|
|
|
message GetUserClubFeaturesResponse {
|
|
repeated UserClubFeatureModel features = 1;
|
|
}
|
|
|
|
message UserClubFeatureModel {
|
|
int64 id = 1;
|
|
int64 club_feature_id = 2;
|
|
string feature_title = 3;
|
|
string feature_description = 4;
|
|
google.protobuf.Timestamp granted_at = 5;
|
|
bool is_active = 6;
|
|
string notes = 7;
|
|
}
|
|
```
|
|
|
|
### ToggleUserClubFeature
|
|
|
|
فعال/غیرفعال کردن فیچر توسط ادمین:
|
|
|
|
```protobuf
|
|
rpc ToggleUserClubFeature (ToggleUserClubFeatureRequest) returns (ToggleUserClubFeatureResponse);
|
|
|
|
message ToggleUserClubFeatureRequest {
|
|
int64 user_club_feature_id = 1;
|
|
bool is_active = 2;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Query های مفید
|
|
|
|
### تعداد فیچرهای فعال هر کاربر
|
|
|
|
```sql
|
|
SELECT u.Mobile, COUNT(ucf.Id) as FeatureCount
|
|
FROM Users u
|
|
JOIN UserClubFeatures ucf ON u.Id = ucf.UserId
|
|
WHERE ucf.IsActive = 1 AND ucf.IsDeleted = 0
|
|
GROUP BY u.Mobile
|
|
```
|
|
|
|
### کاربران بدون فیچر چتیکا فعال
|
|
|
|
```sql
|
|
SELECT u.Id, u.Mobile
|
|
FROM Users u
|
|
JOIN ClubMemberships cm ON u.Id = cm.UserId
|
|
WHERE cm.IsActive = 1
|
|
AND NOT EXISTS (
|
|
SELECT 1 FROM UserClubFeatures ucf
|
|
WHERE ucf.UserId = u.Id
|
|
AND ucf.ClubFeatureId = 1
|
|
AND ucf.IsActive = 1
|
|
)
|
|
```
|
|
|
|
### وضعیت فعالسازی چتیکا
|
|
|
|
```sql
|
|
SELECT
|
|
CASE WHEN Notes IS NOT NULL THEN 'Activated' ELSE 'Pending' END as Status,
|
|
COUNT(*) as Count
|
|
FROM UserClubFeatures
|
|
WHERE ClubFeatureId = 1 AND IsDeleted = 0
|
|
GROUP BY CASE WHEN Notes IS NOT NULL THEN 'Activated' ELSE 'Pending' END
|
|
```
|
|
|
|
---
|
|
|
|
## 📚 مستندات مرتبط
|
|
|
|
- [Chatika Integration](./chatika-integration.md)
|
|
- [Club Membership Migration](./club-membership-migration.md)
|
|
- [Commission System](./commission-system.md)
|