12 KiB
12 KiB
🎁 Club Features System
آخرین بروزرسانی: ۳ دی ۱۴۰۴ (23 December 2025)
وضعیت: ✅ Production Ready
📋 فهرست
معرفی
سیستم فیچرهای باشگاه مشتریان، امکانات ویژهای را برای اعضای باشگاه فراهم میکند. هر کاربر با فعالسازی باشگاه، به تمام 4 فیچر دسترسی پیدا میکند.
فیچرهای باشگاه
| Id | نام | عنوان فارسی | توضیح |
|---|---|---|---|
| 1 | Chatika | چتیکا | دستیار هوش مصنوعی - حساب خودکار ایجاد میشود |
| 2 | Bime | بیمه | خدمات بیمهای |
| 3 | Trip | تریپ | خدمات سفر و گردشگری |
| 4 | Learn | لرن | آموزش و یادگیری |
Entity ها
ClubFeature (تعریف فیچرها)
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 (فیچرهای کاربر)
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
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
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()
};
}
}
استفاده در کد
// ❌ قبل - 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
دریافت لیست فیچرهای فعال کاربر:
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
فعال/غیرفعال کردن فیچر توسط ادمین:
rpc ToggleUserClubFeature (ToggleUserClubFeatureRequest) returns (ToggleUserClubFeatureResponse);
message ToggleUserClubFeatureRequest {
int64 user_club_feature_id = 1;
bool is_active = 2;
}
📊 Query های مفید
تعداد فیچرهای فعال هر کاربر
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
کاربران بدون فیچر چتیکا فعال
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
)
وضعیت فعالسازی چتیکا
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