namespace KArtSell.Modules.IdentityAccess.ManageIdentityAndRoles.Domain; /// /// Role Assignment workflow state (Maker-Checker pattern) /// AEG-VS-01-03: Immutable value object for approval workflow /// public sealed record RoleAssignmentState { public const string PendingApproval = "PENDING_APPROVAL"; public const string ApprovedBy1 = "APPROVED_BY_1"; public const string ApprovedBy2 = "APPROVED_BY_2"; public const string Active = "ACTIVE"; public const string Expired = "EXPIRED"; public const string Revoked = "REVOKED"; public const string Rejected = "REJECTED"; private static readonly HashSet ValidStates = [ PendingApproval, ApprovedBy1, ApprovedBy2, Active, Expired, Revoked, Rejected ]; public string Value { get; } private RoleAssignmentState(string value) { if (!ValidStates.Contains(value)) throw new ArgumentException($"Invalid role assignment state: {value}", nameof(value)); Value = value; } // Factory methods public static RoleAssignmentState CreatePending() => new(PendingApproval); public static RoleAssignmentState Activate() => new(Active); public static RoleAssignmentState Expire() => new(Expired); public static RoleAssignmentState Revoke() => new(Revoked); public static RoleAssignmentState Reject() => new(Rejected); public static RoleAssignmentState Parse(string value) => new(value); // State transitions public RoleAssignmentState ApproveByFirst() { return Value switch { PendingApproval => new(ApprovedBy1), _ => throw new InvalidOperationException($"Cannot approve from {Value}") }; } public RoleAssignmentState ApproveBySecond() { return Value switch { ApprovedBy1 => new(ApprovedBy2), _ => throw new InvalidOperationException($"Cannot approve second from {Value}") }; } public RoleAssignmentState ActivateAfterApproval() { return Value switch { ApprovedBy2 => new(Active), _ => throw new InvalidOperationException($"Cannot activate from {Value}") }; } public RoleAssignmentState ExpireTimebound() { return Value switch { Active => new(Expired), _ => throw new InvalidOperationException($"Cannot expire from {Value}") }; } public RoleAssignmentState RevokeActive() { return Value switch { Active or Expired => new(Revoked), _ => throw new InvalidOperationException($"Cannot revoke from {Value}") }; } public RoleAssignmentState RejectRequest() { return Value switch { PendingApproval or ApprovedBy1 => new(Rejected), _ => throw new InvalidOperationException($"Cannot reject from {Value}") }; } // State queries public bool IsPending() => Value == PendingApproval; public bool IsAwaitingSecondApproval() => Value == ApprovedBy1; public bool IsApproved() => Value == ApprovedBy2; public bool IsActive() => Value == Active; public bool IsExpired() => Value == Expired; public bool IsRevoked() => Value == Revoked; public bool IsRejected() => Value == Rejected; public bool CanApprove() => Value is PendingApproval or ApprovedBy1; public bool RequiresSecondApproval() => Value == ApprovedBy1; public override string ToString() => Value; }