feat(Q27): PackageHistory + ClubMembershipCycleHistory entities
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 8m28s

Q27: History Tables standardization — added missing history entities:
- PackageHistory: tracks price, activation fee, magic settings changes
- ClubMembershipCycleHistory: tracks cycle state transitions
- PackageAction + ClubMembershipCycleAction enums
- EF configurations with proper indexes and FK relationships
- DbSets registered in IApplicationDbContext + ApplicationDbContext
- Navigation properties on Package + ClubMembershipCycle entities
This commit is contained in:
masoodafar-web
2026-02-27 05:31:21 +03:30
parent a1024a3e18
commit fdbb91d2e1
10 changed files with 308 additions and 0 deletions
@@ -39,6 +39,8 @@ public interface IApplicationDbContext
DbSet<ClubMembership> ClubMemberships { get; } DbSet<ClubMembership> ClubMemberships { get; }
DbSet<ClubMembershipHistory> ClubMembershipHistories { get; } DbSet<ClubMembershipHistory> ClubMembershipHistories { get; }
DbSet<ClubMembershipCycle> ClubMembershipCycles { get; } DbSet<ClubMembershipCycle> ClubMembershipCycles { get; }
DbSet<ClubMembershipCycleHistory> ClubMembershipCycleHistories { get; }
DbSet<PackageHistory> PackageHistories { get; }
DbSet<PackageFeature> PackageFeatures { get; } DbSet<PackageFeature> PackageFeatures { get; }
DbSet<ClubFeature> ClubFeatures { get; } DbSet<ClubFeature> ClubFeatures { get; }
DbSet<UserClubFeature> UserClubFeatures { get; } DbSet<UserClubFeature> UserClubFeatures { get; }
@@ -71,4 +71,7 @@ public class ClubMembershipCycle : BaseAuditableEntity
/// آیا این دور فعلی است؟ فقط یک رکورد true می‌باشد /// آیا این دور فعلی است؟ فقط یک رکورد true می‌باشد
/// </summary> /// </summary>
public bool IsCurrentCycle { get; set; } public bool IsCurrentCycle { get; set; }
/// <summary>تاریخچه تغییرات دوره (Q27)</summary>
public virtual ICollection<History.ClubMembershipCycleHistory>? CycleHistories { get; set; }
} }
@@ -0,0 +1,73 @@
namespace CMSMicroservice.Domain.Entities.History;
/// <summary>
/// تاریخچه تغییرات دوره عضویت باشگاه (Q27)
/// هر بار تغییر وضعیت چرخه (شروع، ورود/خروج جادویی، تکمیل)، یک رکورد ذخیره می‌شود.
/// </summary>
public class ClubMembershipCycleHistory : BaseAuditableEntity
{
/// <summary>
/// شناسه چرخه
/// </summary>
public long ClubMembershipCycleId { get; set; }
/// <summary>
/// ClubMembershipCycle Navigation Property
/// </summary>
public virtual Club.ClubMembershipCycle? ClubMembershipCycle { get; set; }
/// <summary>
/// شناسه کاربر
/// </summary>
public long UserId { get; set; }
/// <summary>
/// شماره دور
/// </summary>
public int CycleNumber { get; set; }
/// <summary>
/// IsCurrentCycle قبل از تغییر
/// </summary>
public bool OldIsCurrentCycle { get; set; }
/// <summary>
/// IsCurrentCycle بعد از تغییر
/// </summary>
public bool NewIsCurrentCycle { get; set; }
/// <summary>
/// تاریخ شروع جادویی قبل از تغییر
/// </summary>
public DateTime? OldMagicStartedAt { get; set; }
/// <summary>
/// تاریخ شروع جادویی بعد از تغییر
/// </summary>
public DateTime? NewMagicStartedAt { get; set; }
/// <summary>
/// تاریخ تکمیل جادویی قبل از تغییر
/// </summary>
public DateTime? OldMagicCompletedAt { get; set; }
/// <summary>
/// تاریخ تکمیل جادویی بعد از تغییر
/// </summary>
public DateTime? NewMagicCompletedAt { get; set; }
/// <summary>
/// نوع عملیات
/// </summary>
public ClubMembershipCycleAction Action { get; set; }
/// <summary>
/// چه کسی انجام داده (UserId یا "System")
/// </summary>
public string? PerformedBy { get; set; }
/// <summary>
/// دلیل تغییر (اختیاری)
/// </summary>
public string? Reason { get; set; }
}
@@ -0,0 +1,93 @@
namespace CMSMicroservice.Domain.Entities.History;
/// <summary>
/// تاریخچه تغییرات پکیج (Q27)
/// هر بار تغییر قیمت، تنظیمات جادویی یا کمیسیون، یک رکورد ذخیره می‌شود.
/// </summary>
public class PackageHistory : BaseAuditableEntity
{
/// <summary>
/// شناسه پکیج
/// </summary>
public long PackageId { get; set; }
/// <summary>
/// Package Navigation Property
/// </summary>
public virtual Package? Package { get; set; }
/// <summary>
/// قیمت قبل از تغییر (ریال)
/// </summary>
public long? OldPrice { get; set; }
/// <summary>
/// قیمت بعد از تغییر (ریال)
/// </summary>
public long? NewPrice { get; set; }
/// <summary>
/// سهم Commission Pool قبل از تغییر
/// </summary>
public long? OldActivationFee { get; set; }
/// <summary>
/// سهم Commission Pool بعد از تغییر
/// </summary>
public long? NewActivationFee { get; set; }
/// <summary>
/// ضریب جادویی قبل از تغییر
/// </summary>
public decimal? OldMagicMultiplier { get; set; }
/// <summary>
/// ضریب جادویی بعد از تغییر
/// </summary>
public decimal? NewMagicMultiplier { get; set; }
/// <summary>
/// سقف شارژ جادویی قبل از تغییر
/// </summary>
public long? OldMagicMaxDeposit { get; set; }
/// <summary>
/// سقف شارژ جادویی بعد از تغییر
/// </summary>
public long? NewMagicMaxDeposit { get; set; }
/// <summary>
/// سقف تعادل هر پا قبل از تغییر
/// </summary>
public int? OldMaxBalancesPerLeg { get; set; }
/// <summary>
/// سقف تعادل هر پا بعد از تغییر
/// </summary>
public int? NewMaxBalancesPerLeg { get; set; }
/// <summary>
/// وضعیت فعال قبل از تغییر
/// </summary>
public bool? OldIsActive { get; set; }
/// <summary>
/// وضعیت فعال بعد از تغییر
/// </summary>
public bool? NewIsActive { get; set; }
/// <summary>
/// نوع عملیات
/// </summary>
public PackageAction Action { get; set; }
/// <summary>
/// چه کسی انجام داده (UserId یا "System")
/// </summary>
public string? PerformedBy { get; set; }
/// <summary>
/// دلیل تغییر (اختیاری)
/// </summary>
public string? Reason { get; set; }
}
@@ -73,4 +73,7 @@ public class Package : BaseAuditableEntity
/// <summary>خریدهای پکیج</summary> /// <summary>خریدهای پکیج</summary>
public virtual ICollection<UserPackagePurchase>? Purchases { get; set; } public virtual ICollection<UserPackagePurchase>? Purchases { get; set; }
/// <summary>تاریخچه تغییرات پکیج (Q27)</summary>
public virtual ICollection<History.PackageHistory>? PackageHistories { get; set; }
} }
@@ -0,0 +1,14 @@
namespace CMSMicroservice.Domain.Enums;
/// <summary>
/// نوع عملیات تغییر دوره عضویت باشگاه (Q27)
/// </summary>
public enum ClubMembershipCycleAction
{
Started = 0,
MagicEntered = 1,
MagicCompleted = 2,
Completed = 3,
Cancelled = 4,
ManualFix = 5
}
@@ -0,0 +1,16 @@
namespace CMSMicroservice.Domain.Enums;
/// <summary>
/// نوع عملیات تغییر پکیج (Q27)
/// </summary>
public enum PackageAction
{
Created = 0,
Updated = 1,
PriceChanged = 2,
Deactivated = 3,
Reactivated = 4,
MagicSettingsChanged = 5,
CommissionSettingsChanged = 6,
ManualFix = 7
}
@@ -110,6 +110,8 @@ public class ApplicationDbContext : DbContext, IApplicationDbContext
public DbSet<UserClubFeature> UserClubFeatures => Set<UserClubFeature>(); public DbSet<UserClubFeature> UserClubFeatures => Set<UserClubFeature>();
public DbSet<ClubMembershipHistory> ClubMembershipHistories => Set<ClubMembershipHistory>(); public DbSet<ClubMembershipHistory> ClubMembershipHistories => Set<ClubMembershipHistory>();
public DbSet<ClubMembershipCycle> ClubMembershipCycles => Set<ClubMembershipCycle>(); public DbSet<ClubMembershipCycle> ClubMembershipCycles => Set<ClubMembershipCycle>();
public DbSet<ClubMembershipCycleHistory> ClubMembershipCycleHistories => Set<ClubMembershipCycleHistory>();
public DbSet<PackageHistory> PackageHistories => Set<PackageHistory>();
public DbSet<PackageFeature> PackageFeatures => Set<PackageFeature>(); public DbSet<PackageFeature> PackageFeatures => Set<PackageFeature>();
// Network // Network
@@ -0,0 +1,51 @@
using CMSMicroservice.Domain.Entities.History;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace CMSMicroservice.Infrastructure.Persistence.Configurations;
/// <summary>
/// تاریخچه تغییرات دوره عضویت باشگاه (Q27)
/// </summary>
public class ClubMembershipCycleHistoryConfiguration : IEntityTypeConfiguration<ClubMembershipCycleHistory>
{
public void Configure(EntityTypeBuilder<ClubMembershipCycleHistory> builder)
{
builder.HasQueryFilter(p => !p.IsDeleted);
builder.Ignore(entity => entity.DomainEvents);
builder.HasKey(entity => entity.Id);
builder.Property(entity => entity.Id).UseIdentityColumn();
builder.Property(entity => entity.ClubMembershipCycleId).IsRequired();
builder.Property(entity => entity.UserId).IsRequired();
builder.Property(entity => entity.CycleNumber).IsRequired();
builder.Property(entity => entity.OldIsCurrentCycle).IsRequired();
builder.Property(entity => entity.NewIsCurrentCycle).IsRequired();
builder.Property(entity => entity.OldMagicStartedAt).IsRequired(false);
builder.Property(entity => entity.NewMagicStartedAt).IsRequired(false);
builder.Property(entity => entity.OldMagicCompletedAt).IsRequired(false);
builder.Property(entity => entity.NewMagicCompletedAt).IsRequired(false);
builder.Property(entity => entity.Action).IsRequired();
builder.Property(entity => entity.PerformedBy).IsRequired(false).HasMaxLength(100);
builder.Property(entity => entity.Reason).IsRequired(false).HasMaxLength(500);
// رابطه با ClubMembershipCycle
builder.HasOne(entity => entity.ClubMembershipCycle)
.WithMany(c => c.CycleHistories)
.HasForeignKey(entity => entity.ClubMembershipCycleId)
.OnDelete(DeleteBehavior.Restrict);
// Index برای UserId و Created
builder.HasIndex(e => new { e.UserId, e.Created })
.HasDatabaseName("IX_ClubMembershipCycleHistory_UserId_Created");
// Index برای ClubMembershipCycleId
builder.HasIndex(e => e.ClubMembershipCycleId)
.HasDatabaseName("IX_ClubMembershipCycleHistory_CycleId");
// Index برای Action
builder.HasIndex(e => e.Action)
.HasDatabaseName("IX_ClubMembershipCycleHistory_Action");
}
}
@@ -0,0 +1,51 @@
using CMSMicroservice.Domain.Entities.History;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace CMSMicroservice.Infrastructure.Persistence.Configurations;
/// <summary>
/// تاریخچه تغییرات پکیج (Q27)
/// </summary>
public class PackageHistoryConfiguration : IEntityTypeConfiguration<PackageHistory>
{
public void Configure(EntityTypeBuilder<PackageHistory> builder)
{
builder.HasQueryFilter(p => !p.IsDeleted);
builder.Ignore(entity => entity.DomainEvents);
builder.HasKey(entity => entity.Id);
builder.Property(entity => entity.Id).UseIdentityColumn();
builder.Property(entity => entity.PackageId).IsRequired();
builder.Property(entity => entity.OldPrice).IsRequired(false);
builder.Property(entity => entity.NewPrice).IsRequired(false);
builder.Property(entity => entity.OldActivationFee).IsRequired(false);
builder.Property(entity => entity.NewActivationFee).IsRequired(false);
builder.Property(entity => entity.OldMagicMultiplier).IsRequired(false).HasPrecision(18, 4);
builder.Property(entity => entity.NewMagicMultiplier).IsRequired(false).HasPrecision(18, 4);
builder.Property(entity => entity.OldMagicMaxDeposit).IsRequired(false);
builder.Property(entity => entity.NewMagicMaxDeposit).IsRequired(false);
builder.Property(entity => entity.OldMaxBalancesPerLeg).IsRequired(false);
builder.Property(entity => entity.NewMaxBalancesPerLeg).IsRequired(false);
builder.Property(entity => entity.OldIsActive).IsRequired(false);
builder.Property(entity => entity.NewIsActive).IsRequired(false);
builder.Property(entity => entity.Action).IsRequired();
builder.Property(entity => entity.PerformedBy).IsRequired(false).HasMaxLength(100);
builder.Property(entity => entity.Reason).IsRequired(false).HasMaxLength(500);
// رابطه با Package
builder.HasOne(entity => entity.Package)
.WithMany(p => p.PackageHistories)
.HasForeignKey(entity => entity.PackageId)
.OnDelete(DeleteBehavior.Restrict);
// Index برای PackageId و Created
builder.HasIndex(e => new { e.PackageId, e.Created })
.HasDatabaseName("IX_PackageHistory_PackageId_Created");
// Index برای Action
builder.HasIndex(e => e.Action)
.HasDatabaseName("IX_PackageHistory_Action");
}
}