forked from xiongyuxing/tiku-backend.net
feat: add core persistence model
This commit is contained in:
126
Tiku.Domain/Catalog/CatalogEntities.cs
Normal file
126
Tiku.Domain/Catalog/CatalogEntities.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
using System.Text.Json;
|
||||
using Tiku.Domain.Common;
|
||||
|
||||
namespace Tiku.Domain.Catalog;
|
||||
|
||||
public sealed class Region : AuditableTenantEntity
|
||||
{
|
||||
public string? LegacyId { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string? Code { get; set; }
|
||||
public string? ShortName { get; set; }
|
||||
public string? FullName { get; set; }
|
||||
public string? Icon { get; set; }
|
||||
public string? Pinyin { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
public bool IsHot { get; set; }
|
||||
public bool IsActive { get; set; } = true;
|
||||
public JsonElement Config { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
|
||||
public sealed class RegionModule : AuditableTenantEntity
|
||||
{
|
||||
public Guid? RegionId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string? Type { get; set; }
|
||||
public string? Icon { get; set; }
|
||||
public string? Color { get; set; }
|
||||
public string? TextColor { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? Route { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
public bool IsPrimarySchoolModule { get; set; }
|
||||
public bool IsActive { get; set; } = true;
|
||||
}
|
||||
|
||||
public sealed class ModuleNode : AuditableTenantEntity
|
||||
{
|
||||
public Guid? RegionId { get; set; }
|
||||
public Guid? ModuleId { get; set; }
|
||||
public Guid? ParentId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public string? LegacyParentId { get; set; }
|
||||
public string? LegacyModuleId { get; set; }
|
||||
public ModuleNodeType Type { get; set; } = ModuleNodeType.Custom;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string? Path { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
public bool IsActive { get; set; } = true;
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
|
||||
public enum ModuleNodeType
|
||||
{
|
||||
Category,
|
||||
Subject,
|
||||
Chapter,
|
||||
Paper,
|
||||
School,
|
||||
Major,
|
||||
Custom
|
||||
}
|
||||
|
||||
public sealed class School : AuditableTenantEntity
|
||||
{
|
||||
public Guid? RegionId { get; set; }
|
||||
public Guid? ModuleId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string? ProfessionalExamDate { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
|
||||
public sealed class Major : AuditableTenantEntity
|
||||
{
|
||||
public Guid? RegionId { get; set; }
|
||||
public Guid? SchoolId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string? Description { get; set; }
|
||||
public string? StudyTips { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
public bool IsActive { get; set; } = true;
|
||||
}
|
||||
|
||||
public sealed class Subject : AuditableTenantEntity
|
||||
{
|
||||
public Guid? RegionId { get; set; }
|
||||
public Guid? ModuleId { get; set; }
|
||||
public Guid? SchoolId { get; set; }
|
||||
public Guid? MajorId { get; set; }
|
||||
public Guid? NodeId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public SubjectType? Type { get; set; }
|
||||
public JsonElement MajorLegacyIds { get; set; } = JsonDefaults.Array();
|
||||
public string? Icon { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public JsonElement Stats { get; set; } = JsonDefaults.Object();
|
||||
public int SortOrder { get; set; }
|
||||
public bool IsActive { get; set; } = true;
|
||||
}
|
||||
|
||||
public enum SubjectType
|
||||
{
|
||||
Cultural,
|
||||
Professional
|
||||
}
|
||||
|
||||
public sealed class Category : AuditableTenantEntity
|
||||
{
|
||||
public Guid? SubjectId { get; set; }
|
||||
public Guid? NodeId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public CategoryType? CategoryType { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
public int? SvipQuestionLimit { get; set; }
|
||||
public bool IsActive { get; set; } = true;
|
||||
}
|
||||
|
||||
public enum CategoryType
|
||||
{
|
||||
Chapter,
|
||||
Paper
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Tiku.Domain;
|
||||
|
||||
public class Class1
|
||||
{
|
||||
|
||||
}
|
||||
46
Tiku.Domain/Common/Entity.cs
Normal file
46
Tiku.Domain/Common/Entity.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Tiku.Domain.Common;
|
||||
|
||||
public abstract class Entity
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
}
|
||||
|
||||
public interface IHasTimestamps
|
||||
{
|
||||
DateTimeOffset CreatedAt { get; set; }
|
||||
DateTimeOffset UpdatedAt { get; set; }
|
||||
}
|
||||
|
||||
public abstract class AuditableEntity : Entity, IHasTimestamps
|
||||
{
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
public DateTimeOffset UpdatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public abstract class TenantEntity : Entity
|
||||
{
|
||||
public Guid TenantId { get; set; }
|
||||
}
|
||||
|
||||
public abstract class AuditableTenantEntity : TenantEntity, IHasTimestamps
|
||||
{
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
public DateTimeOffset UpdatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public static class JsonDefaults
|
||||
{
|
||||
public static JsonElement Object()
|
||||
{
|
||||
using var document = JsonDocument.Parse("{}");
|
||||
return document.RootElement.Clone();
|
||||
}
|
||||
|
||||
public static JsonElement Array()
|
||||
{
|
||||
using var document = JsonDocument.Parse("[]");
|
||||
return document.RootElement.Clone();
|
||||
}
|
||||
}
|
||||
20
Tiku.Domain/Identity/StudentProfile.cs
Normal file
20
Tiku.Domain/Identity/StudentProfile.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Text.Json;
|
||||
using Tiku.Domain.Common;
|
||||
|
||||
namespace Tiku.Domain.Identity;
|
||||
|
||||
public sealed class StudentProfile : AuditableTenantEntity
|
||||
{
|
||||
public Guid UserId { get; set; }
|
||||
public string? LegacyUserId { get; set; }
|
||||
public Guid? RegionId { get; set; }
|
||||
public Guid? SelectedSchoolId { get; set; }
|
||||
public Guid? SelectedMajorId { get; set; }
|
||||
public int QuestionsAnsweredToday { get; set; }
|
||||
public int MasteredWordsCount { get; set; }
|
||||
public DateOnly? LastCheckInDate { get; set; }
|
||||
public JsonElement Stats { get; set; } = JsonDefaults.Object();
|
||||
public JsonElement Progress { get; set; } = JsonDefaults.Object();
|
||||
public JsonElement ModuleSelections { get; set; } = JsonDefaults.Object();
|
||||
public JsonElement RecentActivities { get; set; } = JsonDefaults.Array();
|
||||
}
|
||||
20
Tiku.Domain/Identity/User.cs
Normal file
20
Tiku.Domain/Identity/User.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Text.Json;
|
||||
using Tiku.Domain.Common;
|
||||
|
||||
namespace Tiku.Domain.Identity;
|
||||
|
||||
public sealed class User : AuditableEntity
|
||||
{
|
||||
public string? LegacyId { get; set; }
|
||||
public string? Username { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public string? Phone { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? AvatarUrl { get; set; }
|
||||
public string PrimaryRole { get; set; } = "student";
|
||||
public int Score { get; set; }
|
||||
public DateTimeOffset? LastSeenAt { get; set; }
|
||||
public string? LegacyPasswordHash { get; set; }
|
||||
public bool PasswordMigrationRequired { get; set; }
|
||||
public JsonElement RawProfile { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
16
Tiku.Domain/Identity/UserIdentity.cs
Normal file
16
Tiku.Domain/Identity/UserIdentity.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.Text.Json;
|
||||
using Tiku.Domain.Common;
|
||||
|
||||
namespace Tiku.Domain.Identity;
|
||||
|
||||
public sealed class UserIdentity : AuditableEntity
|
||||
{
|
||||
public Guid UserId { get; set; }
|
||||
public string Provider { get; set; } = string.Empty;
|
||||
public string ProviderSubject { get; set; } = string.Empty;
|
||||
public string? UnionId { get; set; }
|
||||
public string? OpenId { get; set; }
|
||||
public string? Phone { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public JsonElement SecretPayload { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
64
Tiku.Domain/Learning/LearningEntities.cs
Normal file
64
Tiku.Domain/Learning/LearningEntities.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System.Text.Json;
|
||||
using Tiku.Domain.Common;
|
||||
|
||||
namespace Tiku.Domain.Learning;
|
||||
|
||||
public sealed class PracticeSession : TenantEntity
|
||||
{
|
||||
public Guid UserId { get; set; }
|
||||
public string Mode { get; set; } = "chapter";
|
||||
public string? TargetType { get; set; }
|
||||
public Guid? TargetId { get; set; }
|
||||
public DateTimeOffset StartedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
public DateTimeOffset? FinishedAt { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
|
||||
public sealed class AnswerRecord : TenantEntity
|
||||
{
|
||||
public Guid UserId { get; set; }
|
||||
public Guid? QuestionId { get; set; }
|
||||
public Guid? QuestionVersionId { get; set; }
|
||||
public Guid? PracticeSessionId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public string? LegacyQuestionId { get; set; }
|
||||
public string? LegacyCategoryId { get; set; }
|
||||
public JsonElement SelectedOptions { get; set; } = JsonDefaults.Array();
|
||||
public string? AnswerText { get; set; }
|
||||
public bool? IsCorrect { get; set; }
|
||||
public DateTimeOffset AnsweredAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public sealed class FavoriteQuestion
|
||||
{
|
||||
public Guid TenantId { get; set; }
|
||||
public Guid UserId { get; set; }
|
||||
public Guid QuestionId { get; set; }
|
||||
public string Source { get; set; } = "imported";
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public sealed class WrongQuestion
|
||||
{
|
||||
public Guid TenantId { get; set; }
|
||||
public Guid UserId { get; set; }
|
||||
public Guid QuestionId { get; set; }
|
||||
public int WrongCount { get; set; } = 1;
|
||||
public DateTimeOffset LastWrongAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
public DateTimeOffset? ResolvedAt { get; set; }
|
||||
}
|
||||
|
||||
public sealed class RecentPractice : AuditableTenantEntity
|
||||
{
|
||||
public Guid? UserId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public string? PracticeType { get; set; }
|
||||
public string? TargetLegacyId { get; set; }
|
||||
public string? TargetName { get; set; }
|
||||
public int Progress { get; set; }
|
||||
public string? Color { get; set; }
|
||||
public DateTimeOffset? LastAccessAt { get; set; }
|
||||
public DateTimeOffset? LastPracticeAt { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
71
Tiku.Domain/QuestionBanks/QuestionEntities.cs
Normal file
71
Tiku.Domain/QuestionBanks/QuestionEntities.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System.Text.Json;
|
||||
using Tiku.Domain.Common;
|
||||
|
||||
namespace Tiku.Domain.QuestionBanks;
|
||||
|
||||
public sealed class QuestionBank : AuditableTenantEntity
|
||||
{
|
||||
public Guid? RegionId { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public QuestionBankScope SourceScope { get; set; } = QuestionBankScope.Tenant;
|
||||
public QuestionBankStatus Status { get; set; } = QuestionBankStatus.Active;
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
|
||||
public enum QuestionBankScope
|
||||
{
|
||||
Platform,
|
||||
Tenant
|
||||
}
|
||||
|
||||
public enum QuestionBankStatus
|
||||
{
|
||||
Active,
|
||||
Archived
|
||||
}
|
||||
|
||||
public sealed class Question : AuditableTenantEntity
|
||||
{
|
||||
public Guid? QuestionBankId { get; set; }
|
||||
public Guid? SubjectId { get; set; }
|
||||
public Guid? CategoryId { get; set; }
|
||||
public Guid? NodeId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public string? LegacySubjectId { get; set; }
|
||||
public string? LegacyCategoryId { get; set; }
|
||||
public string? LegacyNodeId { get; set; }
|
||||
public string Type { get; set; } = "choice";
|
||||
public string? TypeLabel { get; set; }
|
||||
public int? Difficulty { get; set; }
|
||||
public JsonElement Tags { get; set; } = JsonDefaults.Array();
|
||||
public string? MediaUrl { get; set; }
|
||||
public bool HasVideoExplanation { get; set; }
|
||||
public QuestionStatus Status { get; set; } = QuestionStatus.Published;
|
||||
public Guid? CurrentVersionId { get; set; }
|
||||
}
|
||||
|
||||
public enum QuestionStatus
|
||||
{
|
||||
Draft,
|
||||
Published,
|
||||
Archived
|
||||
}
|
||||
|
||||
public sealed class QuestionVersion : Entity
|
||||
{
|
||||
public Guid TenantId { get; set; }
|
||||
public Guid QuestionId { get; set; }
|
||||
public int VersionNo { get; set; } = 1;
|
||||
public string? Content { get; set; }
|
||||
public JsonElement Options { get; set; } = JsonDefaults.Array();
|
||||
public int? CorrectOptionIndex { get; set; }
|
||||
public JsonElement CorrectOptionIndices { get; set; } = JsonDefaults.Array();
|
||||
public string? AnswerText { get; set; }
|
||||
public string? Explanation { get; set; }
|
||||
public JsonElement SubQuestions { get; set; } = JsonDefaults.Array();
|
||||
public string? CodeLang { get; set; }
|
||||
public string? CodeTemplate { get; set; }
|
||||
public string? SourceHash { get; set; }
|
||||
public Guid? CreatedBy { get; set; }
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
40
Tiku.Domain/Tenancy/Tenant.cs
Normal file
40
Tiku.Domain/Tenancy/Tenant.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.Text.Json;
|
||||
using Tiku.Domain.Common;
|
||||
|
||||
namespace Tiku.Domain.Tenancy;
|
||||
|
||||
public sealed class Tenant : AuditableEntity
|
||||
{
|
||||
public string Slug { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string? LegalName { get; set; }
|
||||
public TenantStatus Status { get; set; } = TenantStatus.Active;
|
||||
public TenantMode Mode { get; set; } = TenantMode.Saas;
|
||||
public BillingStatus BillingStatus { get; set; } = BillingStatus.Trial;
|
||||
public Guid? OwnerUserId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
|
||||
public enum TenantStatus
|
||||
{
|
||||
Draft,
|
||||
Active,
|
||||
Suspended,
|
||||
Archived
|
||||
}
|
||||
|
||||
public enum TenantMode
|
||||
{
|
||||
PlatformOwned,
|
||||
Saas,
|
||||
Dedicated
|
||||
}
|
||||
|
||||
public enum BillingStatus
|
||||
{
|
||||
Trial,
|
||||
Active,
|
||||
PastDue,
|
||||
Cancelled
|
||||
}
|
||||
32
Tiku.Domain/Tenancy/TenantMembership.cs
Normal file
32
Tiku.Domain/Tenancy/TenantMembership.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.Text.Json;
|
||||
using Tiku.Domain.Common;
|
||||
|
||||
namespace Tiku.Domain.Tenancy;
|
||||
|
||||
public sealed class TenantMembership : AuditableTenantEntity
|
||||
{
|
||||
public Guid UserId { get; set; }
|
||||
public TenantRole Role { get; set; } = TenantRole.Student;
|
||||
public MembershipStatus Status { get; set; } = MembershipStatus.Active;
|
||||
public JsonElement Permissions { get; set; } = JsonDefaults.Object();
|
||||
public string? LegacyRole { get; set; }
|
||||
}
|
||||
|
||||
public enum TenantRole
|
||||
{
|
||||
PlatformAdmin,
|
||||
TenantOwner,
|
||||
TenantAdmin,
|
||||
TenantOperator,
|
||||
Teacher,
|
||||
Sales,
|
||||
Agent,
|
||||
Student
|
||||
}
|
||||
|
||||
public enum MembershipStatus
|
||||
{
|
||||
Active,
|
||||
Invited,
|
||||
Disabled
|
||||
}
|
||||
Reference in New Issue
Block a user