namespace KArtSell.Modules.IdentityAccess.ManageIdentityAndRoles.Domain; /// /// Identity lifecycle state machine (AEG-VS-01-03) /// Immutable value object for state transitions /// public sealed record IdentityState { public const string Undefined = "UNDEFINED"; public const string Active = "ACTIVE"; public const string RequiresMfaSetup = "REQUIRES_MFA_SETUP"; public const string MfaConfigured = "MFA_CONFIGURED"; public const string MfaSuspended = "MFA_SUSPENDED"; public const string Inactive = "INACTIVE"; public const string Revoked = "REVOKED"; private static readonly HashSet ValidStates = [ Undefined, Active, RequiresMfaSetup, MfaConfigured, MfaSuspended, Inactive, Revoked ]; public string Value { get; } private IdentityState(string value) { if (!ValidStates.Contains(value)) throw new ArgumentException($"Invalid identity state: {value}", nameof(value)); Value = value; } // Factory methods public static IdentityState CreateUndefined() => new(Undefined); public static IdentityState CreateActive() => new(Active); public static IdentityState CreateInactive() => new(Inactive); public static IdentityState CreateRevoked() => new(Revoked); public static IdentityState Parse(string value) => new(value); // State transitions (immutable - return new state) public IdentityState Register() { return Value switch { Undefined => new(Active), _ => throw new InvalidOperationException($"Cannot register from {Value}") }; } public IdentityState RequestMfaSetup() { return Value switch { Active => new(RequiresMfaSetup), _ => throw new InvalidOperationException($"Cannot request MFA setup from {Value}") }; } public IdentityState CompleteMfaSetup() { return Value switch { RequiresMfaSetup => new(MfaConfigured), _ => throw new InvalidOperationException($"Cannot complete MFA setup from {Value}") }; } public IdentityState SuspendMfaTemporarily() { return Value switch { MfaConfigured => new(MfaSuspended), _ => throw new InvalidOperationException($"Cannot suspend MFA from {Value}") }; } public IdentityState ResumeMfa() { return Value switch { MfaSuspended => new(MfaConfigured), _ => throw new InvalidOperationException($"Cannot resume MFA from {Value}") }; } public IdentityState Deactivate() { return Value switch { Active or RequiresMfaSetup or MfaConfigured or MfaSuspended => new(Inactive), _ => throw new InvalidOperationException($"Cannot deactivate from {Value}") }; } public IdentityState Revoke() { return Value switch { Inactive => new(Revoked), _ => throw new InvalidOperationException($"Cannot revoke from {Value}") }; } // State queries public bool IsActive() => Value == Active; public bool IsMfaRequired() => Value is RequiresMfaSetup or MfaConfigured or MfaSuspended; public bool IsMfaConfigured() => Value == MfaConfigured; public bool IsInactive() => Value == Inactive; public bool IsRevoked() => Value == Revoked; public bool CanRegister() => Value == Undefined; public bool CanReceiveRoles() => Value is Active or RequiresMfaSetup or MfaConfigured; public override string ToString() => Value; }