Clinic management system. Supports the management of staff, offices, appointments, patients and medical records.
The project implements Clean Architecture, CQRS pattern, MediatR, minimal api with api versioning, repository pattern, EF, custom JWT authorization, fluent validation.
👷 Frameworks, Libraries and Technologies
🐳 List of docker containers
app - container for all application layers
database - MSSQL database container
cloudbeaver - graphical access to SQLServer
The first time the containers are launched, random data generation will be performed to check the functionality
(Bogus package).
Build and start Docker images based on the configuration defined in the docker-compose.yml
> make up # docker-compose up --build
Stop and remove containers
> make down # docker-compose down
Swagger UI
http://localhost:5000/swagger/index.html
Swagger static file
https://github.com/gitEugeneL/RightPlace/blob/main/swagger.json
🔧 Implementation features
Authentication is implemented using a JWT access token and refresh token.
AccessToken is used to authorize users, the refresh token is used to update a pair of tokens.
RefreshToken is recorded in the database and allows each user to have 5 active devices at the same time.
POST
/api/v1/auth/login
(allows you to login, issues accessToken and sets refreshToken in cookies)
name
type
data type
email
required
string
password
required
string
http code
content-type
response
200
application/json
{"type: "Bearer", "accessToken": "eyJhbGciOi..........."}
400
application/json
array
name
example
refreshToken
refreshToken=Wna@3da...; Expires=...; Secure; HttpOnly; Domain=...;`
POST
/api/v1/auth/refresh
(allows to refresh access and refresh tokens)
name
example
refreshToken
refreshToken=Wna@3da...;
http code
content-type
response
200
application/json
{"type: "Bearer", "accessToken": "eyJhbGciOi..........."}
400
application/json
array
401
application/json
string
POST
/api/v1/auth/logout
(allows to logout and deactivates refresh token)
Valid access JWT Bearer token in the header
http code
content-type
response
204
application/json
and remove HttpOnly Cookie
NoCOntent
400
application/json
string
401
application/json
string
Functionality that allows to manage and interact with managers
Register new manager (Token required , 🔒admin policy)
POST
/api/v1/manager
(allows to register new manager 🔒️[admin policy])
name
type
data type
"email"
required
string
"password"
required
string
http code
content-type
response
201
application/json
{"userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "email": "string", "firstName": "string", "lastName": "string", "phone": "string", "position": "string"}
400
application/json
array
401
application/json
string
403
application/json
string
409
application/json
string
Update your manager account (Token required , 🔒manager policy)
PUT
/api/v1/manager
(allows to update manager account 🔒️[manager policy])
name
type
data type
"firstName"
not required
string
"lastName"
not required
string
"phone"
not required
string
"position"
not required
string
http code
content-type
response
200
application/json
{"userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "email": "string", "firstName": "string", "lastName": "string", "phone": "string", "position": "string"}
400
application/json
array
401
application/json
string
403
application/json
string
404
application/json
string
Functionality that allows to manage and interact with doctors
Create new doctor (Token required , 🔒manager policy)
POST
/api/v1/doctor
(allows to create new doctor 🔒️[manager policy])
name
type
data type
"email"
required
string
"password"
required
string
http code
content-type
response
201
application/json
{"userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "email": "string", "firstName": "string", "lastName": "string", "phone": "string", "status": "string", "description": "string", "education": "string", "appointmentSettingsId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "specializationIds": [ "3fa85f64-5717-4562-b3fc-2c963f66afa6" ] }
400
application/json
array
401
application/json
string
403
application/json
string
409
application/json
string
Update your doctor account (Token required , 🔒doctor policy)
PUT
/api/v1/doctor
(allows to update doctor account 🔒️[doctor policy])
name
type
data type
"firstName"
not required
string
"lastName"
not required
string
"phone"
not required
string
"status"
not required
string
"description"
not required
string
"education"
not required
string
http code
content-type
response
200
application/json
{"userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "email": "string", "firstName": "string", "lastName": "string", "phone": "string", "status": "string", "description": "string", "education": "string", "appointmentSettingsId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "specializationIds": [ "3fa85f64-5717-4562-b3fc-2c963f66afa6" ] }
400
application/json
array
401
application/json
string
403
application/json
string
404
application/json
string
GET
/api/v1/doctor
(allows to get all doctors)
name
type
data type
PageNumber
not required
int32
PageSize
not required
int32
http code
content-type
response
200
application/json
{"items": [ { "userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "email": "string", "firstName": "string", "lastName": "string", "phone": "string", "status": "string", "description": "string", "education": "string", "appointmentSettingsId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "specializationIds": [ "3fa85f64-5717-4562-b3fc-2c963f66afa6" ] } ], "pageNumber": 0, "totalPages": 0, "totalItemsCount": 0 }
GET
/api/v1/doctor/{ userId:uuid }
(allows to get one doctor)
http code
content-type
response
200
application/json
{"userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "email": "string", "firstName": "string", "lastName": "string", "phone": "string", "status": "string", "description": "string", "education": "string", "appointmentSettingsId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "specializationIds": [ "3fa85f64-5717-4562-b3fc-2c963f66afa6" ] }
404
application/json
string
Functionality that allows to manage and interact with patients
POST
/api/v1/patient
(allows to register new patient)
name
type
data type
"email"
required
string
"password"
required
string
http code
content-type
response
201
application/json
{ "userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "email": "string", "firstName": "string", "lastName": "string", "phone": "string", "pesel": "string", "dateOfBirth": "string", "insurance": "string", "addressId": "3fa85f64-5717-4562-b3fc-2c963f66afa6" }
400
application/json
array
409
application/json
string
Update your patient account (Token required , 🔒patient policy)
PUT
/api/v1/patient
(allows to update your patient account 🔒[patient policy])
name
type
data type
"firstName"
not required
string
"lastName"
not required
string
"phone"
not required
string
"pesel"
not required
string
"dateOfBirth"
not required
string
"insurance"
not required
string
"firstName"
not required
string
http code
content-type
response
200
application/json
{ "userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "email": "string", "firstName": "string", "lastName": "string", "phone": "string", "pesel": "string", "dateOfBirth": "string", "insurance": "string", "addressId": "3fa85f64-5717-4562-b3fc-2c963f66afa6" }
400
application/json
array
401
application/json
string
403
application/json
string
404
application/json
string
Delete your patient account (Token required , 🔒patient policy)
DELETE
/api/v1/patient
(allows to delete your patient account 🔒[patient policy])
http code
content-type
response
204
application/json
NoContent
401
application/json
string
403
application/json
string
404
application/json
string
Get all patients (Token required , 🔒doctor-or-manager policy)
GET
/api/v1/patient
(allows to get all patients 🔒[doctor-or-manager policy])
name
type
data type
PageNumber
not required
int32
PageSize
not required
int32
http code
content-type
response
204
application/json
{"items": [ { "userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "email": "string", "firstName": "string", "lastName": "string", "phone": "string", "pesel": "string", "dateOfBirth": "string", "insurance": "string", "addressId": "3fa85f64-5717-4562-b3fc-2c963f66afa6" } ], "pageNumber": 0, "totalPages": 0, "totalItemsCount": 0 }
401
application/json
string
403
application/json
string
Get one patient (Token required , 🔒doctor-or-manager policy)
GET
/api/v1/patient{ userId:uuid: }
(allows to get one patient 🔒[doctor-or-manager policy])
http code
content-type
response
200
application/json
{"userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "email": "string", "firstName": "string", "lastName": "string", "phone": "string", "pesel": "string", "dateOfBirth": "string", "insurance": "string", "addressId": "3fa85f64-5717-4562-b3fc-2c963f66afa6" }
401
application/json
string
403
application/json
string
404
application/json
string
Functionality allows to manage the patients' addresses (entity is created automatically when a patient is registered)
Update patient address (Token required , 🔒patient policy)
PUT
/api/v1/address
(allows to update patient address 🔒[patient policy])
name
type
data type
"province"
not required
string
"postalCode"
not required
string
"city"
not required
string
"street"
not required
string
"house"
not required
string
"apartment"
not required
string
http code
content-type
response
200
application/json
{"province": "string", "postalCode": "string", "city": "string", "street": "string", "hose": "string", "apartment": "string" }
400
application/json
array
401
application/json
string
403
application/json
string
404
application/json
string
Get patient's address (Token required , 🔒doctor-or-manager policy)
GET
/api/v1/address/{ addressId:uuid }
(allows to get patient's address 🔒[doctor-or-manager policy])
http code
content-type
response
200
application/json
{"province": "string", "postalCode": "string", "city": "string", "street": "string", "hose": "string", "apartment": "string"}
401
application/json
string
403
application/json
string
404
application/json
string
Functionality that allows to manage and interact with appointments
Find doctor's free time (Token required , 🔒patient policy)
GET
/api/v1/appointment/find-time/{ userDoctorId:uuid }/{ date:string }
(allows find doctor's free time 🔒[patient policy])
http code
content-type
response
200
application/json
{ "userDoctorId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "freeHours": [ { "start": "08:00", "end": "09:00" } ] }
401
application/json
string
403
application/json
string
404
application/json
string
422
application/json
string
Create new appointment (Token required , 🔒patient policy)
POST
/api/v1/appointment
(allows to create new appointment 🔒[patient policy])
name
type
data type
"userDoctorId"
required
uuid
"date"
required
string
"startTime"
required
string
http code
content-type
response
201
application/json
{"appointmentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userPatientId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userDoctorId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "date": "string", "startTime": "string", "endTime": "string", "isCompleted": true, "isCanceled": true }
400
application/json
array
401
application/json
string
403
application/json
string
404
application/json
string
Get personal appointment list (Token required )
POST
/api/v1/appointment/{ date:string }
(allows to get your personal an appointment list 🔒[token required])
http code
content-type
response
200
application/json
[ { "appointmentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userPatientId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userDoctorId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "date": "string", "startTime": "string", "endTime": "string", "isCompleted": true, "isCanceled": true } ]
401
application/json
string
403
application/json
string
404
application/json
string
422
application/json
string
Finalise appointment (Token required , 🔒doctor policy)
PUT
/api/v1/appointment/finalise/{ appointmentId:uuid }
(allows to finalise an appointment 🔒[doctor policy])
http code
content-type
response
200
application/json
{"appointmentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userPatientId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userDoctorId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "date": "string", "startTime": "string", "endTime": "string", "isCompleted": true, "isCanceled": true }
400
application/json
array
401
application/json
string
403
application/json
string
404
application/json
string
422
application/json
string
Cancel appointment (Token required , 🔒doctor policy)
PUT
/api/v1/appointment/cancel/{ appointmentId:uuid }
(allows to cancel an appointment 🔒[doctor policy])
http code
content-type
response
200
application/json
{"appointmentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userPatientId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userDoctorId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "date": "string", "startTime": "string", "endTime": "string", "isCompleted": true, "isCanceled": true }
400
application/json
array
401
application/json
string
403
application/json
string
404
application/json
string
422
application/json
string
Functionality for configuring doctors' appointments settings (entity is created automatically when a doctor is created)
Configuration doctor (Token required , 🔒doctor policy)
PUT
/api/v1/appointment-settings
(allows to config a doctor 🔒[doctor policy])
name
type
data type
"startTime"
required
string
"endTime"
required
string
"interval"
required
string
"workdays"
required
array
http code
content-type
response
200
application/json
{ "startTime": "10:00", "endTime": "17:00", "interval": "30M", "workdays": [ 1, 2, 3, 4, 5 ] }
400
application/json
array
401
application/json
string
403
application/json
string
404
application/json
string
422
application/json
string
Get doctor configuration (Token required )
GET
/api/v1/appointment-settings/{ settingsId:uuid }
(allows to get a doctor's configuration 🔒[token required])
http code
content-type
response
200
application/json
{"startTime": "08:00, "endTime": "15:00", "interval": "1H", "workdays": [ 1, 2, 4, 5 ] }
401
application/json
string
403
application/json
string
404
application/json
string
Functionality that allows to manage and interact with specializations
Create new specialization (Token required , 🔒manager policy)
POST
/api/v1/specialization
(allows to create new specialization 🔒[manager policy])
name
type
data type
"value"
required
string
"description"
not required
string
http code
content-type
response
201
application/json
{ "specializationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "value": "string", "description": "string", "userDoctorIds": [ "3fa85f64-5717-4562-b3fc-2c963f66afa6" ] }
400
application/json
array
401
application/json
string
403
application/json
string
409
application/json
string
Update a specialization (Token required , 🔒manager policy)
PUT
/api/v1/specialization
(allows to update specialization 🔒[manager policy])
name
type
data type
"specializationId"
required
uuid
"description"
not required
string
http code
content-type
response
201
application/json
{ "specializationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "value": "string", "description": "string", "userDoctorIds": [ "3fa85f64-5717-4562-b3fc-2c963f66afa6" ] }
400
application/json
array
401
application/json
string
403
application/json
string
404
application/json
string
Delete a specialization (Token required , 🔒manager policy)
DELETE
/api/v1/specialization/{ specializationId:uuid }
(allows to delete specialization 🔒[manager policy])
http code
content-type
response
204
application/json
NoContent
401
application/json
string
403
application/json
string
404
application/json
string
GET
/api/v1/specialization
(allows to get all specialization)
http code
content-type
response
200
application/json
[{ "specializationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "value": "string", "description": "string", "userDoctorIds": [ "3fa85f64-5717-4562-b3fc-2c963f66afa6" ] } ]
Include a doctor (Token required , 🔒manager policy)
PUT
/api/v1/specialization/include-doctor
(allows to include a doctor 🔒[manager policy])
name
type
data type
"specializationId"
required
uuid
"userDoctorId"
required
uuid
http code
content-type
response
200
application/json
{ "specializationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "value": "string", "description": "string", "userDoctorIds": [ "3fa85f64-5717-4562-b3fc-2c963f66afa6" ] } ]
401
application/json
string
403
application/json
string
404
application/json
string
409
application/json
string
Exclude a doctor (Token required , 🔒manager policy)
PUT
/api/v1/specialization/exclude-doctor
(allows to exclude a doctor 🔒[manager policy])
name
type
data type
"specializationId"
required
uuid
"userDoctorId"
required
uuid
http code
content-type
response
200
application/json
{ "specializationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "value": "string", "description": "string", "userDoctorIds": [ "3fa85f64-5717-4562-b3fc-2c963f66afa6" ] } ]
401
application/json
string
403
application/json
string
404
application/json
string
409
application/json
string
Functionality that allows to manage and interact with medical records
Create medical records (Token required , 🔒doctor policy)
POST
/api/v1/medical-record
(allows to create medical records 🔒[doctor policy])
name
type
data type
"appointmentId"
required
uuid
"userPatientId"
required
uuid
"title"
required
string
"doctorNote"
not required
string
http code
content-type
response
201
application/json
{ "medicalRecordId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userPatientId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userDoctorId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "appointmentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "title": "string", "doctorNote": "string", "created": "2024-04-20T19:46:52.893Z" }
400
application/json
array
401
application/json
string
403
application/json
string
404
application/json
string
409
application/json
string
Update medical records (Token required , 🔒doctor policy)
PUT
/api/v1/medical-record
(allows to update medical records 🔒[doctor policy])
name
type
data type
"medicalRecordId"
required
uuid
"title"
not required
string
"doctorNote"
not required
string
http code
content-type
response
200
application/json
{ "medicalRecordId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userPatientId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userDoctorId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "appointmentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "title": "string", "doctorNote": "string", "created": "2024-04-20T19:50:45.998Z" }
400
application/json
array
401
application/json
string
403
application/json
string
404
application/json
string
Get one medical record (Token required , 🔒doctor-or-patient policy)
GET
/api/v1/medical-record/{ medicalRecordId:uuid }
(allows to get one medical record 🔒[doctor-or-patient policy])
http code
content-type
response
200
application/json
{ "medicalRecordId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userPatientId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userDoctorId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "appointmentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "title": "string", "doctorNote": "string", "created": "2024-04-20T19:53:30.118Z" }
401
application/json
string
403
application/json
string
404
application/json
string
Get all medical records for patient (Token required , 🔒patient policy)
GET
/api/v1/medical-record/for-patient
(allows to get your records 🔒[patient policy])
name
type
data type
SortByDate
not required
boolean
SortOrderAsc
not required
boolean
PageNumber
not required
int32
PageSize
not required
int32
http code
content-type
response
200
application/json
{ "items": [ { "medicalRecordId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userPatientId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userDoctorId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "appointmentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "title": "string", "doctorNote": "string", "created": "2024-04-20T19:55:13.407Z" } ], "pageNumber": 0, "totalPages": 0, "totalItemsCount": 0 }
401
application/json
string
403
application/json
string
404
application/json
string
Get all medical records for doctor (Token required , 🔒doctor policy)
GET
/api/v1/medical-record/for-doctor
(allows to get your records 🔒[doctor policy])
name
type
data type
UserPatientId
not required
uuid
SortByDate
not required
boolean
SortOrderAsc
not required
boolean
PageNumber
not required
int32
PageSize
not required
int32
http code
content-type
response
200
application/json
{ "items": [ { "medicalRecordId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userPatientId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userDoctorId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "appointmentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "title": "string", "doctorNote": "string", "created": "2024-04-20T19:55:13.407Z" } ], "pageNumber": 0, "totalPages": 0, "totalItemsCount": 0 }
401
application/json
string
403
application/json
string
404
application/json
string
Functionality that allows to manage and interact with offices
Create offices (Token required , 🔒manager policy)
POST
/api/v1/office
(allows to create new office 🔒[manager policy])
name
type
data type
"name"
required
string
"number"
required
int
http code
content-type
response
201
application/json
{ "officeId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "name": "string", "number": 201, "isAvailable": true }
400
application/json
array
401
application/json
string
403
application/json
string
409
application/json
string
Update offices (Token required , 🔒manager policy)
PUT
/api/v1/office
(allows to update offices 🔒[manager policy])
name
type
data type
"officeId"
required
uuid
"name"
required
string
http code
content-type
response
200
application/json
{ "officeId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "name": "string", "number": 201, "isAvailable": true }
400
application/json
array
401
application/json
string
403
application/json
string
404
application/json
string
Lock or unlock an office (Token required , 🔒doctor-or-manager policy)
PATCH
/api/v1/office
(allows to lock or unlock an office 🔒[doctor-or-manager policy])
name
type
data type
"officeId"
required
uuid
http code
content-type
response
200
application/json
{ "officeId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "name": "string", "number": 201, "isAvailable": true }
400
application/json
array
401
application/json
string
403
application/json
string
404
application/json
string
Get all offices (Token required , 🔒doctor-or-manager policy)
GET
/api/v1/office
(allows to get all offices 🔒[doctor-or-manager policy])
http code
content-type
response
200
application/json
[ { "officeId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "name": "string", "number": 10, "isAvailable": true } ]
400
application/json
array
401
application/json
string
403
application/json
string