| Version 10 (modified by , 22 hours ago) ( diff ) |
|---|
ER Diagram
Diagram
Data Requirements
Entities
Doctor_Level
A reference entity holding the set of rank levels a doctor can hold (e.g. Resident, Specialist, Consultant). Modeled as its own entity so the list of valid levels can be maintained centrally and referential integrity is enforced through the FK instead of relying on consistent free text.
- Candidate keys:
level_id (surrogate)
level (natural, UNIQUE).
level_id was chosen as PK because it is stable, renaming a level would otherwise cascade an update to every Doctors row.
- Attributes:
level_id (PK, bigint) — required
level (text) — required, unique
Doctor_Specialization
Doctor_Specialization is an entity listing the medical specializations doctors can practice. It is kept separate from Doctors so Procedures can reference which specializations are allowed to perform them.
- Candidate keys:
specialization_id (surrogate)
specialization_name (natural, UNIQUE).
specialization_id was chosen as PK so a rename doesn't cascade into Doctors and Specialization_Procedures.
- Attributes:
specialization_id (PK, bigint) — required; supplied by the application
specialization_name (text) — required, unique
Departments
Departments is an entity representing the clinic's organizational departments. Departments both employ doctors (works_in) and offer procedures (performs), so it needed to be a first-class entity.
- Candidate keys:
department_id (surrogate)
department_name (natural, UNIQUE).
department_id was chosen as PK so a rename doesn't cascade into Doctors and Department_Procedures.
- Attributes:
department_id (PK, bigint) — required
department_name (text) — required, unique
Doctors
Doctors is the central entity for doctors who use the system to see patients, record diagnoses, order tests and perform procedures. Level, specialization and department are FKs to lookup entities rather than free text to prevent inconsistent values and allow filtering.
- Candidate keys:
doctor_id (surrogate)
email_address (natural, UNIQUE).
doctor_id was chosen as PK because an email address can change, and using a mutable value as PK would force cascading updates across every table referencing a doctor.
- Attributes:
doctor_id (PK, bigint) — required
first_name (text) — required
last_name (text) — required
email_address (text) — required, unique, must contain an "@" (
LIKE '%@%'- format check)
level_id (FK, bigint) — required, references Doctor_Level
specialization_id (FK, bigint) — required, references Doctor_Specialization
department_id (FK, bigint) — required, references Departments
Patients
Patients represents the people receiving care, it is the anchor entity for almost all clinical data like appointments, diagnoses, medical records, tests, procedures, billing.
- Candidate keys:
patient_id (surrogate),
embg (natural - the Macedonian unique master citizen number, required and unique).
patient_id was still chosen as PK rather than embg: embg is sensitive personal data that is better not propagated as a foreign key into every dependent table (Diagnosis, Appointments, Medical_Records, etc.), and a numeric surrogate keeps those relationships smaller and independent of a nationally issued identifier.
- Attributes:
patient_id (PK, bigint) — required
first_name (text) — required
last_name (text) — required
email_address (text) — optional, unique if provided
date_of_birth (date) — required
blood_type (text) — optional, restricted to one of: A+, A-, B+, B-, AB+, AB-, O+, O-
gender (text) — optional, restricted to one of: MALE, FEMALE
phone_number (text) — optional, free text
embg (text) — required, unique, 13-digit format
Admin
Represents clinic administrative staff who manage billing and back-office operations. Kept separate from Doctors and Lab_Technician since admins have no clinical attributes.
- Candidate keys:
admin_id (surrogate),
username (natural, UNIQUE),
email (natural, UNIQUE).
admin_id was chosen as PK so a username change doesn't cascade into Users and Billing.
- Attributes:
admin_id (PK, bigint) — required
username (text) — required, unique
name (text) — required
lastname (text) — required
email (text) — required, unique, must contain "@adminmedora" (
LIKE '%@adminmedora%'- restricts admins to the internal admin email domain)
Lab_Technician
Lab Technician entity is the lab staff who conduct the tests ordered by doctors and record results in Performed_Lab_Tests. Modeled separately from Doctors since technicians don't diagnose or prescribe.
- Candidate keys:
technician_id (surrogate), username (natural, UNIQUE), email (natural, UNIQUE).
technician_id was chosen as PK for the same reason as Admin.
- Attributes:
technician_id (PK, bigint) — required, supplied by the application
username (text) — required, unique
name (text) — required
lastname (text) — required
email (text) — required, unique, must contain "@labmedora" (
LIKE '%@labmedora%'- restricts technicians email domain)
Users
Users is the authentication and login entity implementing role based access. A Users row is meant to serve exactly one of Patients, Doctors, Admin or Lab_Technician via whichever of the four nullable FKs is populated.
- Candidate keys:
user_id (surrogate)
username (natural, UNIQUE).
user_id was chosen as PK so a username change doesn't break session/audit data referencing the account. user_id is the one PK in this schema that is DB-generated (SERIAL).
- Attributes:
user_id (PK, serial) — required, auto-generated by the database
username (varchar(255)) — required, unique
password (varchar(255)) — required, expected to be stored as a hash
role (varchar(50)) — required, intended to be one of patient/doctor/admin/technician
first_name (varchar(100)) — optional
last_name (varchar(100)) — optional
patient_id (FK, bigint, nullable) — references Patients
doctor_id (FK, bigint, nullable) — references Doctors
admin_id (FK, bigint, nullable) — references Admin
technician_id (FK, bigint, nullable) — references Lab_Technician
is_active (boolean) — optional, defaults to true
Appointments
Appointments represents a scheduled meeting between one patient and one doctor. No natural key exists, so a surrogate key is mandatory.
- Candidate keys:
appointment_id (surrogate) only.
- Attributes:
appointment_id (PK, bigint) — required
appointment_date (date) — required
appointment_time (time) — required
status (text) — required, restricted to one of: SCHEDULED, COMPLETED, CANCELLED, IN_PROGRESS
patient_id (FK, bigint) — required, references Patients
doctor_id (FK, bigint) — required, references Doctors
Diagnosis
Diagnosis entity represents a diagnosis a doctor makes for a patient. It is the pivot the clinical model turns on since procedures, referrals and medical records all connect back to it.
- Candidate keys:
diagnosis_id (surrogate) only.
the same diagnosis name can legitimately recur for the same patient over time.
- Attributes:
diagnosis_id (PK, bigint) — required; supplied by the application
name (text) — required
description (text) — optional
patient_id (FK, bigint) — required, references Patients
doctor_id (FK, bigint) — required, references Doctors
Procedures
Procedures is a catalog entry describing a type of procedure with its cost and the diagnosis it was primarily created for. Each row carries a direct diagnosis_id FK for its main diagnosis (1:N), while Diagnosis_Procedures (M:N) additionally lets the same catalog procedure be linked to other diagnoses without duplicating the row.
- Candidate keys:
procedure_id (surrogate) only.
procedure_type alone isn't unique, since the same type can be cataloged for different diagnoses at different costs.
- Attributes:
procedure_id (PK, bigint) — required; supplied by the application
procedure_type (text) — required, must not be blank/whitespace-only
procedure_date (date) — required
description (text) — optional
cost (decimal) — required, must be ≥ 0
doctor_id (FK, bigint) — required, references Doctors
diagnosis_id (FK, bigint) — required, references Diagnosis
Procedure_Results
Procedure_Results stores the outcome of a performed procedure. Kept separate from Procedures since one procedure can generate more than one result over time.
- Candidate keys:
result_id (surrogate) only.
- Attributes:
result_id (PK, bigint) — required
result_description (text) — optional, must not be blank
result_date (date) - required
procedure_id (FK, bigint) - required, references Procedures
Prescriptions
Prescriptions is an entity for medications that can be prescribed. Kept minimal because everything patient specific like dosage, frequency, duration lives on Prescription_Medical_Records instead, since it varies per medical record.
- Candidate keys:
prescription_id (surrogate) only.
medication_name is required but has no UNIQUE constraint in this schema, so it is not a true candidate key as implemented.
- Attributes:
prescription_id (PK, bigint) - required
medication_name (text) - required not enforced unique
Prescription_Restriction
Entity that records a restriction attached to a prescription. Separate entity because one prescription can carry multiple independent restrictions.
- Candidate keys:
restriction_id (surrogate) only.
- Attributes:
restriction_id (PK, bigint) - required
description (text) - required, must not be blank
prescription_id (FK, bigint) — required, references Prescriptions
Lab_Tests
A catalog entity describing the lab tests the clinic offers, with standard cost. Separate from Performed_Lab_Tests, which records each actual instance of a test being run.
- Candidate keys:
test_id (surrogate) only.
- Attributes:
test_id (PK, bigint) — required
test_name (text) — required, must be blank, not enforced unique
description (text) — optional
cost (decimal) — required, must be ≥ 0
Lab_Results
Entity that stores the outcome of a catalog lab test, linked directly to the Lab_Tests catalog entry so the result stays reusable across reports (Medical_Report_Lab_Results, Medical_Record_Lab_Results).
- Candidate keys:
result_id (surrogate) only.
- Attributes:
result_id (PK, bigint) - required
results (text) - required, must not be blank
result_date (date) — required, must not be later than the current date
test_id (FK, bigint) — required, references Lab_Tests
Medical_Records
Acts as a folder aggregating everything about a patient's clinical episode, by being the hub that other entities connect back to. Kept deliberately minimal so record specific detail lives on the appropriate junction table instead of being duplicated here.
- Candidate keys:
record_id (surrogate) only.
a patient can have multiple records over time, so patient_id alone isn't unique.
- Attributes:
record_id (PK, bigint) — required
patient_id (FK, bigint) — required, references Patients
Allergies
An entity listing known allergies with a general severity classification, so the same allergy can be linked to many patients without re-entering its description each time.
- Candidate keys:
allergy_id (surrogate)
name (natural, UNIQUE).
allergy_id was chosen as PK so it survives a naming correction.
- Attributes:
allergy_id (PK, bigint) - required
name (text) — required, unique, must not be blank
allergy_severity (text) - required, restricted to one of: LOW, MEDIUM, HIGH, CRITICAL
Symptoms
A catalog entity listing known symptoms so the same symptom can be reused across many patients and diagnoses rather than typed freely each time.
- Candidate keys:
symptom_id (surrogate)
name (natural, UNIQUE-enforced).
symptom_id was chosen as PK for consistency with other catalog entities.
- Attributes:
symptom_id (PK, bigint) — required
name (text) — required, unique, must be blank
description (text) — optional, if present, must not be blank
Referrals
Records one doctor referring a patient's medical record to another doctor. Carries two separate FKs to Doctors (from_doctor_id, to_doctor_id) because a referral inherently involves two distinct doctor roles.
- Candidate keys:
referral_id (surrogate) only.
- Attributes:
referral_id (PK, bigint) — required
reason (text) — required, must be blank
referral_date (date) — required
record_id (FK, bigint) — required, references Medical_Records
from_doctor_id (FK, bigint) — required, references Doctors
to_doctor_id (FK, bigint) — required, references Doctors
Medical_Report
Represents a formal written report a doctor produces based on a medical record, which can reference multiple lab results as supporting evidence.
- Candidate keys:
report_id (surrogate) only.
a record can generate more than one report over time.
- Attributes:
report_id (PK, bigint) — required; supplied by the application
description (text) — required
report_date (date) — required
record_id (FK, bigint) — required, references Medical_Records
doctor_id (FK, bigint) — required, references Doctors
Billing
Represents an invoice generated for a medical record, covering whichever procedures/tests it includes, processed by an administrator. payment_date is nullable since a bill can be Pending before it's ever paid.
- Candidate keys:
bill_id (surrogate) only.
- Attributes:
bill_id (PK, bigint) — required
total_cost (decimal) — required, must be ≥ 0
payment_status (text) — required, restricted to one of: PENDING, PAID, CANCELLED
payment_date (date) — optional
record_id (FK, bigint) — required, references Medical_Records
admin_id (FK, bigint) — required, references Admin
Performed_Procedures
Records a specific, actual occurrence of a catalog procedure carried out on a patient. Distinct from Procedures, the catalog definition. diagnosis_id is nullable since a performed procedure isn't always tied to a newly recorded diagnosis.
- Candidate keys:
performed_id (surrogate) only.
- Attributes:
performed_id (PK, bigint) — required
procedure_id (FK, bigint) — required, references Procedures
doctor_id (FK, bigint) — required, references Doctors
patient_id (FK, bigint) — required, references Patients
diagnosis_id (FK, bigint, nullable) — references Diagnosis
procedure_date (date) — required
notes (text) — optional
Performed_Lab_Tests
Records a specific, actual occurrence of a catalog lab test carried out on a patient that is ordered by a doctor, conducted by a technician.
- Candidate keys:
performed_test_id (surrogate) only.
- Attributes:
performed_test_id (PK, bigint) — required
test_id (FK, bigint) — required, references Lab_Tests
patient_id (FK, bigint) — required, references Patients
doctor_id (FK, bigint) — required, references Doctors
technician_id (FK, bigint) — required, references Lab_Technician
test_date (date) — required
notes (text) — optional
Associative entities (M:N junctions that carry their own attributes)
Prescription_Medical_Records
An associative (M:N) entity linking Prescriptions to Medical_Records. Carries its own attributes because dosage/frequency/duration are specific to the record a medication was prescribed within, not to the medication itself.
- Candidate keys:
the composite (prescription_id, record_id) — a medication should appear at most once per record.
- Attributes:
prescription_id (FK, bigint) — required, part of composite PK, references Prescriptions
record_id (FK, bigint) — required, part of composite PK, references Medical_Records
dosage (text) — required
frequency (text) — required
duration (text) — required
notes (text) — optional
Medical_Record_Symptoms
An associative (M:N) entity linking Medical_Records to Symptoms. Intended to carry a per-record severity, since how severe a symptom is is specific to that record/visit, not the symptom catalog entry.
- Candidate keys:
the composite (record_id, symptom_id) - a symptom should appear at most once per record.
- Attributes:
record_id (FK, bigint) — required, part of composite PK, references Medical_Records
symptom_id (FK, bigint) — required, part of composite PK, references Symptoms
severity (text) — optional; no restricted value set enforced in the database
Medical_Record_Allergies
An associative (M:N) entity linking Medical_Records to Allergies. Intended to carry the reaction and severity observed for that patient within that specific record, distinct from the general allergy catalog entry.
- Candidate keys:
the composite (record_id, allergy_id) — an allergy should appear at most once per record.
- Attributes:
record_id (FK, bigint) — required, part of composite PK, references Medical_Records
allergy_id (FK, bigint) — required, part of composite PK, references Allergies
reaction (text) — optional
severity (text) — optional
Relations
is (Doctor_Level ↔ Doctors, 1:N)
each doctor has one level, a level applies to many doctors.
has_specialization (Doctor_Specialization ↔ Doctors, 1:N)
each doctor has one specialization, a specialization applies to many doctors.
works_in (Departments ↔ Doctors, 1:N)
each doctor belongs to one department, a department employs many doctors.
identifies (Users ↔ Patients / Doctors / Admin / Lab_Technician, 1:1)
a user account links to exactly one underlying person record, depending on role.
has_allergies (Patients ↔ Allergies, M:N via Patient_Allergies)
patients can have multiple allergies, an allergy can affect many patients.
affects_prescription (Allergies ↔ Prescription_Restriction, M:N via Allergy_Prescription_Restrictions)
an allergy can be tied to multiple restrictions; a restriction can apply to multiple allergies.
has_symptoms (Patients ↔ Symptoms, M:N via Patient_Symptoms)
patients can report multiple symptoms, a symptom can be reported by many patients.
indicates (Symptoms ↔ Diagnosis, M:N via Diagnosis_Symptoms)
a diagnosis can involve multiple symptoms, a symptom can appear in multiple diagnoses.
books (Patients ↔ Appointments, 1:N)
a patient books many appointments, each appointment belongs to one patient.
attends (Doctors ↔ Appointments, 1:N)
a doctor attends many appointments, each appointment is handled by one doctor.
diagnoses (Doctors ↔ Diagnosis, 1:N)
a doctor makes many diagnoses, each diagnosis is made by one doctor.
diagnosed_with (Patients ↔ Diagnosis, 1:N)
a patient can have many diagnoses; each diagnosis belongs to one patient.
performs_allowed (Doctor_Specialization ↔ Procedures, M:N via Specialization_Procedures)
a specialization is linked to the procedures it's allowed to perform.
requires (Diagnosis ↔ Procedures, M:N via Diagnosis_Procedures)
a diagnosis can require multiple procedures, and the same procedure can be linked to multiple diagnoses ,in addition to the direct diagnosis_id FK each procedure row already carries.
produces (Procedures ↔ Procedure_Results, 1:N)
a procedure can produce multiple results, each result belongs to one procedure.
performs (Departments ↔ Procedures, M:N via Department_Procedures)
a department can perform multiple procedures, and a procedure can be performed in multiple departments.
billed_for (Procedures ↔ Billing, M:N via Billing_Procedures)
a bill can include multiple procedures, a procedure can appear on multiple bills.
restricts (Prescriptions ↔ Prescription_Restriction, 1:N)
a prescription can have multiple restrictions, each restriction belongs to one prescription.
tested_as (Lab_Tests ↔ Performed_Lab_Tests, 1:N)
a catalog test can be performed many times; each performed test refers to one catalog test.
takes_test (Patients ↔ Performed_Lab_Tests, 1:N)
a patient can undergo many performed tests, each performed test belongs to one patient.
orders_test (Doctors ↔ Performed_Lab_Tests, 1:N)
a doctor can order many tests, each performed test is ordered by one doctor.
conducts (Lab_Technician ↔ Performed_Lab_Tests, 1:N)
a technician can conduct many tests, each performed test is run by one technician.
produces_test (Lab_Tests ↔ Lab_Results, 1:N)
a catalog test can produce multiple results, each result belongs to one test.
billed_for_test (Lab_Tests ↔ Billing, M:N via Billing_Lab_Tests)
a bill can include multiple tests, a test can appear on multiple bills.
performed_as (Procedures ↔ Performed_Procedures, 1:N)
a catalog procedure can be performed many times.
performed_on (Patients ↔ Performed_Procedures, 1:N)
a patient can have many procedures performed, each performed procedure belongs to one patient.
performed_by (Doctors ↔ Performed_Procedures, 1:N)
a doctor can perform many procedures, each performed procedure has one doctor.
has (Patients ↔ Medical_Records, 1:N as constrained)
each medical record belongs to one patient.
updates (Doctors ↔ Medical_Records, M:N via Doctor_Medical_Records)
doctors can update multiple records; a record can be updated by multiple doctors.
relates_to (Diagnosis ↔ Medical_Records, M:N via Diagnosis_Medical_Records)
diagnoses can relate to multiple records, a record can include multiple diagnoses.
linked_to (Prescriptions ↔ Medical_Records, M:N via Prescription_Medical_Records)
prescriptions can be linked to multiple records, a record can include multiple prescriptions, each with its own dosage/frequency/duration/notes for that record.
contains_symptoms (Medical_Records ↔ Symptoms, M:N via Medical_Record_Symptoms)
a record can list multiple symptoms, each with its own severity.
contains_allergies (Medical_Records ↔ Allergies, M:N via Medical_Record_Allergies)
a record can list multiple allergies, each with its own reaction and severity.
includes_procedures (Medical_Records ↔ Procedures, M:N via Medical_Record_Procedures)
a record can reference multiple procedures.
includes_lab_results (Medical_Records ↔ Lab_Results, M:N via Medical_Record_Lab_Results)
a record can reference multiple lab results.
generates_referral (Medical_Records ↔ Referrals, 1:N)
a record can generate multiple referrals, each referral is based on one record.
issues (Doctors ↔ Referrals as from_doctor_id, 1:N)
a doctor can issue many referrals.
receives_referral (Doctors ↔ Referrals as to_doctor_id, 1:N)
a doctor can receive many referrals.
creates (Doctors ↔ Medical_Report, 1:N)
a doctor can create multiple reports, each report is created by one doctor.
generates_report (Medical_Records ↔ Medical_Report, 1:N)
a record can generate multiple reports, each report is based on one record.
includes_lab_results_report (Medical_Report ↔ Lab_Results, M:N via Medical_Report_Lab_Results)
a report can include multiple lab results, a result can appear in multiple reports.
processes (Admin ↔ Billing, 1:N)
an admin can process multiple bills, each bill is processed by one admin.
generates_bill (Medical_Records ↔ Billing, 1:N)
a record can generate multiple bills, each bill is tied to one record.
Attachments (4)
-
Hospital_ER_Diagram.drawio.png
(1.0 MB
) - added by 5 months ago.
er_diagram_first
- Hospital_ER_Diagram2.drawio.png (988.8 KB ) - added by 4 months ago.
- newModoradigram.drawio (2).png (1.4 MB ) - added by 2 weeks ago.
- ERModel_v03.png (1.4 MB ) - added by 22 hours ago.

