User management in ClinicFlow is handled entirely through MediatR commands and queries. There is no REST layer; commands are dispatched directly viaDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/0Crazy-0/ClinicFlow/llms.txt
Use this file to discover all available pages before exploring further.
IMediator.Send() in the presentation layer. All commands use FluentValidation pipelines that run before the handler, and all write operations are wrapped in a IUnitOfWork that commits atomically.
Registration Commands
RegisterUserCommand
Registers a new Patient user account.
Returns: IRequest<Guid> — the newly created user’s Id.
Valid email address. Must be unique across all users. Maximum length is defined by
EmailAddress.MaximumLength.Plain-text password to hash and store. Minimum 8 characters.
Phone number in any format accepted by the
PhoneNumber value object. Minimum/maximum length enforced.- Checks
IUserRepository.ExistsByEmailAsyncand throwsBusinessRuleValidationException(DomainErrors.User.EmailAlreadyExists) if the email is taken. - Creates
EmailAddressandPhoneNumbervalue objects (format-validated by their constructors). - Hashes the password via
IPasswordHasherService. - Calls
User.Create(email, hash, phone, UserRole.Patient)and persists viaIUnitOfWork.
Guid Id.
RegisterDoctorUserCommand
Registers a new Doctor user account. Identical field structure to RegisterUserCommand; the handler assigns UserRole.Doctor.
Returns: IRequest<Guid>
Unique, valid email address.
Plain-text password. Minimum 8 characters.
Phone number within
PhoneNumber.MinimumLength – PhoneNumber.MaximumLength.RegisterUserCommand except UserRole.Doctor is assigned.
RegisterReceptionistUserCommand
Registers a new Receptionist user account.
Returns: IRequest<Guid>
RegisterUserCommand. Handler assigns UserRole.Receptionist.
RegisterAdminUserCommand
Registers a new Admin user account.
Returns: IRequest<Guid>
RegisterUserCommand. Handler assigns UserRole.Admin.
Account Lifecycle Commands
DeactivateUserCommand
Soft-deactivates a user account, preventing login without deleting data.
Returns: IRequest (no return value)
The
Id of the user to deactivate. Must be a non-empty Guid.- Fetches the user or throws
EntityNotFoundException. - Calls
user.Deactivate()which throwsBusinessRuleValidationException(DomainErrors.User.AlreadyInactive) if already inactive. - Sets
IsActive = falseon the domain entity.
ReactivateUserCommand
Restores a deactivated user account and resets the lockout state.
Returns: IRequest (no return value)
The
Id of the user to reactivate. Must be a non-empty Guid.- Fetches the user or throws
EntityNotFoundException. - Calls
user.Reactivate()which throwsBusinessRuleValidationException(DomainErrors.User.AlreadyActive) if already active. - Sets
IsActive = true, resetsFailedLoginAttempts = 0, and clearsLockoutEnd.
Query: GetUsers
Retrieves a paginated, filterable list of all users. Returns:IRequest<PaginatedList<UserDto>>
1-based page index.
Number of records per page.
Optional role filter. One of
Patient (1), Doctor (2), Receptionist (3), Admin (4).Optional active-status filter.
null returns all users.Optional free-text search applied by the repository against email or phone.
PaginatedList<UserDto> — see UserDto below.
Query: GetUserById
Retrieves a single user by their primary key. Returns:IRequest<UserDto>
The user’s primary key.
EntityNotFoundException if no user with the given Id exists.
Query: GetLockedOutUsers
Retrieves a paginated list of users whose accounts are currently locked out (i.e.,LockoutEnd is in the future).
Returns: IRequest<PaginatedList<UserDto>>
1-based page index.
Number of records per page.
TimeProvider.GetUtcNow() as the reference time to determine which accounts are still locked. Accounts become locked after User.MaxFailedLoginAttempts (5) failed attempts; lockout lasts 15 minutes.
Query: CheckEmailUniqueness
Returnstrue if the given email is not already registered. Useful for real-time form validation.
Returns: IRequest<bool>
The email address to check.
true when the email is available; false when it is already in use.
Query: CheckPhoneUniqueness
Returnstrue if the given phone number is not already registered.
Returns: IRequest<bool>
The phone number to check.
true when the phone number is available; false when it is already in use.
UserDto Response Shape
All user queries returnUserDto or PaginatedList<UserDto>.
The user’s primary key.
The user’s email address (unwrapped from the
EmailAddress value object).The user’s phone number (unwrapped from the
PhoneNumber value object).Integer-backed enum:
Patient = 1, Doctor = 2, Receptionist = 3, Admin = 4.true if the account is active and can authenticate.true if the phone number has been verified via OTP. Required before a patient can schedule appointments.UTC timestamp of the most recent successful login.
null if never logged in.Number of consecutive failed login attempts since the last successful login or password change.
UTC timestamp when the current lockout expires.
null if the account is not locked.PaginatedList Wrapper
Paginated queries wrap results inPaginatedList<T>:
The page’s records.
Total number of matching records across all pages.
Current 1-based page number.
Computed as
ceil(TotalCount / PageSize).true when PageNumber > 1.true when PageNumber < TotalPages.