Skip to main content

Documentation 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.

The Penalties module enforces booking-eligibility rules by recording warnings and temporary blocks against patient profiles. Penalties are created in two ways: automatically by the domain when a patient no-shows or cancels too late, and manually by clinic staff using the BlockPatient command. Manual blocks always result in a TemporaryBlock penalty with a staff-defined duration. Automatic warnings and blocks are created internally by domain event handlers and are not exposed as commands.
Automatic penalties (warnings for late cancellations, blocks for repeat no-shows) are raised by domain event handlers that react to AppointmentMarkedAsNoShowEvent and AppointmentLateCancelledEvent. These internal penalty records share the same PatientPenalty entity and DTO as manual blocks, and appear in all penalty query results. The AppointmentId field on the DTO is non-null for automatic penalties and null for manual blocks.

BlockDuration Enum

BlockDuration specifies the predefined duration in calendar days for a manual block.
public enum BlockDuration
{
    Minor    = 5,   // 5-day block
    Moderate = 15,  // 15-day block
    Severe   = 30,  // 30-day block
}
ValueDaysUse case
Minor5First or minor infraction
Moderate15Repeated or moderately serious behaviour
Severe30Persistent non-compliance
The BlockedUntil date is computed as today + (int)BlockDuration using TimeProvider.GetUtcNow().

PenaltyType Enum

public enum PenaltyType
{
    Warning        = 1,  // Non-blocking advisory notice
    TemporaryBlock = 2,  // Prevents new appointment bookings until BlockedUntil
}
A Warning does not prevent booking; it is advisory only. A TemporaryBlock prevents the patient from booking new appointments until the BlockedUntil date has passed or the penalty is manually removed.

Commands

BlockPatient

Type: IRequest<Guid> Manually creates a TemporaryBlock penalty for a patient. The handler calls PatientPenalty.CreateManualBlock, which sets Type = TemporaryBlock and calculates BlockedUntil = today + (int)duration in UTC. No appointment ID is associated with manual blocks.
public sealed record BlockPatientCommand(
    Guid PatientId,
    string Reason,
    BlockDuration Duration
) : IRequest<Guid>;

Parameters

PatientId
Guid
required
The patient to block. Must be a non-empty GUID. The patient does not need to be unblocked to receive a new block — multiple active block records can co-exist.
Reason
string
required
A free-text justification for the block, visible to staff in audit queries. Must not be empty.
Duration
BlockDuration
required
The predefined block duration. Must be a valid BlockDuration enum member (Minor, Moderate, or Severe).
Returns: The newly created PatientPenalty.Id as a Guid.

RemovePenalty

Type: IRequest (returns Unit) Marks an existing penalty (warning or block) as removed. Removed penalties are excluded from all active-block eligibility checks, effectively restoring the patient’s booking rights immediately if no other active block exists. Calling Remove() on an already-removed penalty throws DomainValidationException with DomainErrors.Penalty.AlreadyRemoved.
public sealed record RemovePenaltyCommand(Guid PenaltyId) : IRequest;

Parameters

PenaltyId
Guid
required
The primary key of the penalty record to remove. Must be a non-empty GUID. Throws EntityNotFoundException if not found.
Returns: Unit (void).

Queries

GetPenaltiesByPatientId

Type: IRequest<PaginatedList<PatientPenaltyDto>> Returns a paginated history of all penalties — active, expired, and removed — for a specific patient. Useful for auditing a patient’s full penalty timeline.
public sealed record GetPenaltiesByPatientIdQuery(
    Guid PatientId,
    int PageNumber,
    int PageSize
) : IRequest<PaginatedList<PatientPenaltyDto>>;

Parameters

PatientId
Guid
required
The patient whose penalties to retrieve. Must be a non-empty GUID.
PageNumber
int
required
1-based page index. Must be ≥ 1.
PageSize
int
required
Records per page. Must be between 1 and 100 (inclusive).
Returns: A PaginatedList<PatientPenaltyDto> containing the complete penalty history for the patient.

GetActiveWarnings

Type: IRequest<PaginatedList<PatientPenaltyDto>> Returns a paginated list of all active (non-removed) Warning penalties across all patients. An active warning has Type = Warning and IsRemoved = false.
public sealed record GetActiveWarningsQuery(int PageNumber, int PageSize)
    : IRequest<PaginatedList<PatientPenaltyDto>>;

Parameters

PageNumber
int
required
1-based page index. Must be ≥ 1.
PageSize
int
required
Records per page. Must be between 1 and 100 (inclusive).
Returns: A PaginatedList<PatientPenaltyDto> of all active warnings.

GetActiveBlockedPatients

Type: IRequest<PaginatedList<PatientPenaltyDto>> Returns a paginated list of all TemporaryBlock penalties that are currently in effect — meaning Type = TemporaryBlock, IsRemoved = false, and BlockedUntil >= today.
public sealed record GetActiveBlockedPatientsQuery(int PageNumber, int PageSize)
    : IRequest<PaginatedList<PatientPenaltyDto>>;

Parameters

PageNumber
int
required
1-based page index. Must be ≥ 1.
PageSize
int
required
Records per page. Must be between 1 and 100 (inclusive).
Returns: A PaginatedList<PatientPenaltyDto> of all currently active temporary blocks.

Response Shape

PatientPenaltyDto

public sealed record PatientPenaltyDto(
    Guid Id,
    Guid PatientId,
    Guid? AppointmentId,
    string Type,
    string Reason,
    DateOnly? BlockedUntil,
    bool IsRemoved
);
Id
Guid
The unique identifier of this penalty record.
PatientId
Guid
The patient this penalty is applied to.
AppointmentId
Guid | null
The appointment that triggered the penalty. Populated for automatic penalties (e.g. no-show, late cancellation); null for manual blocks created via BlockPatient.
Type
string
The penalty type as a string. One of "Warning" or "TemporaryBlock" (mapped from PenaltyType enum).
Reason
string
The human-readable reason for the penalty — either a system-generated message for automatic penalties or the staff-provided text for manual blocks.
BlockedUntil
DateOnly | null
The expiry date of a TemporaryBlock penalty. null for Warning type penalties. Computed as issueDate + (int)BlockDuration in UTC days.
IsRemoved
bool
true if the penalty has been cleared by staff via RemovePenalty; false while the penalty is active.

Build docs developers (and LLMs) love