Files
KArtSell.Aegis/src/Modules/IdentityAccess/ManageIdentityAndRoles/Domain/IdentityState.cs
T
kjh2064 dc8f3466c9 WIP: AEG-VS-01-04 Part 2 - DI setup + Endpoint refactoring (token budget constraint)
- Added IdentityAccessModule.cs with DI registration
- Added KArtSell.Modules.IdentityAccess.csproj with FastEndpoints deps
- Added project files for UnitTests & IntegrationTests
- Updated Program.cs to register IdentityAccessModule
- Updated Host.csproj to reference IdentityAccess module
- Fixed Directory.Packages.props with Moq + MS.Extensions.DependencyInjection

ISSUES (to fix next session):
- FastEndpoints Send/SendAsync/SendOkAsync method resolution incomplete
- Response record initialization requires field values
- Need to refactor endpoints to match ModelOperations pattern exactly

WORKING:
- Domain layer (IdentityState, RoleAssignmentState) 
- SQL repositories (Dapper) 
- Unit tests (RegisterIdentity, RequestMfaSetup handlers) 
- Integration test structure ready 

Next: Simplify endpoints using 'Endpoint<Req,Resp>' pattern from GetApprovalQueue sample

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-08-17 17:50:25 +09:00

113 lines
3.6 KiB
C#

namespace KArtSell.Modules.IdentityAccess.ManageIdentityAndRoles.Domain;
/// <summary>
/// Identity lifecycle state machine (AEG-VS-01-03)
/// Immutable value object for state transitions
/// </summary>
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<string> 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;
}