feat: normalize subscription architecture, integrate pgvector, and implement Stripe webhook subscription management.
This commit is contained in:
@@ -23,6 +23,10 @@ public class Ebook
|
||||
|
||||
public string? CoverUrl { get; set; }
|
||||
|
||||
[Required]
|
||||
[MaxLength(128)]
|
||||
public string TenantId { get; set; } = "global";
|
||||
|
||||
public DateTime AddedDate { get; set; } = DateTime.UtcNow;
|
||||
|
||||
public DateTime? LastReadDate { get; set; }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using NexusReader.Domain.Enums;
|
||||
using Pgvector;
|
||||
|
||||
namespace NexusReader.Domain.Entities;
|
||||
|
||||
@@ -30,8 +31,7 @@ public class KnowledgeUnit
|
||||
[MaxLength(128)]
|
||||
public string TenantId { get; set; } = string.Empty;
|
||||
|
||||
[Column(TypeName = "vector(768)")] // Default for text-embedding-004
|
||||
public float[]? Vector { get; set; }
|
||||
public Vector? Vector { get; set; }
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
|
||||
@@ -1,34 +1,49 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace NexusReader.Domain.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Extended Identity user for the Nexus AI E-Reader SaaS platform.
|
||||
/// </summary>
|
||||
public class NexusUser : IdentityUser
|
||||
{
|
||||
/// <summary>
|
||||
/// Total number of AI tokens allowed for the current billing period.
|
||||
/// User's display name or full name.
|
||||
/// </summary>
|
||||
[MaxLength(100)]
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total AI tokens available for the user (depends on subscription).
|
||||
/// </summary>
|
||||
public int AITokenLimit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of AI tokens consumed in the current billing period.
|
||||
/// AI tokens consumed by the user in the current billing period.
|
||||
/// </summary>
|
||||
public int AITokensUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unique identifier for the tenant (SaaS multi-tenancy support).
|
||||
/// Date when the user last performed an AI-related action.
|
||||
/// </summary>
|
||||
public DateTime? LastAiActionDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Multi-tenant identifier.
|
||||
/// </summary>
|
||||
[Required]
|
||||
[MaxLength(128)]
|
||||
public string TenantId { get; set; } = "global";
|
||||
|
||||
/// <summary>
|
||||
/// Current subscription plan (e.g., "Free", "Pro", "Enterprise").
|
||||
/// Foreign key for the current subscription plan.
|
||||
/// </summary>
|
||||
public string CurrentPlan { get; set; } = "Free";
|
||||
[Required]
|
||||
public int SubscriptionPlanId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Navigation property for the current subscription plan.
|
||||
/// </summary>
|
||||
public SubscriptionPlan? SubscriptionPlan { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Collection of e-books owned by the user.
|
||||
@@ -43,10 +58,11 @@ public class NexusUser : IdentityUser
|
||||
/// <summary>
|
||||
/// ID of the last page read by the user.
|
||||
/// </summary>
|
||||
[MaxLength(255)]
|
||||
public string? LastReadPageId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of the last reading progress update.
|
||||
/// Last read timestamp.
|
||||
/// </summary>
|
||||
public DateTime? LastReadAt { get; set; }
|
||||
}
|
||||
|
||||
@@ -17,6 +17,10 @@ public class QuizResult
|
||||
[ForeignKey(nameof(UserId))]
|
||||
public NexusUser? User { get; set; }
|
||||
|
||||
[Required]
|
||||
[MaxLength(128)]
|
||||
public string TenantId { get; set; } = "global";
|
||||
|
||||
[Required]
|
||||
public string Topic { get; set; } = string.Empty;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Pgvector;
|
||||
|
||||
namespace NexusReader.Domain.Entities;
|
||||
|
||||
@@ -27,8 +28,7 @@ public class SemanticKnowledgeCache
|
||||
[MaxLength(128)]
|
||||
public string TenantId { get; set; } = string.Empty;
|
||||
|
||||
[Column(TypeName = "vector(1536)")] // text-embedding-004 has 768 or 1536 dims, assuming 1536 for high-fidelity
|
||||
public float[]? Vector { get; set; }
|
||||
public Vector? Vector { get; set; }
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace NexusReader.Domain.Entities;
|
||||
|
||||
public class SubscriptionPlan
|
||||
{
|
||||
public const string FreeName = "Free";
|
||||
public const string BasicName = "Basic";
|
||||
public const string ProName = "Pro";
|
||||
public const string EnterpriseName = "Enterprise";
|
||||
|
||||
public const int FreeId = 1;
|
||||
public const int BasicId = 2;
|
||||
public const int ProId = 3;
|
||||
public const int EnterpriseId = 4;
|
||||
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[MaxLength(50)]
|
||||
public string PlanName { get; set; } = string.Empty;
|
||||
|
||||
public int AITokenLimit { get; set; }
|
||||
|
||||
public decimal MonthlyPrice { get; set; }
|
||||
|
||||
[MaxLength(50)]
|
||||
public string StripeProductId { get; set; } = string.Empty;
|
||||
}
|
||||
Reference in New Issue
Block a user