using System.Text.Json; using Tiku.Domain.Common; namespace Tiku.Domain.Tenancy; public sealed class TenantExternalProvider : AuditableTenantEntity { public TenantExternalProviderCapability Capability { get; set; } = TenantExternalProviderCapability.Identity; public string Provider { get; set; } = string.Empty; public TenantExternalProviderStatus Status { get; set; } = TenantExternalProviderStatus.Disabled; public string? DisplayName { get; set; } public string? SecretRef { get; set; } public int Priority { get; set; } = 100; public JsonElement ConfigPublic { get; set; } = JsonDefaults.Object(); public JsonElement Metadata { get; set; } = JsonDefaults.Object(); } public sealed class TenantSecret : AuditableTenantEntity { public string Purpose { get; set; } = string.Empty; public string Provider { get; set; } = string.Empty; public string SecretKey { get; set; } = string.Empty; public string SecretRef { get; set; } = string.Empty; public TenantSecretStatus Status { get; set; } = TenantSecretStatus.Active; public string EncryptionKeyId { get; set; } = string.Empty; public byte[] EncryptedPayload { get; set; } = []; public byte[] EncryptionNonce { get; set; } = []; public byte[] EncryptionTag { get; set; } = []; public DateTimeOffset? RotatedAt { get; set; } public DateTimeOffset? ExpiresAt { get; set; } } public sealed class SmsVerificationCode : Entity, ITenantOwned { public Guid TenantId { get; set; } public string Phone { get; set; } = string.Empty; public SmsPurpose Purpose { get; set; } = SmsPurpose.Login; public string CodeHash { get; set; } = string.Empty; public string Provider { get; set; } = "mock"; public SmsVerificationStatus Status { get; set; } = SmsVerificationStatus.Pending; public int Attempts { get; set; } public DateTimeOffset ExpiresAt { get; set; } public DateTimeOffset? ConsumedAt { get; set; } public string? IpAddress { get; set; } public string? UserAgent { get; set; } public JsonElement Metadata { get; set; } = JsonDefaults.Object(); public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; } public sealed class AuthLoginEvent : Entity { public Guid? TenantId { get; set; } public Guid? UserId { get; set; } public string Provider { get; set; } = string.Empty; public string? Identifier { get; set; } public AuthLoginResult Result { get; set; } = AuthLoginResult.Failed; public string? FailureCode { get; set; } public string? IpAddress { get; set; } public string? UserAgent { get; set; } public JsonElement Metadata { get; set; } = JsonDefaults.Object(); public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; } public sealed class AuthSession : AuditableEntity { public AuthRealm Realm { get; set; } = AuthRealm.Tenant; public Guid? TenantId { get; set; } public Guid UserId { get; set; } public Guid TokenFamilyId { get; set; } public Guid? ParentSessionId { get; set; } public Guid? ReplacedBySessionId { get; set; } public string TokenHash { get; set; } = string.Empty; public string SecurityStamp { get; set; } = string.Empty; public bool MfaSatisfied { get; set; } public string Provider { get; set; } = string.Empty; public DateTimeOffset ExpiresAt { get; set; } public DateTimeOffset? RevokedAt { get; set; } public string? RevokedReason { get; set; } public string? IpAddress { get; set; } public string? UserAgent { get; set; } public JsonElement Metadata { get; set; } = JsonDefaults.Object(); } public enum AuthRealm { Tenant, Platform } public sealed class AuthChallenge : Entity { public Guid UserId { get; set; } public AuthRealm Realm { get; set; } public Guid? TenantId { get; set; } public AuthChallengePurpose Purpose { get; set; } public string TokenHash { get; set; } = string.Empty; public string SecurityStamp { get; set; } = string.Empty; public string Provider { get; set; } = string.Empty; public DateTimeOffset ExpiresAt { get; set; } public DateTimeOffset? ConsumedAt { get; set; } public string? IpAddress { get; set; } public string? UserAgent { get; set; } public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; } public enum AuthChallengePurpose { MfaEnrollment, MfaVerification, PasswordChange } public sealed class SmsSendRateLimit : ITenantOwned { public Guid TenantId { get; set; } public SmsRateLimitDimension Dimension { get; set; } = SmsRateLimitDimension.Phone; public string ScopeHash { get; set; } = string.Empty; public DateTimeOffset BucketStart { get; set; } public int RequestCount { get; set; } public DateTimeOffset UpdatedAt { get; set; } = DateTimeOffset.UtcNow; } public sealed class TenantClass : AuditableTenantEntity { public Guid? RegionId { get; set; } public string? LegacyId { get; set; } public string? Code { get; set; } public string Name { get; set; } = string.Empty; public string? Description { get; set; } public TenantRecordStatus Status { get; set; } = TenantRecordStatus.Active; public int SortOrder { get; set; } public JsonElement Metadata { get; set; } = JsonDefaults.Object(); public Guid? CreatedBy { get; set; } public Guid? UpdatedBy { get; set; } } public sealed class TenantClassMember : AuditableTenantEntity { public Guid ClassId { get; set; } public Guid UserId { get; set; } public TenantClassMemberType MemberType { get; set; } = TenantClassMemberType.Student; public TenantClassMemberStatus Status { get; set; } = TenantClassMemberStatus.Active; public DateTimeOffset JoinedAt { get; set; } = DateTimeOffset.UtcNow; public DateTimeOffset? LeftAt { get; set; } public JsonElement Metadata { get; set; } = JsonDefaults.Object(); public Guid? CreatedBy { get; set; } public Guid? UpdatedBy { get; set; } } public sealed class TenantStudentNote : AuditableTenantEntity { public Guid StudentUserId { get; set; } public StudentNoteType NoteType { get; set; } = StudentNoteType.General; public string Content { get; set; } = string.Empty; public StudentNoteVisibility Visibility { get; set; } = StudentNoteVisibility.TenantStaff; public bool IsPinned { get; set; } public JsonElement Metadata { get; set; } = JsonDefaults.Object(); public Guid? CreatedBy { get; set; } public Guid? UpdatedBy { get; set; } } public sealed class TenantStudentFollowup : AuditableTenantEntity { public Guid StudentUserId { get; set; } public Guid? AssignedToUserId { get; set; } public Guid? ClassId { get; set; } public string Title { get; set; } = string.Empty; public string? Description { get; set; } public StudentFollowupType FollowupType { get; set; } = StudentFollowupType.Learning; public StudentFollowupPriority Priority { get; set; } = StudentFollowupPriority.Normal; public StudentFollowupStatus Status { get; set; } = StudentFollowupStatus.Open; public DateTimeOffset? DueAt { get; set; } public DateTimeOffset? CompletedAt { get; set; } public Guid? CompletedBy { get; set; } public JsonElement Metadata { get; set; } = JsonDefaults.Object(); public Guid? CreatedBy { get; set; } public Guid? UpdatedBy { get; set; } } public enum TenantExternalProviderCapability { Identity, ObjectStorage, Sms, Payment, Notification } public enum TenantExternalProviderStatus { Active, Disabled, Testing } public enum TenantSecretStatus { Active, Disabled, Rotating } public enum SmsPurpose { Login, BindPhone, ResetPassword } public enum SmsVerificationStatus { Pending, Sent, Verified, Expired, Blocked, Failed } public enum AuthLoginResult { Sent, Success, Failed, Blocked } public enum SmsRateLimitDimension { Tenant, Phone, Ip, Device } public enum TenantRecordStatus { Active, Disabled, Archived } public enum TenantClassMemberType { Student, Teacher, Assistant, HeadTeacher } public enum TenantClassMemberStatus { Active, Disabled, Removed } public enum StudentNoteType { General, Learning, Service, Sales, Risk, FollowUp } public enum StudentNoteVisibility { TenantStaff, ClassStaff, AuthorOnly } public enum StudentFollowupType { Learning, Service, Sales, Renewal, Risk, Custom } public enum StudentFollowupPriority { Low, Normal, High, Urgent } public enum StudentFollowupStatus { Open, InProgress, Done, Cancelled }