Designing a Healthcare ERD: Rehabilitation Platform with PlantUML

In the rapidly evolving landscape of digital health, the integrity of data architecture is paramount for platforms that manage patient rehabilitation. A physical therapy exercise prescription and progress monitoring system is not merely a database of workouts; it is a complex ecosystem where clinical outcomes depend on the precise tracking of patient history, therapist expertise, exercise parameters, and session logs. For software architects and healthcare developers, visualizing these intricate relationships is the first step toward building a compliant, scalable, and user-friendly application.

Real-world system context and operational workflow illustration

Traditional drag-and-drop diagramming tools often struggle to maintain consistency when modeling complex healthcare schemas involving multiple entity types and strict cardinality rules. Diagram-as-code approaches, specifically using PlantUML, offer a superior alternative by allowing developers to define the schema in text, ensuring version-friendly documentation and rapid iteration. By leveraging VPasCode, a free web-based editor, architects can instantly render these complex Entity Relationship Diagrams (ERDs) without the overhead of local installations, enabling real-time collaboration and immediate visual feedback on data modeling decisions.

Understanding the Model: Purpose, Scope & Problem Framing

Diagram Abstraction & Representation
This Entity Relationship Diagram (ERD) serves as the structural blueprint for a Rehabilitation Physical Therapy platform. It models the critical data entities required to support the clinical workflow: from patient intake and diagnosis to the creation of personalized exercise plans, the logging of daily sessions, and the assessment of progress over time. The diagram uses standard ERD notation to define entities (tables), their attributes (columns), and the cardinality of relationships (foreign keys) between them.

Target Domain Scope & Scenario
The scope of this model covers the core operational domain of a physical therapy clinic or remote rehabilitation service. It explicitly models the interaction between Users (who can be either Patients or Therapists), the Exercise library, and the dynamic records of Prescriptions, Sessions, and Progress. It intentionally excludes peripheral systems like billing or insurance processing to focus on the clinical data lifecycle, ensuring the diagram remains clear and focused on patient care workflows.

Key Takeaways & Educational Insights
By studying this diagram, you will gain insights into how to structure a healthcare database to support flexible exercise prescription logic, track patient progress with granular metrics (e.g., pain levels, range of motion), and maintain a clear audit trail of clinical notes. You will learn how to use inheritance patterns (User as a parent to Patient and Therapist) and how to manage many-to-many relationships through junction entities like ExercisePrescription.

Complete Diagram & Full Source Code

Rehabilitation Physical Therapy ERD showing relationships between User, Patient, Therapist, Exercise, Prescription, Session, Progress, Plan, Appointment, and Clinical Note entities

@startuml
!include https://static.visual-paradigm.com/web/resources/plantuml-stdlib/themes/vp.puml

title Rehabilitation Physical Therapy Exercise Prescription and Progress Monitoring Platform ERD

/' 
This ERD models a rehabilitation physical therapy platform where clinicians prescribe 
personalized exercise programs to patients and track their recovery over time. The diagram 
captures the core entities needed to manage therapy plans, exercise definitions, prescribed 
routines, session logging, progress assessments, and clinical notes. It supports the workflow 
from initial patient intake and diagnosis through exercise prescription, daily completion 
tracking, periodic outcome measurement, and ongoing plan adjustment. Key relationships 
connect patients to their prescriptions, prescriptions to the exercises they contain, and 
patients to the progress records generated during rehabilitation.
'/

' ==================== ENTITIES ====================

entity "User" as user {
  * user_id : UUID <<PK>>
  --
  username : VARCHAR
  password_hash : VARCHAR
  email : VARCHAR
  role : ENUM
  first_name : VARCHAR
  last_name : VARCHAR
  created_at : TIMESTAMP
}

entity "Patient" as patient {
  * patient_id : UUID <<PK>>
  --
  user_id : UUID <<FK>>
  date_of_birth : DATE
  gender : ENUM
  contact_phone : VARCHAR
  address : TEXT
  emergency_contact : VARCHAR
  primary_diagnosis : TEXT
  medical_history : TEXT
  created_at : TIMESTAMP
}

entity "Therapist" as therapist {
  * therapist_id : UUID <<PK>>
  --
  user_id : UUID <<FK>>
  license_number : VARCHAR
  specialization : VARCHAR
  years_of_experience : INT
  clinic_location : VARCHAR
  bio : TEXT
}

entity "Exercise" as exercise {
  * exercise_id : UUID <<PK>>
  --
  name : VARCHAR
  category : ENUM
  body_region : ENUM
  description : TEXT
  instructions : TEXT
  video_url : VARCHAR
  difficulty_level : ENUM
  default_sets : INT
  default_reps : INT
  default_duration_sec : INT
  created_by : UUID <<FK>>
  created_at : TIMESTAMP
}

entity "ExercisePrescription" as prescription {
  * prescription_id : UUID <<PK>>
  --
  patient_id : UUID <<FK>>
  therapist_id : UUID <<FK>>
  exercise_id : UUID <<FK>>
  prescribed_date : DATE
  start_date : DATE
  end_date : DATE
  frequency_per_week : INT
  sets : INT
  reps : INT
  duration_sec : INT
  resistance_level : VARCHAR
  special_notes : TEXT
  status : ENUM
  created_at : TIMESTAMP
}

entity "ExerciseSession" as session {
  * session_id : UUID <<PK>>
  --
  prescription_id : UUID <<FK>>
  patient_id : UUID <<FK>>
  session_date : DATE
  completed_sets : INT
  completed_reps : INT
  actual_duration_sec : INT
  pain_level_before : INT
  pain_level_after : INT
  perceived_exertion : INT
  comments : TEXT
  logged_at : TIMESTAMP
}

entity "ProgressRecord" as progress {
  * progress_id : UUID <<PK>>
  --
  patient_id : UUID <<FK>>
  therapist_id : UUID <<FK>>
  assessment_date : DATE
  range_of_motion_deg : DECIMAL
  muscle_strength_grade : INT
  functional_score : DECIMAL
  pain_scale : INT
  balance_score : DECIMAL
  endurance_score : DECIMAL
  notes : TEXT
  created_at : TIMESTAMP
}

entity "TreatmentPlan" as plan {
  * plan_id : UUID <<PK>>
  --
  patient_id : UUID <<FK>>
  therapist_id : UUID <<FK>>
  plan_name : VARCHAR
  diagnosis : TEXT
  goals : TEXT
  start_date : DATE
  target_end_date : DATE
  status : ENUM
  created_at : TIMESTAMP
}

entity "Appointment" as appointment {
  * appointment_id : UUID <<PK>>
  --
  patient_id : UUID <<FK>>
  therapist_id : UUID <<FK>>
  appointment_date : DATETIME
  duration_min : INT
  type : ENUM
  status : ENUM
  location : VARCHAR
  notes : TEXT
}

entity "ClinicalNote" as note {
  * note_id : UUID <<PK>>
  --
  patient_id : UUID <<FK>>
  therapist_id : UUID <<FK>>
  appointment_id : UUID <<FK>>
  note_date : DATETIME
  subjective : TEXT
  objective : TEXT
  assessment : TEXT
  plan : TEXT
  created_at : TIMESTAMP
}

' ==================== RELATIONSHIPS ====================

user ||--o| patient : "is a"
user ||--o| therapist : "is a"

patient ||--o{ prescription : "receives"
therapist ||--o{ prescription : "prescribes"
exercise ||--o{ prescription : "included in"

prescription ||--o{ session : "logged as"
patient ||--o{ session : "performs"

patient ||--o{ progress : "has"
therapist ||--o{ progress : "assesses"

patient ||--o{ plan : "assigned"
therapist ||--o{ plan : "manages"

patient ||--o{ appointment : "schedules"
therapist ||--o{ appointment : "conducts"

patient ||--o{ note : "documented"
therapist ||--o{ note : "writes"
appointment ||--o| note : "generates"

@enduml

Step-by-Step Architectural Walkthrough

Phase 1: Canvas Configuration & Layout Directives

The foundation of any professional PlantUML diagram lies in its configuration. In this section, we set the theme and title to ensure the diagram aligns with the Visual Paradigm aesthetic and clearly states its purpose.

We begin by including the standard PlantUML library theme. This directive loads a pre-defined set of styles, colors, and fonts that give the diagram a modern, consistent look without manual CSS tweaking.

!include https://static.visual-paradigm.com/web/resources/plantuml-stdlib/themes/vp.puml

Next, we define the diagram title. This appears at the top of the rendered output, providing immediate context for stakeholders reviewing the architecture.

title Rehabilitation Physical Therapy Exercise Prescription and Progress Monitoring Platform ERD

Finally, we add a comment block using the /' and '/ syntax. This allows us to embed a rich description of the diagram’s context directly within the code, serving as documentation that travels with the file.

/' 
This ERD models a rehabilitation physical therapy platform...
'/

Phase 2: Declaring Core Entities, Actors, and Boundaries

The core of the ERD is the definition of entities. In PlantUML, we use the entity keyword followed by the entity name (in quotes), an alias, and a block containing attributes.

We start with the User entity. This acts as a parent entity in our inheritance model. It contains authentication and basic profile data.

entity "User" as user {
  * user_id : UUID <>
  --
  username : VARCHAR
  password_hash : VARCHAR
  email : VARCHAR
  role : ENUM
  first_name : VARCHAR
  last_name : VARCHAR
  created_at : TIMESTAMP
}

Notice the use of * to mark the Primary Key (PK) and UUID as the data type. We also use the -- separator to visually divide keys from other attributes, a best practice for readability.

Similarly, we define Patient and Therapist entities. Both reference user_id as a Foreign Key (FK) to link back to the User entity, establishing the “is a” relationship (a Patient is a User).

entity "Patient" as patient {
  * patient_id : UUID <>
  --
  user_id : UUID <>
  date_of_birth : DATE
  ...

We continue this pattern for Exercise, ExercisePrescription, ExerciseSession, ProgressRecord, TreatmentPlan, Appointment, and ClinicalNote, ensuring each entity captures the specific data points required for the healthcare domain.

Phase 3: Mapping Data Flows & Key Interactions

Once entities are defined, we map the relationships using the ||--o{ and ||--o| syntax. This notation defines cardinality: one-to-many or one-to-one.

For example, a single Patient can receive many Prescriptions, but a Prescription belongs to only one Patient.

patient ||--o{ prescription : "receives"

We also model the relationship between Therapist and Prescription, indicating that a therapist prescribes multiple plans.

therapist ||--o{ prescription : "prescribes"

The ExercisePrescription entity acts as a junction table (or associative entity) linking Patient, Therapist, and Exercise. This allows a patient to have multiple prescriptions, and each prescription can include specific details like sets, reps, and resistance_level that differ from the default exercise definition.

exercise ||--o{ prescription : "included in"

We continue mapping relationships for sessions, progress records, and clinical notes, ensuring the flow of data from intake to assessment is logically sound.

Phase 4: Grouping, Annotations & Visual Polish

While the core logic is in the relationships, visual polish enhances readability. The VP theme handles most styling, but we can add specific annotations.

We use the role attribute in the User entity to differentiate between a patient and a therapist at the application level, though the ERD uses separate entities for clarity. We also ensure that all foreign keys are explicitly marked with <> in the attribute list, which helps developers quickly identify referential integrity constraints.

The use of ENUM for fields like gender, difficulty_level, and status ensures data consistency and restricts input to valid values, a critical requirement in healthcare applications.

Syntax & Keyword Deep Dive

To build this diagram effectively, it is essential to understand the specific PlantUML syntax elements used:

  • entity: The primary keyword used to define a table or entity in an ERD. It is followed by the display name and an alias.
  • entity "Name" as alias: Allows you to specify a friendly name (e.g., “Patient”) and a shorter alias (e.g., patient) for use in relationship definitions.
  • * (Asterisk): Placed before an attribute name to denote it as the Primary Key (PK).
  • <> and <>: Stereotypes used to explicitly label Primary Keys and Foreign Keys within the entity block.
  • -- (Double Dash): A visual separator line within an entity block that divides keys from other attributes.
  • ||--o{: The relationship arrow syntax representing “One or more to Zero or more” (One-to-Many). The || indicates mandatory participation on the left, and o{ indicates optional participation on the right.
  • ||--o|: The relationship arrow syntax representing “One or more to Zero or One” (One-to-One or Optional One).
  • /' ... '/: The syntax for multi-line comments, allowing for detailed documentation within the code block.
  • !include: A directive to load external resources, such as themes or libraries, to standardize the diagram’s appearance.

Best Practices & Pitfalls to Avoid

When modeling complex healthcare ERDs, adherence to best practices ensures the diagram remains maintainable and accurate.

1. Use Aliases for Readability
Always define an alias for your entities (e.g., entity "Patient" as patient). This prevents the diagram from becoming cluttered with long entity names in relationship lines and makes the code easier to read.

2. Normalize Data Types
Be consistent with data types. Use UUID for unique identifiers, TIMESTAMP for creation/modification times, and ENUM for fixed lists of values. This clarity helps developers map the diagram directly to database schema definitions.

3. Avoid Over-Normalization in Visual Models
While normalization is key for databases, ERDs should focus on business relationships. Ensure that junction entities like ExercisePrescription are used appropriately to capture attributes specific to the relationship (e.g., the specific sets prescribed) rather than just linking tables.

4. Document Relationships Clearly
Always label your relationship lines (e.g., : "receives"). Without labels, the meaning of the connection is ambiguous, especially in a diagram with many entities.

Try It Yourself with VPasCode

Start Building Healthcare ERDs Faster with VPasCode

Instantly render and customize your complex PlantUML Entity Relationship Diagrams online with zero local setup or tool installation.

Scroll to Top