From 57671242ee0388aebdc61c1e02b71face29df4d5 Mon Sep 17 00:00:00 2001 From: mforce Date: Mon, 5 Oct 2026 23:40:31 +0000 Subject: [PATCH 1/4] refactor(arch): split the Platform records out of the two Access-claimed ports move.py split: IIdentityProvider.cs keeps only IIdentityProvider, and IStepUpGrantService.cs only IStepUpGrantService. FarmSignIn, RefreshTokenRevocationOutcome, TokenPair, UserSummary, UserProfile, StepUpGrant and StepUpErrorCodes each go to their own file in Application/Common, the same namespace, as verbatim slices. Access's Types claim covers only the two interfaces, so these seven are Platform today; moving them with the interfaces would make them Access-owned, adding an Access -> Commerce edge symbol (UserProfile names EggUnit) and an adapter reach through a non-contract type (AuthEndpoints through TokenPair). Refs #1087 --- .../Common/FarmSignIn.cs | 5 ++++ .../Common/IIdentityProvider.cs | 26 ------------------- .../Common/IStepUpGrantService.cs | 10 ------- .../Common/RefreshTokenRevocationOutcome.cs | 9 +++++++ .../Common/StepUpErrorCodes.cs | 12 +++++++++ .../Common/StepUpGrant.cs | 5 ++++ src/Cluckwork.Application/Common/TokenPair.cs | 13 ++++++++++ .../Common/UserProfile.cs | 7 +++++ .../Common/UserSummary.cs | 8 ++++++ 9 files changed, 59 insertions(+), 36 deletions(-) create mode 100644 src/Cluckwork.Application/Common/FarmSignIn.cs create mode 100644 src/Cluckwork.Application/Common/RefreshTokenRevocationOutcome.cs create mode 100644 src/Cluckwork.Application/Common/StepUpErrorCodes.cs create mode 100644 src/Cluckwork.Application/Common/StepUpGrant.cs create mode 100644 src/Cluckwork.Application/Common/TokenPair.cs create mode 100644 src/Cluckwork.Application/Common/UserProfile.cs create mode 100644 src/Cluckwork.Application/Common/UserSummary.cs diff --git a/src/Cluckwork.Application/Common/FarmSignIn.cs b/src/Cluckwork.Application/Common/FarmSignIn.cs new file mode 100644 index 000000000..dec8e4c59 --- /dev/null +++ b/src/Cluckwork.Application/Common/FarmSignIn.cs @@ -0,0 +1,5 @@ +using Cluckwork.Domain.Modules.Commerce.Contracts; + +namespace Cluckwork.Application.Common; + +public sealed record FarmSignIn(Guid AccountId, bool IsActive); diff --git a/src/Cluckwork.Application/Common/IIdentityProvider.cs b/src/Cluckwork.Application/Common/IIdentityProvider.cs index 0edb2e8bf..02b90408b 100644 --- a/src/Cluckwork.Application/Common/IIdentityProvider.cs +++ b/src/Cluckwork.Application/Common/IIdentityProvider.cs @@ -2,14 +2,6 @@ namespace Cluckwork.Application.Common; -public sealed record FarmSignIn(Guid AccountId, bool IsActive); - -public enum RefreshTokenRevocationOutcome -{ - OutOfScope, - InScope, -} - // Port — abstraction over ASP.NET Core Identity + JWT. Swap to Keycloak/Entra // in a future IIdentityProvider implementation without touching Application. public interface IIdentityProvider @@ -194,21 +186,3 @@ Task SetStepperUnitAsync( Guid accountId, Guid userId, EggUnit? unit, CancellationToken ct = default); } -public sealed record TokenPair( - string AccessToken, - string RefreshToken, - DateTimeOffset AccessTokenExpiry, - // #532 — the farm the token pair belongs to. Login/ChangeOwnPassword know it - // at mint time; Refresh recovers it from the stored token row. The - // per-farm refresh cookie (#532 per-farm rename) needs it to know WHICH - // cookie name to write, because the token value itself is opaque. - Guid AccountId); - -// #356 — DisabledAt is null for an active user. Exposed on the LIST rather -// than filtered out of it: an Owner cannot re-enable someone they cannot see. -public sealed record UserSummary( - Guid Id, string Email, string? DisplayName, string Role, DateTimeOffset? DisabledAt); - -public sealed record UserProfile( - Guid Id, string Email, string? DisplayName, string Role, string? Language, - EggUnit? PreferredStepperUnit); diff --git a/src/Cluckwork.Application/Common/IStepUpGrantService.cs b/src/Cluckwork.Application/Common/IStepUpGrantService.cs index 65358fb5b..e9de17bad 100644 --- a/src/Cluckwork.Application/Common/IStepUpGrantService.cs +++ b/src/Cluckwork.Application/Common/IStepUpGrantService.cs @@ -30,13 +30,3 @@ Task ValidateAsync( Guid accountId, Guid userId, string? stepUpToken, CancellationToken ct = default); } -public sealed record StepUpGrant(string Token, DateTimeOffset ExpiresAt); - -public static class StepUpErrorCodes -{ - // #308 — every step-up rejection reason (missing, malformed, expired, - // replayed, wrong-account/user, stamp-revoked, logout-revoked) maps to - // this one code so a gated endpoint's caller cannot enumerate WHY a grant - // failed. - public const string Required = "Identity.StepUpRequired"; -} diff --git a/src/Cluckwork.Application/Common/RefreshTokenRevocationOutcome.cs b/src/Cluckwork.Application/Common/RefreshTokenRevocationOutcome.cs new file mode 100644 index 000000000..c847d28d2 --- /dev/null +++ b/src/Cluckwork.Application/Common/RefreshTokenRevocationOutcome.cs @@ -0,0 +1,9 @@ +using Cluckwork.Domain.Modules.Commerce.Contracts; + +namespace Cluckwork.Application.Common; + +public enum RefreshTokenRevocationOutcome +{ + OutOfScope, + InScope, +} diff --git a/src/Cluckwork.Application/Common/StepUpErrorCodes.cs b/src/Cluckwork.Application/Common/StepUpErrorCodes.cs new file mode 100644 index 000000000..011b434e6 --- /dev/null +++ b/src/Cluckwork.Application/Common/StepUpErrorCodes.cs @@ -0,0 +1,12 @@ +using Cluckwork.Domain.Common; + +namespace Cluckwork.Application.Common; + +public static class StepUpErrorCodes +{ + // #308 — every step-up rejection reason (missing, malformed, expired, + // replayed, wrong-account/user, stamp-revoked, logout-revoked) maps to + // this one code so a gated endpoint's caller cannot enumerate WHY a grant + // failed. + public const string Required = "Identity.StepUpRequired"; +} diff --git a/src/Cluckwork.Application/Common/StepUpGrant.cs b/src/Cluckwork.Application/Common/StepUpGrant.cs new file mode 100644 index 000000000..0f1a26a71 --- /dev/null +++ b/src/Cluckwork.Application/Common/StepUpGrant.cs @@ -0,0 +1,5 @@ +using Cluckwork.Domain.Common; + +namespace Cluckwork.Application.Common; + +public sealed record StepUpGrant(string Token, DateTimeOffset ExpiresAt); diff --git a/src/Cluckwork.Application/Common/TokenPair.cs b/src/Cluckwork.Application/Common/TokenPair.cs new file mode 100644 index 000000000..700c94369 --- /dev/null +++ b/src/Cluckwork.Application/Common/TokenPair.cs @@ -0,0 +1,13 @@ +using Cluckwork.Domain.Modules.Commerce.Contracts; + +namespace Cluckwork.Application.Common; + +public sealed record TokenPair( + string AccessToken, + string RefreshToken, + DateTimeOffset AccessTokenExpiry, + // #532 — the farm the token pair belongs to. Login/ChangeOwnPassword know it + // at mint time; Refresh recovers it from the stored token row. The + // per-farm refresh cookie (#532 per-farm rename) needs it to know WHICH + // cookie name to write, because the token value itself is opaque. + Guid AccountId); diff --git a/src/Cluckwork.Application/Common/UserProfile.cs b/src/Cluckwork.Application/Common/UserProfile.cs new file mode 100644 index 000000000..287f6167c --- /dev/null +++ b/src/Cluckwork.Application/Common/UserProfile.cs @@ -0,0 +1,7 @@ +using Cluckwork.Domain.Modules.Commerce.Contracts; + +namespace Cluckwork.Application.Common; + +public sealed record UserProfile( + Guid Id, string Email, string? DisplayName, string Role, string? Language, + EggUnit? PreferredStepperUnit); diff --git a/src/Cluckwork.Application/Common/UserSummary.cs b/src/Cluckwork.Application/Common/UserSummary.cs new file mode 100644 index 000000000..8e384f090 --- /dev/null +++ b/src/Cluckwork.Application/Common/UserSummary.cs @@ -0,0 +1,8 @@ +using Cluckwork.Domain.Modules.Commerce.Contracts; + +namespace Cluckwork.Application.Common; + +// #356 — DisabledAt is null for an active user. Exposed on the LIST rather +// than filtered out of it: an Owner cannot re-enable someone they cannot see. +public sealed record UserSummary( + Guid Id, string Email, string? DisplayName, string Role, DateTimeOffset? DisabledAt); From 684886fa88afef860cc37c58a394b342c38db6d8 Mon Sep 17 00:00:00 2001 From: mforce Date: Mon, 5 Oct 2026 23:41:13 +0000 Subject: [PATCH 2/4] refactor(arch): move Access into Modules/Access move.py move with the slice's table: the Users feature (Application), the Identity code (Infrastructure) and the Auth, Me and Users endpoints (Api) go under Modules/Access, contract types under Contracts, with the namespace taken from the folder. IIdentityProvider and IStepUpGrantService leave Application/Common for Application/Modules/Access/Users, so the rules file drops its Types claim: their namespace now gives them to Access. The rules file names Cluckwork.Application.Modules.Access and Cluckwork.Infrastructure.Modules.Access; Implementations stay for S9. Tenant-bypass symbols and files, edge symbols and the guards' path lists follow by name. move.py prune drops the usings the move left unused. Refs #1087 --- .../plans/2026-08-02-credential-epoch.md | 10 +-- .../plans/2026-08-25-change-user-email.md | 22 +++---- specs/001-searchable-entity-picker/tasks.md | 2 +- .../Cli/BootstrapAdminCliCommand.cs | 2 +- .../Cli/ProvisionAccountCliCommand.cs | 2 +- .../Cli/ReactivateAccountCliCommand.cs | 2 +- .../Cli/RecoverAdminCliCommand.cs | 2 +- .../Cli/RenameAccountCliCommand.cs | 2 +- .../Cli/SuspendAccountCliCommand.cs | 2 +- ...workIdentityServiceCollectionExtensions.cs | 53 +++++++-------- ...kPersistenceServiceCollectionExtensions.cs | 4 +- ...workPlatformServiceCollectionExtensions.cs | 8 +-- .../Middleware/CredentialEpochMiddleware.cs | 2 +- .../FlockScopeResolutionMiddleware.cs | 3 +- .../Middleware/IdempotencyMiddleware.cs | 1 - .../Middleware/TenantResolutionMiddleware.cs | 1 - .../Access}/Auth/AuthCookies.cs | 2 +- .../Access}/Auth/AuthEndpoints.cs | 5 +- .../Access}/Auth/LoginRequestValidator.cs | 4 +- .../Access}/Auth/StepUpRequestValidator.cs | 4 +- .../Access}/Me/MeEndpoints.cs | 6 +- .../Access}/Users/UserEndpoints.cs | 28 +++----- src/Cluckwork.Api/Program.cs | 6 +- .../Common/FarmSignIn.cs | 2 - .../Common/RefreshTokenRevocationOutcome.cs | 2 - .../Common/StepUpErrorCodes.cs | 2 - .../Common/StepUpGrant.cs | 2 - src/Cluckwork.Application/Common/TokenPair.cs | 2 - .../Common/UserSummary.cs | 2 - .../Contracts}/AccessOperationOutcomes.cs | 2 +- .../Access/Contracts}/AssignFlockCommand.cs | 2 +- .../Contracts}/ChangeOwnPasswordCommand.cs | 2 +- .../Contracts}/ChangeUserEmailCommand.cs | 2 +- .../Contracts}/ChangeUserRoleCommand.cs | 2 +- .../Access/Contracts}/CreateUserCommand.cs | 2 +- .../Access/Contracts}/DisableUserCommand.cs | 2 +- .../Access/Contracts}/EnableUserCommand.cs | 2 +- .../Contracts}/IAccessAccountLifecycle.cs | 2 +- .../Access/Contracts}/IAccessFixture.cs | 2 +- .../Access/Contracts}/IAccessLookup.cs | 2 +- .../Access/Contracts}/IAccessModule.cs | 13 +--- .../Access/Contracts}/IAccessOperations.cs | 2 +- .../Access/Contracts}/IAccessSeedLookup.cs | 2 +- .../Contracts}/ICredentialEpochVerifier.cs | 2 +- .../Access/Contracts}/IRefreshTokenPurge.cs | 2 +- .../Access/Contracts}/SetLanguageCommand.cs | 2 +- .../Contracts}/SetStepperUnitCommand.cs | 2 +- .../Contracts}/SetUserPasswordCommand.cs | 2 +- .../Access/Contracts}/UnassignFlockCommand.cs | 2 +- .../Access/Contracts}/UpdateUserCommand.cs | 2 +- .../Users/AssignFlock/AssignFlockHandler.cs | 3 +- .../ChangeOwnPasswordHandler.cs | 3 +- .../ChangeOwnPasswordValidator.cs | 9 +-- .../ChangeUserEmail/ChangeUserEmailHandler.cs | 4 +- .../ChangeUserEmailValidator.cs | 3 +- .../ChangeUserRole/ChangeUserRoleHandler.cs | 6 +- .../ChangeUserRole/ChangeUserRoleValidator.cs | 5 +- .../Users/CreateUser/CreateUserHandler.cs | 5 +- .../Users/CreateUser/CreateUserValidator.cs | 7 +- .../Users/DisableUser/DisableUserHandler.cs | 4 +- .../Users/DisableUser/DisableUserValidator.cs | 3 +- .../Users/EnableUser/EnableUserHandler.cs | 4 +- .../Access/Users}/IIdentityProvider.cs | 3 +- .../Access/Users}/IStepUpGrantService.cs | 5 +- .../Users/IUserRoleAssignmentRepository.cs | 2 +- .../Access}/Users/PasswordRules.cs | 2 +- .../Users/SetLanguage/SetLanguageHandler.cs | 4 +- .../Users/SetLanguage/SetLanguageValidator.cs | 3 +- .../SetStepperUnit/SetStepperUnitHandler.cs | 4 +- .../SetStepperUnit/SetStepperUnitValidator.cs | 3 +- .../SetUserPassword/SetUserPasswordHandler.cs | 4 +- .../SetUserPasswordValidator.cs | 7 +- .../Users/UpdateUser/UpdateUserHandler.cs | 5 +- .../Users/UpdateUser/UpdateUserValidator.cs | 5 +- .../Access}/Users/UserName.cs | 2 +- .../Sales/ConfirmSale/ConfirmSaleHandler.cs | 2 +- .../Common/Architecture/Modules/Access.cs | 64 +++++++++---------- .../Jobs/RefreshTokenPurgeSweep.cs | 2 +- .../Identity/AccessAccountLifecycle.cs | 4 +- .../Access}/Identity/AccessFixture.cs | 4 +- .../Access}/Identity/AccessLookup.cs | 4 +- .../Access}/Identity/AccessModule.cs | 27 ++++---- .../Access}/Identity/AccessOperations.cs | 6 +- .../Access}/Identity/AccessSeedLookup.cs | 4 +- .../Access}/Identity/AccountLockout.cs | 2 +- .../Access}/Identity/AccountProvisioner.cs | 5 +- .../Access}/Identity/AccountRenameService.cs | 4 +- .../Identity/AccountScopedUserValidator.cs | 2 +- .../Identity/AccountSuspensionService.cs | 4 +- .../Access}/Identity/AccountUserDirectory.cs | 2 +- .../Access}/Identity/AdminRecoveryService.cs | 5 +- .../Access}/Identity/ApplicationRole.cs | 2 +- .../Access}/Identity/ApplicationUser.cs | 2 +- .../Identity/AuthSecurityEventLogger.cs | 2 +- .../Identity/CredentialEpochVerifier.cs | 4 +- .../Access}/Identity/FirstRunAdminService.cs | 5 +- .../Access}/Identity/FirstRunStatusService.cs | 2 +- .../Access}/Identity/IStepUpGrantRegistry.cs | 2 +- .../Access}/Identity/IdentityProvider.cs | 3 +- .../Access}/Identity/JwtOptions.cs | 2 +- .../Access}/Identity/JwtTokenService.cs | 2 +- .../{ => Modules/Access}/Identity/PemKey.cs | 2 +- .../Identity/PersistentStepUpGrantRegistry.cs | 2 +- .../Access}/Identity/RefreshToken.cs | 2 +- .../Access}/Identity/RefreshTokenPurge.cs | 4 +- .../Access}/Identity/StepUpGrantService.cs | 3 +- .../Access}/Identity/TemporaryPassword.cs | 2 +- .../Access}/Identity/TimingEqualization.cs | 2 +- .../Persistence/AppDbContext.cs | 2 +- .../ApplicationUserConfiguration.cs | 2 +- .../Persistence/DemoDataSeeder.cs | 3 +- .../Migrations/AppDbContextModelSnapshot.cs | 22 +++---- .../Persistence/PlatformBusinessRecords.cs | 2 +- .../Persistence/SimulationDataSeeder.cs | 7 +- .../UserRoleAssignmentRepository.cs | 3 +- .../AccessAuthorizationContractTests.cs | 7 +- .../AccessFixtureTests.cs | 2 +- .../AccessLifecycleDependencyTests.cs | 6 +- .../AccessLookupTests.cs | 2 +- .../AccessSeedAssignmentAtomicityTests.cs | 2 +- .../AccessSeedDependencyTests.cs | 4 +- .../AccessSeedFailureTests.cs | 4 +- .../AccessSeedLookupTests.cs | 4 +- .../AccessSeederActorTests.cs | 2 +- .../AccountIdConcurrencyTokenModelTests.cs | 2 +- .../AccountLifecycleCommandTests.cs | 2 +- .../AccountLockoutTests.cs | 2 +- .../AccountProvisioningTests.cs | 4 +- .../AccountRenameServiceTests.cs | 2 +- ...untScopedUserValidatorRegistrationTests.cs | 2 +- .../AccountScopedUserValidatorTests.cs | 2 +- .../AccountSuspensionTests.cs | 6 +- .../AdminGatingTests.cs | 4 +- .../AdminRecoveryServiceTests.cs | 3 +- .../ApplicationUserIndexModelTests.cs | 2 +- .../AuditActorTests.cs | 1 - .../AuthBodyLimitTests.cs | 2 +- .../AuthCookieContractTests.cs | 2 +- .../AuthRateLimitLoggingTests.cs | 2 +- .../AuthSessionContractTests.cs | 3 +- .../BootstrapAdminCommandTests.cs | 2 +- .../BootstrapAdvisoryLockContinuityTests.cs | 2 +- .../BusinessRecordModelTests.cs | 2 +- .../ChangeUserEmailRaceTests.cs | 9 +-- .../ChangeUserEmailTests.cs | 9 +-- .../ChangeUserRoleRaceTests.cs | 7 +- .../ChangeUserRoleTests.cs | 6 +- .../CredentialEpochFloorTests.cs | 6 +- .../CredentialEpochFreshReadTests.cs | 2 +- .../CredentialEpochMiddlewareVerdictTests.cs | 2 +- .../CredentialEpochRaceTests.cs | 4 +- .../CredentialEpochTests.cs | 6 +- .../DailyEntryAdjustTests.cs | 2 +- .../DemoSeedActorTests.cs | 2 +- .../DemoSeedCleanupTests.cs | 4 +- .../DemoSeedTests.cs | 2 +- .../DisableUserRaceTests.cs | 11 ++-- .../DisableUserTests.cs | 6 +- .../ExceptionHandlerReExecutionTests.cs | 2 +- .../FarmSettingsTests.cs | 2 +- .../FirstRunAdminUnlockCleanupTests.cs | 2 +- .../FirstRunLoginNoticeTests.cs | 4 +- .../FixturePortRegistrationTests.cs | 2 +- .../FlockScopeMiddlewareTests.cs | 4 +- .../FlockScopeTests.cs | 2 +- .../GlobalUserLookupGuardTests.cs | 4 +- .../Infrastructure/TestHarness.cs | 4 +- .../LoginRequestValidatorTests.cs | 4 +- .../MustChangePasswordGateTests.cs | 11 ++-- .../NamedEntityDiscoveryTests.cs | 4 +- .../NamedRowProjectionTests.cs | 2 +- .../OneShotVerbMinimalConfigTests.cs | 2 +- .../RateLimitingTests.cs | 2 +- .../RecoverAdminCommandTests.cs | 2 +- .../RefreshAccountBindingTests.cs | 2 +- .../RefreshTokenFlowTests.cs | 1 - .../RefreshTokenPurgeBatchTests.cs | 2 +- .../RefreshTokenPurgeSweepTests.cs | 2 +- .../RequestLoggingTests.cs | 2 +- .../RetryBoundaryTests.cs | 4 +- .../RoleMatrixTests.cs | 2 +- .../SaleAllocationPolicyTests.cs | 2 +- .../SecurityEventLoggingTests.cs | 2 +- .../SimulationCrossDayRerunTests.cs | 2 +- .../SimulationDeepSeedDrainTests.cs | 1 - .../SimulationSeederTests.cs | 2 +- .../StepUpAuthTests.cs | 5 +- .../StepUpGrantRegistrySharedStoreTests.cs | 2 +- .../StepUpGrantRegistryTests.cs | 2 +- .../TemporaryPasswordTests.cs | 2 +- .../TenantResolutionMiddlewareTests.cs | 2 +- .../TwoFarmIsolationMatrixTests.cs | 6 +- .../UserNameTests.cs | 2 +- .../UserPasswordTests.cs | 2 +- .../UserRoleAccountIdModelTests.cs | 2 +- .../Architecture/AccessOwnershipClaimTests.cs | 4 +- .../Architecture/RealModuleLedger.Adapters.cs | 38 +++++------ .../Common/AuditVocabularyCoverageTests.cs | 2 +- .../FlockScoping/FlockScopeGuardTests.cs | 2 +- .../TenantBypass/BypassAllowList.cs | 36 +++++------ .../TenantBypass/FilterFreeSetSites.cs | 64 +++++++++---------- .../TenantBypass/FindBySlugCallerTests.cs | 2 +- .../TenantBypassDiscoveryTests.cs | 2 +- .../TenantBypass/TenantBypassRealTreeTests.cs | 3 +- .../TenantBypass/TenantBypassWalkTests.cs | 2 +- .../PasswordMaxLengthValidatorTests.cs | 9 +-- 206 files changed, 486 insertions(+), 506 deletions(-) rename src/Cluckwork.Api/{Endpoints => Modules/Access}/Auth/AuthCookies.cs (99%) rename src/Cluckwork.Api/{Endpoints => Modules/Access}/Auth/AuthEndpoints.cs (99%) rename src/Cluckwork.Api/{Endpoints => Modules/Access}/Auth/LoginRequestValidator.cs (97%) rename src/Cluckwork.Api/{Endpoints => Modules/Access}/Auth/StepUpRequestValidator.cs (89%) rename src/Cluckwork.Api/{Endpoints => Modules/Access}/Me/MeEndpoints.cs (96%) rename src/Cluckwork.Api/{Endpoints => Modules/Access}/Users/UserEndpoints.cs (94%) rename src/Cluckwork.Application/{Features/Users => Modules/Access/Contracts}/AccessOperationOutcomes.cs (97%) rename src/Cluckwork.Application/{Features/Users/AssignFlock => Modules/Access/Contracts}/AssignFlockCommand.cs (68%) rename src/Cluckwork.Application/{Features/Users/ChangeOwnPassword => Modules/Access/Contracts}/ChangeOwnPasswordCommand.cs (84%) rename src/Cluckwork.Application/{Features/Users/ChangeUserEmail => Modules/Access/Contracts}/ChangeUserEmailCommand.cs (65%) rename src/Cluckwork.Application/{Features/Users/ChangeUserRole => Modules/Access/Contracts}/ChangeUserRoleCommand.cs (88%) rename src/Cluckwork.Application/{Features/Users/CreateUser => Modules/Access/Contracts}/CreateUserCommand.cs (88%) rename src/Cluckwork.Application/{Features/Users/DisableUser => Modules/Access/Contracts}/DisableUserCommand.cs (88%) rename src/Cluckwork.Application/{Features/Users/EnableUser => Modules/Access/Contracts}/EnableUserCommand.cs (86%) rename src/Cluckwork.Application/{Features/Users => Modules/Access/Contracts}/IAccessAccountLifecycle.cs (89%) rename src/Cluckwork.Application/{Features/Users => Modules/Access/Contracts}/IAccessFixture.cs (91%) rename src/Cluckwork.Application/{Features/Users => Modules/Access/Contracts}/IAccessLookup.cs (94%) rename src/Cluckwork.Application/{Features/Users => Modules/Access/Contracts}/IAccessModule.cs (84%) rename src/Cluckwork.Application/{Features/Users => Modules/Access/Contracts}/IAccessOperations.cs (94%) rename src/Cluckwork.Application/{Features/Users => Modules/Access/Contracts}/IAccessSeedLookup.cs (94%) rename src/Cluckwork.Application/{Features/Users => Modules/Access/Contracts}/ICredentialEpochVerifier.cs (94%) rename src/Cluckwork.Application/{Features/Users => Modules/Access/Contracts}/IRefreshTokenPurge.cs (87%) rename src/Cluckwork.Application/{Features/Users/SetLanguage => Modules/Access/Contracts}/SetLanguageCommand.cs (73%) rename src/Cluckwork.Application/{Features/Users/SetStepperUnit => Modules/Access/Contracts}/SetStepperUnitCommand.cs (85%) rename src/Cluckwork.Application/{Features/Users/SetUserPassword => Modules/Access/Contracts}/SetUserPasswordCommand.cs (88%) rename src/Cluckwork.Application/{Features/Users/AssignFlock => Modules/Access/Contracts}/UnassignFlockCommand.cs (69%) rename src/Cluckwork.Application/{Features/Users/UpdateUser => Modules/Access/Contracts}/UpdateUserCommand.cs (81%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/AssignFlock/AssignFlockHandler.cs (97%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/ChangeOwnPassword/ChangeOwnPasswordHandler.cs (74%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/ChangeOwnPassword/ChangeOwnPasswordValidator.cs (74%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/ChangeUserEmail/ChangeUserEmailHandler.cs (81%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/ChangeUserEmail/ChangeUserEmailValidator.cs (83%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/ChangeUserRole/ChangeUserRoleHandler.cs (85%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/ChangeUserRole/ChangeUserRoleValidator.cs (71%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/CreateUser/CreateUserHandler.cs (91%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/CreateUser/CreateUserValidator.cs (84%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/DisableUser/DisableUserHandler.cs (94%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/DisableUser/DisableUserValidator.cs (87%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/EnableUser/EnableUserHandler.cs (86%) rename src/Cluckwork.Application/{Common => Modules/Access/Users}/IIdentityProvider.cs (99%) rename src/Cluckwork.Application/{Common => Modules/Access/Users}/IStepUpGrantService.cs (89%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/IUserRoleAssignmentRepository.cs (90%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/PasswordRules.cs (93%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/SetLanguage/SetLanguageHandler.cs (79%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/SetLanguage/SetLanguageValidator.cs (88%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/SetStepperUnit/SetStepperUnitHandler.cs (92%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/SetStepperUnit/SetStepperUnitValidator.cs (89%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/SetUserPassword/SetUserPasswordHandler.cs (89%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/SetUserPassword/SetUserPasswordValidator.cs (63%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/UpdateUser/UpdateUserHandler.cs (77%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/UpdateUser/UpdateUserValidator.cs (56%) rename src/Cluckwork.Application/{Features => Modules/Access}/Users/UserName.cs (89%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/AccessAccountLifecycle.cs (88%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/AccessFixture.cs (93%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/AccessLookup.cs (95%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/AccessModule.cs (87%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/AccessOperations.cs (87%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/AccessSeedLookup.cs (93%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/AccountLockout.cs (99%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/AccountProvisioner.cs (98%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/AccountRenameService.cs (98%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/AccountScopedUserValidator.cs (99%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/AccountSuspensionService.cs (99%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/AccountUserDirectory.cs (98%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/AdminRecoveryService.cs (98%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/ApplicationRole.cs (76%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/ApplicationUser.cs (97%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/AuthSecurityEventLogger.cs (97%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/CredentialEpochVerifier.cs (96%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/FirstRunAdminService.cs (99%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/FirstRunStatusService.cs (99%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/IStepUpGrantRegistry.cs (98%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/IdentityProvider.cs (99%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/JwtOptions.cs (95%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/JwtTokenService.cs (98%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/PemKey.cs (85%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/PersistentStepUpGrantRegistry.cs (99%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/RefreshToken.cs (98%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/RefreshTokenPurge.cs (86%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/StepUpGrantService.cs (99%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/TemporaryPassword.cs (97%) rename src/Cluckwork.Infrastructure/{ => Modules/Access}/Identity/TimingEqualization.cs (91%) diff --git a/docs/superpowers/plans/2026-08-02-credential-epoch.md b/docs/superpowers/plans/2026-08-02-credential-epoch.md index 2eeb12316..caac43f55 100644 --- a/docs/superpowers/plans/2026-08-02-credential-epoch.md +++ b/docs/superpowers/plans/2026-08-02-credential-epoch.md @@ -24,9 +24,9 @@ ### Task 1: Storage, migration, and token issuance **Files:** -- Modify: `src/Cluckwork.Infrastructure/Identity/ApplicationUser.cs` -- Modify: `src/Cluckwork.Infrastructure/Identity/RefreshToken.cs` -- Modify: `src/Cluckwork.Infrastructure/Identity/JwtTokenService.cs` +- Modify: `src/Cluckwork.Infrastructure/Modules/Access/Identity/ApplicationUser.cs` +- Modify: `src/Cluckwork.Infrastructure/Modules/Access/Identity/RefreshToken.cs` +- Modify: `src/Cluckwork.Infrastructure/Modules/Access/Identity/JwtTokenService.cs` - Modify: `src/Cluckwork.Infrastructure/Persistence/Configurations/ApplicationUserConfiguration.cs` - Modify: `src/Cluckwork.Infrastructure/Persistence/Migrations/20260801190854_InitialCreate.cs` - Modify: `src/Cluckwork.Infrastructure/Persistence/Migrations/AppDbContextModelSnapshot.cs` @@ -45,8 +45,8 @@ **Files:** - Create: `src/Cluckwork.Api/Middleware/CredentialEpochMiddleware.cs` - Modify: `src/Cluckwork.Api/Program.cs` -- Modify: `src/Cluckwork.Infrastructure/Identity/IdentityProvider.cs` -- Modify: `src/Cluckwork.Infrastructure/Identity/StepUpGrantService.cs` +- Modify: `src/Cluckwork.Infrastructure/Modules/Access/Identity/IdentityProvider.cs` +- Modify: `src/Cluckwork.Infrastructure/Modules/Access/Identity/StepUpGrantService.cs` - Test: `tests/Cluckwork.Api.IntegrationTests/CredentialEpochTests.cs` **Interfaces:** diff --git a/docs/superpowers/plans/2026-08-25-change-user-email.md b/docs/superpowers/plans/2026-08-25-change-user-email.md index d8751976c..5e5112db5 100644 --- a/docs/superpowers/plans/2026-08-25-change-user-email.md +++ b/docs/superpowers/plans/2026-08-25-change-user-email.md @@ -50,9 +50,9 @@ Run: ```bash git ls-files \ - src/Cluckwork.Application/Features/Users/ChangeUserEmail/ChangeUserEmailCommand.cs \ - src/Cluckwork.Application/Features/Users/ChangeUserEmail/ChangeUserEmailValidator.cs \ - src/Cluckwork.Application/Features/Users/ChangeUserEmail/ChangeUserEmailHandler.cs \ + src/Cluckwork.Application/Modules/Access/Contracts/ChangeUserEmailCommand.cs \ + src/Cluckwork.Application/Modules/Access/Users/ChangeUserEmail/ChangeUserEmailValidator.cs \ + src/Cluckwork.Application/Modules/Access/Users/ChangeUserEmail/ChangeUserEmailHandler.cs \ tests/Cluckwork.Api.IntegrationTests/ChangeUserEmailTests.cs \ tests/Cluckwork.Api.IntegrationTests/ChangeUserEmailRaceTests.cs ``` @@ -86,15 +86,15 @@ Expected: branch is `feat/change-user-email`, based on the recorded baseline SHA **Files:** -- Create: `src/Cluckwork.Application/Features/Users/ChangeUserEmail/ChangeUserEmailCommand.cs` -- Create: `src/Cluckwork.Application/Features/Users/ChangeUserEmail/ChangeUserEmailValidator.cs` -- Create: `src/Cluckwork.Application/Features/Users/ChangeUserEmail/ChangeUserEmailHandler.cs` +- Create: `src/Cluckwork.Application/Modules/Access/Contracts/ChangeUserEmailCommand.cs` +- Create: `src/Cluckwork.Application/Modules/Access/Users/ChangeUserEmail/ChangeUserEmailValidator.cs` +- Create: `src/Cluckwork.Application/Modules/Access/Users/ChangeUserEmail/ChangeUserEmailHandler.cs` - Create: `tests/Cluckwork.Api.IntegrationTests/ChangeUserEmailTests.cs` - Create: `tests/Cluckwork.Api.IntegrationTests/ChangeUserEmailRaceTests.cs` -- Modify: `src/Cluckwork.Application/Common/IIdentityProvider.cs` +- Modify: `src/Cluckwork.Application/Modules/Access/Users/IIdentityProvider.cs` - Modify: `src/Cluckwork.Application/Common/AuditActions.cs` -- Modify: `src/Cluckwork.Infrastructure/Identity/IdentityProvider.cs` -- Modify: `src/Cluckwork.Api/Endpoints/Users/UserEndpoints.cs` +- Modify: `src/Cluckwork.Infrastructure/Modules/Access/Identity/IdentityProvider.cs` +- Modify: `src/Cluckwork.Api/Modules/Access/Users/UserEndpoints.cs` - Modify: `src/Cluckwork.Api/Hosting/CluckworkFeatureServiceCollectionExtensions.cs` - Modify: `tests/Cluckwork.Application.Tests/TenantBypass/Data/filter-free-set-sites.tsv` - Modify: `web/src/i18n/enums.ts` @@ -294,8 +294,8 @@ Expected: focused tests pass; build ends `0 Warning(s) 0 Error(s)`. - [ ] **Step 9: Commit the backend vertical slice.** ```bash -git add src/Cluckwork.Application src/Cluckwork.Infrastructure/Identity/IdentityProvider.cs \ - src/Cluckwork.Api/Endpoints/Users/UserEndpoints.cs \ +git add src/Cluckwork.Application src/Cluckwork.Infrastructure/Modules/Access/Identity/IdentityProvider.cs \ + src/Cluckwork.Api/Modules/Access/Users/UserEndpoints.cs \ src/Cluckwork.Api/Hosting/CluckworkFeatureServiceCollectionExtensions.cs \ tests/Cluckwork.Api.IntegrationTests/ChangeUserEmailTests.cs \ tests/Cluckwork.Api.IntegrationTests/ChangeUserEmailRaceTests.cs \ diff --git a/specs/001-searchable-entity-picker/tasks.md b/specs/001-searchable-entity-picker/tasks.md index 73b39f3f5..c529d436c 100644 --- a/specs/001-searchable-entity-picker/tasks.md +++ b/specs/001-searchable-entity-picker/tasks.md @@ -147,7 +147,7 @@ - [X] T044 [US4] Implement scoped bulk flock-reference reads and restrict movement aggregation to returned flock IDs in `src/Cluckwork.Application/Modules/FlockManagement/Flocks/IFlockRepository.cs`, `src/Cluckwork.Application/Modules/FlockManagement/Flocks/IBirdMovementRepository.cs`, `src/Cluckwork.Infrastructure/Repositories/FlockRepository.cs`, `src/Cluckwork.Infrastructure/Repositories/BirdMovementRepository.cs`, and `src/Cluckwork.Api/Modules/FlockManagement/Flocks/FlockEndpoints.cs`. - [X] T045 [P] [US4] Add `flockName`/`flockStatus` to Daily Entry list/detail projection through one scoped bulk read in `src/Cluckwork.Api/Modules/EggOperations/DailyEntries/DailyEntryEndpoints.cs` and `src/Cluckwork.Infrastructure/Repositories/DailyEntryRepository.cs`. - [X] T046 [P] [US4] Add row-owned `flockName` to Feed and Water list projections in `src/Cluckwork.Api/Modules/GeneralInventory/Inventory/InventoryEndpoints.cs`, `src/Cluckwork.Api/Modules/GeneralInventory/Water/WaterUsageEndpoints.cs`, `src/Cluckwork.Infrastructure/Repositories/FeedUsageRepository.cs`, and `src/Cluckwork.Infrastructure/Repositories/WaterUsageRepository.cs`. -- [X] T047 [P] [US4] Return nullable assignment `flockName` from one scoped left join while keeping the list unpaged in `src/Cluckwork.Application/Features/Users/IUserRoleAssignmentRepository.cs`, `src/Cluckwork.Infrastructure/Repositories/UserRoleAssignmentRepository.cs`, and `src/Cluckwork.Api/Endpoints/Users/UserEndpoints.cs`. +- [X] T047 [P] [US4] Return nullable assignment `flockName` from one scoped left join while keeping the list unpaged in `src/Cluckwork.Application/Modules/Access/Users/IUserRoleAssignmentRepository.cs`, `src/Cluckwork.Infrastructure/Repositories/UserRoleAssignmentRepository.cs`, and `src/Cluckwork.Api/Modules/Access/Users/UserEndpoints.cs`. - [X] T048 [P] [US4] Implement scoped bulk customer references and add `customerName` to Sales list/detail responses in `src/Cluckwork.Application/Modules/Commerce/Customers/ICustomerRepository.cs`, `src/Cluckwork.Infrastructure/Repositories/CustomerRepository.cs`, and `src/Cluckwork.Api/Modules/Commerce/Sales/SaleEndpoints.cs`. - [X] T049 [P] [US4] Add nullable `flockName` to Expense list/detail/adjust responses through scoped grouped reads in `src/Cluckwork.Application/Modules/Finance/Expenses/IExpenseRepositories.cs`, `src/Cluckwork.Infrastructure/Repositories/ExpenseRepositories.cs`, and `src/Cluckwork.Api/Modules/Finance/Expenses/ExpenseEndpoints.cs`. - [X] T050 [US4] Add all six required/nullable row-owned response fields to the frontend types and remove every ID-fragment reference fallback in `web/src/api/cluckwork.ts`. diff --git a/src/Cluckwork.Api/Cli/BootstrapAdminCliCommand.cs b/src/Cluckwork.Api/Cli/BootstrapAdminCliCommand.cs index bbe4481e9..4d683554f 100644 --- a/src/Cluckwork.Api/Cli/BootstrapAdminCliCommand.cs +++ b/src/Cluckwork.Api/Cli/BootstrapAdminCliCommand.cs @@ -1,4 +1,4 @@ -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Builder; using Microsoft.EntityFrameworkCore; diff --git a/src/Cluckwork.Api/Cli/ProvisionAccountCliCommand.cs b/src/Cluckwork.Api/Cli/ProvisionAccountCliCommand.cs index e3da9d4da..169531763 100644 --- a/src/Cluckwork.Api/Cli/ProvisionAccountCliCommand.cs +++ b/src/Cluckwork.Api/Cli/ProvisionAccountCliCommand.cs @@ -1,4 +1,4 @@ -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Accounts; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; diff --git a/src/Cluckwork.Api/Cli/ReactivateAccountCliCommand.cs b/src/Cluckwork.Api/Cli/ReactivateAccountCliCommand.cs index 4bee02dfc..83f863ae2 100644 --- a/src/Cluckwork.Api/Cli/ReactivateAccountCliCommand.cs +++ b/src/Cluckwork.Api/Cli/ReactivateAccountCliCommand.cs @@ -1,5 +1,5 @@ using Cluckwork.Application.Features.Accounts; -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; diff --git a/src/Cluckwork.Api/Cli/RecoverAdminCliCommand.cs b/src/Cluckwork.Api/Cli/RecoverAdminCliCommand.cs index 182ec55ec..701299a66 100644 --- a/src/Cluckwork.Api/Cli/RecoverAdminCliCommand.cs +++ b/src/Cluckwork.Api/Cli/RecoverAdminCliCommand.cs @@ -1,4 +1,4 @@ -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; diff --git a/src/Cluckwork.Api/Cli/RenameAccountCliCommand.cs b/src/Cluckwork.Api/Cli/RenameAccountCliCommand.cs index 12ecd65d1..fba80247a 100644 --- a/src/Cluckwork.Api/Cli/RenameAccountCliCommand.cs +++ b/src/Cluckwork.Api/Cli/RenameAccountCliCommand.cs @@ -1,5 +1,5 @@ using Cluckwork.Application.Features.Accounts; -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Accounts; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; diff --git a/src/Cluckwork.Api/Cli/SuspendAccountCliCommand.cs b/src/Cluckwork.Api/Cli/SuspendAccountCliCommand.cs index a29b84a94..7d66e0f69 100644 --- a/src/Cluckwork.Api/Cli/SuspendAccountCliCommand.cs +++ b/src/Cluckwork.Api/Cli/SuspendAccountCliCommand.cs @@ -1,5 +1,5 @@ using Cluckwork.Application.Features.Accounts; -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; diff --git a/src/Cluckwork.Api/Hosting/CluckworkIdentityServiceCollectionExtensions.cs b/src/Cluckwork.Api/Hosting/CluckworkIdentityServiceCollectionExtensions.cs index 7ad91fc76..d75851afa 100644 --- a/src/Cluckwork.Api/Hosting/CluckworkIdentityServiceCollectionExtensions.cs +++ b/src/Cluckwork.Api/Hosting/CluckworkIdentityServiceCollectionExtensions.cs @@ -1,13 +1,14 @@ +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users; +using Cluckwork.Application.Modules.Access.Users.CreateUser; +using Cluckwork.Application.Modules.Access.Users.SetLanguage; +using Cluckwork.Application.Modules.Access.Users.SetStepperUnit; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Security.Cryptography; using Cluckwork.Api.Configuration; using Cluckwork.Api.Middleware; using Cluckwork.Api.Security; using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; -using Cluckwork.Application.Features.Users.CreateUser; -using Cluckwork.Application.Features.Users.SetLanguage; -using Cluckwork.Application.Features.Users.SetStepperUnit; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Cluckwork.Infrastructure.Repositories; using FluentValidation; @@ -176,48 +177,48 @@ private static void AddUserFeatures(IServiceCollection services) UserRoleAssignmentRepository>(); services.AddScoped, CreateUserValidator>(); services.AddScoped< - IValidator, - Cluckwork.Application.Features.Users.UpdateUser.UpdateUserValidator>(); + IValidator, + Cluckwork.Application.Modules.Access.Users.UpdateUser.UpdateUserValidator>(); services.AddScoped< - IValidator, - Cluckwork.Application.Features.Users.SetUserPassword.SetUserPasswordValidator>(); + IValidator, + Cluckwork.Application.Modules.Access.Users.SetUserPassword.SetUserPasswordValidator>(); services.AddScoped< - IValidator, - Cluckwork.Application.Features.Users.ChangeOwnPassword.ChangeOwnPasswordValidator>(); + IValidator, + Cluckwork.Application.Modules.Access.Users.ChangeOwnPassword.ChangeOwnPasswordValidator>(); services.AddScoped< - IValidator, - Cluckwork.Application.Features.Users.ChangeUserRole.ChangeUserRoleValidator>(); + IValidator, + Cluckwork.Application.Modules.Access.Users.ChangeUserRole.ChangeUserRoleValidator>(); services.AddScoped< - IValidator, - Cluckwork.Application.Features.Users.ChangeUserEmail.ChangeUserEmailValidator>(); + IValidator, + Cluckwork.Application.Modules.Access.Users.ChangeUserEmail.ChangeUserEmailValidator>(); // #356 — disable carries an optional reason; enable carries no body at // all and therefore has no validator. services.AddScoped< - IValidator, - Cluckwork.Application.Features.Users.DisableUser.DisableUserValidator>(); + IValidator, + Cluckwork.Application.Modules.Access.Users.DisableUser.DisableUserValidator>(); services.AddScoped, SetLanguageValidator>(); services.AddScoped, SetStepperUnitValidator>(); services.AddScoped(); services.AddScoped< - Cluckwork.Application.Features.Users.UpdateUser.UpdateUserHandler>(); + Cluckwork.Application.Modules.Access.Users.UpdateUser.UpdateUserHandler>(); services.AddScoped< - Cluckwork.Application.Features.Users.SetUserPassword.SetUserPasswordHandler>(); + Cluckwork.Application.Modules.Access.Users.SetUserPassword.SetUserPasswordHandler>(); services.AddScoped< - Cluckwork.Application.Features.Users.ChangeOwnPassword.ChangeOwnPasswordHandler>(); + Cluckwork.Application.Modules.Access.Users.ChangeOwnPassword.ChangeOwnPasswordHandler>(); services.AddScoped< - Cluckwork.Application.Features.Users.ChangeUserRole.ChangeUserRoleHandler>(); + Cluckwork.Application.Modules.Access.Users.ChangeUserRole.ChangeUserRoleHandler>(); services.AddScoped< - Cluckwork.Application.Features.Users.ChangeUserEmail.ChangeUserEmailHandler>(); + Cluckwork.Application.Modules.Access.Users.ChangeUserEmail.ChangeUserEmailHandler>(); services.AddScoped< - Cluckwork.Application.Features.Users.DisableUser.DisableUserHandler>(); + Cluckwork.Application.Modules.Access.Users.DisableUser.DisableUserHandler>(); services.AddScoped< - Cluckwork.Application.Features.Users.EnableUser.EnableUserHandler>(); + Cluckwork.Application.Modules.Access.Users.EnableUser.EnableUserHandler>(); services.AddScoped(); services.AddScoped(); services.AddScoped< - Cluckwork.Application.Features.Users.AssignFlock.AssignFlockHandler>(); + Cluckwork.Application.Modules.Access.Users.AssignFlock.AssignFlockHandler>(); services.AddScoped< - Cluckwork.Application.Features.Users.AssignFlock.UnassignFlockHandler>(); + Cluckwork.Application.Modules.Access.Users.AssignFlock.UnassignFlockHandler>(); } // Serving-only (#347). A one-shot verb neither issues nor validates a token, diff --git a/src/Cluckwork.Api/Hosting/CluckworkPersistenceServiceCollectionExtensions.cs b/src/Cluckwork.Api/Hosting/CluckworkPersistenceServiceCollectionExtensions.cs index 6ec585450..4f920507f 100644 --- a/src/Cluckwork.Api/Hosting/CluckworkPersistenceServiceCollectionExtensions.cs +++ b/src/Cluckwork.Api/Hosting/CluckworkPersistenceServiceCollectionExtensions.cs @@ -1,13 +1,13 @@ using Cluckwork.Application.Common; using Cluckwork.Application.Features.Accounts; -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Application.Modules.Commerce.Contracts; using Cluckwork.Application.Modules.EggOperations.Contracts; using Cluckwork.Application.Modules.Finance.Contracts; using Cluckwork.Application.Modules.FlockManagement.Contracts; using Cluckwork.Application.Modules.GeneralInventory.Contracts; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Jobs; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Persistence; using Cluckwork.Infrastructure.Persistence.Interceptors; using Cluckwork.Infrastructure.Providers; diff --git a/src/Cluckwork.Api/Hosting/Modules/CluckworkPlatformServiceCollectionExtensions.cs b/src/Cluckwork.Api/Hosting/Modules/CluckworkPlatformServiceCollectionExtensions.cs index b2f73b370..d7bc94956 100644 --- a/src/Cluckwork.Api/Hosting/Modules/CluckworkPlatformServiceCollectionExtensions.cs +++ b/src/Cluckwork.Api/Hosting/Modules/CluckworkPlatformServiceCollectionExtensions.cs @@ -22,12 +22,12 @@ public static IServiceCollection AddCluckworkPlatformServices( // #309 — the login DTO validator lives in the Api assembly (it validates // the Api LoginRequest). MAX-length only; see LoginRequestValidator. services.AddScoped< - IValidator, - Cluckwork.Api.Endpoints.Auth.LoginRequestValidator>(); + IValidator, + Cluckwork.Api.Modules.Access.Auth.LoginRequestValidator>(); // #308 services.AddScoped< - IValidator, - Cluckwork.Api.Endpoints.Auth.StepUpRequestValidator>(); + IValidator, + Cluckwork.Api.Modules.Access.Auth.StepUpRequestValidator>(); // #307 — lease duration / max-wait bounds for the idempotency claim protocol. services.Configure( diff --git a/src/Cluckwork.Api/Middleware/CredentialEpochMiddleware.cs b/src/Cluckwork.Api/Middleware/CredentialEpochMiddleware.cs index adf8a03b2..8120a9c35 100644 --- a/src/Cluckwork.Api/Middleware/CredentialEpochMiddleware.cs +++ b/src/Cluckwork.Api/Middleware/CredentialEpochMiddleware.cs @@ -1,6 +1,6 @@ +using Cluckwork.Application.Modules.Access.Contracts; using System.Globalization; using System.IdentityModel.Tokens.Jwt; -using Cluckwork.Application.Features.Users; using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc; diff --git a/src/Cluckwork.Api/Middleware/FlockScopeResolutionMiddleware.cs b/src/Cluckwork.Api/Middleware/FlockScopeResolutionMiddleware.cs index 457e40880..33268bb47 100644 --- a/src/Cluckwork.Api/Middleware/FlockScopeResolutionMiddleware.cs +++ b/src/Cluckwork.Api/Middleware/FlockScopeResolutionMiddleware.cs @@ -1,5 +1,4 @@ -using Cluckwork.Application.Features.Users; -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Diagnostics; diff --git a/src/Cluckwork.Api/Middleware/IdempotencyMiddleware.cs b/src/Cluckwork.Api/Middleware/IdempotencyMiddleware.cs index 991b1a034..eb0723d0a 100644 --- a/src/Cluckwork.Api/Middleware/IdempotencyMiddleware.cs +++ b/src/Cluckwork.Api/Middleware/IdempotencyMiddleware.cs @@ -1,6 +1,5 @@ using System.Security.Cryptography; using System.Text; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Diagnostics; using Microsoft.EntityFrameworkCore; diff --git a/src/Cluckwork.Api/Middleware/TenantResolutionMiddleware.cs b/src/Cluckwork.Api/Middleware/TenantResolutionMiddleware.cs index 95bc6d39d..04ccafcd2 100644 --- a/src/Cluckwork.Api/Middleware/TenantResolutionMiddleware.cs +++ b/src/Cluckwork.Api/Middleware/TenantResolutionMiddleware.cs @@ -1,4 +1,3 @@ -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; namespace Cluckwork.Api.Middleware; diff --git a/src/Cluckwork.Api/Endpoints/Auth/AuthCookies.cs b/src/Cluckwork.Api/Modules/Access/Auth/AuthCookies.cs similarity index 99% rename from src/Cluckwork.Api/Endpoints/Auth/AuthCookies.cs rename to src/Cluckwork.Api/Modules/Access/Auth/AuthCookies.cs index 45c2c9f90..a5038449b 100644 --- a/src/Cluckwork.Api/Endpoints/Auth/AuthCookies.cs +++ b/src/Cluckwork.Api/Modules/Access/Auth/AuthCookies.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Api.Endpoints.Auth; +namespace Cluckwork.Api.Modules.Access.Auth; // #145 — the refresh token lives only in an HttpOnly cookie, never in a response // body or JS-readable storage; the access token stays a Bearer header held in diff --git a/src/Cluckwork.Api/Endpoints/Auth/AuthEndpoints.cs b/src/Cluckwork.Api/Modules/Access/Auth/AuthEndpoints.cs similarity index 99% rename from src/Cluckwork.Api/Endpoints/Auth/AuthEndpoints.cs rename to src/Cluckwork.Api/Modules/Access/Auth/AuthEndpoints.cs index 6b7637a99..8dd02d842 100644 --- a/src/Cluckwork.Api/Endpoints/Auth/AuthEndpoints.cs +++ b/src/Cluckwork.Api/Modules/Access/Auth/AuthEndpoints.cs @@ -3,13 +3,12 @@ using Cluckwork.Api.RateLimiting; using Cluckwork.Api.Validation; using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Accounts; -using Cluckwork.Application.Features.Users.ChangeOwnPassword; using Cluckwork.Infrastructure.Persistence; using FluentValidation; -namespace Cluckwork.Api.Endpoints.Auth; +namespace Cluckwork.Api.Modules.Access.Auth; public static class AuthEndpoints { diff --git a/src/Cluckwork.Api/Endpoints/Auth/LoginRequestValidator.cs b/src/Cluckwork.Api/Modules/Access/Auth/LoginRequestValidator.cs similarity index 97% rename from src/Cluckwork.Api/Endpoints/Auth/LoginRequestValidator.cs rename to src/Cluckwork.Api/Modules/Access/Auth/LoginRequestValidator.cs index 0fdfc4c07..95f5daf13 100644 --- a/src/Cluckwork.Api/Endpoints/Auth/LoginRequestValidator.cs +++ b/src/Cluckwork.Api/Modules/Access/Auth/LoginRequestValidator.cs @@ -1,8 +1,8 @@ -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Users; using Cluckwork.Domain.Accounts; using FluentValidation; -namespace Cluckwork.Api.Endpoints.Auth; +namespace Cluckwork.Api.Modules.Access.Auth; // #309 — MAX-length-only guard on the login credentials, plus a not-null guard // (see below). Deliberately NO NotEmpty / MinLength: an empty ("") or short diff --git a/src/Cluckwork.Api/Endpoints/Auth/StepUpRequestValidator.cs b/src/Cluckwork.Api/Modules/Access/Auth/StepUpRequestValidator.cs similarity index 89% rename from src/Cluckwork.Api/Endpoints/Auth/StepUpRequestValidator.cs rename to src/Cluckwork.Api/Modules/Access/Auth/StepUpRequestValidator.cs index ea1d56187..c4891c0ec 100644 --- a/src/Cluckwork.Api/Endpoints/Auth/StepUpRequestValidator.cs +++ b/src/Cluckwork.Api/Modules/Access/Auth/StepUpRequestValidator.cs @@ -1,7 +1,7 @@ -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Users; using FluentValidation; -namespace Cluckwork.Api.Endpoints.Auth; +namespace Cluckwork.Api.Modules.Access.Auth; // #308 — MAX-length-only, matching LoginRequestValidator's rationale: an // empty/short password must still flow to IStepUpGrantService.IssueAsync and diff --git a/src/Cluckwork.Api/Endpoints/Me/MeEndpoints.cs b/src/Cluckwork.Api/Modules/Access/Me/MeEndpoints.cs similarity index 96% rename from src/Cluckwork.Api/Endpoints/Me/MeEndpoints.cs rename to src/Cluckwork.Api/Modules/Access/Me/MeEndpoints.cs index 1ae6a4e27..7e9ac164c 100644 --- a/src/Cluckwork.Api/Endpoints/Me/MeEndpoints.cs +++ b/src/Cluckwork.Api/Modules/Access/Me/MeEndpoints.cs @@ -1,13 +1,11 @@ using Cluckwork.Api.Validation; using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; -using Cluckwork.Application.Features.Users.SetLanguage; -using Cluckwork.Application.Features.Users.SetStepperUnit; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Common; using Cluckwork.Infrastructure.Persistence; using FluentValidation; -namespace Cluckwork.Api.Endpoints.Me; +namespace Cluckwork.Api.Modules.Access.Me; // #45 — the user-scoped counterpart to the farm-scoped /account group. Identity // comes from the JWT (sub), not the body. Mounted on the DEFAULT auth policy so diff --git a/src/Cluckwork.Api/Endpoints/Users/UserEndpoints.cs b/src/Cluckwork.Api/Modules/Access/Users/UserEndpoints.cs similarity index 94% rename from src/Cluckwork.Api/Endpoints/Users/UserEndpoints.cs rename to src/Cluckwork.Api/Modules/Access/Users/UserEndpoints.cs index 9ca3343c0..bd636b3cd 100644 --- a/src/Cluckwork.Api/Endpoints/Users/UserEndpoints.cs +++ b/src/Cluckwork.Api/Modules/Access/Users/UserEndpoints.cs @@ -1,21 +1,13 @@ using Cluckwork.Api.Hosting; using Cluckwork.Api.Validation; using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; -using Cluckwork.Application.Features.Users.AssignFlock; -using Cluckwork.Application.Features.Users.ChangeUserRole; -using Cluckwork.Application.Features.Users.ChangeUserEmail; -using Cluckwork.Application.Features.Users.CreateUser; -using Cluckwork.Application.Features.Users.DisableUser; -using Cluckwork.Application.Features.Users.EnableUser; -using Cluckwork.Application.Features.Users.SetUserPassword; -using Cluckwork.Application.Features.Users.UpdateUser; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Common; using Cluckwork.Infrastructure.Persistence; using FluentValidation; using Microsoft.AspNetCore.Mvc; -namespace Cluckwork.Api.Endpoints.Users; +namespace Cluckwork.Api.Modules.Access.Users; // #73 — minimal user management: enough for an admin to create a worker (or // another admin) and see who exists. Full user administration is the RBAC slice. @@ -128,7 +120,7 @@ private static async Task ListAssignments( private static async Task AssignFlock( Guid id, AssignFlockRequest request, - [FromHeader(Name = Cluckwork.Api.Endpoints.Auth.AuthEndpoints.StepUpHeaderName)] string? stepUpToken, + [FromHeader(Name = Cluckwork.Api.Modules.Access.Auth.AuthEndpoints.StepUpHeaderName)] string? stepUpToken, IAccessModule access, TenantContext tenant, ICurrentUser currentUser, CancellationToken ct) { @@ -156,7 +148,7 @@ private static async Task AssignFlock( private static async Task UnassignFlock( Guid id, Guid assignmentId, - [FromHeader(Name = Cluckwork.Api.Endpoints.Auth.AuthEndpoints.StepUpHeaderName)] string? stepUpToken, + [FromHeader(Name = Cluckwork.Api.Modules.Access.Auth.AuthEndpoints.StepUpHeaderName)] string? stepUpToken, IAccessModule access, TenantContext tenant, ICurrentUser currentUser, CancellationToken ct) { @@ -172,7 +164,7 @@ private static async Task UnassignFlock( private static async Task CreateUser( CreateUserRequest request, - [FromHeader(Name = Cluckwork.Api.Endpoints.Auth.AuthEndpoints.StepUpHeaderName)] string? stepUpToken, + [FromHeader(Name = Cluckwork.Api.Modules.Access.Auth.AuthEndpoints.StepUpHeaderName)] string? stepUpToken, IAccessModule access, IValidator validator, TenantContext tenant, @@ -227,7 +219,7 @@ private static async Task UpdateUser( private static async Task SetUserPassword( Guid id, SetUserPasswordRequest request, - [FromHeader(Name = Cluckwork.Api.Endpoints.Auth.AuthEndpoints.StepUpHeaderName)] string? stepUpToken, + [FromHeader(Name = Cluckwork.Api.Modules.Access.Auth.AuthEndpoints.StepUpHeaderName)] string? stepUpToken, IAccessModule access, IValidator validator, TenantContext tenant, @@ -276,7 +268,7 @@ private static async Task SetUserPassword( private static async Task ChangeUserRole( Guid id, ChangeUserRoleRequest request, - [FromHeader(Name = Cluckwork.Api.Endpoints.Auth.AuthEndpoints.StepUpHeaderName)] string? stepUpToken, + [FromHeader(Name = Cluckwork.Api.Modules.Access.Auth.AuthEndpoints.StepUpHeaderName)] string? stepUpToken, IAccessModule access, IValidator validator, TenantContext tenant, @@ -319,7 +311,7 @@ private static async Task ChangeUserRole( private static async Task ChangeUserEmail( Guid id, ChangeUserEmailRequest request, - [FromHeader(Name = Cluckwork.Api.Endpoints.Auth.AuthEndpoints.StepUpHeaderName)] string? stepUpToken, + [FromHeader(Name = Cluckwork.Api.Modules.Access.Auth.AuthEndpoints.StepUpHeaderName)] string? stepUpToken, IAccessModule access, IValidator validator, TenantContext tenant, @@ -352,7 +344,7 @@ private static async Task ChangeUserEmail( private static async Task DisableUser( Guid id, DisableUserRequest? request, - [FromHeader(Name = Cluckwork.Api.Endpoints.Auth.AuthEndpoints.StepUpHeaderName)] string? stepUpToken, + [FromHeader(Name = Cluckwork.Api.Modules.Access.Auth.AuthEndpoints.StepUpHeaderName)] string? stepUpToken, IAccessModule access, IValidator validator, TenantContext tenant, @@ -384,7 +376,7 @@ private static async Task DisableUser( private static async Task EnableUser( Guid id, - [FromHeader(Name = Cluckwork.Api.Endpoints.Auth.AuthEndpoints.StepUpHeaderName)] string? stepUpToken, + [FromHeader(Name = Cluckwork.Api.Modules.Access.Auth.AuthEndpoints.StepUpHeaderName)] string? stepUpToken, IAccessModule access, TenantContext tenant, ICurrentUser currentUser, diff --git a/src/Cluckwork.Api/Program.cs b/src/Cluckwork.Api/Program.cs index eb6934c7a..404d4e79f 100644 --- a/src/Cluckwork.Api/Program.cs +++ b/src/Cluckwork.Api/Program.cs @@ -1,13 +1,13 @@ using Cluckwork.Api; using Cluckwork.Api.Cli; using Cluckwork.Api.Endpoints.Accounts; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.Endpoints.ClientErrors; -using Cluckwork.Api.Endpoints.Me; -using Cluckwork.Api.Endpoints.Users; using Cluckwork.Api.Hosting; using Cluckwork.Api.Hosting.Modules; using Cluckwork.Api.Middleware; +using Cluckwork.Api.Modules.Access.Auth; +using Cluckwork.Api.Modules.Access.Me; +using Cluckwork.Api.Modules.Access.Users; using Cluckwork.Api.Modules.Commerce.Catalog; using Cluckwork.Api.Modules.Commerce.Customers; using Cluckwork.Api.Modules.Commerce.Sales; diff --git a/src/Cluckwork.Application/Common/FarmSignIn.cs b/src/Cluckwork.Application/Common/FarmSignIn.cs index dec8e4c59..5cc4305dd 100644 --- a/src/Cluckwork.Application/Common/FarmSignIn.cs +++ b/src/Cluckwork.Application/Common/FarmSignIn.cs @@ -1,5 +1,3 @@ -using Cluckwork.Domain.Modules.Commerce.Contracts; - namespace Cluckwork.Application.Common; public sealed record FarmSignIn(Guid AccountId, bool IsActive); diff --git a/src/Cluckwork.Application/Common/RefreshTokenRevocationOutcome.cs b/src/Cluckwork.Application/Common/RefreshTokenRevocationOutcome.cs index c847d28d2..486e6b228 100644 --- a/src/Cluckwork.Application/Common/RefreshTokenRevocationOutcome.cs +++ b/src/Cluckwork.Application/Common/RefreshTokenRevocationOutcome.cs @@ -1,5 +1,3 @@ -using Cluckwork.Domain.Modules.Commerce.Contracts; - namespace Cluckwork.Application.Common; public enum RefreshTokenRevocationOutcome diff --git a/src/Cluckwork.Application/Common/StepUpErrorCodes.cs b/src/Cluckwork.Application/Common/StepUpErrorCodes.cs index 011b434e6..0a31baeec 100644 --- a/src/Cluckwork.Application/Common/StepUpErrorCodes.cs +++ b/src/Cluckwork.Application/Common/StepUpErrorCodes.cs @@ -1,5 +1,3 @@ -using Cluckwork.Domain.Common; - namespace Cluckwork.Application.Common; public static class StepUpErrorCodes diff --git a/src/Cluckwork.Application/Common/StepUpGrant.cs b/src/Cluckwork.Application/Common/StepUpGrant.cs index 0f1a26a71..5dc83a2c7 100644 --- a/src/Cluckwork.Application/Common/StepUpGrant.cs +++ b/src/Cluckwork.Application/Common/StepUpGrant.cs @@ -1,5 +1,3 @@ -using Cluckwork.Domain.Common; - namespace Cluckwork.Application.Common; public sealed record StepUpGrant(string Token, DateTimeOffset ExpiresAt); diff --git a/src/Cluckwork.Application/Common/TokenPair.cs b/src/Cluckwork.Application/Common/TokenPair.cs index 700c94369..c158ee863 100644 --- a/src/Cluckwork.Application/Common/TokenPair.cs +++ b/src/Cluckwork.Application/Common/TokenPair.cs @@ -1,5 +1,3 @@ -using Cluckwork.Domain.Modules.Commerce.Contracts; - namespace Cluckwork.Application.Common; public sealed record TokenPair( diff --git a/src/Cluckwork.Application/Common/UserSummary.cs b/src/Cluckwork.Application/Common/UserSummary.cs index 8e384f090..0480d1f89 100644 --- a/src/Cluckwork.Application/Common/UserSummary.cs +++ b/src/Cluckwork.Application/Common/UserSummary.cs @@ -1,5 +1,3 @@ -using Cluckwork.Domain.Modules.Commerce.Contracts; - namespace Cluckwork.Application.Common; // #356 — DisabledAt is null for an active user. Exposed on the LIST rather diff --git a/src/Cluckwork.Application/Features/Users/AccessOperationOutcomes.cs b/src/Cluckwork.Application/Modules/Access/Contracts/AccessOperationOutcomes.cs similarity index 97% rename from src/Cluckwork.Application/Features/Users/AccessOperationOutcomes.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/AccessOperationOutcomes.cs index cbe81a4f9..76ece4fc4 100644 --- a/src/Cluckwork.Application/Features/Users/AccessOperationOutcomes.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/AccessOperationOutcomes.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users; +namespace Cluckwork.Application.Modules.Access.Contracts; // #589 — Slug is NULLABLE and sits beside the other nullable fields deliberately. // This record is not a mirror of AccountProvisionOutcome: that one has no no-op diff --git a/src/Cluckwork.Application/Features/Users/AssignFlock/AssignFlockCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/AssignFlockCommand.cs similarity index 68% rename from src/Cluckwork.Application/Features/Users/AssignFlock/AssignFlockCommand.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/AssignFlockCommand.cs index 3fad02229..cbcd3c87a 100644 --- a/src/Cluckwork.Application/Features/Users/AssignFlock/AssignFlockCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/AssignFlockCommand.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users.AssignFlock; +namespace Cluckwork.Application.Modules.Access.Contracts; [ModuleContract("Access")] public sealed record AssignFlockCommand( diff --git a/src/Cluckwork.Application/Features/Users/ChangeOwnPassword/ChangeOwnPasswordCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/ChangeOwnPasswordCommand.cs similarity index 84% rename from src/Cluckwork.Application/Features/Users/ChangeOwnPassword/ChangeOwnPasswordCommand.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/ChangeOwnPasswordCommand.cs index f6946416b..e6763db61 100644 --- a/src/Cluckwork.Application/Features/Users/ChangeOwnPassword/ChangeOwnPasswordCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/ChangeOwnPasswordCommand.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users.ChangeOwnPassword; +namespace Cluckwork.Application.Modules.Access.Contracts; // #165 — self-service: any signed-in user changes their OWN password by proving // the current one. On success every session is revoked and the caller is handed diff --git a/src/Cluckwork.Application/Features/Users/ChangeUserEmail/ChangeUserEmailCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/ChangeUserEmailCommand.cs similarity index 65% rename from src/Cluckwork.Application/Features/Users/ChangeUserEmail/ChangeUserEmailCommand.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/ChangeUserEmailCommand.cs index 496203108..48bd4623d 100644 --- a/src/Cluckwork.Application/Features/Users/ChangeUserEmail/ChangeUserEmailCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/ChangeUserEmailCommand.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users.ChangeUserEmail; +namespace Cluckwork.Application.Modules.Access.Contracts; [ModuleContract("Access")] public sealed record ChangeUserEmailCommand(Guid UserId, string Email, string? StepUpToken); diff --git a/src/Cluckwork.Application/Features/Users/ChangeUserRole/ChangeUserRoleCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/ChangeUserRoleCommand.cs similarity index 88% rename from src/Cluckwork.Application/Features/Users/ChangeUserRole/ChangeUserRoleCommand.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/ChangeUserRoleCommand.cs index 14f83e3ae..59ff86426 100644 --- a/src/Cluckwork.Application/Features/Users/ChangeUserRole/ChangeUserRoleCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/ChangeUserRoleCommand.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users.ChangeUserRole; +namespace Cluckwork.Application.Modules.Access.Contracts; // #355/#360 — StepUpToken carries the same proof as CreateUserCommand and // SetUserPasswordCommand and is required for every requested role. diff --git a/src/Cluckwork.Application/Features/Users/CreateUser/CreateUserCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/CreateUserCommand.cs similarity index 88% rename from src/Cluckwork.Application/Features/Users/CreateUser/CreateUserCommand.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/CreateUserCommand.cs index 86fbfc573..fc6e39ce3 100644 --- a/src/Cluckwork.Application/Features/Users/CreateUser/CreateUserCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/CreateUserCommand.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users.CreateUser; +namespace Cluckwork.Application.Modules.Access.Contracts; // #308/#360 — StepUpToken is the caller's proof-of-recent-auth grant, required // for every interactive user creation regardless of Role. It rides a header, diff --git a/src/Cluckwork.Application/Features/Users/DisableUser/DisableUserCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/DisableUserCommand.cs similarity index 88% rename from src/Cluckwork.Application/Features/Users/DisableUser/DisableUserCommand.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/DisableUserCommand.cs index 4c872c7d7..6a9a7d48c 100644 --- a/src/Cluckwork.Application/Features/Users/DisableUser/DisableUserCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/DisableUserCommand.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users.DisableUser; +namespace Cluckwork.Application.Modules.Access.Contracts; // #356 — Reason is OPTIONAL free text recorded on the audit row (a mandatory // one gets typed "x"). StepUpToken is REQUIRED, unlike ChangeUserRoleCommand's diff --git a/src/Cluckwork.Application/Features/Users/EnableUser/EnableUserCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/EnableUserCommand.cs similarity index 86% rename from src/Cluckwork.Application/Features/Users/EnableUser/EnableUserCommand.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/EnableUserCommand.cs index 6a7a9e13d..ce6f9a9a5 100644 --- a/src/Cluckwork.Application/Features/Users/EnableUser/EnableUserCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/EnableUserCommand.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users.EnableUser; +namespace Cluckwork.Application.Modules.Access.Contracts; // #356 — no reason field: an enable restores the state the account was in // before, and the audit row already records who and when. StepUpToken is diff --git a/src/Cluckwork.Application/Features/Users/IAccessAccountLifecycle.cs b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessAccountLifecycle.cs similarity index 89% rename from src/Cluckwork.Application/Features/Users/IAccessAccountLifecycle.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/IAccessAccountLifecycle.cs index 9caa841e0..2ff67bcba 100644 --- a/src/Cluckwork.Application/Features/Users/IAccessAccountLifecycle.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessAccountLifecycle.cs @@ -1,6 +1,6 @@ using Cluckwork.Domain.Common; -namespace Cluckwork.Application.Features.Users; +namespace Cluckwork.Application.Modules.Access.Contracts; [ModuleContract("Access")] public interface IAccessAccountLifecycle diff --git a/src/Cluckwork.Application/Features/Users/IAccessFixture.cs b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessFixture.cs similarity index 91% rename from src/Cluckwork.Application/Features/Users/IAccessFixture.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/IAccessFixture.cs index 2b9b3c537..b39b36059 100644 --- a/src/Cluckwork.Application/Features/Users/IAccessFixture.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessFixture.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users; +namespace Cluckwork.Application.Modules.Access.Contracts; // Simulation fixture write; registered beside the seeders outside Production. // The trusted seeder holds no step-up grant, so this skips the interactive diff --git a/src/Cluckwork.Application/Features/Users/IAccessLookup.cs b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessLookup.cs similarity index 94% rename from src/Cluckwork.Application/Features/Users/IAccessLookup.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/IAccessLookup.cs index 1094db117..75ef4a83a 100644 --- a/src/Cluckwork.Application/Features/Users/IAccessLookup.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessLookup.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users; +namespace Cluckwork.Application.Modules.Access.Contracts; // #857 — what peer modules need from Access about an actor. Both reads are // fresh, on the caller's scoped context, so a caller inside a transaction reads diff --git a/src/Cluckwork.Application/Features/Users/IAccessModule.cs b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessModule.cs similarity index 84% rename from src/Cluckwork.Application/Features/Users/IAccessModule.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/IAccessModule.cs index 21a4dbd64..052b73618 100644 --- a/src/Cluckwork.Application/Features/Users/IAccessModule.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessModule.cs @@ -1,18 +1,7 @@ using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users.AssignFlock; -using Cluckwork.Application.Features.Users.ChangeOwnPassword; -using Cluckwork.Application.Features.Users.ChangeUserEmail; -using Cluckwork.Application.Features.Users.ChangeUserRole; -using Cluckwork.Application.Features.Users.CreateUser; -using Cluckwork.Application.Features.Users.DisableUser; -using Cluckwork.Application.Features.Users.EnableUser; -using Cluckwork.Application.Features.Users.SetLanguage; -using Cluckwork.Application.Features.Users.SetStepperUnit; -using Cluckwork.Application.Features.Users.SetUserPassword; -using Cluckwork.Application.Features.Users.UpdateUser; using Cluckwork.Domain.Common; -namespace Cluckwork.Application.Features.Users; +namespace Cluckwork.Application.Modules.Access.Contracts; // #857 — Access's surface for HTTP adapters: user administration, the // caller's own profile, flock assignments, and sessions. Each member forwards diff --git a/src/Cluckwork.Application/Features/Users/IAccessOperations.cs b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessOperations.cs similarity index 94% rename from src/Cluckwork.Application/Features/Users/IAccessOperations.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/IAccessOperations.cs index bc98f61d4..4f0d464ec 100644 --- a/src/Cluckwork.Application/Features/Users/IAccessOperations.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessOperations.cs @@ -1,6 +1,6 @@ using Cluckwork.Domain.Common; -namespace Cluckwork.Application.Features.Users; +namespace Cluckwork.Application.Modules.Access.Contracts; // #857 — Access's surface for the operator verbs: one-shot commands whose only // authority is shell access to the deployment. Each member forwards to the diff --git a/src/Cluckwork.Application/Features/Users/IAccessSeedLookup.cs b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessSeedLookup.cs similarity index 94% rename from src/Cluckwork.Application/Features/Users/IAccessSeedLookup.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/IAccessSeedLookup.cs index 3c5b93138..041b42fe2 100644 --- a/src/Cluckwork.Application/Features/Users/IAccessSeedLookup.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessSeedLookup.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users; +namespace Cluckwork.Application.Modules.Access.Contracts; // Fixture actor reads; registered beside the seeders outside Production. [ModuleContract("Access")] diff --git a/src/Cluckwork.Application/Features/Users/ICredentialEpochVerifier.cs b/src/Cluckwork.Application/Modules/Access/Contracts/ICredentialEpochVerifier.cs similarity index 94% rename from src/Cluckwork.Application/Features/Users/ICredentialEpochVerifier.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/ICredentialEpochVerifier.cs index 2f635888e..24ff98325 100644 --- a/src/Cluckwork.Application/Features/Users/ICredentialEpochVerifier.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/ICredentialEpochVerifier.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users; +namespace Cluckwork.Application.Modules.Access.Contracts; // #364/#857 — the credential check CredentialEpochMiddleware runs on every // authenticated request. Each call is one fresh database read: that round trip diff --git a/src/Cluckwork.Application/Features/Users/IRefreshTokenPurge.cs b/src/Cluckwork.Application/Modules/Access/Contracts/IRefreshTokenPurge.cs similarity index 87% rename from src/Cluckwork.Application/Features/Users/IRefreshTokenPurge.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/IRefreshTokenPurge.cs index 0675e30ac..c791ef90d 100644 --- a/src/Cluckwork.Application/Features/Users/IRefreshTokenPurge.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/IRefreshTokenPurge.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users; +namespace Cluckwork.Application.Modules.Access.Contracts; // #857 — the refresh-token purge's DELETE (#270). The sweep owns the cutoff, // the grace and the batch bounds; this removes at most batchSize rows whose diff --git a/src/Cluckwork.Application/Features/Users/SetLanguage/SetLanguageCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/SetLanguageCommand.cs similarity index 73% rename from src/Cluckwork.Application/Features/Users/SetLanguage/SetLanguageCommand.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/SetLanguageCommand.cs index bb300919a..0f46c8d25 100644 --- a/src/Cluckwork.Application/Features/Users/SetLanguage/SetLanguageCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/SetLanguageCommand.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users.SetLanguage; +namespace Cluckwork.Application.Modules.Access.Contracts; // The already-canonicalised (trimmed + lowercased) preference, or null to clear. [ModuleContract("Access")] diff --git a/src/Cluckwork.Application/Features/Users/SetStepperUnit/SetStepperUnitCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/SetStepperUnitCommand.cs similarity index 85% rename from src/Cluckwork.Application/Features/Users/SetStepperUnit/SetStepperUnitCommand.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/SetStepperUnitCommand.cs index 3518729d0..a9e75431a 100644 --- a/src/Cluckwork.Application/Features/Users/SetStepperUnit/SetStepperUnitCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/SetStepperUnitCommand.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users.SetStepperUnit; +namespace Cluckwork.Application.Modules.Access.Contracts; // The requested EggUnit's name (e.g. "Tray"), or null to clear the override and // follow the farm default again. Travels as a string like every other diff --git a/src/Cluckwork.Application/Features/Users/SetUserPassword/SetUserPasswordCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/SetUserPasswordCommand.cs similarity index 88% rename from src/Cluckwork.Application/Features/Users/SetUserPassword/SetUserPasswordCommand.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/SetUserPasswordCommand.cs index 9caeaa97f..f3585cd8f 100644 --- a/src/Cluckwork.Application/Features/Users/SetUserPassword/SetUserPasswordCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/SetUserPasswordCommand.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users.SetUserPassword; +namespace Cluckwork.Application.Modules.Access.Contracts; // #165 — an Owner sets another user's password WITHOUT knowing the current one // (the forgot-password path; there is no email reset). Account-scoped in the diff --git a/src/Cluckwork.Application/Features/Users/AssignFlock/UnassignFlockCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/UnassignFlockCommand.cs similarity index 69% rename from src/Cluckwork.Application/Features/Users/AssignFlock/UnassignFlockCommand.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/UnassignFlockCommand.cs index 68cae90b0..7ae42241b 100644 --- a/src/Cluckwork.Application/Features/Users/AssignFlock/UnassignFlockCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/UnassignFlockCommand.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users.AssignFlock; +namespace Cluckwork.Application.Modules.Access.Contracts; [ModuleContract("Access")] public sealed record UnassignFlockCommand( diff --git a/src/Cluckwork.Application/Features/Users/UpdateUser/UpdateUserCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/UpdateUserCommand.cs similarity index 81% rename from src/Cluckwork.Application/Features/Users/UpdateUser/UpdateUserCommand.cs rename to src/Cluckwork.Application/Modules/Access/Contracts/UpdateUserCommand.cs index c64c0504f..9594e5acb 100644 --- a/src/Cluckwork.Application/Features/Users/UpdateUser/UpdateUserCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/UpdateUserCommand.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users.UpdateUser; +namespace Cluckwork.Application.Modules.Access.Contracts; // #163 — edit an existing user's display name. Name is nullable: passing null (or // blank) clears it back to "—". Role/password editing are separate slices. diff --git a/src/Cluckwork.Application/Features/Users/AssignFlock/AssignFlockHandler.cs b/src/Cluckwork.Application/Modules/Access/Users/AssignFlock/AssignFlockHandler.cs similarity index 97% rename from src/Cluckwork.Application/Features/Users/AssignFlock/AssignFlockHandler.cs rename to src/Cluckwork.Application/Modules/Access/Users/AssignFlock/AssignFlockHandler.cs index 5041e0f47..5df64e86d 100644 --- a/src/Cluckwork.Application/Features/Users/AssignFlock/AssignFlockHandler.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/AssignFlock/AssignFlockHandler.cs @@ -1,9 +1,10 @@ using Cluckwork.Application.Common; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Application.Modules.FlockManagement.Contracts; using Cluckwork.Domain.Accounts; using Cluckwork.Domain.Common; -namespace Cluckwork.Application.Features.Users.AssignFlock; +namespace Cluckwork.Application.Modules.Access.Users.AssignFlock; // #103 (spec §5.2/§5.3) — narrow a worker to assigned flocks. The FIRST // assignment flips the user from account-wide (grandfathered) to scoped. diff --git a/src/Cluckwork.Application/Features/Users/ChangeOwnPassword/ChangeOwnPasswordHandler.cs b/src/Cluckwork.Application/Modules/Access/Users/ChangeOwnPassword/ChangeOwnPasswordHandler.cs similarity index 74% rename from src/Cluckwork.Application/Features/Users/ChangeOwnPassword/ChangeOwnPasswordHandler.cs rename to src/Cluckwork.Application/Modules/Access/Users/ChangeOwnPassword/ChangeOwnPasswordHandler.cs index e37211f0c..5bafec55a 100644 --- a/src/Cluckwork.Application/Features/Users/ChangeOwnPassword/ChangeOwnPasswordHandler.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/ChangeOwnPassword/ChangeOwnPasswordHandler.cs @@ -1,7 +1,8 @@ using Cluckwork.Application.Common; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Common; -namespace Cluckwork.Application.Features.Users.ChangeOwnPassword; +namespace Cluckwork.Application.Modules.Access.Users.ChangeOwnPassword; public sealed class ChangeOwnPasswordHandler(IIdentityProvider identity) { diff --git a/src/Cluckwork.Application/Features/Users/ChangeOwnPassword/ChangeOwnPasswordValidator.cs b/src/Cluckwork.Application/Modules/Access/Users/ChangeOwnPassword/ChangeOwnPasswordValidator.cs similarity index 74% rename from src/Cluckwork.Application/Features/Users/ChangeOwnPassword/ChangeOwnPasswordValidator.cs rename to src/Cluckwork.Application/Modules/Access/Users/ChangeOwnPassword/ChangeOwnPasswordValidator.cs index e6a2b862f..a4a6accae 100644 --- a/src/Cluckwork.Application/Features/Users/ChangeOwnPassword/ChangeOwnPasswordValidator.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/ChangeOwnPassword/ChangeOwnPasswordValidator.cs @@ -1,6 +1,7 @@ +using Cluckwork.Application.Modules.Access.Contracts; using FluentValidation; -namespace Cluckwork.Application.Features.Users.ChangeOwnPassword; +namespace Cluckwork.Application.Modules.Access.Users.ChangeOwnPassword; public sealed class ChangeOwnPasswordValidator : AbstractValidator { @@ -10,14 +11,14 @@ public ChangeOwnPasswordValidator() .Must(v => !string.IsNullOrWhiteSpace(v)).WithMessage("Your current password is required.") .WithErrorCode("Me.CurrentPassword.Required") // #309 — bound the verified credential ahead of the PBKDF2 hash. - .MaximumLength(Cluckwork.Application.Features.Users.PasswordRules.MaxLength) + .MaximumLength(Cluckwork.Application.Modules.Access.Users.PasswordRules.MaxLength) .WithErrorCode("Me.CurrentPassword.MaxLength"); RuleFor(x => x.NewPassword) .Must(v => !string.IsNullOrWhiteSpace(v)).WithMessage("A new password is required.") .WithErrorCode("Me.NewPassword.Required") - .MinimumLength(Cluckwork.Application.Features.Users.PasswordRules.MinLength) + .MinimumLength(Cluckwork.Application.Modules.Access.Users.PasswordRules.MinLength) .WithErrorCode("Me.NewPassword.MinLength") - .MaximumLength(Cluckwork.Application.Features.Users.PasswordRules.MaxLength) + .MaximumLength(Cluckwork.Application.Modules.Access.Users.PasswordRules.MaxLength) .WithErrorCode("Me.NewPassword.MaxLength"); // Re-setting the same password would revoke every other session for no // gain, so refuse it outright rather than silently churning the family. diff --git a/src/Cluckwork.Application/Features/Users/ChangeUserEmail/ChangeUserEmailHandler.cs b/src/Cluckwork.Application/Modules/Access/Users/ChangeUserEmail/ChangeUserEmailHandler.cs similarity index 81% rename from src/Cluckwork.Application/Features/Users/ChangeUserEmail/ChangeUserEmailHandler.cs rename to src/Cluckwork.Application/Modules/Access/Users/ChangeUserEmail/ChangeUserEmailHandler.cs index 546fe8844..027e9ea51 100644 --- a/src/Cluckwork.Application/Features/Users/ChangeUserEmail/ChangeUserEmailHandler.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/ChangeUserEmail/ChangeUserEmailHandler.cs @@ -1,7 +1,7 @@ -using Cluckwork.Application.Common; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Common; -namespace Cluckwork.Application.Features.Users.ChangeUserEmail; +namespace Cluckwork.Application.Modules.Access.Users.ChangeUserEmail; public sealed class ChangeUserEmailHandler(IIdentityProvider identity, IStepUpGrantService stepUp) { diff --git a/src/Cluckwork.Application/Features/Users/ChangeUserEmail/ChangeUserEmailValidator.cs b/src/Cluckwork.Application/Modules/Access/Users/ChangeUserEmail/ChangeUserEmailValidator.cs similarity index 83% rename from src/Cluckwork.Application/Features/Users/ChangeUserEmail/ChangeUserEmailValidator.cs rename to src/Cluckwork.Application/Modules/Access/Users/ChangeUserEmail/ChangeUserEmailValidator.cs index a7f76948f..ac0c91be3 100644 --- a/src/Cluckwork.Application/Features/Users/ChangeUserEmail/ChangeUserEmailValidator.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/ChangeUserEmail/ChangeUserEmailValidator.cs @@ -1,6 +1,7 @@ +using Cluckwork.Application.Modules.Access.Contracts; using FluentValidation; -namespace Cluckwork.Application.Features.Users.ChangeUserEmail; +namespace Cluckwork.Application.Modules.Access.Users.ChangeUserEmail; public sealed class ChangeUserEmailValidator : AbstractValidator { diff --git a/src/Cluckwork.Application/Features/Users/ChangeUserRole/ChangeUserRoleHandler.cs b/src/Cluckwork.Application/Modules/Access/Users/ChangeUserRole/ChangeUserRoleHandler.cs similarity index 85% rename from src/Cluckwork.Application/Features/Users/ChangeUserRole/ChangeUserRoleHandler.cs rename to src/Cluckwork.Application/Modules/Access/Users/ChangeUserRole/ChangeUserRoleHandler.cs index 808257afa..248e8edb3 100644 --- a/src/Cluckwork.Application/Features/Users/ChangeUserRole/ChangeUserRoleHandler.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/ChangeUserRole/ChangeUserRoleHandler.cs @@ -1,8 +1,8 @@ -using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users.CreateUser; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users.CreateUser; using Cluckwork.Domain.Common; -namespace Cluckwork.Application.Features.Users.ChangeUserRole; +namespace Cluckwork.Application.Modules.Access.Users.ChangeUserRole; // #355/#360 — every role change mutates a durable authorization set. The role // capability sets are not totally ordered (Worker and Sales grant different diff --git a/src/Cluckwork.Application/Features/Users/ChangeUserRole/ChangeUserRoleValidator.cs b/src/Cluckwork.Application/Modules/Access/Users/ChangeUserRole/ChangeUserRoleValidator.cs similarity index 71% rename from src/Cluckwork.Application/Features/Users/ChangeUserRole/ChangeUserRoleValidator.cs rename to src/Cluckwork.Application/Modules/Access/Users/ChangeUserRole/ChangeUserRoleValidator.cs index 79272f8d5..9d203e2c9 100644 --- a/src/Cluckwork.Application/Features/Users/ChangeUserRole/ChangeUserRoleValidator.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/ChangeUserRole/ChangeUserRoleValidator.cs @@ -1,7 +1,8 @@ -using Cluckwork.Application.Features.Users.CreateUser; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users.CreateUser; using FluentValidation; -namespace Cluckwork.Application.Features.Users.ChangeUserRole; +namespace Cluckwork.Application.Modules.Access.Users.ChangeUserRole; public sealed class ChangeUserRoleValidator : AbstractValidator { diff --git a/src/Cluckwork.Application/Features/Users/CreateUser/CreateUserHandler.cs b/src/Cluckwork.Application/Modules/Access/Users/CreateUser/CreateUserHandler.cs similarity index 91% rename from src/Cluckwork.Application/Features/Users/CreateUser/CreateUserHandler.cs rename to src/Cluckwork.Application/Modules/Access/Users/CreateUser/CreateUserHandler.cs index 9035d1057..724be7c7d 100644 --- a/src/Cluckwork.Application/Features/Users/CreateUser/CreateUserHandler.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/CreateUser/CreateUserHandler.cs @@ -1,8 +1,7 @@ -using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Common; -namespace Cluckwork.Application.Features.Users.CreateUser; +namespace Cluckwork.Application.Modules.Access.Users.CreateUser; // #103 — users are created with any assignable role (spec §5.1), or as a // plain worker ("Worker" = no role row at all). diff --git a/src/Cluckwork.Application/Features/Users/CreateUser/CreateUserValidator.cs b/src/Cluckwork.Application/Modules/Access/Users/CreateUser/CreateUserValidator.cs similarity index 84% rename from src/Cluckwork.Application/Features/Users/CreateUser/CreateUserValidator.cs rename to src/Cluckwork.Application/Modules/Access/Users/CreateUser/CreateUserValidator.cs index 9f10d736a..6e7261cda 100644 --- a/src/Cluckwork.Application/Features/Users/CreateUser/CreateUserValidator.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/CreateUser/CreateUserValidator.cs @@ -1,6 +1,7 @@ +using Cluckwork.Application.Modules.Access.Contracts; using FluentValidation; -namespace Cluckwork.Application.Features.Users.CreateUser; +namespace Cluckwork.Application.Modules.Access.Users.CreateUser; public sealed class CreateUserValidator : AbstractValidator { @@ -24,7 +25,7 @@ public CreateUserValidator() .MinimumLength(12) .WithErrorCode("User.Password.MinLength") // #309 — bound the credential ahead of the PBKDF2 hash. - .MaximumLength(Cluckwork.Application.Features.Users.PasswordRules.MaxLength) + .MaximumLength(Cluckwork.Application.Modules.Access.Users.PasswordRules.MaxLength) .WithErrorCode("User.Password.MaxLength"); RuleFor(x => x.Role) .Must(r => r == WorkerRole || Cluckwork.Domain.Accounts.Roles.Assignable.Contains(r)) @@ -32,7 +33,7 @@ public CreateUserValidator() .WithErrorCode("User.Role.Allowed"); // #163 — Name is optional; only its length is bounded. RuleFor(x => x.Name) - .MaximumLength(Cluckwork.Application.Features.Users.UserName.MaxLength) + .MaximumLength(Cluckwork.Application.Modules.Access.Users.UserName.MaxLength) .WithErrorCode("User.Name.MaxLength") .When(x => x.Name is not null); } diff --git a/src/Cluckwork.Application/Features/Users/DisableUser/DisableUserHandler.cs b/src/Cluckwork.Application/Modules/Access/Users/DisableUser/DisableUserHandler.cs similarity index 94% rename from src/Cluckwork.Application/Features/Users/DisableUser/DisableUserHandler.cs rename to src/Cluckwork.Application/Modules/Access/Users/DisableUser/DisableUserHandler.cs index 2e511578d..5be92ae39 100644 --- a/src/Cluckwork.Application/Features/Users/DisableUser/DisableUserHandler.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/DisableUser/DisableUserHandler.cs @@ -1,7 +1,7 @@ -using Cluckwork.Application.Common; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Common; -namespace Cluckwork.Application.Features.Users.DisableUser; +namespace Cluckwork.Application.Modules.Access.Users.DisableUser; // #356 — disable a user. Step-up (#308) is required UNCONDITIONALLY, in both // directions: unlike a role change, where demoting a Sales user to ReadOnly is diff --git a/src/Cluckwork.Application/Features/Users/DisableUser/DisableUserValidator.cs b/src/Cluckwork.Application/Modules/Access/Users/DisableUser/DisableUserValidator.cs similarity index 87% rename from src/Cluckwork.Application/Features/Users/DisableUser/DisableUserValidator.cs rename to src/Cluckwork.Application/Modules/Access/Users/DisableUser/DisableUserValidator.cs index a63862fda..4600b901e 100644 --- a/src/Cluckwork.Application/Features/Users/DisableUser/DisableUserValidator.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/DisableUser/DisableUserValidator.cs @@ -1,6 +1,7 @@ +using Cluckwork.Application.Modules.Access.Contracts; using FluentValidation; -namespace Cluckwork.Application.Features.Users.DisableUser; +namespace Cluckwork.Application.Modules.Access.Users.DisableUser; public sealed class DisableUserValidator : AbstractValidator { diff --git a/src/Cluckwork.Application/Features/Users/EnableUser/EnableUserHandler.cs b/src/Cluckwork.Application/Modules/Access/Users/EnableUser/EnableUserHandler.cs similarity index 86% rename from src/Cluckwork.Application/Features/Users/EnableUser/EnableUserHandler.cs rename to src/Cluckwork.Application/Modules/Access/Users/EnableUser/EnableUserHandler.cs index 9d3f073ab..92dd86e25 100644 --- a/src/Cluckwork.Application/Features/Users/EnableUser/EnableUserHandler.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/EnableUser/EnableUserHandler.cs @@ -1,7 +1,7 @@ -using Cluckwork.Application.Common; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Common; -namespace Cluckwork.Application.Features.Users.EnableUser; +namespace Cluckwork.Application.Modules.Access.Users.EnableUser; // #356 — re-enable a disabled user. There is deliberately no validator: the // command carries no free-text field, only the route's id and the step-up diff --git a/src/Cluckwork.Application/Common/IIdentityProvider.cs b/src/Cluckwork.Application/Modules/Access/Users/IIdentityProvider.cs similarity index 99% rename from src/Cluckwork.Application/Common/IIdentityProvider.cs rename to src/Cluckwork.Application/Modules/Access/Users/IIdentityProvider.cs index 02b90408b..61ea7079b 100644 --- a/src/Cluckwork.Application/Common/IIdentityProvider.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/IIdentityProvider.cs @@ -1,6 +1,7 @@ +using Cluckwork.Application.Common; using Cluckwork.Domain.Modules.Commerce.Contracts; -namespace Cluckwork.Application.Common; +namespace Cluckwork.Application.Modules.Access.Users; // Port — abstraction over ASP.NET Core Identity + JWT. Swap to Keycloak/Entra // in a future IIdentityProvider implementation without touching Application. diff --git a/src/Cluckwork.Application/Common/IStepUpGrantService.cs b/src/Cluckwork.Application/Modules/Access/Users/IStepUpGrantService.cs similarity index 89% rename from src/Cluckwork.Application/Common/IStepUpGrantService.cs rename to src/Cluckwork.Application/Modules/Access/Users/IStepUpGrantService.cs index e9de17bad..7f5699ceb 100644 --- a/src/Cluckwork.Application/Common/IStepUpGrantService.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/IStepUpGrantService.cs @@ -1,6 +1,7 @@ +using Cluckwork.Application.Common; using Cluckwork.Domain.Common; -namespace Cluckwork.Application.Common; +namespace Cluckwork.Application.Modules.Access.Users; // #308/#360/#606 — recent-authentication proof required for every interactive // user creation, administrative password reset, role change (#355), @@ -9,7 +10,7 @@ namespace Cluckwork.Application.Common; // current password // (IssueAsync) and is a short-lived, single-use, audience-limited credential // distinct from the normal access token. See the threat-model comment on -// Cluckwork.Infrastructure.Identity.StepUpGrantService for the full design. +// Cluckwork.Infrastructure.Modules.Access.Identity.StepUpGrantService for the full design. public interface IStepUpGrantService { // Verifies currentPassword for (accountId, userId) and mints a grant bound diff --git a/src/Cluckwork.Application/Features/Users/IUserRoleAssignmentRepository.cs b/src/Cluckwork.Application/Modules/Access/Users/IUserRoleAssignmentRepository.cs similarity index 90% rename from src/Cluckwork.Application/Features/Users/IUserRoleAssignmentRepository.cs rename to src/Cluckwork.Application/Modules/Access/Users/IUserRoleAssignmentRepository.cs index 166fd91c3..8976f0829 100644 --- a/src/Cluckwork.Application/Features/Users/IUserRoleAssignmentRepository.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/IUserRoleAssignmentRepository.cs @@ -1,6 +1,6 @@ using Cluckwork.Domain.Accounts; -namespace Cluckwork.Application.Features.Users; +namespace Cluckwork.Application.Modules.Access.Users; public interface IUserRoleAssignmentRepository { diff --git a/src/Cluckwork.Application/Features/Users/PasswordRules.cs b/src/Cluckwork.Application/Modules/Access/Users/PasswordRules.cs similarity index 93% rename from src/Cluckwork.Application/Features/Users/PasswordRules.cs rename to src/Cluckwork.Application/Modules/Access/Users/PasswordRules.cs index 867bb9f57..d91938710 100644 --- a/src/Cluckwork.Application/Features/Users/PasswordRules.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/PasswordRules.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users; +namespace Cluckwork.Application.Modules.Access.Users; // #165 — one place for the new-password bound shared by create, admin-set and // self-service change. Identity enforces the full policy (upper/lower/digit/ diff --git a/src/Cluckwork.Application/Features/Users/SetLanguage/SetLanguageHandler.cs b/src/Cluckwork.Application/Modules/Access/Users/SetLanguage/SetLanguageHandler.cs similarity index 79% rename from src/Cluckwork.Application/Features/Users/SetLanguage/SetLanguageHandler.cs rename to src/Cluckwork.Application/Modules/Access/Users/SetLanguage/SetLanguageHandler.cs index da9c9b91b..8d566f867 100644 --- a/src/Cluckwork.Application/Features/Users/SetLanguage/SetLanguageHandler.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/SetLanguage/SetLanguageHandler.cs @@ -1,7 +1,7 @@ -using Cluckwork.Application.Common; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Common; -namespace Cluckwork.Application.Features.Users.SetLanguage; +namespace Cluckwork.Application.Modules.Access.Users.SetLanguage; // The user id comes from the token (the endpoint), never the body: a caller can // only ever set their OWN language. Account-scoped inside the provider. diff --git a/src/Cluckwork.Application/Features/Users/SetLanguage/SetLanguageValidator.cs b/src/Cluckwork.Application/Modules/Access/Users/SetLanguage/SetLanguageValidator.cs similarity index 88% rename from src/Cluckwork.Application/Features/Users/SetLanguage/SetLanguageValidator.cs rename to src/Cluckwork.Application/Modules/Access/Users/SetLanguage/SetLanguageValidator.cs index 843d40892..83d3178f4 100644 --- a/src/Cluckwork.Application/Features/Users/SetLanguage/SetLanguageValidator.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/SetLanguage/SetLanguageValidator.cs @@ -1,7 +1,8 @@ +using Cluckwork.Application.Modules.Access.Contracts; using System.Text.RegularExpressions; using FluentValidation; -namespace Cluckwork.Application.Features.Users.SetLanguage; +namespace Cluckwork.Application.Modules.Access.Users.SetLanguage; public sealed partial class SetLanguageValidator : AbstractValidator { diff --git a/src/Cluckwork.Application/Features/Users/SetStepperUnit/SetStepperUnitHandler.cs b/src/Cluckwork.Application/Modules/Access/Users/SetStepperUnit/SetStepperUnitHandler.cs similarity index 92% rename from src/Cluckwork.Application/Features/Users/SetStepperUnit/SetStepperUnitHandler.cs rename to src/Cluckwork.Application/Modules/Access/Users/SetStepperUnit/SetStepperUnitHandler.cs index 5702c4a3b..3cd302abb 100644 --- a/src/Cluckwork.Application/Features/Users/SetStepperUnit/SetStepperUnitHandler.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/SetStepperUnit/SetStepperUnitHandler.cs @@ -1,9 +1,9 @@ -using Cluckwork.Application.Common; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Application.Modules.Commerce.Contracts; using Cluckwork.Domain.Common; using Cluckwork.Domain.Modules.Commerce.Contracts; -namespace Cluckwork.Application.Features.Users.SetStepperUnit; +namespace Cluckwork.Application.Modules.Access.Users.SetStepperUnit; // The user id comes from the token (the endpoint), never the body: a caller can // only ever set their OWN stepper-unit preference. Account-scoped inside the diff --git a/src/Cluckwork.Application/Features/Users/SetStepperUnit/SetStepperUnitValidator.cs b/src/Cluckwork.Application/Modules/Access/Users/SetStepperUnit/SetStepperUnitValidator.cs similarity index 89% rename from src/Cluckwork.Application/Features/Users/SetStepperUnit/SetStepperUnitValidator.cs rename to src/Cluckwork.Application/Modules/Access/Users/SetStepperUnit/SetStepperUnitValidator.cs index 5147ef51a..f29ae8cf6 100644 --- a/src/Cluckwork.Application/Features/Users/SetStepperUnit/SetStepperUnitValidator.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/SetStepperUnit/SetStepperUnitValidator.cs @@ -1,7 +1,8 @@ +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Modules.Commerce.Contracts; using FluentValidation; -namespace Cluckwork.Application.Features.Users.SetStepperUnit; +namespace Cluckwork.Application.Modules.Access.Users.SetStepperUnit; public sealed class SetStepperUnitValidator : AbstractValidator { diff --git a/src/Cluckwork.Application/Features/Users/SetUserPassword/SetUserPasswordHandler.cs b/src/Cluckwork.Application/Modules/Access/Users/SetUserPassword/SetUserPasswordHandler.cs similarity index 89% rename from src/Cluckwork.Application/Features/Users/SetUserPassword/SetUserPasswordHandler.cs rename to src/Cluckwork.Application/Modules/Access/Users/SetUserPassword/SetUserPasswordHandler.cs index 05e5850d0..d69eba58c 100644 --- a/src/Cluckwork.Application/Features/Users/SetUserPassword/SetUserPasswordHandler.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/SetUserPassword/SetUserPasswordHandler.cs @@ -1,7 +1,7 @@ -using Cluckwork.Application.Common; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Common; -namespace Cluckwork.Application.Features.Users.SetUserPassword; +namespace Cluckwork.Application.Modules.Access.Users.SetUserPassword; // #165 base behaviour; #308/#360 — every administrative reset replaces an // authenticator and can turn a short-lived stolen Owner token into an diff --git a/src/Cluckwork.Application/Features/Users/SetUserPassword/SetUserPasswordValidator.cs b/src/Cluckwork.Application/Modules/Access/Users/SetUserPassword/SetUserPasswordValidator.cs similarity index 63% rename from src/Cluckwork.Application/Features/Users/SetUserPassword/SetUserPasswordValidator.cs rename to src/Cluckwork.Application/Modules/Access/Users/SetUserPassword/SetUserPasswordValidator.cs index 37df0e72b..915abe9ee 100644 --- a/src/Cluckwork.Application/Features/Users/SetUserPassword/SetUserPasswordValidator.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/SetUserPassword/SetUserPasswordValidator.cs @@ -1,6 +1,7 @@ +using Cluckwork.Application.Modules.Access.Contracts; using FluentValidation; -namespace Cluckwork.Application.Features.Users.SetUserPassword; +namespace Cluckwork.Application.Modules.Access.Users.SetUserPassword; public sealed class SetUserPasswordValidator : AbstractValidator { @@ -9,10 +10,10 @@ public SetUserPasswordValidator() RuleFor(x => x.NewPassword) .Must(v => !string.IsNullOrWhiteSpace(v)).WithMessage("A new password is required.") .WithErrorCode("User.NewPassword.Required") - .MinimumLength(Cluckwork.Application.Features.Users.PasswordRules.MinLength) + .MinimumLength(Cluckwork.Application.Modules.Access.Users.PasswordRules.MinLength) .WithErrorCode("User.NewPassword.MinLength") // #309 — bound the credential ahead of the PBKDF2 hash. - .MaximumLength(Cluckwork.Application.Features.Users.PasswordRules.MaxLength) + .MaximumLength(Cluckwork.Application.Modules.Access.Users.PasswordRules.MaxLength) .WithErrorCode("User.NewPassword.MaxLength"); } } diff --git a/src/Cluckwork.Application/Features/Users/UpdateUser/UpdateUserHandler.cs b/src/Cluckwork.Application/Modules/Access/Users/UpdateUser/UpdateUserHandler.cs similarity index 77% rename from src/Cluckwork.Application/Features/Users/UpdateUser/UpdateUserHandler.cs rename to src/Cluckwork.Application/Modules/Access/Users/UpdateUser/UpdateUserHandler.cs index de9d7b997..8cd0aa9c0 100644 --- a/src/Cluckwork.Application/Features/Users/UpdateUser/UpdateUserHandler.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/UpdateUser/UpdateUserHandler.cs @@ -1,8 +1,7 @@ -using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Common; -namespace Cluckwork.Application.Features.Users.UpdateUser; +namespace Cluckwork.Application.Modules.Access.Users.UpdateUser; // #163 — the update is scoped to the caller's account inside the provider, so a // user id from another tenant resolves to NotFound, never a cross-account edit. diff --git a/src/Cluckwork.Application/Features/Users/UpdateUser/UpdateUserValidator.cs b/src/Cluckwork.Application/Modules/Access/Users/UpdateUser/UpdateUserValidator.cs similarity index 56% rename from src/Cluckwork.Application/Features/Users/UpdateUser/UpdateUserValidator.cs rename to src/Cluckwork.Application/Modules/Access/Users/UpdateUser/UpdateUserValidator.cs index ecf5ff41e..2c57cc3e9 100644 --- a/src/Cluckwork.Application/Features/Users/UpdateUser/UpdateUserValidator.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/UpdateUser/UpdateUserValidator.cs @@ -1,13 +1,14 @@ +using Cluckwork.Application.Modules.Access.Contracts; using FluentValidation; -namespace Cluckwork.Application.Features.Users.UpdateUser; +namespace Cluckwork.Application.Modules.Access.Users.UpdateUser; public sealed class UpdateUserValidator : AbstractValidator { public UpdateUserValidator() { RuleFor(x => x.Name) - .MaximumLength(Cluckwork.Application.Features.Users.UserName.MaxLength) + .MaximumLength(Cluckwork.Application.Modules.Access.Users.UserName.MaxLength) .WithErrorCode("User.Name.MaxLength") .When(x => x.Name is not null); } diff --git a/src/Cluckwork.Application/Features/Users/UserName.cs b/src/Cluckwork.Application/Modules/Access/Users/UserName.cs similarity index 89% rename from src/Cluckwork.Application/Features/Users/UserName.cs rename to src/Cluckwork.Application/Modules/Access/Users/UserName.cs index 89a814a85..2a0eb2d7c 100644 --- a/src/Cluckwork.Application/Features/Users/UserName.cs +++ b/src/Cluckwork.Application/Modules/Access/Users/UserName.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Application.Features.Users; +namespace Cluckwork.Application.Modules.Access.Users; // #163 — one place for the display-name rule shared by create and update: trim // surrounding whitespace, and treat blank as "no name" (null) so a cleared field diff --git a/src/Cluckwork.Application/Modules/Commerce/Sales/ConfirmSale/ConfirmSaleHandler.cs b/src/Cluckwork.Application/Modules/Commerce/Sales/ConfirmSale/ConfirmSaleHandler.cs index 42fba893b..e1891ba3a 100644 --- a/src/Cluckwork.Application/Modules/Commerce/Sales/ConfirmSale/ConfirmSaleHandler.cs +++ b/src/Cluckwork.Application/Modules/Commerce/Sales/ConfirmSale/ConfirmSaleHandler.cs @@ -1,10 +1,10 @@ +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Application.Modules.Commerce.Contracts; using Cluckwork.Application.Modules.EggOperations.Contracts; using Cluckwork.Domain.Modules.Commerce.Sales; using System.Globalization; using Cluckwork.Application.Common; using Cluckwork.Application.Features.Accounts; -using Cluckwork.Application.Features.Users; using Cluckwork.Domain.Accounts; using Cluckwork.Domain.Common; using Microsoft.Extensions.Logging; diff --git a/src/Cluckwork.Domain/Common/Architecture/Modules/Access.cs b/src/Cluckwork.Domain/Common/Architecture/Modules/Access.cs index 32983d2b2..f09672ea0 100644 --- a/src/Cluckwork.Domain/Common/Architecture/Modules/Access.cs +++ b/src/Cluckwork.Domain/Common/Architecture/Modules/Access.cs @@ -2,54 +2,50 @@ namespace Cluckwork.Domain.Common.Architecture; [ModuleOwner("Access", "module", Namespaces = [ - "Cluckwork.Application.Features.Users", - "Cluckwork.Infrastructure.Identity", + "Cluckwork.Application.Modules.Access", + "Cluckwork.Infrastructure.Modules.Access", ], Implementations = [ "Cluckwork.Infrastructure.Repositories.UserRoleAssignmentRepository", - ], - Types = [ - "Cluckwork.Application.Common.IIdentityProvider", - "Cluckwork.Application.Common.IStepUpGrantService", ])] [ModuleEdge( "Access", "Commerce", "W", "W because AccountProvisioner inserts EggUnitConversion.Defaults for a new farm inside its provisioning transaction; the rest of the cell reads. Identity carries the per-user stepper-unit preference: ApplicationUser stores Domain.Catalog.EggUnit, IIdentityProvider, the Identity port Access claims, takes it in SetStepperUnitAsync, IdentityProvider reads and writes it, SetStepperUnitHandler resolves it through Commerce's IEggUnitConversionLookup port (#854) and rejects inactive conversions, and SetStepperUnitValidator validates only the enum name. Nothing prevents a stored preference from pointing at a conversion later deactivated through UpdateEggUnitConversionHandler. Design 3.4 shows Access -> Commerce as none; this is live coupling the target design has still to remove.", - "Cluckwork.Application.Common.IIdentityProvider", - "Cluckwork.Application.Features.Users.SetStepperUnit.SetStepperUnitHandler", - "Cluckwork.Application.Features.Users.SetStepperUnit.SetStepperUnitValidator", - "Cluckwork.Infrastructure.Identity.AccountProvisioner", - "Cluckwork.Infrastructure.Identity.ApplicationUser", - "Cluckwork.Infrastructure.Identity.IdentityProvider")] + "Cluckwork.Application.Modules.Access.Users.IIdentityProvider", + "Cluckwork.Application.Modules.Access.Users.SetStepperUnit.SetStepperUnitHandler", + "Cluckwork.Application.Modules.Access.Users.SetStepperUnit.SetStepperUnitValidator", + "Cluckwork.Infrastructure.Modules.Access.Identity.AccountProvisioner", + "Cluckwork.Infrastructure.Modules.Access.Identity.ApplicationUser", + "Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider")] [ModuleEdge( "Access", "EggOperations", "W", "W because AccountProvisioner inserts a new farm's default grades, Domain.Eggs.EggGrade.Defaults(accountId, SeedDefaults.FarmId), inside its provisioning transaction, so farm provisioning writes Egg Operations' table and depends on its grade shape. Design 3.4 shows Access -> Egg Ops as none; this is live coupling the target design has still to remove.", - "Cluckwork.Infrastructure.Identity.AccountProvisioner")] + "Cluckwork.Infrastructure.Modules.Access.Identity.AccountProvisioner")] [ModuleEdge( "Access", "Farm", "W", "W because AccountProvisioner inserts the new Account inside its provisioning transaction and AccountRenameService calls Account.Rename and saves; the rest of the cell reads. Identity is where a farm is created, renamed, suspended and recovered. AccountProvisioner, AccountRenameService, AccountSuspensionService, AdminRecoveryService, FirstRunAdminService and FirstRunStatusService load Domain.Accounts.Account or inject Farm's IAccountRepository, and IdentityProvider takes that repository by fully qualified name for the account-scoped login (#532). CredentialEpochVerifier reads Account.IsActive in the same fresh per-request query as the user's credential epoch, so a suspended farm's credentials stop working at once (#364, #579, #857). The user validators read Domain.Accounts.Roles for the assignable role set, and IUserRoleAssignmentRepository returns Domain.Accounts.UserRoleAssignment rows, which AccessModule reads to list a user's flock assignments. IAccessLookup returns Domain.Accounts.EffectiveAccountRole, and AccessLookup resolves it with Roles.ResolveEffective in its private effective-role routine (#612, #857). Design 3.4 row Access -> Farm = R. AccessFixture (#858) creates the simulation fixture's UserRoleAssignment through the scoped context, and AccessSeedLookup checks the fixture's Owner role by Roles.Owner.", - "Cluckwork.Application.Features.Users.AssignFlock.AssignFlockHandler", - "Cluckwork.Application.Features.Users.AssignFlock.UnassignFlockHandler", - "Cluckwork.Application.Features.Users.ChangeUserRole.ChangeUserRoleValidator", - "Cluckwork.Application.Features.Users.CreateUser.CreateUserValidator", - "Cluckwork.Application.Features.Users.IAccessLookup", - "Cluckwork.Application.Features.Users.IUserRoleAssignmentRepository", - "Cluckwork.Infrastructure.Identity.AccessFixture", - "Cluckwork.Infrastructure.Identity.AccessLookup", - "Cluckwork.Infrastructure.Identity.AccessModule", - "Cluckwork.Infrastructure.Identity.AccessSeedLookup", - "Cluckwork.Infrastructure.Identity.AccountProvisioner", - "Cluckwork.Infrastructure.Identity.AccountRenameService", - "Cluckwork.Infrastructure.Identity.AccountSuspensionService", - "Cluckwork.Infrastructure.Identity.AdminRecoveryService", - "Cluckwork.Infrastructure.Identity.CredentialEpochVerifier", - "Cluckwork.Infrastructure.Identity.FirstRunAdminService", - "Cluckwork.Infrastructure.Identity.FirstRunStatusService", - "Cluckwork.Infrastructure.Identity.IdentityProvider")] + "Cluckwork.Application.Modules.Access.Users.AssignFlock.AssignFlockHandler", + "Cluckwork.Application.Modules.Access.Users.AssignFlock.UnassignFlockHandler", + "Cluckwork.Application.Modules.Access.Users.ChangeUserRole.ChangeUserRoleValidator", + "Cluckwork.Application.Modules.Access.Users.CreateUser.CreateUserValidator", + "Cluckwork.Application.Modules.Access.Contracts.IAccessLookup", + "Cluckwork.Application.Modules.Access.Users.IUserRoleAssignmentRepository", + "Cluckwork.Infrastructure.Modules.Access.Identity.AccessFixture", + "Cluckwork.Infrastructure.Modules.Access.Identity.AccessLookup", + "Cluckwork.Infrastructure.Modules.Access.Identity.AccessModule", + "Cluckwork.Infrastructure.Modules.Access.Identity.AccessSeedLookup", + "Cluckwork.Infrastructure.Modules.Access.Identity.AccountProvisioner", + "Cluckwork.Infrastructure.Modules.Access.Identity.AccountRenameService", + "Cluckwork.Infrastructure.Modules.Access.Identity.AccountSuspensionService", + "Cluckwork.Infrastructure.Modules.Access.Identity.AdminRecoveryService", + "Cluckwork.Infrastructure.Modules.Access.Identity.CredentialEpochVerifier", + "Cluckwork.Infrastructure.Modules.Access.Identity.FirstRunAdminService", + "Cluckwork.Infrastructure.Modules.Access.Identity.FirstRunStatusService", + "Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider")] [ModuleEdge( "Access", "FlockManagement", "R", "AssignFlockHandler injects Flock Management's IFlockLookup port to prove the flock exists before narrowing a worker to it and to name it in the audit row (#103, spec 5.2/5.3). Design 3.4 row Access -> Flock = R. AccessFixture (#858) reads the same port for the simulation fixture's assignment and audit row. AccessModule names a user's flock assignments through IFlockLookup.GetDisplayNamesAsync, one bounded read whose filters decide which names the caller sees (#613, #859).", - "Cluckwork.Application.Features.Users.AssignFlock.AssignFlockHandler", - "Cluckwork.Infrastructure.Identity.AccessFixture", - "Cluckwork.Infrastructure.Identity.AccessModule")] + "Cluckwork.Application.Modules.Access.Users.AssignFlock.AssignFlockHandler", + "Cluckwork.Infrastructure.Modules.Access.Identity.AccessFixture", + "Cluckwork.Infrastructure.Modules.Access.Identity.AccessModule")] internal static class AccessModuleRules { } diff --git a/src/Cluckwork.Infrastructure/Jobs/RefreshTokenPurgeSweep.cs b/src/Cluckwork.Infrastructure/Jobs/RefreshTokenPurgeSweep.cs index a11d80ab3..8b2aff7a7 100644 --- a/src/Cluckwork.Infrastructure/Jobs/RefreshTokenPurgeSweep.cs +++ b/src/Cluckwork.Infrastructure/Jobs/RefreshTokenPurgeSweep.cs @@ -1,4 +1,4 @@ -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; diff --git a/src/Cluckwork.Infrastructure/Identity/AccessAccountLifecycle.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessAccountLifecycle.cs similarity index 88% rename from src/Cluckwork.Infrastructure/Identity/AccessAccountLifecycle.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessAccountLifecycle.cs index d3ca03399..d42f1472d 100644 --- a/src/Cluckwork.Infrastructure/Identity/AccessAccountLifecycle.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessAccountLifecycle.cs @@ -1,7 +1,7 @@ -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Common; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // Lifecycle verbs must remain independent of the credential and shared-state graph. public sealed class AccessAccountLifecycle( diff --git a/src/Cluckwork.Infrastructure/Identity/AccessFixture.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessFixture.cs similarity index 93% rename from src/Cluckwork.Infrastructure/Identity/AccessFixture.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessFixture.cs index 1141fdf44..06212ec7c 100644 --- a/src/Cluckwork.Infrastructure/Identity/AccessFixture.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessFixture.cs @@ -1,11 +1,11 @@ using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Application.Modules.FlockManagement.Contracts; using Cluckwork.Domain.Accounts; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; public sealed class AccessFixture(AppDbContext db, IFlockLookup flocks, IAuditWriter audit) : IAccessFixture { diff --git a/src/Cluckwork.Infrastructure/Identity/AccessLookup.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessLookup.cs similarity index 95% rename from src/Cluckwork.Infrastructure/Identity/AccessLookup.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessLookup.cs index e59c21544..e4dda6cdc 100644 --- a/src/Cluckwork.Infrastructure/Identity/AccessLookup.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessLookup.cs @@ -1,9 +1,9 @@ -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Accounts; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // #857 — depends on the request's scoped AppDbContext and the scoped // TenantContext its query filter reads, and nothing else, because the diff --git a/src/Cluckwork.Infrastructure/Identity/AccessModule.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessModule.cs similarity index 87% rename from src/Cluckwork.Infrastructure/Identity/AccessModule.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessModule.cs index b2ba81d1e..4c0407d7f 100644 --- a/src/Cluckwork.Infrastructure/Identity/AccessModule.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessModule.cs @@ -1,21 +1,22 @@ using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; -using Cluckwork.Application.Features.Users.AssignFlock; -using Cluckwork.Application.Features.Users.ChangeOwnPassword; -using Cluckwork.Application.Features.Users.ChangeUserEmail; -using Cluckwork.Application.Features.Users.ChangeUserRole; -using Cluckwork.Application.Features.Users.CreateUser; -using Cluckwork.Application.Features.Users.DisableUser; -using Cluckwork.Application.Features.Users.EnableUser; -using Cluckwork.Application.Features.Users.SetLanguage; -using Cluckwork.Application.Features.Users.SetStepperUnit; -using Cluckwork.Application.Features.Users.SetUserPassword; -using Cluckwork.Application.Features.Users.UpdateUser; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users; +using Cluckwork.Application.Modules.Access.Users.AssignFlock; +using Cluckwork.Application.Modules.Access.Users.ChangeOwnPassword; +using Cluckwork.Application.Modules.Access.Users.ChangeUserEmail; +using Cluckwork.Application.Modules.Access.Users.ChangeUserRole; +using Cluckwork.Application.Modules.Access.Users.CreateUser; +using Cluckwork.Application.Modules.Access.Users.DisableUser; +using Cluckwork.Application.Modules.Access.Users.EnableUser; +using Cluckwork.Application.Modules.Access.Users.SetLanguage; +using Cluckwork.Application.Modules.Access.Users.SetStepperUnit; +using Cluckwork.Application.Modules.Access.Users.SetUserPassword; +using Cluckwork.Application.Modules.Access.Users.UpdateUser; using Cluckwork.Application.Modules.FlockManagement.Contracts; using Cluckwork.Domain.Common; using Microsoft.Extensions.Options; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // #857 — lives in Infrastructure because the session members read Identity // configuration and services. It takes IIdentityProvider from DI, never diff --git a/src/Cluckwork.Infrastructure/Identity/AccessOperations.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessOperations.cs similarity index 87% rename from src/Cluckwork.Infrastructure/Identity/AccessOperations.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessOperations.cs index d833f8ad5..e2629fe18 100644 --- a/src/Cluckwork.Infrastructure/Identity/AccessOperations.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessOperations.cs @@ -1,8 +1,8 @@ -using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users; using Cluckwork.Domain.Common; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; public sealed class AccessOperations( FirstRunAdminService firstRunAdmin, diff --git a/src/Cluckwork.Infrastructure/Identity/AccessSeedLookup.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessSeedLookup.cs similarity index 93% rename from src/Cluckwork.Infrastructure/Identity/AccessSeedLookup.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessSeedLookup.cs index 4f0bb3410..7ae2625c3 100644 --- a/src/Cluckwork.Infrastructure/Identity/AccessSeedLookup.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccessSeedLookup.cs @@ -1,10 +1,10 @@ -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Accounts; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; public sealed class AccessSeedLookup( IAccountUserDirectory directory, diff --git a/src/Cluckwork.Infrastructure/Identity/AccountLockout.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountLockout.cs similarity index 99% rename from src/Cluckwork.Infrastructure/Identity/AccountLockout.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountLockout.cs index 28d9946b3..aa316f3f9 100644 --- a/src/Cluckwork.Infrastructure/Identity/AccountLockout.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountLockout.cs @@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // #128 per-account lockout, shared by EVERY password-verification oracle rather // than living inside one of them. diff --git a/src/Cluckwork.Infrastructure/Identity/AccountProvisioner.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountProvisioner.cs similarity index 98% rename from src/Cluckwork.Infrastructure/Identity/AccountProvisioner.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountProvisioner.cs index 55e90f9e9..c960ec2e1 100644 --- a/src/Cluckwork.Infrastructure/Identity/AccountProvisioner.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountProvisioner.cs @@ -1,6 +1,7 @@ using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; using Cluckwork.Application.Features.Accounts; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users; using Cluckwork.Domain.Accounts; using Cluckwork.Domain.Common; using Cluckwork.Domain.Modules.Commerce.Catalog; @@ -9,7 +10,7 @@ using Microsoft.EntityFrameworkCore; using Npgsql; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; public sealed class AccountProvisioner( AppDbContext db, diff --git a/src/Cluckwork.Infrastructure/Identity/AccountRenameService.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountRenameService.cs similarity index 98% rename from src/Cluckwork.Infrastructure/Identity/AccountRenameService.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountRenameService.cs index 592a3efe2..39b763b0c 100644 --- a/src/Cluckwork.Infrastructure/Identity/AccountRenameService.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountRenameService.cs @@ -1,12 +1,12 @@ using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; using Cluckwork.Application.Features.Accounts; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Accounts; using Cluckwork.Domain.Common; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // #732 — changes a farm's code. The operator surface is the `rename-account` verb; this is // the domain path that replaces the guarded raw UPDATE #731 documented, which bumped diff --git a/src/Cluckwork.Infrastructure/Identity/AccountScopedUserValidator.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountScopedUserValidator.cs similarity index 99% rename from src/Cluckwork.Infrastructure/Identity/AccountScopedUserValidator.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountScopedUserValidator.cs index 90d879f78..0a0df788c 100644 --- a/src/Cluckwork.Infrastructure/Identity/AccountScopedUserValidator.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountScopedUserValidator.cs @@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // #532 — REPLACES Identity's stock UserValidator. It does not // run beside it, and that distinction is the whole point: UserManager runs diff --git a/src/Cluckwork.Infrastructure/Identity/AccountSuspensionService.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountSuspensionService.cs similarity index 99% rename from src/Cluckwork.Infrastructure/Identity/AccountSuspensionService.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountSuspensionService.cs index 2a1321d55..afe5320b0 100644 --- a/src/Cluckwork.Infrastructure/Identity/AccountSuspensionService.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountSuspensionService.cs @@ -1,11 +1,11 @@ using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; using Cluckwork.Application.Features.Accounts; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Common; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // #532 — takes a farm offline and brings it back. #534 ships the operator verbs // (`suspend-account` / `reactivate-account`) that call this. Shipping it diff --git a/src/Cluckwork.Infrastructure/Identity/AccountUserDirectory.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountUserDirectory.cs similarity index 98% rename from src/Cluckwork.Infrastructure/Identity/AccountUserDirectory.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountUserDirectory.cs index 072011a76..65453fa19 100644 --- a/src/Cluckwork.Infrastructure/Identity/AccountUserDirectory.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountUserDirectory.cs @@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // #532 — the ONE place production code resolves a user by an ambiguous // identifier. Once an email can exist in several farms, every globally scoped diff --git a/src/Cluckwork.Infrastructure/Identity/AdminRecoveryService.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AdminRecoveryService.cs similarity index 98% rename from src/Cluckwork.Infrastructure/Identity/AdminRecoveryService.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/AdminRecoveryService.cs index e41963c62..b58e4c307 100644 --- a/src/Cluckwork.Infrastructure/Identity/AdminRecoveryService.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AdminRecoveryService.cs @@ -1,12 +1,13 @@ using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; using Cluckwork.Application.Features.Accounts; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users; using Cluckwork.Domain.Common; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // #265 — offline break-glass account recovery. Motivating case: a single-Owner // farm loses its password and there is no email/SMTP reset path, so the only diff --git a/src/Cluckwork.Infrastructure/Identity/ApplicationRole.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/ApplicationRole.cs similarity index 76% rename from src/Cluckwork.Infrastructure/Identity/ApplicationRole.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/ApplicationRole.cs index 48458181b..4b5f6fe5a 100644 --- a/src/Cluckwork.Infrastructure/Identity/ApplicationRole.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/ApplicationRole.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Identity; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; public sealed class ApplicationRole : IdentityRole { diff --git a/src/Cluckwork.Infrastructure/Identity/ApplicationUser.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/ApplicationUser.cs similarity index 97% rename from src/Cluckwork.Infrastructure/Identity/ApplicationUser.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/ApplicationUser.cs index 38662b182..1b7d5f914 100644 --- a/src/Cluckwork.Infrastructure/Identity/ApplicationUser.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/ApplicationUser.cs @@ -2,7 +2,7 @@ using Cluckwork.Domain.Modules.Commerce.Contracts; using Microsoft.AspNetCore.Identity; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; public sealed class ApplicationUser : IdentityUser, IMutableRecord { diff --git a/src/Cluckwork.Infrastructure/Identity/AuthSecurityEventLogger.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AuthSecurityEventLogger.cs similarity index 97% rename from src/Cluckwork.Infrastructure/Identity/AuthSecurityEventLogger.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/AuthSecurityEventLogger.cs index a68b6a10c..017233783 100644 --- a/src/Cluckwork.Infrastructure/Identity/AuthSecurityEventLogger.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/AuthSecurityEventLogger.cs @@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // #273 codex review (P1b) — single emission point for the LoginFailed / // AccountLockedOut security events, shared by EVERY password-verification diff --git a/src/Cluckwork.Infrastructure/Identity/CredentialEpochVerifier.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/CredentialEpochVerifier.cs similarity index 96% rename from src/Cluckwork.Infrastructure/Identity/CredentialEpochVerifier.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/CredentialEpochVerifier.cs index 19a9c7b72..3bc3c5b60 100644 --- a/src/Cluckwork.Infrastructure/Identity/CredentialEpochVerifier.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/CredentialEpochVerifier.cs @@ -1,9 +1,9 @@ -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Accounts; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // #364/#857 — the read behind CredentialEpochMiddleware. Scoped and stateless; // see ICredentialEpochVerifier for why it must stay that way. diff --git a/src/Cluckwork.Infrastructure/Identity/FirstRunAdminService.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/FirstRunAdminService.cs similarity index 99% rename from src/Cluckwork.Infrastructure/Identity/FirstRunAdminService.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/FirstRunAdminService.cs index 6ee43fc67..19c0558da 100644 --- a/src/Cluckwork.Infrastructure/Identity/FirstRunAdminService.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/FirstRunAdminService.cs @@ -1,5 +1,6 @@ using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users; using Cluckwork.Domain.Accounts; using Cluckwork.Domain.Common; using Cluckwork.Infrastructure.Persistence; @@ -7,7 +8,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // #283 Part 2 — first-run admin provisioning. Invoked ONLY by the // `bootstrap-admin` CLI command (Cli/BootstrapAdminCliCommand.cs), a one-shot diff --git a/src/Cluckwork.Infrastructure/Identity/FirstRunStatusService.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/FirstRunStatusService.cs similarity index 99% rename from src/Cluckwork.Infrastructure/Identity/FirstRunStatusService.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/FirstRunStatusService.cs index 688f28cdf..8338895de 100644 --- a/src/Cluckwork.Infrastructure/Identity/FirstRunStatusService.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/FirstRunStatusService.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // #283 follow-up — first-run DISCOVERABILITY. The provisioning mechanism itself // (FirstRunAdminService, the `bootstrap-admin` verb) is unchanged; the gap this diff --git a/src/Cluckwork.Infrastructure/Identity/IStepUpGrantRegistry.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/IStepUpGrantRegistry.cs similarity index 98% rename from src/Cluckwork.Infrastructure/Identity/IStepUpGrantRegistry.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/IStepUpGrantRegistry.cs index afa7e5361..c664864d1 100644 --- a/src/Cluckwork.Infrastructure/Identity/IStepUpGrantRegistry.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/IStepUpGrantRegistry.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // #308/#338 — bookkeeping for the two step-up-grant guarantees a bare stateless // JWT cannot provide: single-use (replay) and logout revocation. #338 moved both diff --git a/src/Cluckwork.Infrastructure/Identity/IdentityProvider.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/IdentityProvider.cs similarity index 99% rename from src/Cluckwork.Infrastructure/Identity/IdentityProvider.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/IdentityProvider.cs index 9cf633f10..ba0a8d5df 100644 --- a/src/Cluckwork.Infrastructure/Identity/IdentityProvider.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/IdentityProvider.cs @@ -1,3 +1,4 @@ +using Cluckwork.Application.Modules.Access.Users; using Cluckwork.Domain.Modules.Commerce.Contracts; using System.Runtime.ExceptionServices; using System.Security.Cryptography; @@ -15,7 +16,7 @@ using Microsoft.Extensions.Options; using Npgsql; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; public sealed class IdentityProvider( UserManager userManager, diff --git a/src/Cluckwork.Infrastructure/Identity/JwtOptions.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/JwtOptions.cs similarity index 95% rename from src/Cluckwork.Infrastructure/Identity/JwtOptions.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/JwtOptions.cs index 020d4eddd..b0a17d48b 100644 --- a/src/Cluckwork.Infrastructure/Identity/JwtOptions.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/JwtOptions.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; public sealed class JwtOptions { diff --git a/src/Cluckwork.Infrastructure/Identity/JwtTokenService.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/JwtTokenService.cs similarity index 98% rename from src/Cluckwork.Infrastructure/Identity/JwtTokenService.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/JwtTokenService.cs index c4602ddd6..471672dc2 100644 --- a/src/Cluckwork.Infrastructure/Identity/JwtTokenService.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/JwtTokenService.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; public interface IJwtTokenService { diff --git a/src/Cluckwork.Infrastructure/Identity/PemKey.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/PemKey.cs similarity index 85% rename from src/Cluckwork.Infrastructure/Identity/PemKey.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/PemKey.cs index 94437e60f..a1445cbf6 100644 --- a/src/Cluckwork.Infrastructure/Identity/PemKey.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/PemKey.cs @@ -1,4 +1,4 @@ -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; public static class PemKey { diff --git a/src/Cluckwork.Infrastructure/Identity/PersistentStepUpGrantRegistry.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/PersistentStepUpGrantRegistry.cs similarity index 99% rename from src/Cluckwork.Infrastructure/Identity/PersistentStepUpGrantRegistry.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/PersistentStepUpGrantRegistry.cs index 26a67837a..8a5a8b1de 100644 --- a/src/Cluckwork.Infrastructure/Identity/PersistentStepUpGrantRegistry.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/PersistentStepUpGrantRegistry.cs @@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // #338 — the shared-store implementation of the two step-up-grant guarantees, // replacing InMemoryStepUpGrantRegistry now that both tables have left the diff --git a/src/Cluckwork.Infrastructure/Identity/RefreshToken.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/RefreshToken.cs similarity index 98% rename from src/Cluckwork.Infrastructure/Identity/RefreshToken.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/RefreshToken.cs index 710f233ba..9d862d721 100644 --- a/src/Cluckwork.Infrastructure/Identity/RefreshToken.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/RefreshToken.cs @@ -1,7 +1,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // Durable, rotating refresh token (tech spec §7.4). The raw token is never stored; // only its SHA-256 hash. Rotation revokes the presented token and issues a new one, diff --git a/src/Cluckwork.Infrastructure/Identity/RefreshTokenPurge.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/RefreshTokenPurge.cs similarity index 86% rename from src/Cluckwork.Infrastructure/Identity/RefreshTokenPurge.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/RefreshTokenPurge.cs index eedb474e5..7834bdd33 100644 --- a/src/Cluckwork.Infrastructure/Identity/RefreshTokenPurge.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/RefreshTokenPurge.cs @@ -1,8 +1,8 @@ -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; public sealed class RefreshTokenPurge(AppDbContext db) : IRefreshTokenPurge { diff --git a/src/Cluckwork.Infrastructure/Identity/StepUpGrantService.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/StepUpGrantService.cs similarity index 99% rename from src/Cluckwork.Infrastructure/Identity/StepUpGrantService.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/StepUpGrantService.cs index b63579ebd..097c80242 100644 --- a/src/Cluckwork.Infrastructure/Identity/StepUpGrantService.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/StepUpGrantService.cs @@ -1,3 +1,4 @@ +using Cluckwork.Application.Modules.Access.Users; using System.Globalization; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; @@ -10,7 +11,7 @@ using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // #308/#360 — THREAT MODEL + MECHANISM (owner-decided; see issues #308 and // #360). diff --git a/src/Cluckwork.Infrastructure/Identity/TemporaryPassword.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/TemporaryPassword.cs similarity index 97% rename from src/Cluckwork.Infrastructure/Identity/TemporaryPassword.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/TemporaryPassword.cs index a9c11fb4c..4bc55f0e3 100644 --- a/src/Cluckwork.Infrastructure/Identity/TemporaryPassword.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/TemporaryPassword.cs @@ -1,6 +1,6 @@ using System.Security.Cryptography; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // #265 — generates a strong random password for break-glass account recovery. // It satisfies the Identity policy configured in Program.cs (RequiredLength = 12 diff --git a/src/Cluckwork.Infrastructure/Identity/TimingEqualization.cs b/src/Cluckwork.Infrastructure/Modules/Access/Identity/TimingEqualization.cs similarity index 91% rename from src/Cluckwork.Infrastructure/Identity/TimingEqualization.cs rename to src/Cluckwork.Infrastructure/Modules/Access/Identity/TimingEqualization.cs index e84e6f375..49675526b 100644 --- a/src/Cluckwork.Infrastructure/Identity/TimingEqualization.cs +++ b/src/Cluckwork.Infrastructure/Modules/Access/Identity/TimingEqualization.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Identity; -namespace Cluckwork.Infrastructure.Identity; +namespace Cluckwork.Infrastructure.Modules.Access.Identity; // Shared PBKDF2 timing-equalization hash (#128 / #308): verifying an // incoming password against this costs the same as a real password check, so diff --git a/src/Cluckwork.Infrastructure/Persistence/AppDbContext.cs b/src/Cluckwork.Infrastructure/Persistence/AppDbContext.cs index 4f1040314..f04c4452d 100644 --- a/src/Cluckwork.Infrastructure/Persistence/AppDbContext.cs +++ b/src/Cluckwork.Infrastructure/Persistence/AppDbContext.cs @@ -7,8 +7,8 @@ using Cluckwork.Domain.Modules.Finance.Expenses; using Cluckwork.Domain.Modules.FlockManagement.Flocks; using Cluckwork.Domain.Modules.GeneralInventory.Inventory; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Jobs; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Providers; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; diff --git a/src/Cluckwork.Infrastructure/Persistence/Configurations/ApplicationUserConfiguration.cs b/src/Cluckwork.Infrastructure/Persistence/Configurations/ApplicationUserConfiguration.cs index 4d22950e9..4df56849f 100644 --- a/src/Cluckwork.Infrastructure/Persistence/Configurations/ApplicationUserConfiguration.cs +++ b/src/Cluckwork.Infrastructure/Persistence/Configurations/ApplicationUserConfiguration.cs @@ -1,4 +1,4 @@ -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/Cluckwork.Infrastructure/Persistence/DemoDataSeeder.cs b/src/Cluckwork.Infrastructure/Persistence/DemoDataSeeder.cs index 6510ba254..d6595c504 100644 --- a/src/Cluckwork.Infrastructure/Persistence/DemoDataSeeder.cs +++ b/src/Cluckwork.Infrastructure/Persistence/DemoDataSeeder.cs @@ -1,13 +1,12 @@ using Cluckwork.Application.Common; using Cluckwork.Application.Features.Accounts; -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Application.Modules.Commerce.Contracts; using Cluckwork.Application.Modules.EggOperations.Contracts; using Cluckwork.Application.Modules.FlockManagement.Contracts; using Cluckwork.Domain.Accounts; using Cluckwork.Domain.Common; using Cluckwork.Domain.Modules.Commerce.Contracts; -using Cluckwork.Infrastructure.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; diff --git a/src/Cluckwork.Infrastructure/Persistence/Migrations/AppDbContextModelSnapshot.cs b/src/Cluckwork.Infrastructure/Persistence/Migrations/AppDbContextModelSnapshot.cs index 39ca70d25..1c3317ae3 100644 --- a/src/Cluckwork.Infrastructure/Persistence/Migrations/AppDbContextModelSnapshot.cs +++ b/src/Cluckwork.Infrastructure/Persistence/Migrations/AppDbContextModelSnapshot.cs @@ -1626,7 +1626,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("SalesOrderItems"); }); - modelBuilder.Entity("Cluckwork.Infrastructure.Identity.ApplicationRole", b => + modelBuilder.Entity("Cluckwork.Infrastructure.Modules.Access.Identity.ApplicationRole", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -1653,7 +1653,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("AspNetRoles", (string)null); }); - modelBuilder.Entity("Cluckwork.Infrastructure.Identity.ApplicationUser", b => + modelBuilder.Entity("Cluckwork.Infrastructure.Modules.Access.Identity.ApplicationUser", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -1768,7 +1768,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) }); }); - modelBuilder.Entity("Cluckwork.Infrastructure.Identity.RefreshToken", b => + modelBuilder.Entity("Cluckwork.Infrastructure.Modules.Access.Identity.RefreshToken", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -2408,7 +2408,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); - modelBuilder.Entity("Cluckwork.Infrastructure.Identity.ApplicationUser", b => + modelBuilder.Entity("Cluckwork.Infrastructure.Modules.Access.Identity.ApplicationUser", b => { b.HasOne("Cluckwork.Domain.Accounts.Account", null) .WithMany() @@ -2419,7 +2419,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { - b.HasOne("Cluckwork.Infrastructure.Identity.ApplicationRole", null) + b.HasOne("Cluckwork.Infrastructure.Modules.Access.Identity.ApplicationRole", null) .WithMany() .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) @@ -2428,7 +2428,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("Cluckwork.Infrastructure.Identity.ApplicationUser", null) + b.HasOne("Cluckwork.Infrastructure.Modules.Access.Identity.ApplicationUser", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -2437,7 +2437,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("Cluckwork.Infrastructure.Identity.ApplicationUser", null) + b.HasOne("Cluckwork.Infrastructure.Modules.Access.Identity.ApplicationUser", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -2446,19 +2446,19 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => { - b.HasOne("Cluckwork.Infrastructure.Identity.ApplicationRole", null) + b.HasOne("Cluckwork.Infrastructure.Modules.Access.Identity.ApplicationRole", null) .WithMany() .HasForeignKey("RoleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Cluckwork.Infrastructure.Identity.ApplicationUser", null) + b.HasOne("Cluckwork.Infrastructure.Modules.Access.Identity.ApplicationUser", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Cluckwork.Infrastructure.Identity.ApplicationUser", null) + b.HasOne("Cluckwork.Infrastructure.Modules.Access.Identity.ApplicationUser", null) .WithMany() .HasForeignKey("UserId", "AccountId") .HasPrincipalKey("Id", "AccountId") @@ -2468,7 +2468,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("Cluckwork.Infrastructure.Identity.ApplicationUser", null) + b.HasOne("Cluckwork.Infrastructure.Modules.Access.Identity.ApplicationUser", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) diff --git a/src/Cluckwork.Infrastructure/Persistence/PlatformBusinessRecords.cs b/src/Cluckwork.Infrastructure/Persistence/PlatformBusinessRecords.cs index 152669011..0a74cc7e1 100644 --- a/src/Cluckwork.Infrastructure/Persistence/PlatformBusinessRecords.cs +++ b/src/Cluckwork.Infrastructure/Persistence/PlatformBusinessRecords.cs @@ -1,6 +1,6 @@ using Cluckwork.Domain.Auditing; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Jobs; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Microsoft.AspNetCore.Identity; namespace Cluckwork.Infrastructure.Persistence; diff --git a/src/Cluckwork.Infrastructure/Persistence/SimulationDataSeeder.cs b/src/Cluckwork.Infrastructure/Persistence/SimulationDataSeeder.cs index 0eade428c..902672044 100644 --- a/src/Cluckwork.Infrastructure/Persistence/SimulationDataSeeder.cs +++ b/src/Cluckwork.Infrastructure/Persistence/SimulationDataSeeder.cs @@ -1,3 +1,6 @@ +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users; +using Cluckwork.Application.Modules.Access.Users.CreateUser; using Cluckwork.Application.Modules.Commerce.Contracts; using Cluckwork.Application.Modules.EggOperations.Contracts; using Cluckwork.Application.Modules.Finance.Contracts; @@ -10,12 +13,8 @@ using Cluckwork.Application.Common; using Cluckwork.Application.Features.Accounts; using Cluckwork.Application.Features.Accounts.UpdateFarmSettings; -using Cluckwork.Application.Features.Users; -using Cluckwork.Application.Features.Users.AssignFlock; -using Cluckwork.Application.Features.Users.CreateUser; using Cluckwork.Domain.Accounts; using Cluckwork.Domain.Common; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Jobs; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; diff --git a/src/Cluckwork.Infrastructure/Repositories/UserRoleAssignmentRepository.cs b/src/Cluckwork.Infrastructure/Repositories/UserRoleAssignmentRepository.cs index 1dd3147ea..539b68d85 100644 --- a/src/Cluckwork.Infrastructure/Repositories/UserRoleAssignmentRepository.cs +++ b/src/Cluckwork.Infrastructure/Repositories/UserRoleAssignmentRepository.cs @@ -1,5 +1,6 @@ using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users; using Cluckwork.Domain.Accounts; using Cluckwork.Domain.Common; using Cluckwork.Infrastructure.Persistence; diff --git a/tests/Cluckwork.Api.IntegrationTests/AccessAuthorizationContractTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccessAuthorizationContractTests.cs index e2fb697c2..eb4f30b29 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccessAuthorizationContractTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccessAuthorizationContractTests.cs @@ -1,12 +1,13 @@ +using Cluckwork.Api.Modules.Access.Auth; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Collections.Concurrent; using System.Data.Common; using System.Net; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; diff --git a/tests/Cluckwork.Api.IntegrationTests/AccessFixtureTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccessFixtureTests.cs index 44c0610f3..f84952831 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccessFixtureTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccessFixtureTests.cs @@ -1,7 +1,7 @@ +using Cluckwork.Application.Modules.Access.Contracts; using System.Text.Json; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; using Cluckwork.Domain.Accounts; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/AccessLifecycleDependencyTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccessLifecycleDependencyTests.cs index 4c4698ac6..99e338bad 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccessLifecycleDependencyTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccessLifecycleDependencyTests.cs @@ -3,9 +3,9 @@ using Cluckwork.Api.Hosting; using Cluckwork.Api.Hosting.Modules; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Identity; diff --git a/tests/Cluckwork.Api.IntegrationTests/AccessLookupTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccessLookupTests.cs index 208b58cbb..d504475c8 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccessLookupTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccessLookupTests.cs @@ -1,7 +1,7 @@ +using Cluckwork.Application.Modules.Access.Contracts; using System.Net; using System.Net.Http.Json; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Features.Users; using Cluckwork.Domain.Accounts; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; diff --git a/tests/Cluckwork.Api.IntegrationTests/AccessSeedAssignmentAtomicityTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccessSeedAssignmentAtomicityTests.cs index cb8f268c5..88a32bfaf 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccessSeedAssignmentAtomicityTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccessSeedAssignmentAtomicityTests.cs @@ -1,7 +1,7 @@ using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Application.Common; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Persistence; using Cluckwork.Infrastructure.Repositories; using Microsoft.AspNetCore.Hosting; diff --git a/tests/Cluckwork.Api.IntegrationTests/AccessSeedDependencyTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccessSeedDependencyTests.cs index 037c123af..eb2709809 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccessSeedDependencyTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccessSeedDependencyTests.cs @@ -2,8 +2,8 @@ using Cluckwork.Api.Hosting; using Cluckwork.Api.Hosting.Modules; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Builder; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/AccessSeedFailureTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccessSeedFailureTests.cs index 4cad97196..767cc4ba3 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccessSeedFailureTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccessSeedFailureTests.cs @@ -1,7 +1,7 @@ using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Features.Users; +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/AccessSeedLookupTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccessSeedLookupTests.cs index e341c4833..a3d458808 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccessSeedLookupTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccessSeedLookupTests.cs @@ -1,8 +1,8 @@ +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Net; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Features.Users; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/AccessSeederActorTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccessSeederActorTests.cs index ba5840405..c1b6b515a 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccessSeederActorTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccessSeederActorTests.cs @@ -1,6 +1,6 @@ using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/AccountIdConcurrencyTokenModelTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccountIdConcurrencyTokenModelTests.cs index 442f14d0b..5e1c396fd 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccountIdConcurrencyTokenModelTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccountIdConcurrencyTokenModelTests.cs @@ -1,6 +1,6 @@ using Cluckwork.Domain.Modules.EggOperations.Eggs; using Cluckwork.Domain.Modules.GeneralInventory.Inventory; -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/AccountLifecycleCommandTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccountLifecycleCommandTests.cs index a7aa0765c..8746b8b92 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccountLifecycleCommandTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccountLifecycleCommandTests.cs @@ -1,8 +1,8 @@ +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Diagnostics; using System.Net; using System.Net.Http.Json; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Infrastructure.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/AccountLockoutTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccountLockoutTests.cs index e2d95a3b4..9768e6404 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccountLockoutTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccountLockoutTests.cs @@ -1,8 +1,8 @@ +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Linq; using System.Net; using System.Net.Http.Json; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; diff --git a/tests/Cluckwork.Api.IntegrationTests/AccountProvisioningTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccountProvisioningTests.cs index 2663ea59a..1ba3ad10e 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccountProvisioningTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccountProvisioningTests.cs @@ -1,12 +1,12 @@ +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Domain.Modules.Commerce.Catalog; using Cluckwork.Domain.Modules.EggOperations.Eggs; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Net; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; using Cluckwork.Domain.Accounts; using Cluckwork.Domain.Common; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; diff --git a/tests/Cluckwork.Api.IntegrationTests/AccountRenameServiceTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccountRenameServiceTests.cs index 1d534f854..111a6ecf3 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccountRenameServiceTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccountRenameServiceTests.cs @@ -1,6 +1,6 @@ using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Application.Common; -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; diff --git a/tests/Cluckwork.Api.IntegrationTests/AccountScopedUserValidatorRegistrationTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccountScopedUserValidatorRegistrationTests.cs index ad99c9155..205dfb2d8 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccountScopedUserValidatorRegistrationTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccountScopedUserValidatorRegistrationTests.cs @@ -1,5 +1,5 @@ using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; diff --git a/tests/Cluckwork.Api.IntegrationTests/AccountScopedUserValidatorTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccountScopedUserValidatorTests.cs index c81d3e07a..f94dbd1ab 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccountScopedUserValidatorTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccountScopedUserValidatorTests.cs @@ -1,5 +1,5 @@ using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/AccountSuspensionTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccountSuspensionTests.cs index 72874eefb..354a0d253 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccountSuspensionTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccountSuspensionTests.cs @@ -1,9 +1,9 @@ +using Cluckwork.Api.Modules.Access.Auth; +using Cluckwork.Application.Modules.Access.Users; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Net; using System.Net.Http.Json; -using Cluckwork.Api.Endpoints.Auth; -using Cluckwork.Application.Common; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/AdminGatingTests.cs b/tests/Cluckwork.Api.IntegrationTests/AdminGatingTests.cs index 638e3b215..b779e6f09 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AdminGatingTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AdminGatingTests.cs @@ -1,9 +1,9 @@ +using Cluckwork.Api.Modules.Access.Auth; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Net; using System.Text.Json; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; diff --git a/tests/Cluckwork.Api.IntegrationTests/AdminRecoveryServiceTests.cs b/tests/Cluckwork.Api.IntegrationTests/AdminRecoveryServiceTests.cs index cb7b94b7a..0a0604d23 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AdminRecoveryServiceTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AdminRecoveryServiceTests.cs @@ -1,7 +1,8 @@ using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Application.Common; +using Cluckwork.Application.Modules.Access.Users; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/ApplicationUserIndexModelTests.cs b/tests/Cluckwork.Api.IntegrationTests/ApplicationUserIndexModelTests.cs index e714ff060..ae7f41d45 100644 --- a/tests/Cluckwork.Api.IntegrationTests/ApplicationUserIndexModelTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/ApplicationUserIndexModelTests.cs @@ -1,4 +1,4 @@ -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata; diff --git a/tests/Cluckwork.Api.IntegrationTests/AuditActorTests.cs b/tests/Cluckwork.Api.IntegrationTests/AuditActorTests.cs index ceea7447b..025b4b515 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AuditActorTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AuditActorTests.cs @@ -2,7 +2,6 @@ using Cluckwork.Application.Common; using Cluckwork.Domain.Accounts; using Cluckwork.Domain.Auditing; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; diff --git a/tests/Cluckwork.Api.IntegrationTests/AuthBodyLimitTests.cs b/tests/Cluckwork.Api.IntegrationTests/AuthBodyLimitTests.cs index a244a73bb..19e261da6 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AuthBodyLimitTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AuthBodyLimitTests.cs @@ -1,10 +1,10 @@ +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Net; using System.Net.Http.Headers; using System.Net.Http.Json; using System.Text; using System.Text.Json; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Infrastructure.Identity; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.TestHost; diff --git a/tests/Cluckwork.Api.IntegrationTests/AuthCookieContractTests.cs b/tests/Cluckwork.Api.IntegrationTests/AuthCookieContractTests.cs index 4821a62a3..12858c56e 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AuthCookieContractTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AuthCookieContractTests.cs @@ -1,7 +1,7 @@ +using Cluckwork.Api.Modules.Access.Auth; using System.Net; using System.Net.Http.Headers; using System.Text.Json; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Microsoft.AspNetCore.Mvc.Testing; diff --git a/tests/Cluckwork.Api.IntegrationTests/AuthRateLimitLoggingTests.cs b/tests/Cluckwork.Api.IntegrationTests/AuthRateLimitLoggingTests.cs index 3ecfe66c1..f6ed65223 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AuthRateLimitLoggingTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AuthRateLimitLoggingTests.cs @@ -1,7 +1,7 @@ +using Cluckwork.Api.Modules.Access.Auth; using System.Collections.Concurrent; using System.Net; using System.Net.Http.Headers; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Application.Common; using Microsoft.AspNetCore.Hosting; diff --git a/tests/Cluckwork.Api.IntegrationTests/AuthSessionContractTests.cs b/tests/Cluckwork.Api.IntegrationTests/AuthSessionContractTests.cs index 400559913..1bcacd667 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AuthSessionContractTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AuthSessionContractTests.cs @@ -1,11 +1,10 @@ +using Cluckwork.Api.Modules.Access.Auth; using System.Globalization; using System.Net; using System.Net.Http.Headers; using System.Net.Http.Json; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Application.Common; -using Cluckwork.Infrastructure.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/BootstrapAdminCommandTests.cs b/tests/Cluckwork.Api.IntegrationTests/BootstrapAdminCommandTests.cs index c782b70fb..a9d556820 100644 --- a/tests/Cluckwork.Api.IntegrationTests/BootstrapAdminCommandTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/BootstrapAdminCommandTests.cs @@ -1,8 +1,8 @@ +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Diagnostics; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Application.Common; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/BootstrapAdvisoryLockContinuityTests.cs b/tests/Cluckwork.Api.IntegrationTests/BootstrapAdvisoryLockContinuityTests.cs index 5a63926ad..cb8b90bd6 100644 --- a/tests/Cluckwork.Api.IntegrationTests/BootstrapAdvisoryLockContinuityTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/BootstrapAdvisoryLockContinuityTests.cs @@ -1,7 +1,7 @@ +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Data.Common; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; diff --git a/tests/Cluckwork.Api.IntegrationTests/BusinessRecordModelTests.cs b/tests/Cluckwork.Api.IntegrationTests/BusinessRecordModelTests.cs index f402c1502..eb37951d8 100644 --- a/tests/Cluckwork.Api.IntegrationTests/BusinessRecordModelTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/BusinessRecordModelTests.cs @@ -6,7 +6,7 @@ using Cluckwork.Domain.Modules.Finance.Expenses; using Cluckwork.Domain.Modules.FlockManagement.Flocks; using Cluckwork.Domain.Modules.GeneralInventory.Inventory; -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata; diff --git a/tests/Cluckwork.Api.IntegrationTests/ChangeUserEmailRaceTests.cs b/tests/Cluckwork.Api.IntegrationTests/ChangeUserEmailRaceTests.cs index 5c8377568..92aa69c97 100644 --- a/tests/Cluckwork.Api.IntegrationTests/ChangeUserEmailRaceTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/ChangeUserEmailRaceTests.cs @@ -1,14 +1,15 @@ +using Cluckwork.Api.Modules.Access.Auth; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users; +using Cluckwork.Application.Modules.Access.Users.ChangeUserEmail; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Data.Common; using System.Net; using System.Net.Http.Json; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users.ChangeUserEmail; using Cluckwork.Domain.Accounts; using Cluckwork.Domain.Auditing; using Cluckwork.Domain.Common; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; diff --git a/tests/Cluckwork.Api.IntegrationTests/ChangeUserEmailTests.cs b/tests/Cluckwork.Api.IntegrationTests/ChangeUserEmailTests.cs index 6e562f16a..5e42029a2 100644 --- a/tests/Cluckwork.Api.IntegrationTests/ChangeUserEmailTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/ChangeUserEmailTests.cs @@ -1,10 +1,11 @@ +using Cluckwork.Api.Modules.Access.Auth; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users; +using Cluckwork.Application.Modules.Access.Users.ChangeUserEmail; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Net; using System.Net.Http.Json; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users.ChangeUserEmail; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; diff --git a/tests/Cluckwork.Api.IntegrationTests/ChangeUserRoleRaceTests.cs b/tests/Cluckwork.Api.IntegrationTests/ChangeUserRoleRaceTests.cs index b970b55d7..f22f2c33e 100644 --- a/tests/Cluckwork.Api.IntegrationTests/ChangeUserRoleRaceTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/ChangeUserRoleRaceTests.cs @@ -1,6 +1,7 @@ using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users.ChangeUserRole; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users; +using Cluckwork.Application.Modules.Access.Users.ChangeUserRole; using Cluckwork.Domain.Common; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; @@ -81,7 +82,7 @@ private async Task InvokeProviderAsync( using var scope = factory.Services.CreateScope(); scope.ResolveTenantAndActor(accountId, actingUserId); var identity = scope.ServiceProvider.GetRequiredService(); - var storedRole = role == Cluckwork.Application.Features.Users.CreateUser.CreateUserValidator.WorkerRole + var storedRole = role == Cluckwork.Application.Modules.Access.Users.CreateUser.CreateUserValidator.WorkerRole ? null : role; return await identity.ChangeUserRoleAsync( diff --git a/tests/Cluckwork.Api.IntegrationTests/ChangeUserRoleTests.cs b/tests/Cluckwork.Api.IntegrationTests/ChangeUserRoleTests.cs index 7d12b60bd..3813de703 100644 --- a/tests/Cluckwork.Api.IntegrationTests/ChangeUserRoleTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/ChangeUserRoleTests.cs @@ -1,7 +1,7 @@ +using Cluckwork.Api.Modules.Access.Auth; using System.Net; using System.Net.Http.Headers; using System.Net.Http.Json; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; @@ -44,7 +44,7 @@ private static async Task FindUserAsync(HttpClient owner, string email) using var scope = factory.Services.CreateScope(); var tenant = scope.ServiceProvider.GetRequiredService(); tenant.Resolve(accountId); - var identity = scope.ServiceProvider.GetRequiredService(); + var identity = scope.ServiceProvider.GetRequiredService(); var user = (await identity.ListUsersAsync(accountId)).Single(u => u.Email == email); return (email, user.Id); } @@ -443,7 +443,7 @@ public async Task RoleChange_InvalidatesTheTargets_OutstandingStepUpGrant() using var scope = factory.Services.CreateScope(); scope.ServiceProvider.GetRequiredService() .Resolve(accountId); - var stepUpService = scope.ServiceProvider.GetRequiredService(); + var stepUpService = scope.ServiceProvider.GetRequiredService(); var validated = await stepUpService.ValidateAsync(accountId, targetId, targetGrant, CancellationToken.None); Assert.True(validated.IsFailure, "a step-up grant issued before the role change must not survive it"); diff --git a/tests/Cluckwork.Api.IntegrationTests/CredentialEpochFloorTests.cs b/tests/Cluckwork.Api.IntegrationTests/CredentialEpochFloorTests.cs index e2f4cd8fe..d0d75703d 100644 --- a/tests/Cluckwork.Api.IntegrationTests/CredentialEpochFloorTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/CredentialEpochFloorTests.cs @@ -1,11 +1,11 @@ +using Cluckwork.Api.Modules.Access.Auth; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Net; using System.Security.Cryptography; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; diff --git a/tests/Cluckwork.Api.IntegrationTests/CredentialEpochFreshReadTests.cs b/tests/Cluckwork.Api.IntegrationTests/CredentialEpochFreshReadTests.cs index 403046aaf..08f42e01d 100644 --- a/tests/Cluckwork.Api.IntegrationTests/CredentialEpochFreshReadTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/CredentialEpochFreshReadTests.cs @@ -1,6 +1,6 @@ +using Cluckwork.Api.Modules.Access.Auth; using System.Data.Common; using System.Net; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Hosting; diff --git a/tests/Cluckwork.Api.IntegrationTests/CredentialEpochMiddlewareVerdictTests.cs b/tests/Cluckwork.Api.IntegrationTests/CredentialEpochMiddlewareVerdictTests.cs index 6b05aaa2f..37625ed71 100644 --- a/tests/Cluckwork.Api.IntegrationTests/CredentialEpochMiddlewareVerdictTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/CredentialEpochMiddlewareVerdictTests.cs @@ -1,8 +1,8 @@ +using Cluckwork.Application.Modules.Access.Contracts; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text.Json; using Cluckwork.Api.Middleware; -using Cluckwork.Application.Features.Users; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; diff --git a/tests/Cluckwork.Api.IntegrationTests/CredentialEpochRaceTests.cs b/tests/Cluckwork.Api.IntegrationTests/CredentialEpochRaceTests.cs index efd665376..b71c9404f 100644 --- a/tests/Cluckwork.Api.IntegrationTests/CredentialEpochRaceTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/CredentialEpochRaceTests.cs @@ -1,8 +1,8 @@ +using Cluckwork.Application.Modules.Access.Users; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Data.Common; using System.Net; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Common; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; diff --git a/tests/Cluckwork.Api.IntegrationTests/CredentialEpochTests.cs b/tests/Cluckwork.Api.IntegrationTests/CredentialEpochTests.cs index c9f79e30a..5c7281206 100644 --- a/tests/Cluckwork.Api.IntegrationTests/CredentialEpochTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/CredentialEpochTests.cs @@ -1,13 +1,13 @@ +using Cluckwork.Api.Modules.Access.Auth; +using Cluckwork.Application.Modules.Access.Users; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Net; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; using System.Text; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Common; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; diff --git a/tests/Cluckwork.Api.IntegrationTests/DailyEntryAdjustTests.cs b/tests/Cluckwork.Api.IntegrationTests/DailyEntryAdjustTests.cs index bad603d4f..597706b6e 100644 --- a/tests/Cluckwork.Api.IntegrationTests/DailyEntryAdjustTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/DailyEntryAdjustTests.cs @@ -1,8 +1,8 @@ using Cluckwork.Domain.Modules.EggOperations.Contracts; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Net; using System.Text.Json; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Jobs; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; diff --git a/tests/Cluckwork.Api.IntegrationTests/DemoSeedActorTests.cs b/tests/Cluckwork.Api.IntegrationTests/DemoSeedActorTests.cs index f31b345d0..2ab2d5cd1 100644 --- a/tests/Cluckwork.Api.IntegrationTests/DemoSeedActorTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/DemoSeedActorTests.cs @@ -1,6 +1,6 @@ using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/DemoSeedCleanupTests.cs b/tests/Cluckwork.Api.IntegrationTests/DemoSeedCleanupTests.cs index f246fdc4e..6bd0890de 100644 --- a/tests/Cluckwork.Api.IntegrationTests/DemoSeedCleanupTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/DemoSeedCleanupTests.cs @@ -1,11 +1,11 @@ +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Application.Modules.Commerce.Contracts; using Cluckwork.Application.Modules.EggOperations.Contracts; using Cluckwork.Domain.Modules.Commerce.Contracts; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Data.Common; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Features.Users; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/DemoSeedTests.cs b/tests/Cluckwork.Api.IntegrationTests/DemoSeedTests.cs index ede09e2ba..0078f5bc9 100644 --- a/tests/Cluckwork.Api.IntegrationTests/DemoSeedTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/DemoSeedTests.cs @@ -1,8 +1,8 @@ using Cluckwork.Domain.Modules.EggOperations.Contracts; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Net.Http.Headers; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; diff --git a/tests/Cluckwork.Api.IntegrationTests/DisableUserRaceTests.cs b/tests/Cluckwork.Api.IntegrationTests/DisableUserRaceTests.cs index 452a8f1e6..d8c97f820 100644 --- a/tests/Cluckwork.Api.IntegrationTests/DisableUserRaceTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/DisableUserRaceTests.cs @@ -1,10 +1,11 @@ +using Cluckwork.Api.Modules.Access.Auth; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users; +using Cluckwork.Application.Modules.Access.Users.DisableUser; +using Cluckwork.Application.Modules.Access.Users.EnableUser; using System.Net; using System.Net.Http.Json; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Common; -using Cluckwork.Application.Features.Users.DisableUser; -using Cluckwork.Application.Features.Users.EnableUser; using Cluckwork.Domain.Common; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; @@ -672,7 +673,7 @@ public async Task StaleOwnerActor_OverHttp_Is403_NotA422() Content = JsonContent.Create(new { reason = (string?)null }), }; request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString()); - request.Headers.Add(Cluckwork.Api.Endpoints.Auth.AuthEndpoints.StepUpHeaderName, stepUpToken); + request.Headers.Add(Cluckwork.Api.Modules.Access.Auth.AuthEndpoints.StepUpHeaderName, stepUpToken); var inFlight = Task.Run(() => client.SendAsync(request)); Assert.True(await factory.WaitUntilDoneOrBlockedAsync(inFlight, pid), "the request must park on the account lock after passing authorization"); diff --git a/tests/Cluckwork.Api.IntegrationTests/DisableUserTests.cs b/tests/Cluckwork.Api.IntegrationTests/DisableUserTests.cs index b7e0a6cdc..abf9764ff 100644 --- a/tests/Cluckwork.Api.IntegrationTests/DisableUserTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/DisableUserTests.cs @@ -1,6 +1,6 @@ +using Cluckwork.Api.Modules.Access.Auth; using System.Net; using System.Net.Http.Json; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -51,7 +51,7 @@ private static async Task FindUserAsync(HttpClient owner, string email) scope.ServiceProvider .GetRequiredService() .Resolve(accountId); - var identity = scope.ServiceProvider.GetRequiredService(); + var identity = scope.ServiceProvider.GetRequiredService(); var user = (await identity.ListUsersAsync(accountId)).Single(u => u.Email == email); return (email, user.Id); } @@ -316,7 +316,7 @@ public async Task Disable_InvalidatesTheTargetsOutstandingStepUpGrant() .GetRequiredService() .Resolve(accountId); var stepUp = scope.ServiceProvider - .GetRequiredService(); + .GetRequiredService(); Assert.True((await stepUp.ValidateAsync(accountId, targetId, targetGrant, CancellationToken.None)).IsFailure, "a step-up grant issued before the disable must not survive a re-enable"); diff --git a/tests/Cluckwork.Api.IntegrationTests/ExceptionHandlerReExecutionTests.cs b/tests/Cluckwork.Api.IntegrationTests/ExceptionHandlerReExecutionTests.cs index aee8b0846..76b623756 100644 --- a/tests/Cluckwork.Api.IntegrationTests/ExceptionHandlerReExecutionTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/ExceptionHandlerReExecutionTests.cs @@ -1,9 +1,9 @@ +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Application.Modules.Finance.Contracts; using System.Net; using System.Security.Cryptography; using System.Text; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Features.Users.ChangeOwnPassword; using Cluckwork.Infrastructure.Persistence; using FluentValidation; using Microsoft.AspNetCore.Hosting; diff --git a/tests/Cluckwork.Api.IntegrationTests/FarmSettingsTests.cs b/tests/Cluckwork.Api.IntegrationTests/FarmSettingsTests.cs index b55fa0773..9dc420505 100644 --- a/tests/Cluckwork.Api.IntegrationTests/FarmSettingsTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/FarmSettingsTests.cs @@ -880,7 +880,7 @@ private async Task SeedFlockAssignmentAsync(Guid accountId, string email) { using var scope = factory.Services.CreateScope(); var users = scope.ServiceProvider - .GetRequiredService>(); + .GetRequiredService>(); var user = await users.FindByEmailAsync(email) ?? throw new InvalidOperationException($"No user {email}"); diff --git a/tests/Cluckwork.Api.IntegrationTests/FirstRunAdminUnlockCleanupTests.cs b/tests/Cluckwork.Api.IntegrationTests/FirstRunAdminUnlockCleanupTests.cs index a3743f560..20e8b7b8f 100644 --- a/tests/Cluckwork.Api.IntegrationTests/FirstRunAdminUnlockCleanupTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/FirstRunAdminUnlockCleanupTests.cs @@ -1,7 +1,7 @@ +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Data.Common; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; diff --git a/tests/Cluckwork.Api.IntegrationTests/FirstRunLoginNoticeTests.cs b/tests/Cluckwork.Api.IntegrationTests/FirstRunLoginNoticeTests.cs index bdb261112..46076270f 100644 --- a/tests/Cluckwork.Api.IntegrationTests/FirstRunLoginNoticeTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/FirstRunLoginNoticeTests.cs @@ -1,9 +1,9 @@ +using Cluckwork.Api.Modules.Access.Auth; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Net; using System.Net.Http.Json; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/FixturePortRegistrationTests.cs b/tests/Cluckwork.Api.IntegrationTests/FixturePortRegistrationTests.cs index 608e876b8..16a1d0915 100644 --- a/tests/Cluckwork.Api.IntegrationTests/FixturePortRegistrationTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/FixturePortRegistrationTests.cs @@ -1,7 +1,7 @@ +using Cluckwork.Application.Modules.Access.Contracts; using System.Diagnostics; using System.Text.Json; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Features.Users; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; diff --git a/tests/Cluckwork.Api.IntegrationTests/FlockScopeMiddlewareTests.cs b/tests/Cluckwork.Api.IntegrationTests/FlockScopeMiddlewareTests.cs index eb32728f3..691f8e339 100644 --- a/tests/Cluckwork.Api.IntegrationTests/FlockScopeMiddlewareTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/FlockScopeMiddlewareTests.cs @@ -1,9 +1,9 @@ +using Cluckwork.Api.Modules.Access.Auth; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Net; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Api.Middleware; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Http; diff --git a/tests/Cluckwork.Api.IntegrationTests/FlockScopeTests.cs b/tests/Cluckwork.Api.IntegrationTests/FlockScopeTests.cs index fb2802357..49bbb9cf2 100644 --- a/tests/Cluckwork.Api.IntegrationTests/FlockScopeTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/FlockScopeTests.cs @@ -1,3 +1,4 @@ +using Cluckwork.Api.Modules.Access.Auth; using Cluckwork.Application.Modules.EggOperations.Contracts; using Cluckwork.Application.Modules.EggOperations.DailyEntries.RecordDailyEntry; using Cluckwork.Application.Modules.GeneralInventory.Contracts; @@ -10,7 +11,6 @@ using Cluckwork.Domain.Modules.FlockManagement.Flocks; using Cluckwork.Domain.Modules.GeneralInventory.Inventory; using System.Net; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Domain.Accounts; using Cluckwork.Domain.Common; diff --git a/tests/Cluckwork.Api.IntegrationTests/GlobalUserLookupGuardTests.cs b/tests/Cluckwork.Api.IntegrationTests/GlobalUserLookupGuardTests.cs index 2d57dcd03..9dfd04ded 100644 --- a/tests/Cluckwork.Api.IntegrationTests/GlobalUserLookupGuardTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/GlobalUserLookupGuardTests.cs @@ -47,8 +47,8 @@ public sealed class GlobalUserLookupGuardTests // guessing (Recovery.Ambiguous). private static readonly string[] AllowedFiles = [ - "Cluckwork.Infrastructure/Identity/AccountUserDirectory.cs", - "Cluckwork.Infrastructure/Identity/AdminRecoveryService.cs", + "Cluckwork.Infrastructure/Modules/Access/Identity/AccountUserDirectory.cs", + "Cluckwork.Infrastructure/Modules/Access/Identity/AdminRecoveryService.cs", ]; // True when fileName[start..start+length) is all ASCII digits. Validating diff --git a/tests/Cluckwork.Api.IntegrationTests/Infrastructure/TestHarness.cs b/tests/Cluckwork.Api.IntegrationTests/Infrastructure/TestHarness.cs index 184e0990a..3e200c877 100644 --- a/tests/Cluckwork.Api.IntegrationTests/Infrastructure/TestHarness.cs +++ b/tests/Cluckwork.Api.IntegrationTests/Infrastructure/TestHarness.cs @@ -1,12 +1,12 @@ +using Cluckwork.Api.Modules.Access.Auth; using Cluckwork.Domain.Modules.Commerce.Sales; using Cluckwork.Domain.Modules.EggOperations.Contracts; using Cluckwork.Domain.Modules.EggOperations.Eggs; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Collections.Concurrent; using System.Linq; using System.Net.Http.Headers; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/LoginRequestValidatorTests.cs b/tests/Cluckwork.Api.IntegrationTests/LoginRequestValidatorTests.cs index 0a68301b8..11528a0d7 100644 --- a/tests/Cluckwork.Api.IntegrationTests/LoginRequestValidatorTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/LoginRequestValidatorTests.cs @@ -1,5 +1,5 @@ -using Cluckwork.Api.Endpoints.Auth; -using Cluckwork.Application.Features.Users; +using Cluckwork.Api.Modules.Access.Auth; +using Cluckwork.Application.Modules.Access.Users; namespace Cluckwork.Api.IntegrationTests; diff --git a/tests/Cluckwork.Api.IntegrationTests/MustChangePasswordGateTests.cs b/tests/Cluckwork.Api.IntegrationTests/MustChangePasswordGateTests.cs index 00749eb19..de9b940ea 100644 --- a/tests/Cluckwork.Api.IntegrationTests/MustChangePasswordGateTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/MustChangePasswordGateTests.cs @@ -1,7 +1,8 @@ +using Cluckwork.Api.Modules.Access.Auth; +using Cluckwork.Application.Modules.Access.Users; using Cluckwork.Domain.Modules.Commerce.Contracts; using System.Net; using System.Net.Http.Headers; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Application.Common; using Cluckwork.Domain.Accounts; @@ -62,10 +63,10 @@ public async Task PendingUser_AllowedEndpointHandlerThrows_GetsMappedError_NotMu using var throwingFactory = factory.WithWebHostBuilder(builder => builder.ConfigureTestServices(services => { - services.AddScoped(); + services.AddScoped(); services.AddScoped(sp => new ChangePasswordThrowingIdentityProvider( - sp.GetRequiredService())); + sp.GetRequiredService())); })); var accountId = Guid.NewGuid(); @@ -86,7 +87,7 @@ await factory.WithTenantScopeAsync(accountId, async db => var loginResponse = await loginClient.PostAsJsonAsync( "/api/v1/auth/login", new { farmCode = await factory.FarmCodeForAsync(email), email, password = TestHarness.Password }); loginResponse.EnsureSuccessStatusCode(); - var token = (await loginResponse.Content.ReadFromJsonAsync())!.AccessToken; + var token = (await loginResponse.Content.ReadFromJsonAsync())!.AccessToken; var client = throwingFactory.CreateClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); @@ -188,7 +189,7 @@ await factory.WithTenantScopeAsync(accountId, async db => new { currentPassword = TestHarness.Password, newPassword }); Assert.Equal(HttpStatusCode.OK, changeResponse.StatusCode); var newAccessToken = (await changeResponse.Content - .ReadFromJsonAsync())!.AccessToken; + .ReadFromJsonAsync())!.AccessToken; var freshClient = factory.CreateAuthedClient(newAccessToken); var flocksResponse = await freshClient.GetAsync("/api/v1/flocks"); diff --git a/tests/Cluckwork.Api.IntegrationTests/NamedEntityDiscoveryTests.cs b/tests/Cluckwork.Api.IntegrationTests/NamedEntityDiscoveryTests.cs index 6e3ae536f..5c23f4a24 100644 --- a/tests/Cluckwork.Api.IntegrationTests/NamedEntityDiscoveryTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/NamedEntityDiscoveryTests.cs @@ -1,9 +1,9 @@ +using Cluckwork.Api.Modules.Access.Auth; using Cluckwork.Domain.Modules.Commerce.Sales; using Cluckwork.Domain.Modules.FlockManagement.Contracts; using Cluckwork.Domain.Modules.FlockManagement.Flocks; using System.Net; using System.Text.Json; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; @@ -1049,7 +1049,7 @@ private static async Task AssignFlockAsync( stepUp.EnsureSuccessStatusCode(); request.Headers.Add( AuthEndpoints.StepUpHeaderName, - (await stepUp.Content.ReadFromJsonAsync())!.Token); + (await stepUp.Content.ReadFromJsonAsync())!.Token); return await client.SendAsync(request); } } diff --git a/tests/Cluckwork.Api.IntegrationTests/NamedRowProjectionTests.cs b/tests/Cluckwork.Api.IntegrationTests/NamedRowProjectionTests.cs index bdfb04537..e41c2407d 100644 --- a/tests/Cluckwork.Api.IntegrationTests/NamedRowProjectionTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/NamedRowProjectionTests.cs @@ -1,3 +1,4 @@ +using Cluckwork.Application.Modules.Access.Contracts; using Cluckwork.Application.Modules.Commerce.Contracts; using Cluckwork.Application.Modules.FlockManagement.Contracts; using Cluckwork.Domain.Modules.Commerce.Sales; @@ -8,7 +9,6 @@ using Cluckwork.Domain.Modules.GeneralInventory.Inventory; using System.Net; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Features.Users; using Cluckwork.Domain.Accounts; using Cluckwork.Domain.Common; using Cluckwork.Infrastructure.Persistence; diff --git a/tests/Cluckwork.Api.IntegrationTests/OneShotVerbMinimalConfigTests.cs b/tests/Cluckwork.Api.IntegrationTests/OneShotVerbMinimalConfigTests.cs index a975dff3f..69da0c5d6 100644 --- a/tests/Cluckwork.Api.IntegrationTests/OneShotVerbMinimalConfigTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/OneShotVerbMinimalConfigTests.cs @@ -266,7 +266,7 @@ public async Task NoServingOnlySection_CanAbortAVerbByBeingUnparseable( [Fact] public void EveryConfigSection_IsEitherProbedOrDeliberatelyExcluded() { - var sections = new[] { typeof(Program).Assembly, typeof(Cluckwork.Infrastructure.Identity.JwtOptions).Assembly } + var sections = new[] { typeof(Program).Assembly, typeof(Cluckwork.Infrastructure.Modules.Access.Identity.JwtOptions).Assembly } .SelectMany(a => a.GetTypes()) .Select(t => t.GetField("SectionName", BindingFlags.Public | BindingFlags.Static)) .Where(f => f is { IsLiteral: true, FieldType: { } ft } && ft == typeof(string)) diff --git a/tests/Cluckwork.Api.IntegrationTests/RateLimitingTests.cs b/tests/Cluckwork.Api.IntegrationTests/RateLimitingTests.cs index f7c0eb499..faaa378ab 100644 --- a/tests/Cluckwork.Api.IntegrationTests/RateLimitingTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/RateLimitingTests.cs @@ -1,5 +1,5 @@ +using Cluckwork.Api.Modules.Access.Auth; using System.Net; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; diff --git a/tests/Cluckwork.Api.IntegrationTests/RecoverAdminCommandTests.cs b/tests/Cluckwork.Api.IntegrationTests/RecoverAdminCommandTests.cs index 1ff709275..cdec8f0b1 100644 --- a/tests/Cluckwork.Api.IntegrationTests/RecoverAdminCommandTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/RecoverAdminCommandTests.cs @@ -1,7 +1,7 @@ +using Cluckwork.Application.Modules.Access.Users; using Cluckwork.Domain.Accounts; using System.Diagnostics; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Common; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; diff --git a/tests/Cluckwork.Api.IntegrationTests/RefreshAccountBindingTests.cs b/tests/Cluckwork.Api.IntegrationTests/RefreshAccountBindingTests.cs index 2d0355065..d7d157ea3 100644 --- a/tests/Cluckwork.Api.IntegrationTests/RefreshAccountBindingTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/RefreshAccountBindingTests.cs @@ -1,7 +1,7 @@ +using Cluckwork.Api.Modules.Access.Auth; using System.Net; using System.Net.Http.Json; using System.Net.Http.Headers; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/RefreshTokenFlowTests.cs b/tests/Cluckwork.Api.IntegrationTests/RefreshTokenFlowTests.cs index bdb4c9bfa..a6dafa48e 100644 --- a/tests/Cluckwork.Api.IntegrationTests/RefreshTokenFlowTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/RefreshTokenFlowTests.cs @@ -1,5 +1,4 @@ using System.Net; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Microsoft.Extensions.DependencyInjection; using Microsoft.AspNetCore.Hosting; diff --git a/tests/Cluckwork.Api.IntegrationTests/RefreshTokenPurgeBatchTests.cs b/tests/Cluckwork.Api.IntegrationTests/RefreshTokenPurgeBatchTests.cs index 72fd03b38..15240b97e 100644 --- a/tests/Cluckwork.Api.IntegrationTests/RefreshTokenPurgeBatchTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/RefreshTokenPurgeBatchTests.cs @@ -1,7 +1,7 @@ +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Collections.Concurrent; using System.Data.Common; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Jobs; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Hosting; diff --git a/tests/Cluckwork.Api.IntegrationTests/RefreshTokenPurgeSweepTests.cs b/tests/Cluckwork.Api.IntegrationTests/RefreshTokenPurgeSweepTests.cs index e9460e364..215ca37cb 100644 --- a/tests/Cluckwork.Api.IntegrationTests/RefreshTokenPurgeSweepTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/RefreshTokenPurgeSweepTests.cs @@ -1,6 +1,6 @@ +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Net; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Jobs; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Mvc.Testing; diff --git a/tests/Cluckwork.Api.IntegrationTests/RequestLoggingTests.cs b/tests/Cluckwork.Api.IntegrationTests/RequestLoggingTests.cs index 4c9505b71..5eb84a897 100644 --- a/tests/Cluckwork.Api.IntegrationTests/RequestLoggingTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/RequestLoggingTests.cs @@ -1,7 +1,7 @@ +using Cluckwork.Application.Modules.Access.Contracts; using System.Collections.Concurrent; using System.Diagnostics; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Features.Users.ChangeOwnPassword; using FluentValidation; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; diff --git a/tests/Cluckwork.Api.IntegrationTests/RetryBoundaryTests.cs b/tests/Cluckwork.Api.IntegrationTests/RetryBoundaryTests.cs index 0275efb97..89f705e98 100644 --- a/tests/Cluckwork.Api.IntegrationTests/RetryBoundaryTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/RetryBoundaryTests.cs @@ -1,8 +1,8 @@ +using Cluckwork.Application.Modules.Access.Users; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Net; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Common; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; diff --git a/tests/Cluckwork.Api.IntegrationTests/RoleMatrixTests.cs b/tests/Cluckwork.Api.IntegrationTests/RoleMatrixTests.cs index 93fe8e5a5..9f52c8c36 100644 --- a/tests/Cluckwork.Api.IntegrationTests/RoleMatrixTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/RoleMatrixTests.cs @@ -1,6 +1,6 @@ +using Cluckwork.Api.Modules.Access.Auth; using System.Net; using System.Text.Json; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Domain.Accounts; diff --git a/tests/Cluckwork.Api.IntegrationTests/SaleAllocationPolicyTests.cs b/tests/Cluckwork.Api.IntegrationTests/SaleAllocationPolicyTests.cs index e24724a35..ecdaf2d0b 100644 --- a/tests/Cluckwork.Api.IntegrationTests/SaleAllocationPolicyTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/SaleAllocationPolicyTests.cs @@ -1,10 +1,10 @@ +using Cluckwork.Api.Modules.Access.Auth; using Cluckwork.Application.Modules.EggOperations.Contracts; using Cluckwork.Application.Modules.EggOperations.EggLots; using Cluckwork.Domain.Modules.EggOperations.Contracts; using Cluckwork.Domain.Modules.EggOperations.Eggs; using System.Net; using System.Net.Http.Json; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Application.Common; using Cluckwork.Domain.Accounts; diff --git a/tests/Cluckwork.Api.IntegrationTests/SecurityEventLoggingTests.cs b/tests/Cluckwork.Api.IntegrationTests/SecurityEventLoggingTests.cs index d3978f0b5..f8bcb604b 100644 --- a/tests/Cluckwork.Api.IntegrationTests/SecurityEventLoggingTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/SecurityEventLoggingTests.cs @@ -1,9 +1,9 @@ +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Collections.Concurrent; using System.Data.Common; using System.Net; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Application.Common; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; diff --git a/tests/Cluckwork.Api.IntegrationTests/SimulationCrossDayRerunTests.cs b/tests/Cluckwork.Api.IntegrationTests/SimulationCrossDayRerunTests.cs index 69fe58f2d..97d7eb25b 100644 --- a/tests/Cluckwork.Api.IntegrationTests/SimulationCrossDayRerunTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/SimulationCrossDayRerunTests.cs @@ -1,11 +1,11 @@ using Cluckwork.Domain.Modules.EggOperations.Contracts; using Cluckwork.Domain.Modules.GeneralInventory.Inventory; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.IO; using System.Text.Json; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Application.Common; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; diff --git a/tests/Cluckwork.Api.IntegrationTests/SimulationDeepSeedDrainTests.cs b/tests/Cluckwork.Api.IntegrationTests/SimulationDeepSeedDrainTests.cs index 2f0f61c78..7ad1cf610 100644 --- a/tests/Cluckwork.Api.IntegrationTests/SimulationDeepSeedDrainTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/SimulationDeepSeedDrainTests.cs @@ -2,7 +2,6 @@ using Cluckwork.Application.Common; using Cluckwork.Domain.Accounts; using Cluckwork.Domain.Modules.EggOperations.Contracts; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Jobs; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Hosting; diff --git a/tests/Cluckwork.Api.IntegrationTests/SimulationSeederTests.cs b/tests/Cluckwork.Api.IntegrationTests/SimulationSeederTests.cs index c9c2dff57..cad8d886d 100644 --- a/tests/Cluckwork.Api.IntegrationTests/SimulationSeederTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/SimulationSeederTests.cs @@ -3,6 +3,7 @@ using Cluckwork.Domain.Modules.FlockManagement.Contracts; using Cluckwork.Domain.Modules.FlockManagement.Flocks; using Cluckwork.Domain.Modules.GeneralInventory.Inventory; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.IO; using System.Net.Http.Json; using System.Text; @@ -11,7 +12,6 @@ using Cluckwork.Application.Common; using Cluckwork.Domain.Accounts; using Cluckwork.Domain.Auditing; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; diff --git a/tests/Cluckwork.Api.IntegrationTests/StepUpAuthTests.cs b/tests/Cluckwork.Api.IntegrationTests/StepUpAuthTests.cs index 928a86baa..bf5a009ca 100644 --- a/tests/Cluckwork.Api.IntegrationTests/StepUpAuthTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/StepUpAuthTests.cs @@ -1,11 +1,12 @@ +using Cluckwork.Api.Modules.Access.Auth; +using Cluckwork.Application.Modules.Access.Users; using Cluckwork.Domain.Modules.Commerce.Contracts; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Net; using System.Net.Http.Headers; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Application.Common; using Cluckwork.Domain.Common; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Cluckwork.Infrastructure.SharedState; using Microsoft.AspNetCore.Identity; diff --git a/tests/Cluckwork.Api.IntegrationTests/StepUpGrantRegistrySharedStoreTests.cs b/tests/Cluckwork.Api.IntegrationTests/StepUpGrantRegistrySharedStoreTests.cs index 9e2b7422a..7cb0b4446 100644 --- a/tests/Cluckwork.Api.IntegrationTests/StepUpGrantRegistrySharedStoreTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/StepUpGrantRegistrySharedStoreTests.cs @@ -1,6 +1,6 @@ using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Api.IntegrationTests.SharedState; -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Persistence; using Cluckwork.Infrastructure.SharedState; using Microsoft.AspNetCore.Identity; diff --git a/tests/Cluckwork.Api.IntegrationTests/StepUpGrantRegistryTests.cs b/tests/Cluckwork.Api.IntegrationTests/StepUpGrantRegistryTests.cs index ecc018277..8a4292c17 100644 --- a/tests/Cluckwork.Api.IntegrationTests/StepUpGrantRegistryTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/StepUpGrantRegistryTests.cs @@ -1,6 +1,6 @@ using Cluckwork.Api.IntegrationTests.Infrastructure; using Cluckwork.Api.IntegrationTests.SharedState; -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Persistence; using Cluckwork.Infrastructure.SharedState; using Microsoft.AspNetCore.Identity; diff --git a/tests/Cluckwork.Api.IntegrationTests/TemporaryPasswordTests.cs b/tests/Cluckwork.Api.IntegrationTests/TemporaryPasswordTests.cs index ec9ebb932..2e89b34e9 100644 --- a/tests/Cluckwork.Api.IntegrationTests/TemporaryPasswordTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/TemporaryPasswordTests.cs @@ -1,5 +1,5 @@ +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Linq; -using Cluckwork.Infrastructure.Identity; namespace Cluckwork.Api.IntegrationTests; diff --git a/tests/Cluckwork.Api.IntegrationTests/TenantResolutionMiddlewareTests.cs b/tests/Cluckwork.Api.IntegrationTests/TenantResolutionMiddlewareTests.cs index 681c58e34..c3c9c1897 100644 --- a/tests/Cluckwork.Api.IntegrationTests/TenantResolutionMiddlewareTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/TenantResolutionMiddlewareTests.cs @@ -1,7 +1,7 @@ +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Security.Claims; using Cluckwork.Api.Middleware; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/TwoFarmIsolationMatrixTests.cs b/tests/Cluckwork.Api.IntegrationTests/TwoFarmIsolationMatrixTests.cs index 29089cdcc..b9e98492e 100644 --- a/tests/Cluckwork.Api.IntegrationTests/TwoFarmIsolationMatrixTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/TwoFarmIsolationMatrixTests.cs @@ -1,9 +1,9 @@ +using Cluckwork.Api.Modules.Access.Auth; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Infrastructure.Modules.Access.Identity; using System.Net; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; -using Cluckwork.Application.Features.Users; using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; diff --git a/tests/Cluckwork.Api.IntegrationTests/UserNameTests.cs b/tests/Cluckwork.Api.IntegrationTests/UserNameTests.cs index a505c2285..f80617589 100644 --- a/tests/Cluckwork.Api.IntegrationTests/UserNameTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/UserNameTests.cs @@ -1,6 +1,6 @@ +using Cluckwork.Api.Modules.Access.Auth; using System.Net; using System.Net.Http.Json; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; namespace Cluckwork.Api.IntegrationTests; diff --git a/tests/Cluckwork.Api.IntegrationTests/UserPasswordTests.cs b/tests/Cluckwork.Api.IntegrationTests/UserPasswordTests.cs index 37345227e..118dc4312 100644 --- a/tests/Cluckwork.Api.IntegrationTests/UserPasswordTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/UserPasswordTests.cs @@ -1,6 +1,6 @@ +using Cluckwork.Api.Modules.Access.Auth; using System.Net; using System.Net.Http.Json; -using Cluckwork.Api.Endpoints.Auth; using Cluckwork.Api.IntegrationTests.Infrastructure; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Api.IntegrationTests/UserRoleAccountIdModelTests.cs b/tests/Cluckwork.Api.IntegrationTests/UserRoleAccountIdModelTests.cs index 5f66d5b8a..e34d9c073 100644 --- a/tests/Cluckwork.Api.IntegrationTests/UserRoleAccountIdModelTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/UserRoleAccountIdModelTests.cs @@ -1,4 +1,4 @@ -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Application.Tests/Architecture/AccessOwnershipClaimTests.cs b/tests/Cluckwork.Application.Tests/Architecture/AccessOwnershipClaimTests.cs index 65c043250..be3ad66c1 100644 --- a/tests/Cluckwork.Application.Tests/Architecture/AccessOwnershipClaimTests.cs +++ b/tests/Cluckwork.Application.Tests/Architecture/AccessOwnershipClaimTests.cs @@ -3,8 +3,8 @@ namespace Cluckwork.Application.Tests.Architecture; public sealed class AccessOwnershipClaimTests { [Theory] - [InlineData("Cluckwork.Application.Common.IIdentityProvider")] - [InlineData("Cluckwork.Application.Common.IStepUpGrantService")] + [InlineData("Cluckwork.Application.Modules.Access.Users.IIdentityProvider")] + [InlineData("Cluckwork.Application.Modules.Access.Users.IStepUpGrantService")] public void CommonIdentityPortRemainsOwnedByContractedAccess(string type) { var access = Assert.Single(RealModuleLedger.Value.Owners, owner => owner.Name == "Access"); diff --git a/tests/Cluckwork.Application.Tests/Architecture/RealModuleLedger.Adapters.cs b/tests/Cluckwork.Application.Tests/Architecture/RealModuleLedger.Adapters.cs index 15bf35d8f..666004bd1 100644 --- a/tests/Cluckwork.Application.Tests/Architecture/RealModuleLedger.Adapters.cs +++ b/tests/Cluckwork.Application.Tests/Architecture/RealModuleLedger.Adapters.cs @@ -52,11 +52,11 @@ internal static partial class RealModuleLedger new("Cluckwork.Api.Endpoints.Accounts.FarmLogoEndpoints.SetLogo", ["Farm"]), new("Cluckwork.Api.Endpoints.Accounts.FarmLogoEndpoints.ToResponse", ["Farm"]), new("Cluckwork.Api.Modules.Insights.Audit.AuditEndpoints.ListAuditEvents", ["Insights"]), - new("Cluckwork.Api.Endpoints.Auth.AuthEndpoints.ChangePassword", ["Access"]), - new("Cluckwork.Api.Endpoints.Auth.AuthEndpoints.Login", ["Access"]), - new("Cluckwork.Api.Endpoints.Auth.AuthEndpoints.Logout", ["Access"]), - new("Cluckwork.Api.Endpoints.Auth.AuthEndpoints.Refresh", ["Access"]), - new("Cluckwork.Api.Endpoints.Auth.AuthEndpoints.StepUp", ["Access"]), + new("Cluckwork.Api.Modules.Access.Auth.AuthEndpoints.ChangePassword", ["Access"]), + new("Cluckwork.Api.Modules.Access.Auth.AuthEndpoints.Login", ["Access"]), + new("Cluckwork.Api.Modules.Access.Auth.AuthEndpoints.Logout", ["Access"]), + new("Cluckwork.Api.Modules.Access.Auth.AuthEndpoints.Refresh", ["Access"]), + new("Cluckwork.Api.Modules.Access.Auth.AuthEndpoints.StepUp", ["Access"]), new("Cluckwork.Api.Modules.Commerce.Catalog.ProductEndpoints.CreateProduct", ["Commerce"]), new("Cluckwork.Api.Modules.Commerce.Catalog.ProductEndpoints.ListConversions", ["Commerce"]), new("Cluckwork.Api.Modules.Commerce.Catalog.ProductEndpoints.ListProducts", ["Commerce"]), @@ -169,9 +169,9 @@ internal static partial class RealModuleLedger new("Cluckwork.Api.Modules.GeneralInventory.Inventory.InventoryEndpoints.SetActive", ["GeneralInventory"]), new("Cluckwork.Api.Modules.GeneralInventory.Inventory.InventoryEndpoints.ToResponse", ["GeneralInventory"]), new("Cluckwork.Api.Modules.GeneralInventory.Inventory.InventoryEndpoints.UpdateItem", ["GeneralInventory"]), - new("Cluckwork.Api.Endpoints.Me.MeEndpoints.GetMe", ["Access"]), - new("Cluckwork.Api.Endpoints.Me.MeEndpoints.SetLanguage", ["Access"]), - new("Cluckwork.Api.Endpoints.Me.MeEndpoints.SetStepperUnit", ["Access"]), + new("Cluckwork.Api.Modules.Access.Me.MeEndpoints.GetMe", ["Access"]), + new("Cluckwork.Api.Modules.Access.Me.MeEndpoints.SetLanguage", ["Access"]), + new("Cluckwork.Api.Modules.Access.Me.MeEndpoints.SetStepperUnit", ["Access"]), new("Cluckwork.Api.Modules.Insights.Reports.ReportEndpoints.Expenses", ["Insights"]), new("Cluckwork.Api.Modules.Insights.Reports.ReportEndpoints.Production", [ "FlockManagement", @@ -212,17 +212,17 @@ internal static partial class RealModuleLedger new("Cluckwork.Api.Modules.EggOperations.Stock.StockEndpoints.ListLotMovements", ["EggOperations"]), new("Cluckwork.Api.Modules.EggOperations.Stock.StockEndpoints.ListLots", ["EggOperations"]), new("Cluckwork.Api.Modules.EggOperations.Stock.StockEndpoints.RecordLotMovement", ["EggOperations"]), - new("Cluckwork.Api.Endpoints.Users.UserEndpoints.AssignFlock", ["Access"]), - new("Cluckwork.Api.Endpoints.Users.UserEndpoints.ChangeUserEmail", ["Access"]), - new("Cluckwork.Api.Endpoints.Users.UserEndpoints.ChangeUserRole", ["Access"]), - new("Cluckwork.Api.Endpoints.Users.UserEndpoints.CreateUser", ["Access"]), - new("Cluckwork.Api.Endpoints.Users.UserEndpoints.DisableUser", ["Access"]), - new("Cluckwork.Api.Endpoints.Users.UserEndpoints.EnableUser", ["Access"]), - new("Cluckwork.Api.Endpoints.Users.UserEndpoints.ListAssignments", ["Access"]), - new("Cluckwork.Api.Endpoints.Users.UserEndpoints.ListUsers", ["Access"]), - new("Cluckwork.Api.Endpoints.Users.UserEndpoints.SetUserPassword", ["Access"]), - new("Cluckwork.Api.Endpoints.Users.UserEndpoints.UnassignFlock", ["Access"]), - new("Cluckwork.Api.Endpoints.Users.UserEndpoints.UpdateUser", ["Access"]), + new("Cluckwork.Api.Modules.Access.Users.UserEndpoints.AssignFlock", ["Access"]), + new("Cluckwork.Api.Modules.Access.Users.UserEndpoints.ChangeUserEmail", ["Access"]), + new("Cluckwork.Api.Modules.Access.Users.UserEndpoints.ChangeUserRole", ["Access"]), + new("Cluckwork.Api.Modules.Access.Users.UserEndpoints.CreateUser", ["Access"]), + new("Cluckwork.Api.Modules.Access.Users.UserEndpoints.DisableUser", ["Access"]), + new("Cluckwork.Api.Modules.Access.Users.UserEndpoints.EnableUser", ["Access"]), + new("Cluckwork.Api.Modules.Access.Users.UserEndpoints.ListAssignments", ["Access"]), + new("Cluckwork.Api.Modules.Access.Users.UserEndpoints.ListUsers", ["Access"]), + new("Cluckwork.Api.Modules.Access.Users.UserEndpoints.SetUserPassword", ["Access"]), + new("Cluckwork.Api.Modules.Access.Users.UserEndpoints.UnassignFlock", ["Access"]), + new("Cluckwork.Api.Modules.Access.Users.UserEndpoints.UpdateUser", ["Access"]), new("Cluckwork.Api.Modules.GeneralInventory.Water.WaterUsageEndpoints.ListWaterUsage", [ "FlockManagement", "GeneralInventory", diff --git a/tests/Cluckwork.Application.Tests/Common/AuditVocabularyCoverageTests.cs b/tests/Cluckwork.Application.Tests/Common/AuditVocabularyCoverageTests.cs index ec9af2d56..fa658ed32 100644 --- a/tests/Cluckwork.Application.Tests/Common/AuditVocabularyCoverageTests.cs +++ b/tests/Cluckwork.Application.Tests/Common/AuditVocabularyCoverageTests.cs @@ -448,7 +448,7 @@ private static (string[] Args, int EndIndex) SplitTopLevelArguments(string sourc // string parameter, and the forwarder's callers were actually checked. private static readonly HashSet<(string File, string Parameter)> KnownIndirectActionCallSites = [ - ("Cluckwork.Infrastructure/Identity/IdentityProvider.cs", "auditAction"), + ("Cluckwork.Infrastructure/Modules/Access/Identity/IdentityProvider.cs", "auditAction"), ]; // Fails closed on anything but a direct AuditActions.X reference, a diff --git a/tests/Cluckwork.Application.Tests/FlockScoping/FlockScopeGuardTests.cs b/tests/Cluckwork.Application.Tests/FlockScoping/FlockScopeGuardTests.cs index 02e7f183e..eb49da573 100644 --- a/tests/Cluckwork.Application.Tests/FlockScoping/FlockScopeGuardTests.cs +++ b/tests/Cluckwork.Application.Tests/FlockScoping/FlockScopeGuardTests.cs @@ -1,5 +1,5 @@ using Cluckwork.Application.Common; -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Persistence; using Cluckwork.Infrastructure.Repositories; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Application.Tests/TenantBypass/BypassAllowList.cs b/tests/Cluckwork.Application.Tests/TenantBypass/BypassAllowList.cs index a7e66f63d..89491f144 100644 --- a/tests/Cluckwork.Application.Tests/TenantBypass/BypassAllowList.cs +++ b/tests/Cluckwork.Application.Tests/TenantBypass/BypassAllowList.cs @@ -33,43 +33,43 @@ internal static class BypassAllowList [ new() { - Symbol = "Cluckwork.Infrastructure.Identity.AccountProvisioner.ProvisionAsync(string? name, string? slug, string? ownerEmail, string? locale, string? currencyCode, string? timeZoneId, CancellationToken ct)", - File = "src/Cluckwork.Infrastructure/Identity/AccountProvisioner.cs", + Symbol = "Cluckwork.Infrastructure.Modules.Access.Identity.AccountProvisioner.ProvisionAsync(string? name, string? slug, string? ownerEmail, string? locale, string? currencyCode, string? timeZoneId, CancellationToken ct)", + File = "src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountProvisioner.cs", Hash = "e99bb5a2", Justification = "Provisions a NEW account; checks the global slug for a collision before any tenant exists. Runs at unresolved tenant by design (#533).", }, new() { - Symbol = "Cluckwork.Infrastructure.Identity.CredentialEpochVerifier.VerifyAsync(Guid userId, Guid accountId, int tokenEpoch, CancellationToken ct)", - File = "src/Cluckwork.Infrastructure/Identity/CredentialEpochVerifier.cs", + Symbol = "Cluckwork.Infrastructure.Modules.Access.Identity.CredentialEpochVerifier.VerifyAsync(Guid userId, Guid accountId, int tokenEpoch, CancellationToken ct)", + File = "src/Cluckwork.Infrastructure/Modules/Access/Identity/CredentialEpochVerifier.cs", Hash = "f24c7872", Justification = "DEFENSIVE bypass: reads the user's own account to check IsActive. The read is scoped to the JWT's account id; IgnoreQueryFilters makes it work even before TenantContext resolves. #364 fail-closed guarantee. Moved here from CredentialEpochMiddleware.InvokeAsync by #857, query unchanged.", }, new() { - Symbol = "Cluckwork.Infrastructure.Identity.FirstRunAdminService.ProvisionAsync(string? email, CancellationToken ct)", - File = "src/Cluckwork.Infrastructure/Identity/FirstRunAdminService.cs", + Symbol = "Cluckwork.Infrastructure.Modules.Access.Identity.FirstRunAdminService.ProvisionAsync(string? email, CancellationToken ct)", + File = "src/Cluckwork.Infrastructure/Modules/Access/Identity/FirstRunAdminService.cs", Hash = "dd08f719", Justification = "First-run admin bootstraps the DEFAULT account; checks for an existing Owner at unresolved tenant by design (#283).", }, new() { - Symbol = "Cluckwork.Infrastructure.Identity.FirstRunAdminService.HoldsProvisioningLockAsync(CancellationToken ct)", - File = "src/Cluckwork.Infrastructure/Identity/FirstRunAdminService.cs", + Symbol = "Cluckwork.Infrastructure.Modules.Access.Identity.FirstRunAdminService.HoldsProvisioningLockAsync(CancellationToken ct)", + File = "src/Cluckwork.Infrastructure/Modules/Access/Identity/FirstRunAdminService.cs", Hash = "673eed0b", Justification = "Raw SQL advisory lock for first-run; not tenant-scoped (it is a process-level boot guard, #283).", }, new() { - Symbol = "Cluckwork.Infrastructure.Identity.IdentityProvider.RefreshAsync(string refreshToken, CancellationToken ct, Guid? expectedAccountId)", - File = "src/Cluckwork.Infrastructure/Identity/IdentityProvider.cs", + Symbol = "Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.RefreshAsync(string refreshToken, CancellationToken ct, Guid? expectedAccountId)", + File = "src/Cluckwork.Infrastructure/Modules/Access/Identity/IdentityProvider.cs", Hash = "8ac33f82", Justification = "Refresh-token rotation reads the account to verify it is active; scoped to the token's account id, IgnoreQueryFilters because TenantContext may be unresolved during the auth handshake.", }, new() { - Symbol = "Cluckwork.Infrastructure.Identity.IdentityProvider.ExecuteLineageFenceAsync(string currentHash, string[] ancestorHashes, Guid rootUserId, Guid rootAccountId, int rootIssuedEpoch, DateTimeOffset now, string rotatedStamp, CancellationToken ct)", - File = "src/Cluckwork.Infrastructure/Identity/IdentityProvider.cs", + Symbol = "Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.ExecuteLineageFenceAsync(string currentHash, string[] ancestorHashes, Guid rootUserId, Guid rootAccountId, int rootIssuedEpoch, DateTimeOffset now, string rotatedStamp, CancellationToken ct)", + File = "src/Cluckwork.Infrastructure/Modules/Access/Identity/IdentityProvider.cs", Hash = "aec72489", Justification = "Low-level raw-SQL data-modifying CTE for logout lineage fencing. Both refresh-token UPDATE arms are explicitly constrained by UserId, AccountId, and IssuedEpoch; the dedicated atomic-logout CTE guard pins both arms and the builder-to-RelationalCommand execution seam.", }, @@ -285,8 +285,8 @@ internal static class BypassAllowList }, new() { - Symbol = "Cluckwork.Infrastructure.Identity.FirstRunAdminService.ProvisionUnderLockAsync(Guid accountId, string accountSlug, string email, CancellationToken ct)", - File = "src/Cluckwork.Infrastructure/Identity/FirstRunAdminService.cs", + Symbol = "Cluckwork.Infrastructure.Modules.Access.Identity.FirstRunAdminService.ProvisionUnderLockAsync(Guid accountId, string accountSlug, string email, CancellationToken ct)", + File = "src/Cluckwork.Infrastructure/Modules/Access/Identity/FirstRunAdminService.cs", Hash = "28ffc7ff", Justification = "Caller of HoldsProvisioningLockAsync (a forwarding wrapper). First-run admin bootstrap runs at unresolved tenant by design (#283); the provisioning lock is a process-level advisory lock, not tenant-scoped.", }, @@ -299,15 +299,15 @@ internal static class BypassAllowList }, new() { - Symbol = "Cluckwork.Infrastructure.Identity.AccountRenameService.RenameAsync(string currentSlug, string? newSlug, string? reason, CancellationToken ct)", - File = "src/Cluckwork.Infrastructure/Identity/AccountRenameService.cs", + Symbol = "Cluckwork.Infrastructure.Modules.Access.Identity.AccountRenameService.RenameAsync(string currentSlug, string? newSlug, string? reason, CancellationToken ct)", + File = "src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountRenameService.cs", Hash = "b43347b9", Justification = "Caller of ResolveSlugsAsync (a forwarding wrapper). Operator CLI resolves the source farm by its globally unique code AND checks the destination code's availability in that one read, before any tenant is resolved. The service's locked read is tenant-keyed; the global IX_Accounts_Slug index and its unique-violation catch remain authoritative for the destination (#732). Same justified call site as AccountSlugLookup.ResolveAsync (#536).", }, new() { - Symbol = "Cluckwork.Infrastructure.Identity.AccountRenameService.ResolveSlugsAsync(string currentSlug, string target, CancellationToken ct)", - File = "src/Cluckwork.Infrastructure/Identity/AccountRenameService.cs", + Symbol = "Cluckwork.Infrastructure.Modules.Access.Identity.AccountRenameService.ResolveSlugsAsync(string currentSlug, string target, CancellationToken ct)", + File = "src/Cluckwork.Infrastructure/Modules/Access/Identity/AccountRenameService.cs", Hash = "3b4358c4", Justification = "One unresolved-tenant read covering both the source code and the destination code: the operator CLI runs before any tenant exists, so IgnoreQueryFilters is required rather than defensive. Neither half is an authority — the post-lock fence covers the source by comparing the locked row's slug AND Version against this read's snapshot, and the global IX_Accounts_Slug index plus its unique-violation catch cover the destination (#732).", }, diff --git a/tests/Cluckwork.Application.Tests/TenantBypass/FilterFreeSetSites.cs b/tests/Cluckwork.Application.Tests/TenantBypass/FilterFreeSetSites.cs index 6d8808598..86ca2f69d 100644 --- a/tests/Cluckwork.Application.Tests/TenantBypass/FilterFreeSetSites.cs +++ b/tests/Cluckwork.Application.Tests/TenantBypass/FilterFreeSetSites.cs @@ -57,100 +57,100 @@ internal static class FilterFreeSetSites new("Cluckwork.Api.Middleware.IdempotencyMiddleware.TryClaimOrInspectAsync(AppDbContext db, Guid accountId, string endpointHash, string keyHash, string requestHash, Guid ownerToken, DateTimeOffset leaseExpiresAt, DateTimeOffset now, CancellationToken ct)", "db.IdempotencyRecords", "5a00a5f9", "by-key: unique index (AccountId, EndpointHash, IdempotencyKeyHash) is enforced by the DB; the method carries accountId and the record is written with it. The claim read is by (endpointHash, keyHash) within the caller's resolved account."), - new("Cluckwork.Infrastructure.Identity.AccessSeedLookup.OwnerRoleExistsAsync(CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.AccessSeedLookup.OwnerRoleExistsAsync(CancellationToken ct)", "db.Roles", "36c0e024", "global-reference: non-Production simulation fixture port (#858) checks the migration-baked Owner role (AspNetRoles is farm-wide reference data); the seeder calls it at unresolved tenant by design (#279)."), - new("Cluckwork.Infrastructure.Identity.AccountScopedUserValidator.ValidateAsync(UserManager manager, ApplicationUser user)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.AccountScopedUserValidator.ValidateAsync(UserManager manager, ApplicationUser user)", "db.Users", "104f7fd4", "by-id: re-reads the current user by primary key (candidate.Id == user.Id) to compare against the persisted row; the user's account is already resolved by the caller. #529 legacy-import guard."), - new("Cluckwork.Infrastructure.Identity.AccountUserDirectory.FindByAccountRoleAsync(Guid accountId, string roleName, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.AccountUserDirectory.FindByAccountRoleAsync(Guid accountId, string roleName, CancellationToken ct)", "db.Roles", "f4f82571", "global-reference: AspNetRoles has no AccountId column — roles are farm-wide reference data (the four base roles are global); the query is scoped by the join to the tenant's UserRows, not by an account predicate."), - new("Cluckwork.Infrastructure.Identity.AccountUserDirectory.FindByAccountRoleAsync(Guid accountId, string roleName, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.AccountUserDirectory.FindByAccountRoleAsync(Guid accountId, string roleName, CancellationToken ct)", "db.UserRoles", "f4f82571", "scoped-by-join: the role query joins db.Users (which carries AccountId) on user.Id, and the WHERE names user.AccountId == accountId; the UserRoles join is therefore tenant-scoped transitively."), - new("Cluckwork.Infrastructure.Identity.AdminRecoveryService.RecoverAsync(string? email, Guid? accountId, string? reason, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.AdminRecoveryService.RecoverAsync(string? email, Guid? accountId, string? reason, CancellationToken ct)", "db.Users", "59037298", "by-id+account: break-glass recovery looks up the user by email within the recovered account; the method takes accountId and the lookup is scoped to it. #265."), - new("Cluckwork.Infrastructure.Identity.FirstRunStatusService.IsProvisionedAsync(CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.FirstRunStatusService.IsProvisionedAsync(CancellationToken ct)", "db.Roles", "fd78330f", "global-reference: role lookup by name (AspNetRoles is farm-wide reference data); scoped by the join to the tenant's user rows."), - new("Cluckwork.Infrastructure.Identity.FirstRunStatusService.IsProvisionedAsync(CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.FirstRunStatusService.IsProvisionedAsync(CancellationToken ct)", "db.UserRoles", "fd78330f", "scoped-by-join: checks the Owner role by joining db.Users (carries AccountId) on user.Id; tenant-scoped transitively through the user row."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.ChangeOwnPasswordAsync(Guid userId, string currentPassword, string newPassword, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.ChangeOwnPasswordAsync(Guid userId, string currentPassword, string newPassword, CancellationToken ct)", "db.RefreshTokens", "fdec8b5b", "by-user: password change revokes the user's tokens by user id (account-unique)."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.CountOtherActiveOwnersAsync(Guid accountId, Guid excludingUserId, CancellationToken token)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.CountOtherActiveOwnersAsync(Guid accountId, Guid excludingUserId, CancellationToken token)", "db.Roles", "57009ecd", "global-reference: Owner-role filter by name in the owner-count (AspNetRoles is farm-wide reference data)."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.CountOtherActiveOwnersAsync(Guid accountId, Guid excludingUserId, CancellationToken token)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.CountOtherActiveOwnersAsync(Guid accountId, Guid excludingUserId, CancellationToken token)", "db.UserRoles", "57009ecd", "scoped-by-user-id: counts other active Owners by joining UserRoles on the user id (account-unique) and the user's AccountId == accountId."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.DisableUserAsync(Guid accountId, Guid userId, Guid actingUserId, string? reason, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.DisableUserAsync(Guid accountId, Guid userId, Guid actingUserId, string? reason, CancellationToken ct)", "db.Roles", "9b6fec98", "global-reference: role lookup by name in the disable path (AspNetRoles is farm-wide reference data)."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.DisableUserAsync(Guid accountId, Guid userId, Guid actingUserId, string? reason, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.DisableUserAsync(Guid accountId, Guid userId, Guid actingUserId, string? reason, CancellationToken ct)", "db.UserRoles", "9b6fec98", "scoped-by-user-id: DisableUser READS the target's Owner membership by userRole.UserId == userId (account-unique) for the last-Owner check; it writes no role row (it disables the user, rotates the stamp, bumps the epoch, revokes refresh tokens)."), - new("Cluckwork.Infrastructure.Identity.AccessLookup.GetEffectiveRoleAsync(Guid accountId, Guid userId, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.AccessLookup.GetEffectiveRoleAsync(Guid accountId, Guid userId, CancellationToken ct)", "db.Roles", "4adcdb84", "global-reference: role name resolution in the effective-role routine (#612; IAccessLookup owns it since #857) (AspNetRoles is farm-wide reference data)."), - new("Cluckwork.Infrastructure.Identity.AccessLookup.GetEffectiveRoleAsync(Guid accountId, Guid userId, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.AccessLookup.GetEffectiveRoleAsync(Guid accountId, Guid userId, CancellationToken ct)", "db.UserRoles", "4adcdb84", "scoped-by-account: the effective-role routine (#612; owned by IAccessLookup since #857) loads the user's roles; the method takes accountId and has already confirmed the user is an ACTIVE member of it via a preceding db.Users AnyAsync(u.Id == userId && u.AccountId == accountId && u.DisabledAt == null) check."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.GetUserAsync(Guid accountId, Guid userId, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.GetUserAsync(Guid accountId, Guid userId, CancellationToken ct)", "db.Roles", "3696c8d2", "global-reference: role name resolution in GetUser (AspNetRoles is farm-wide reference data)."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.GetUserAsync(Guid accountId, Guid userId, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.GetUserAsync(Guid accountId, Guid userId, CancellationToken ct)", "db.UserRoles", "3696c8d2", "scoped-by-account: GetUser loads the user's roles; the method takes accountId and the user lookup is scoped to it."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.InspectGraceReplacementAsync(RefreshToken revoked, DateTimeOffset now, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.InspectGraceReplacementAsync(RefreshToken revoked, DateTimeOffset now, CancellationToken ct)", "db.RefreshTokens", "2c93fbd6", "by-root-lineage: attaches only the replacement entity projected by the fresh hash + UserId + AccountId parent/child inspection; Attach performs no query and the later CAS save retains the row's AccountId."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.ListUsersAsync(Guid accountId, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.ListUsersAsync(Guid accountId, CancellationToken ct)", "db.Roles", "2eb84bd1", "global-reference: role name resolution in ListUsers (AspNetRoles is farm-wide reference data)."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.ListUsersAsync(Guid accountId, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.ListUsersAsync(Guid accountId, CancellationToken ct)", "db.UserRoles", "2eb84bd1", "scoped-by-account: lists the account's users with their roles; the query carries u.AccountId == accountId (the UserRoles join is scoped by the user rows)."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.LoginAsync(Guid accountId, string email, string password, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.LoginAsync(Guid accountId, string email, string password, CancellationToken ct)", "db.RefreshTokens", "9d5e17f7", "by-hash: login rotates the user's refresh tokens by user id (account-unique); the token hash embeds the account."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.MintedTokenIsDurableAsync(string mintedHash)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.MintedTokenIsDurableAsync(string mintedHash)", "db.RefreshTokens", "737b7a77", "by-hash: the post-save durability probe uses the hash of 256-bit random bytes minted by this single attempt and not yet exposed; presence proves this attempt's transaction committed."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.RefreshAsync(string refreshToken, CancellationToken ct, Guid? expectedAccountId)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.RefreshAsync(string refreshToken, CancellationToken ct, Guid? expectedAccountId)", "db.RefreshTokens", "84591a87", "by-hash: refresh-token rotation reads by token hash; the hash is account-scoped by construction."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.RefreshAsync(string refreshToken, CancellationToken ct, Guid? expectedAccountId)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.RefreshAsync(string refreshToken, CancellationToken ct, Guid? expectedAccountId)", "db.RefreshTokens", "9d5e17f7", "by-hash: same rotation path, second read by token hash."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.RequireActiveOwnerAsync(Guid accountId, Guid actingUserId, CancellationToken token)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.RequireActiveOwnerAsync(Guid accountId, Guid actingUserId, CancellationToken token)", "db.Roles", "aed7b297", "global-reference: role lookup by name in the Owner check (AspNetRoles is farm-wide reference data)."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.RequireActiveOwnerAsync(Guid accountId, Guid actingUserId, CancellationToken token)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.RequireActiveOwnerAsync(Guid accountId, Guid actingUserId, CancellationToken token)", "db.UserRoles", "aed7b297", "scoped-by-user-id: checks the acting user's Owner role by userRole.UserId == actingUserId (the user id is account-unique); the Role join is to global reference data."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.RevokeAllActiveForUserAsync(Guid userId, int? issuedEpoch, DateTimeOffset now, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.RevokeAllActiveForUserAsync(Guid userId, int? issuedEpoch, DateTimeOffset now, CancellationToken ct)", "db.RefreshTokens", "34d066f2", "by-user: revokes all active tokens for a user by user id (account-unique)."), - new("Cluckwork.Infrastructure.Identity.IdentityProvider.RevokeRefreshTokenAsync(string refreshToken, CancellationToken ct, Guid? expectedAccountId)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.RevokeRefreshTokenAsync(string refreshToken, CancellationToken ct, Guid? expectedAccountId)", "db.RefreshTokens", "1a753d3f", "by-hash: logout attribution reads by the globally unique opaque credential hash, then immediately compares the projected AccountId when a farm was selected; the projection is part of that scope gate. Review P1-3 surfaced this candidate because the old Contains(\"AccountId\") check mistook a projection for a predicate."), - new("Cluckwork.Infrastructure.Identity.PersistentStepUpGrantRegistry.IsRevokedByLogoutAsync(Guid userId, int grantEpoch, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.PersistentStepUpGrantRegistry.IsRevokedByLogoutAsync(Guid userId, int grantEpoch, CancellationToken ct)", "db.Users", "5e42ce0b", "by-id: checks revocation by the user's StepUpLogoutEpoch (account-unique)."), - new("Cluckwork.Infrastructure.Identity.PersistentStepUpGrantRegistry.RecordLogoutAsync(Guid userId, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.PersistentStepUpGrantRegistry.RecordLogoutAsync(Guid userId, CancellationToken ct)", "db.Users", "8f838564", "by-id: records a logout by bumping the user's StepUpLogoutEpoch (account-unique)."), - new("Cluckwork.Infrastructure.Identity.PersistentStepUpGrantRegistry.TryConsumeIfNotLoggedOutAsync(Guid userId, Guid jti, int grantEpoch, DateTimeOffset expiresAt, DateTimeOffset now, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.PersistentStepUpGrantRegistry.TryConsumeIfNotLoggedOutAsync(Guid userId, Guid jti, int grantEpoch, DateTimeOffset expiresAt, DateTimeOffset now, CancellationToken ct)", "db.Users", "5e42ce0b", "by-id: reads the user's StepUpLogoutEpoch by user id (account-unique) to check the grant is not revoked; #338 shared-state."), - new("Cluckwork.Infrastructure.Identity.RefreshTokenPurge.DeleteExpiredBatchAsync(DateTimeOffset cutoff, int batchSize, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.RefreshTokenPurge.DeleteExpiredBatchAsync(DateTimeOffset cutoff, int batchSize, CancellationToken ct)", "db.RefreshTokens", "7d79d25a", "non-tenant sweep: purges expired refresh tokens across all tenants (single-leader gate #271); scoped by expiry."), - new("Cluckwork.Infrastructure.Identity.StepUpGrantService.ValidateAsync(Guid accountId, Guid userId, string? stepUpToken, CancellationToken ct)", + new("Cluckwork.Infrastructure.Modules.Access.Identity.StepUpGrantService.ValidateAsync(Guid accountId, Guid userId, string? stepUpToken, CancellationToken ct)", "db.Users", "ed4ecf61", "by-id: validates the grant's security stamp by user id (account-unique), then rejects when the persisted user's AccountId does not match the grant account; the read is no-tracking so a later account-locked mutation cannot identity-resolve this pre-lock row."), new("Cluckwork.Infrastructure.Jobs.DurableJobWorker.ProcessPendingJobsAsync(CancellationToken ct)", diff --git a/tests/Cluckwork.Application.Tests/TenantBypass/FindBySlugCallerTests.cs b/tests/Cluckwork.Application.Tests/TenantBypass/FindBySlugCallerTests.cs index 159fd3c22..9bbb64840 100644 --- a/tests/Cluckwork.Application.Tests/TenantBypass/FindBySlugCallerTests.cs +++ b/tests/Cluckwork.Application.Tests/TenantBypass/FindBySlugCallerTests.cs @@ -18,7 +18,7 @@ public sealed class FindBySlugCallerTests private const string Member = "FindBySlugAsync"; private const string Login = - "Cluckwork.Infrastructure.Identity.IdentityProvider.ResolveFarmCodeAsync(string farmCode, CancellationToken ct)"; + "Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.ResolveFarmCodeAsync(string farmCode, CancellationToken ct)"; [Fact] public void OnlyLoginCallsTheCrossFarmSlugLookup() diff --git a/tests/Cluckwork.Application.Tests/TenantBypass/TenantBypassDiscoveryTests.cs b/tests/Cluckwork.Application.Tests/TenantBypass/TenantBypassDiscoveryTests.cs index 4b011d437..19bff7dc6 100644 --- a/tests/Cluckwork.Application.Tests/TenantBypass/TenantBypassDiscoveryTests.cs +++ b/tests/Cluckwork.Application.Tests/TenantBypass/TenantBypassDiscoveryTests.cs @@ -1,5 +1,5 @@ using Cluckwork.Domain.Accounts; -using Cluckwork.Infrastructure.Identity; +using Cluckwork.Infrastructure.Modules.Access.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; diff --git a/tests/Cluckwork.Application.Tests/TenantBypass/TenantBypassRealTreeTests.cs b/tests/Cluckwork.Application.Tests/TenantBypass/TenantBypassRealTreeTests.cs index 5b7fe54c3..14c3fa269 100644 --- a/tests/Cluckwork.Application.Tests/TenantBypass/TenantBypassRealTreeTests.cs +++ b/tests/Cluckwork.Application.Tests/TenantBypass/TenantBypassRealTreeTests.cs @@ -1,4 +1,3 @@ -using Cluckwork.Infrastructure.Identity; using Cluckwork.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; @@ -35,7 +34,7 @@ public void RealSourceTree_AllBypassesAreAllowListed() public void AtomicLogoutCte_BothUpdateArmsRetainOwnerScope() { const string symbol = - "Cluckwork.Infrastructure.Identity.IdentityProvider.ExecuteLineageFenceAsync(string currentHash, " + + "Cluckwork.Infrastructure.Modules.Access.Identity.IdentityProvider.ExecuteLineageFenceAsync(string currentHash, " + "string[] ancestorHashes, Guid rootUserId, Guid rootAccountId, int rootIssuedEpoch, " + "DateTimeOffset now, string rotatedStamp, CancellationToken ct)"; var report = GuardScanner.Scan(SrcRoot(), BypassAllowList.Entries); diff --git a/tests/Cluckwork.Application.Tests/TenantBypass/TenantBypassWalkTests.cs b/tests/Cluckwork.Application.Tests/TenantBypass/TenantBypassWalkTests.cs index 678c25ecd..21dff6fb1 100644 --- a/tests/Cluckwork.Application.Tests/TenantBypass/TenantBypassWalkTests.cs +++ b/tests/Cluckwork.Application.Tests/TenantBypass/TenantBypassWalkTests.cs @@ -30,7 +30,7 @@ public void Walk_SeesTheWholeSourceTree() // disappears from the walk, the exclusion logic is eating real source. var known = files.Select(f => f.Replace('\\', '/')); Assert.Contains(known, f => f.EndsWith("src/Cluckwork.Infrastructure/Repositories/EggLotRepository.cs")); - Assert.Contains(known, f => f.EndsWith("src/Cluckwork.Infrastructure/Identity/IdentityProvider.cs")); + Assert.Contains(known, f => f.EndsWith("src/Cluckwork.Infrastructure/Modules/Access/Identity/IdentityProvider.cs")); } [Fact] diff --git a/tests/Cluckwork.Application.Tests/Validation/PasswordMaxLengthValidatorTests.cs b/tests/Cluckwork.Application.Tests/Validation/PasswordMaxLengthValidatorTests.cs index dbccdb5b6..1f0f8ee5f 100644 --- a/tests/Cluckwork.Application.Tests/Validation/PasswordMaxLengthValidatorTests.cs +++ b/tests/Cluckwork.Application.Tests/Validation/PasswordMaxLengthValidatorTests.cs @@ -1,7 +1,8 @@ -using Cluckwork.Application.Features.Users; -using Cluckwork.Application.Features.Users.ChangeOwnPassword; -using Cluckwork.Application.Features.Users.CreateUser; -using Cluckwork.Application.Features.Users.SetUserPassword; +using Cluckwork.Application.Modules.Access.Contracts; +using Cluckwork.Application.Modules.Access.Users; +using Cluckwork.Application.Modules.Access.Users.ChangeOwnPassword; +using Cluckwork.Application.Modules.Access.Users.CreateUser; +using Cluckwork.Application.Modules.Access.Users.SetUserPassword; namespace Cluckwork.Application.Tests.Validation; From 080594b7f3937a44b3eeefac12ec113ed3b0f25c Mon Sep 17 00:00:00 2001 From: mforce Date: Mon, 5 Oct 2026 23:07:02 +0000 Subject: [PATCH 3/4] refactor(arch): read Access's Identity-port ownership from the namespace AccessOwnershipClaimTests asserted the two ports through Access's Types claim, which the move retires. It now resolves each type through the ledger's namespace index and requires a namespace claim owned by the contracted Access module. GlobalUserLookupGuardTests' fixture and AccountSuspensionTests' source read build their Identity paths by segments, which the codemod's path rewrite does not match. Two comments and the simulation runbook pointed at a stale Identity/SimulationOptions.cs; it lives in Persistence. Refs #1087 --- .../simulation-fixture-on-a-dev-database.md | 2 +- .../AccountSuspensionTests.cs | 2 +- .../GlobalUserLookupGuardTests.cs | 4 ++-- .../Architecture/AccessOwnershipClaimTests.cs | 22 ++++++++++++++----- tools/simulation/bootstrap.sh | 2 +- tools/simulation/k6/config.js | 2 +- 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/docs/runbooks/simulation-fixture-on-a-dev-database.md b/docs/runbooks/simulation-fixture-on-a-dev-database.md index a20a8017f..a2d578191 100644 --- a/docs/runbooks/simulation-fixture-on-a-dev-database.md +++ b/docs/runbooks/simulation-fixture-on-a-dev-database.md @@ -212,7 +212,7 @@ A does not exist for form B, and vice versa. ### 4. The knobs All bind from the `Simulation` section -([`SimulationOptions.cs`](../../src/Cluckwork.Infrastructure/Identity/SimulationOptions.cs)); +([`SimulationOptions.cs`](../../src/Cluckwork.Infrastructure/Persistence/SimulationOptions.cs)); as environment variables the separator is `__`. | Key | Default | What it does | diff --git a/tests/Cluckwork.Api.IntegrationTests/AccountSuspensionTests.cs b/tests/Cluckwork.Api.IntegrationTests/AccountSuspensionTests.cs index 354a0d253..f94781c19 100644 --- a/tests/Cluckwork.Api.IntegrationTests/AccountSuspensionTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/AccountSuspensionTests.cs @@ -330,7 +330,7 @@ await d.AuditEvents.AsNoTracking() dir = dir.Parent; Assert.NotNull(dir); var serviceSource = await File.ReadAllTextAsync( - Path.Combine(dir!.FullName, "src", "Cluckwork.Infrastructure", "Identity", "AccountSuspensionService.cs")); + Path.Combine(dir!.FullName, "src", "Cluckwork.Infrastructure", "Modules", "Access", "Identity", "AccountSuspensionService.cs")); // Find every SaveChanges call site. The needle includes the receiver // dot: the file carries "SaveChanges" in a COMMENT (line 193, "before // The comment above ("before SaveChanges, so the row lands") is not a diff --git a/tests/Cluckwork.Api.IntegrationTests/GlobalUserLookupGuardTests.cs b/tests/Cluckwork.Api.IntegrationTests/GlobalUserLookupGuardTests.cs index 9dfd04ded..9d001eb07 100644 --- a/tests/Cluckwork.Api.IntegrationTests/GlobalUserLookupGuardTests.cs +++ b/tests/Cluckwork.Api.IntegrationTests/GlobalUserLookupGuardTests.cs @@ -104,7 +104,7 @@ public void MigrationShapedFile_ContainingBannedToken_IsExempt() // Force underMigrations = false by renaming to a non-migration name // in a non-Migrations directory, proving the guard CAUGHT it there. - var prodDir = Path.Combine(srcRoot, "Cluckwork.Infrastructure", "Identity"); + var prodDir = Path.Combine(srcRoot, "Cluckwork.Infrastructure", "Modules", "Access", "Identity"); var prodPath = Path.Combine(prodDir, "20990101000000_TempExemptionTest.cs"); File.Move(filePath, prodPath); var caughtOffenders = ScanFiles([prodPath]); @@ -119,7 +119,7 @@ public void MigrationShapedFile_ContainingBannedToken_IsExempt() } finally { - foreach (var p in new[] { filePath, Path.Combine(srcRoot, "Cluckwork.Infrastructure", "Identity", "20990101000000_TempExemptionTest.cs") }) + foreach (var p in new[] { filePath, Path.Combine(srcRoot, "Cluckwork.Infrastructure", "Modules", "Access", "Identity", "20990101000000_TempExemptionTest.cs") }) if (File.Exists(p)) File.Delete(p); } } diff --git a/tests/Cluckwork.Application.Tests/Architecture/AccessOwnershipClaimTests.cs b/tests/Cluckwork.Application.Tests/Architecture/AccessOwnershipClaimTests.cs index be3ad66c1..cb8b9f357 100644 --- a/tests/Cluckwork.Application.Tests/Architecture/AccessOwnershipClaimTests.cs +++ b/tests/Cluckwork.Application.Tests/Architecture/AccessOwnershipClaimTests.cs @@ -1,14 +1,26 @@ +using Cluckwork.Application.Modules.Access.Users; + namespace Cluckwork.Application.Tests.Architecture; public sealed class AccessOwnershipClaimTests { + // The two Identity ports left Application.Common for Access's own namespace (#1087), so Access owns them + // through a namespace claim, not a type claim. [Theory] - [InlineData("Cluckwork.Application.Modules.Access.Users.IIdentityProvider")] - [InlineData("Cluckwork.Application.Modules.Access.Users.IStepUpGrantService")] - public void CommonIdentityPortRemainsOwnedByContractedAccess(string type) + [InlineData(typeof(IIdentityProvider))] + [InlineData(typeof(IStepUpGrantService))] + public void IdentityPortIsOwnedByContractedAccessThroughItsNamespace(Type type) { - var access = Assert.Single(RealModuleLedger.Value.Owners, owner => owner.Name == "Access"); + var ledger = RealModuleLedger.Value; + var access = Assert.Single(ledger.Owners, owner => owner.Name == "Access"); Assert.NotEmpty(access.Contract); - Assert.Contains(type, access.Types); + + var errors = new List(); + var index = ModuleLedgerScanner.BuildNamespaceIndex(ledger, errors); + Assert.Empty(errors); + var owner = ModuleLedgerScanner.Resolve(index, type.FullName!, declared: true); + Assert.NotNull(owner); + Assert.Equal("Access", owner.Value.Owner); + Assert.True(index[owner.Value.Namespace].Subtree, $"{type.FullName} must be owned through a namespace"); } } diff --git a/tools/simulation/bootstrap.sh b/tools/simulation/bootstrap.sh index 8821aeeb6..b71810490 100755 --- a/tools/simulation/bootstrap.sh +++ b/tools/simulation/bootstrap.sh @@ -71,7 +71,7 @@ command -v python3 >/dev/null 2>&1 || { echo "bootstrap.sh requires python3 on P # --- Cast shape ------------------------------------------------------------ # Mirrors SimulationOptions' own defaults (Managers=1, Sales=1, Workers=3, -# ReadOnly=4 — src/Cluckwork.Infrastructure/Identity/SimulationOptions.cs). +# ReadOnly=4 — src/Cluckwork.Infrastructure/Persistence/SimulationOptions.cs). # Written explicitly into .env.sim below (Simulation__Managers etc.) so this # script's cast list can never silently drift from what the app actually # seeds — the counts here are the ONE source of truth for both files. diff --git a/tools/simulation/k6/config.js b/tools/simulation/k6/config.js index 653722703..dbb6d2444 100644 --- a/tools/simulation/k6/config.js +++ b/tools/simulation/k6/config.js @@ -15,7 +15,7 @@ export const BASE_URL = __ENV.BASE_URL || 'http://127.0.0.1:8081'; // Presence-only CSRF guard the API requires on /auth/refresh — any value is // accepted, but the header must be present. See -// src/Cluckwork.Api/Endpoints/Auth/AuthCookies.cs (CsrfHeaderName). +// src/Cluckwork.Api/Modules/Access/Auth/AuthCookies.cs (CsrfHeaderName). export const CSRF_HEADER_NAME = 'X-Cluckwork-Auth'; export const CSRF_HEADER_VALUE = '1'; From ad0aac701bff09592c90cea4cdf79db192d75f8f Mon Sep 17 00:00:00 2001 From: mforce Date: Mon, 5 Oct 2026 23:41:13 +0000 Subject: [PATCH 4/4] refactor(arch): delete the Access [ModuleContract] marks The twenty-nine Access contract types now sit in Application's Contracts folder; the folder makes them contract, and a type with both fails. Refs #1087 --- .../Modules/Access/Contracts/AccessOperationOutcomes.cs | 5 ----- .../Modules/Access/Contracts/AssignFlockCommand.cs | 1 - .../Modules/Access/Contracts/ChangeOwnPasswordCommand.cs | 1 - .../Modules/Access/Contracts/ChangeUserEmailCommand.cs | 1 - .../Modules/Access/Contracts/ChangeUserRoleCommand.cs | 1 - .../Modules/Access/Contracts/CreateUserCommand.cs | 1 - .../Modules/Access/Contracts/DisableUserCommand.cs | 1 - .../Modules/Access/Contracts/EnableUserCommand.cs | 1 - .../Modules/Access/Contracts/IAccessAccountLifecycle.cs | 1 - .../Modules/Access/Contracts/IAccessFixture.cs | 1 - .../Modules/Access/Contracts/IAccessLookup.cs | 1 - .../Modules/Access/Contracts/IAccessModule.cs | 2 -- .../Modules/Access/Contracts/IAccessOperations.cs | 1 - .../Modules/Access/Contracts/IAccessSeedLookup.cs | 3 --- .../Modules/Access/Contracts/ICredentialEpochVerifier.cs | 2 -- .../Modules/Access/Contracts/IRefreshTokenPurge.cs | 1 - .../Modules/Access/Contracts/SetLanguageCommand.cs | 1 - .../Modules/Access/Contracts/SetStepperUnitCommand.cs | 1 - .../Modules/Access/Contracts/SetUserPasswordCommand.cs | 1 - .../Modules/Access/Contracts/UnassignFlockCommand.cs | 1 - .../Modules/Access/Contracts/UpdateUserCommand.cs | 1 - 21 files changed, 29 deletions(-) diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/AccessOperationOutcomes.cs b/src/Cluckwork.Application/Modules/Access/Contracts/AccessOperationOutcomes.cs index 76ece4fc4..f8e3aeb13 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/AccessOperationOutcomes.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/AccessOperationOutcomes.cs @@ -5,7 +5,6 @@ namespace Cluckwork.Application.Modules.Access.Contracts; // path, so all its fields are non-null, whereas AlreadyProvisioned() here returns // a value with nothing populated. Copying its non-nullable `string Slug` across // would make the idempotent branch unrepresentable. -[ModuleContract("Access")] public sealed record FirstRunAdminOutcome( bool WasAlreadyProvisioned, string? Email, @@ -27,20 +26,16 @@ public static FirstRunAdminOutcome Provisioned( // is populated and none are nullable. The slug is read off `lockedAccount` // (already loaded FOR UPDATE in the transaction, no new query) and printed by // recover-admin because #532 made the farm code a required login input. -[ModuleContract("Access")] public sealed record AdminRecoveryResult(string Email, Guid AccountId, string Slug, string TemporaryPassword); // Changed = "this command transitioned the farm", so a verb can report a no-op // re-run without going back to the database to work out what it did. -[ModuleContract("Access")] public sealed record AccountLifecycleOutcome(bool Changed); // Changed = "this command changed the code", so the verb can tell an operator their // re-run was a no-op without re-reading the database. Deliberately NOT "the farm is fine". -[ModuleContract("Access")] public sealed record AccountRenameOutcome(bool Changed); -[ModuleContract("Access")] public sealed record AccountProvisionOutcome( Guid AccountId, string Slug, diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/AssignFlockCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/AssignFlockCommand.cs index cbcd3c87a..6068b301e 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/AssignFlockCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/AssignFlockCommand.cs @@ -1,5 +1,4 @@ namespace Cluckwork.Application.Modules.Access.Contracts; -[ModuleContract("Access")] public sealed record AssignFlockCommand( Guid UserId, Guid FlockId, string? StepUpToken = null); diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/ChangeOwnPasswordCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/ChangeOwnPasswordCommand.cs index e6763db61..a42dd30f4 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/ChangeOwnPasswordCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/ChangeOwnPasswordCommand.cs @@ -3,5 +3,4 @@ namespace Cluckwork.Application.Modules.Access.Contracts; // #165 — self-service: any signed-in user changes their OWN password by proving // the current one. On success every session is revoked and the caller is handed // a fresh pair, so other devices are signed out but this one stays in. -[ModuleContract("Access")] public sealed record ChangeOwnPasswordCommand(string CurrentPassword, string NewPassword); diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/ChangeUserEmailCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/ChangeUserEmailCommand.cs index 48bd4623d..5f44cf9b0 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/ChangeUserEmailCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/ChangeUserEmailCommand.cs @@ -1,4 +1,3 @@ namespace Cluckwork.Application.Modules.Access.Contracts; -[ModuleContract("Access")] public sealed record ChangeUserEmailCommand(Guid UserId, string Email, string? StepUpToken); diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/ChangeUserRoleCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/ChangeUserRoleCommand.cs index 59ff86426..c18c420d5 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/ChangeUserRoleCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/ChangeUserRoleCommand.cs @@ -5,5 +5,4 @@ namespace Cluckwork.Application.Modules.Access.Contracts; // Role is non-nullable — the caller always states an // explicit target, using the same "Worker" sentinel CreateUserValidator // defines rather than null (matching CreateUserCommand's own shape). -[ModuleContract("Access")] public sealed record ChangeUserRoleCommand(Guid UserId, string Role, string? StepUpToken = null); diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/CreateUserCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/CreateUserCommand.cs index fc6e39ce3..c710b42c8 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/CreateUserCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/CreateUserCommand.cs @@ -4,7 +4,6 @@ namespace Cluckwork.Application.Modules.Access.Contracts; // for every interactive user creation regardless of Role. It rides a header, // never the request body proper, but the command carries it alongside the rest // of the form data the handler needs. -[ModuleContract("Access")] public sealed record CreateUserCommand( string Email, string Password, diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/DisableUserCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/DisableUserCommand.cs index 6a9a7d48c..7ee899278 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/DisableUserCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/DisableUserCommand.cs @@ -4,5 +4,4 @@ namespace Cluckwork.Application.Modules.Access.Contracts; // one gets typed "x"). StepUpToken is REQUIRED, unlike ChangeUserRoleCommand's // conditional shape: disabling any user removes their access outright, so // there is no "ordinary farm administration" case here to leave ungated. -[ModuleContract("Access")] public sealed record DisableUserCommand(Guid UserId, string? Reason = null, string? StepUpToken = null); diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/EnableUserCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/EnableUserCommand.cs index ce6f9a9a5..0db21e1c9 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/EnableUserCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/EnableUserCommand.cs @@ -4,5 +4,4 @@ namespace Cluckwork.Application.Modules.Access.Contracts; // before, and the audit row already records who and when. StepUpToken is // required for the same reason as on the disable side — re-enabling an Owner // restores exactly the access a disable took away. -[ModuleContract("Access")] public sealed record EnableUserCommand(Guid UserId, string? StepUpToken = null); diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/IAccessAccountLifecycle.cs b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessAccountLifecycle.cs index 2ff67bcba..49b96c6a5 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/IAccessAccountLifecycle.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessAccountLifecycle.cs @@ -2,7 +2,6 @@ namespace Cluckwork.Application.Modules.Access.Contracts; -[ModuleContract("Access")] public interface IAccessAccountLifecycle { Task> SuspendAccountAsync(Guid accountId, string? reason, CancellationToken ct); diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/IAccessFixture.cs b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessFixture.cs index b39b36059..64be4253a 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/IAccessFixture.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessFixture.cs @@ -3,7 +3,6 @@ namespace Cluckwork.Application.Modules.Access.Contracts; // Simulation fixture write; registered beside the seeders outside Production. // The trusted seeder holds no step-up grant, so this skips the interactive // AssignFlockHandler's step-up and Worker-role checks, and nothing else. -[ModuleContract("Access")] public interface IAccessFixture { // Assigns the flock to the farm's user unless already assigned, writes the diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/IAccessLookup.cs b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessLookup.cs index 75ef4a83a..bd6207c4f 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/IAccessLookup.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessLookup.cs @@ -4,7 +4,6 @@ namespace Cluckwork.Application.Modules.Access.Contracts; // fresh, on the caller's scoped context, so a caller inside a transaction reads // inside it: ConfirmSaleHandler reads the role and the assignments after its // account and order locks (#612, #727). Nothing here is cached. -[ModuleContract("Access")] public interface IAccessLookup { // Null when the user is not an ACTIVE member of the account (#612). diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/IAccessModule.cs b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessModule.cs index 052b73618..c49ff8479 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/IAccessModule.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessModule.cs @@ -7,7 +7,6 @@ namespace Cluckwork.Application.Modules.Access.Contracts; // caller's own profile, flock assignments, and sessions. Each member forwards // to the existing handler or identity service, so step-up checks, locks, audit // rows, tokens and errors are theirs, unchanged. Peers use IAccessLookup instead. -[ModuleContract("Access")] public interface IAccessModule { Task> CreateUserAsync( @@ -79,5 +78,4 @@ Task> IssueStepUpGrantAsync( // #512 T047 — an assignment with its flock's CURRENT name. FlockName is null for // a farm-wide assignment (FlockId null) and for a flock this caller may not see // or that no longer resolves; FlockId is kept either way. -[ModuleContract("Access")] public sealed record UserFlockAssignment(Guid Id, Guid? FlockId, string? FlockName); diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/IAccessOperations.cs b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessOperations.cs index 4f0d464ec..93b1ae290 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/IAccessOperations.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessOperations.cs @@ -6,7 +6,6 @@ namespace Cluckwork.Application.Modules.Access.Contracts; // authority is shell access to the deployment. Each member forwards to the // existing service, so validation, locks, audit rows and generated passwords // are theirs, unchanged. HTTP adapters use IAccessModule instead. -[ModuleContract("Access")] public interface IAccessOperations { Task> BootstrapAdminAsync(string? email, CancellationToken ct); diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/IAccessSeedLookup.cs b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessSeedLookup.cs index 041b42fe2..40dc01f48 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/IAccessSeedLookup.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/IAccessSeedLookup.cs @@ -1,7 +1,6 @@ namespace Cluckwork.Application.Modules.Access.Contracts; // Fixture actor reads; registered beside the seeders outside Production. -[ModuleContract("Access")] public interface IAccessSeedLookup { Task FindUserByEmailAsync(Guid accountId, string email, CancellationToken ct = default); @@ -18,8 +17,6 @@ Task> ListUsersInRoleAsync( Task CountUsersAsync(Guid accountId, CancellationToken ct = default); } -[ModuleContract("Access")] public sealed record AccessActor(Guid Id, string? Email, DateTimeOffset? DisabledAt, IReadOnlyList Roles); -[ModuleContract("Access")] public sealed record AccessUserSummary(Guid Id, string? Email, DateTimeOffset? DisabledAt); diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/ICredentialEpochVerifier.cs b/src/Cluckwork.Application/Modules/Access/Contracts/ICredentialEpochVerifier.cs index 24ff98325..613726a06 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/ICredentialEpochVerifier.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/ICredentialEpochVerifier.cs @@ -7,7 +7,6 @@ namespace Cluckwork.Application.Modules.Access.Contracts; // and a failed read must throw rather than return a verdict. // CredentialEpochFreshReadTests exercises each of those rules on the paths it // drives; it cannot prove them for every implementation, so review still must. -[ModuleContract("Access")] public interface ICredentialEpochVerifier { Task VerifyAsync( @@ -16,7 +15,6 @@ Task VerifyAsync( // Zero is deliberately not Current: a default(CredentialVerdict), whether from a // swallowed exception, a test double or an uninitialised local, must refuse. -[ModuleContract("Access")] public enum CredentialVerdict { None = 0, diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/IRefreshTokenPurge.cs b/src/Cluckwork.Application/Modules/Access/Contracts/IRefreshTokenPurge.cs index c791ef90d..a98d181a5 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/IRefreshTokenPurge.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/IRefreshTokenPurge.cs @@ -3,7 +3,6 @@ namespace Cluckwork.Application.Modules.Access.Contracts; // #857 — the refresh-token purge's DELETE (#270). The sweep owns the cutoff, // the grace and the batch bounds; this removes at most batchSize rows whose // ExpiresAt is before the cutoff, oldest first, and returns how many it removed. -[ModuleContract("Access")] public interface IRefreshTokenPurge { Task DeleteExpiredBatchAsync(DateTimeOffset cutoff, int batchSize, CancellationToken ct); diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/SetLanguageCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/SetLanguageCommand.cs index 0f46c8d25..6047c2ca1 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/SetLanguageCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/SetLanguageCommand.cs @@ -1,5 +1,4 @@ namespace Cluckwork.Application.Modules.Access.Contracts; // The already-canonicalised (trimmed + lowercased) preference, or null to clear. -[ModuleContract("Access")] public sealed record SetLanguageCommand(string? Language); diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/SetStepperUnitCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/SetStepperUnitCommand.cs index a9e75431a..a176b85bc 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/SetStepperUnitCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/SetStepperUnitCommand.cs @@ -4,5 +4,4 @@ namespace Cluckwork.Application.Modules.Access.Contracts; // follow the farm default again. Travels as a string like every other // enum-by-name field in this API (UnitSystem, FirstDayOfWeek) — the validator // proves it names a defined EggUnit before the handler parses it. -[ModuleContract("Access")] public sealed record SetStepperUnitCommand(string? Unit); diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/SetUserPasswordCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/SetUserPasswordCommand.cs index f3585cd8f..7140d9ad1 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/SetUserPasswordCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/SetUserPasswordCommand.cs @@ -6,5 +6,4 @@ namespace Cluckwork.Application.Modules.Access.Contracts; // // #308/#360 — StepUpToken is the caller's proof-of-recent-auth grant, required // for every administrative reset regardless of the target's current role. -[ModuleContract("Access")] public sealed record SetUserPasswordCommand(Guid UserId, string NewPassword, string? StepUpToken = null); diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/UnassignFlockCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/UnassignFlockCommand.cs index 7ae42241b..86aa4808f 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/UnassignFlockCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/UnassignFlockCommand.cs @@ -1,5 +1,4 @@ namespace Cluckwork.Application.Modules.Access.Contracts; -[ModuleContract("Access")] public sealed record UnassignFlockCommand( Guid UserId, Guid AssignmentId, string? StepUpToken = null); diff --git a/src/Cluckwork.Application/Modules/Access/Contracts/UpdateUserCommand.cs b/src/Cluckwork.Application/Modules/Access/Contracts/UpdateUserCommand.cs index 9594e5acb..0f482b945 100644 --- a/src/Cluckwork.Application/Modules/Access/Contracts/UpdateUserCommand.cs +++ b/src/Cluckwork.Application/Modules/Access/Contracts/UpdateUserCommand.cs @@ -2,5 +2,4 @@ namespace Cluckwork.Application.Modules.Access.Contracts; // #163 — edit an existing user's display name. Name is nullable: passing null (or // blank) clears it back to "—". Role/password editing are separate slices. -[ModuleContract("Access")] public sealed record UpdateUserCommand(Guid UserId, string? Name);