ClinicFlow is organized as a three-project Clean Architecture solution. Each layer has a clearly defined responsibility and a strict dependency rule: inner layers know nothing about outer layers. Domain has no project references at all. Application references only Domain. Infrastructure references both Domain and Application — it is the outermost layer responsible for I/O, persistence, and external services.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.
Layer 1 — Domain
Project:ClinicFlow.Domain (net10.0, no <PackageReference> entries)
The Domain layer is the heart of ClinicFlow. It contains every concept that belongs to the clinic’s ubiquitous language and enforces every invariant without reaching outside itself.
Entities
All entities inherit fromBaseEntity, which provides a Guid identity, auditing support, and a domain-event collection:
SoftDeletableEntity, which adds an IsDeleted flag and MarkAsDeleted() / UndoDeletion() helpers. Doctor is the primary example — suspending a doctor soft-deletes the record and triggers a DoctorSuspendedEvent that cascades into appointment reassignment.
| Entity | Description |
|---|---|
Appointment | Full lifecycle: Scheduled → CheckedIn → InProgress → Completed / Cancelled / NoShow / LateCancellation / RequiresReassignment |
Doctor | Physician linked to a User, a MedicalSpecialty, and a ConsultationRoom; supports suspension and reactivation |
Patient | Primary and family-member profiles with scheduling clearance and penalty tracking |
User | Authentication identity shared across roles; holds UserRole, hashed password, phone verification state |
MedicalRecord | Clinical encounter record attached to a completed appointment |
Schedule | Doctor’s weekly availability slots used to validate appointment time ranges |
MedicalSpecialty | Named specialty referenced by doctors and appointment type restrictions |
AppointmentTypeDefinition | Configurable appointment type with category, duration, age policy, and specialty restrictions |
ClinicalFormTemplate | JSON-schema-backed template for dynamic clinical detail forms |
PatientPenalty | Penalty record (late cancellation, no-show) with block duration and expiry |
Value objects
Value objects encapsulate domain concepts that have no identity of their own — they are equal when their data is equal:| Value Object | Wraps |
|---|---|
PersonName | First and last name |
EmailAddress | Validated e-mail string |
PhoneNumber | Validated phone string |
MedicalLicenseNumber | Physician license identifier |
ConsultationRoom | Room identifier for a doctor |
TimeRange | Start/end TimeOnly pair for appointment slots |
BloodType | Patient blood type enum wrapper |
PenaltyHistory | Aggregated count and recency of patient penalties |
SchedulingClearance | Derived from penalty history — grants or denies booking rights |
AgeEligibilityPolicy | Min/max age bounds for appointment types |
CancellationLimit | Allowed cancellation window for an appointment type |
EmergencyContact | Name and phone for a patient’s emergency contact |
EncounterDuration | Duration of a clinical encounter |
Domain events
Events implement theIDomainEvent marker interface and are raised inside entity methods via AddDomainEvent(). They are pending in memory until the Infrastructure layer dispatches them after persistence.
Appointment events: AppointmentScheduledEvent, AppointmentRescheduledEvent, AppointmentCancelledEvent, AppointmentLateCancelledEvent, AppointmentCheckedInEvent, AppointmentStartedEvent, AppointmentCompletedEvent, AppointmentMarkedAsNoShowEvent, AppointmentReassignedEvent, AppointmentSystemCancelledEvent
Other events: DoctorSuspendedEvent, PatientReactivatedEvent, ScheduleDeactivatedEvent
Domain services
Domain services coordinate multi-entity operations that don’t belong on any single entity:| Service | Responsibility |
|---|---|
AppointmentSchedulingService | Validates patient clearance, doctor availability, and slot conflicts before calling Appointment.Schedule() |
AppointmentCancellationService | Determines standard vs. late cancellation based on the cancellation window and issues penalties |
AppointmentReschedulingService | Enforces the single-reschedule rule and checks new slot availability |
AppointmentReassignmentService | Assigns a new doctor and time slot to a RequiresReassignment appointment |
MedicalEncounterService | Orchestrates appointment start, completion, and medical record creation |
PatientPenaltyService | Applies, evaluates, and resolves patient penalties |
DoctorRegistrationService | Creates a Doctor record and links it to an existing User |
PrimaryProfileRegistrationService | Registers a new User + Patient pair |
FamilyMemberRegistrationService | Adds a dependent patient profile under an existing account |
WeeklyScheduleSetupService | Creates or replaces a doctor’s weekly schedule, enforcing slot overlap rules |
UserAuthenticationService | Login, logout, and lockout logic |
PatientAccessService | Checks that the requesting user is authorized to act on behalf of a patient |
Repository and service interfaces
All persistence and external-service contracts are declared inClinicFlow.Domain/Interfaces/, keeping the Domain layer independent of any concrete implementation:
- Repositories:
IAppointmentRepository,IAppointmentTypeDefinitionRepository,IClinicalFormTemplateRepository,IDoctorRepository,IMedicalRecordRepository,IMedicalSpecialtyRepository,IPatientPenaltyRepository,IPatientRepository,IScheduleRepository,IUserRepository - Unit of work:
IUnitOfWork - Services:
IPasswordHasherService,IPhoneVerificationService,IRegionalSchedulingService
Layer 2 — Application
Project:ClinicFlow.Application (net10.0)
CQRS structure
Every use case is expressed as either a Command (mutates state, returns no or minimal data) or a Query (reads state, never mutates). Commands and queries are organized by feature area, each in its own folder with three files: the request record, the handler, and the validator.- Commands (sample)
- Queries (sample)
Appointments, AppointmentTypes, ClinicalFormTemplates, Doctors, MedicalRecords, MedicalSpecialties, Patients, Penalties, Schedules, Users.
ValidationBehavior pipeline
All commands and queries pass through theValidationBehavior<TRequest, TResponse> MediatR pipeline behavior before reaching their handler. It runs every registered FluentValidation IValidator<TRequest> in parallel and throws an application-level ValidationException if any rules fail — preventing any invalid request from touching the domain or the database.
Dependency injection registration
AddApplicationServices() is the single extension method that wires up the Application layer:
AddValidatorsFromAssembly auto-discovers every IValidator<T> in the Application assembly. AddBehavior ensures the ValidationBehavior wraps every IRequest<T> dispatch globally.
Layer 3 — Infrastructure
Project:ClinicFlow.Infrastructure (net10.0)
Persistence
ApplicationDbContext is the EF Core DbContext. Each entity has a dedicated IEntityTypeConfiguration<T> in Persistence/Configurations/ that maps value objects as owned types, configures check constraints, sets max lengths, and defines relationships.
The UnitOfWork implementation wraps ApplicationDbContext.SaveChangesAsync() and is the single point where all persistence changes are flushed to PostgreSQL.
Repository implementations (AppointmentRepository, AppointmentTypeDefinitionRepository) implement the domain’s IRepository interfaces using EF Core LINQ queries against the ApplicationDbContext.
Data seeding
WhenSeedOnStartup: true is configured, DbSeeder is hooked into EF Core’s UseSeeding and UseAsyncSeeding callbacks inside AddInfrastructureServices(). The seeder uses the Bogus library to generate realistic fake data — doctors, patients, specialties, appointment type definitions, clinical form templates, and appointments — populating the database on the first run without any manual SQL.
External service stubs
The Infrastructure layer provides concrete implementations for the domain service interfaces:IPhoneVerificationService— phone OTP verification flowIPasswordHasherService— password hashing and verification
Dependency injection registration
AddInfrastructureServices() wires the full Infrastructure layer:
DatabaseOptions reads from the Database configuration section, which must supply ConnectionString and an optional SeedOnStartup boolean.
Dependency flow summary
Domain Model
Explore every entity, value object, and domain event in detail — including the full appointment lifecycle state machine.
CQRS and MediatR
See how commands, queries, handlers, and the ValidationBehavior pipeline are used end-to-end across all feature areas.