Medical Examination System Documentation
Overview
This document describes the comprehensive medical examination system implementation for dermatology, neurology, and cardiology examinations. The system follows the therapy notes pattern with independent examination models not tied to prescriptions, proper event-based appointment linking, and comprehensive validation rules.
Table of Contents
- API Endpoints
- Database Schema
- Models and Validations
- Controllers and Actions
- Interactors
- Serializers
- Patient History Integration
- Soft Delete Implementation
API Endpoints
Base Path
/clinic_patients/:clinic_patient_id/Dermatology Examinations
GET /derma_examinations # Index all derma examinations
GET /derma_examinations/:id # Show specific derma examination
POST /derma_examinations # Create new derma examination
PUT /derma_examinations/:id # Update derma examination
DELETE /derma_examinations/:id # Soft delete derma examinationNeurology Examinations
GET /neuro_examinations # Index all neuro examinations
GET /neuro_examinations/:id # Show specific neuro examination
POST /neuro_examinations # Create new neuro examination
PUT /neuro_examinations/:id # Update neuro examination
DELETE /neuro_examinations/:id # Soft delete neuro examinationCardiology Examinations
GET /cardio_examinations # Index all cardio examinations
GET /cardio_examinations/:id # Show specific cardio examination
POST /cardio_examinations # Create new cardio examination
PUT /cardio_examinations/:id # Update cardio examination
DELETE /cardio_examinations/:id # Soft delete cardio examinationDatabase Schema
Entity Relationship Diagram
Models and Validations
Dermatology Examination Model
File: backend/parts/patient/models/derma_examination.rb
Columns and Validations
| Column | Type | Validations | Allowed Values |
|---|---|---|---|
clinic_patient_id | integer | presence: true | - |
clinic_id | integer | presence: true | - |
doctor_id | integer | presence: true | - |
event_id | integer | optional | - |
event_type | string | optional | 'Appointment' |
examination_site | string | inclusion, allow_blank | 'localized', 'generalized', 'symmetrical' |
lesion_type | string | inclusion, allow_blank | 'macule', 'papule', 'vesicle', 'pustule', 'plaque', 'nodule' |
lesion_color | string | inclusion, allow_blank | 'erythematous', 'hyperpigmented', 'hypopigmented' |
lesion_configuration | string | inclusion, allow_blank | 'annular', 'linear', 'grouped', 'scattered' |
surface | string | inclusion, allow_blank | 'smooth', 'scaly', 'crusted', 'ulcerated' |
secondary_changes | string | inclusion, allow_blank | 'excoriation', 'lichenification', 'atrophy', 'scar' |
notes | text | length: { maximum: 2000 } | - |
deleted | boolean | - | false (default) |
deleted_at | datetime | - | - |
deleted_by_user_id | integer | - | - |
deleted_reason | text | - | - |
Associations
belongs_to :clinic_patient
belongs_to :clinic
belongs_to :doctor
belongs_to :event, polymorphic: true, optional: trueScopes
scope :active, -> { where(deleted: false) }
scope :order_by_latest, -> { order('created_at desc') }Neurology Examination Model
File: backend/parts/patient/models/neuro_examination.rb
Columns and Validations
| Column | Type | Validations | Allowed Values |
|---|---|---|---|
clinic_patient_id | integer | presence: true | - |
clinic_id | integer | presence: true | - |
doctor_id | integer | presence: true | - |
event_id | integer | optional | - |
event_type | string | optional | 'Appointment' |
level_of_consciousness | string | inclusion, allow_blank | 'alert', 'drowsy', 'unconscious' |
orientation | string | inclusion, allow_blank | 'oriented', 'disoriented' |
speech | string | inclusion, allow_blank | 'normal', 'dysarthric', 'aphasic' |
higher_functions | string | inclusion, allow_blank | 'normal', 'impaired' |
cranial_nerves | string | inclusion, allow_blank | 'normal', 'abnormal' |
motor_system | string | inclusion, allow_blank | 'normal', 'weak', 'spastic', 'flaccid' |
sensory_system | string | inclusion, allow_blank | 'normal', 'impaired' |
reflexes | string | inclusion, allow_blank | 'normal', 'brisk', 'diminished' |
meningeal_signs | string | inclusion, allow_blank | 'absent', 'present' |
gait | string | inclusion, allow_blank | 'normal', 'ataxic', 'hemiplegic' |
coordination | string | inclusion, allow_blank | 'normal', 'impaired' |
tremors | string | inclusion, allow_blank | 'absent', 'present' |
involuntary_movements | string | inclusion, allow_blank | 'absent', 'present' |
neuro_examination_data | jsonb | - | - |
deleted | boolean | - | false (default) |
deleted_at | datetime | - | - |
deleted_by_user_id | integer | - | - |
deleted_reason | text | - | - |
Associations
belongs_to :clinic_patient
belongs_to :clinic
belongs_to :doctor
belongs_to :event, polymorphic: true, optional: trueCardiology Examination Model
File: backend/parts/patient/models/cardio_examination.rb
Columns and Validations
| Column | Type | Validations | Allowed Values |
|---|---|---|---|
clinic_patient_id | integer | presence: true | - |
clinic_id | integer | presence: true | - |
doctor_id | integer | presence: true | - |
event_id | integer | optional | - |
event_type | string | optional | 'Appointment' |
| General Physical Examination | |||
built_nutrition | string | inclusion, allow_blank | 'normal', 'thin', 'obese' |
pallor_cyanosis_clubbing_edema | string | inclusion, allow_blank | 'present', 'absent' |
systemic_appearance | string | inclusion, allow_blank | 'comfortable', 'distressed', 'dyspneic' |
| Inspection | |||
chest_shape | string | inclusion, allow_blank | 'normal', 'barrel', 'pectus' |
visible_pulsations | string | inclusion, allow_blank | 'present', 'absent' |
surgical_scars | string | inclusion, allow_blank | 'present', 'absent' |
jvd_peripheral_signs | string | inclusion, allow_blank | 'present', 'absent' |
| Palpation | |||
apex_beat | string | inclusion, allow_blank | 'normal', 'displaced', 'heaving', 'tapping' |
parasternal_heave | string | inclusion, allow_blank | 'present', 'absent' |
thrill | string | inclusion, allow_blank | 'present', 'absent' |
pulse_character_capillary_refill | string | inclusion, allow_blank | 'normal', 'bounding', 'thready' |
| Percussion | |||
cardiac_borders | string | inclusion, allow_blank | 'normal', 'shifted' |
dullness_assessment | string | inclusion, allow_blank | 'normal', 'increased' |
| Auscultation | |||
s1_s2_sounds | string | inclusion, allow_blank | 'normal', 'soft', 'loud', 'split' |
added_sounds | string | inclusion, allow_blank | 'present', 'absent' |
murmurs | string | inclusion, allow_blank | 'present', 'absent' |
pericardial_rub | string | inclusion, allow_blank | 'present', 'absent' |
| Additional Findings | |||
jvp | string | inclusion, allow_blank | 'normal', 'raised' |
hepatomegaly | string | inclusion, allow_blank | 'present', 'absent' |
edema | string | inclusion, allow_blank | 'present', 'absent' |
limb_bp_difference | string | inclusion, allow_blank | 'present', 'absent' |
peripheral_cyanosis_temperature | string | inclusion, allow_blank | 'normal', 'cold', 'warm' |
| Soft Delete Fields | |||
deleted | boolean | - | false (default) |
deleted_at | datetime | - | - |
deleted_by_user_id | integer | - | - |
deleted_reason | text | - | - |
Controllers and Actions
All examination controllers follow the same pattern with CRUD operations (index, show, create, update, destroy) and use corresponding interactors for business logic.
Controller Files
| Controller | File | Purpose |
|---|---|---|
DermaExaminationsController | backend/parts/clinic/controllers/derma_examinations_controller.rb | Dermatology examination CRUD operations |
NeuroExaminationsController | backend/parts/clinic/controllers/neuro_examinations_controller.rb | Neurology examination CRUD operations |
CardioExaminationsController | backend/parts/clinic/controllers/cardio_examinations_controller.rb | Cardiology examination CRUD operations |
Interactors
Interactor Files
| Interactor | File | Purpose |
|---|---|---|
DermaExaminationActions::Save | backend/parts/clinic/interactors/derma_examination_actions/save.rb | Create/update derma examinations |
DermaExaminationActions::Delete | backend/parts/clinic/interactors/derma_examination_actions/delete.rb | Soft delete derma examinations |
NeuroExaminationActions::Save | backend/parts/clinic/interactors/neuro_examination_actions/save.rb | Create/update neuro examinations |
NeuroExaminationActions::Delete | backend/parts/clinic/interactors/neuro_examination_actions/delete.rb | Soft delete neuro examinations |
CardioExaminationActions::Save | backend/parts/clinic/interactors/cardio_examination_actions/save.rb | Create/update cardio examinations |
CardioExaminationActions::Delete | backend/parts/clinic/interactors/cardio_examination_actions/delete.rb | Soft delete cardio examinations |
All interactors follow the same pattern:
- Validate clinic patient and doctor
- Handle event-based appointment linking
- Comprehensive validation with detailed error messages
- Transaction-based saving for data consistency
- Soft delete with audit trail
Serializers
Base Serializer Pattern
All serializers follow the same structure:
class ExaminationSerializer < ActiveModel::Serializer
attributes :id, :clinic_patient_id, :doctor_id, :clinic_id, :event_id, :event_type,
:examination_fields, :notes, :deleted, :deleted_at, :created_at, :updated_at
has_one :doctor, serializer: DoctorSerializer
has_one :clinic_patient, serializer: ClinicPatientSerializer
has_one :event, polymorphic: true
def examination_fields
# Implementation varies by examination type
end
endSerializer Files
| Serializer | File | Purpose |
|---|---|---|
DermaExaminationSerializer | backend/parts/clinic/serializers/patient_derma_examination_serializer.rb | Dermatology examination response formatting |
NeuroExaminationSerializer | backend/parts/clinic/serializers/patient_neuro_examination_serializer.rb | Neurology examination response formatting |
CardioExaminationSerializer | backend/parts/clinic/serializers/patient_cardio_examination_serializer.rb | Cardiology examination response formatting |
Patient History Integration
History Logging
All examination models include the PatientHistoryActivity concern and automatically log to patient history:
# In each examination model
include PatientHistoryActivity
after_save :save_patient_history
def save_patient_history
return unless clinic_patient_id.present?
PatientHistory::SaveHistory.perform_now(
id,
'EXAMINATION_TYPE' # DERMA_EXAMINATION, NEURO_EXAMINATION, CARDIO_EXAMINATION
)
endPatient History Services
| Service | File | Purpose |
|---|---|---|
SaveDermaExamination | backend/parts/clinic/services/patient_history/save_derma_examination.rb | Logs derma examination changes to patient history |
SaveNeuroExamination | backend/parts/clinic/services/patient_history/save_neuro_examination.rb | Logs neuro examination changes to patient history |
SaveCardioExamination | backend/parts/clinic/services/patient_history/save_cardio_examination.rb | Logs cardio examination changes to patient history |
Soft Delete and Patient History
Soft deletes are handled using update_columns to bypass validations, with manual patient history logging:
def soft_delete!(user_id: nil, reason: nil)
update_columns(
deleted: true,
deleted_at: Time.current,
deleted_by_user_id: user_id,
deleted_reason: reason
)
# Manually trigger patient history save for deletion since update_columns bypasses callbacks
save_patient_history
endAPI Request/Response Examples
Create Dermatology Examination
Request:
POST /api/v1/clinic_patients/17/derma_examinations
Content-Type: application/json
{
"doctor_id": 8,
"appointment_id": 424,
"dermatology_examination_data": {
"derma_examination_data": {
"general_examination": "Patient appears alert and cooperative",
"vitals": {
"bp": "120/80 mmHg",
"pulse": "72 bpm",
"temperature": "98.6°F",
"respiratory_rate": "16 cpm"
},
"systemic_examination": {
"cardiovascular": "Normal S1,S2, no murmurs",
"respiratory": "Bilateral air entry present, no adventitious sounds",
"abdomen": "Soft, non-tender, no organomegaly"
}
},
"examination_site": "localized",
"lesion_type": "papule",
"lesion_color": "erythematous",
"lesion_configuration": "grouped",
"surface": "smooth",
"secondary_changes": "lichenification",
"notes": "Patient presents with acne-like eruptions on the face and neck. Patient appears alert and cooperative. Vitals: BP 120/80 mmHg, pulse 72 bpm, temperature 98.6°F, respiratory rate 16 cpm. Systemic examination shows cardiovascular: normal S1,S2, no murmurs; respiratory: bilateral air entry present, no adventitious sounds; abdomen: soft, non-tender, no organomegaly."
}
}Create Cardiology Examination
Request:
POST /api/v1/clinic_patients/17/cardio_examinations
Content-Type: application/json
{
"doctor_id": 8,
"appointment_id": 424,
"cardiology_examination_data": {
"built_nutrition": "normal",
"pallor_cyanosis_clubbing_edema": "absent",
"systemic_appearance": "comfortable",
"chest_shape": "normal",
"visible_pulsations": "absent",
"surgical_scars": "absent",
"jvd_peripheral_signs": "absent",
"apex_beat": "normal",
"parasternal_heave": "absent",
"thrill": "absent",
"pulse_character_capillary_refill": "normal",
"cardiac_borders": "normal",
"dullness_assessment": "normal",
"s1_s2_sounds": "normal",
"added_sounds": "absent",
"murmurs": "present",
"pericardial_rub": "absent",
"jvp": "normal",
"hepatomegaly": "absent",
"edema": "absent",
"limb_bp_difference": "absent",
"peripheral_cyanosis_temperature": "warm"
}
}Create Neurology Examination
Request:
POST /api/v1/clinic_patients/17/neuro_examinations
Content-Type: application/json
{
"doctor_id": 8,
"appointment_id": 424,
"neurology_examination_data": {
"level_of_consciousness": "alert",
"orientation": "alert",
"speech": "normal",
"gait": "normal",
"involuntary_movements": "none",
"memory": "intact",
"attention_concentration": "normal",
"language": "normal",
"mood_behavior": "normal",
"olfactory": "normal",
"optic": "normal",
"oculomotor_group": "normal",
"trigeminal": "normal",
"facial": "normal",
"vestibulocochlear": "normal",
"glossopharyngeal_vagus": "normal",
"accessory": "normal",
"hypoglossal": "normal",
"muscle_bulk": "normal",
"tone": "normal",
"power": "5",
"reflexes": "biceps",
"plantar_response": "flexor",
"touch_sensation": "normal",
"pain": "normal",
"temperature": "normal",
"vibration_sense": "normal",
"joint_position_sense": "normal",
"finger_nose_test": "normal",
"rapid_alternating_movements": "normal",
"coordination_gait": "normal",
"romberg_test": "negative",
"neck_stiffness": "absent",
"kernigs_sign": "absent",
"brudzinskis_sign": "absent",
"localization": "Left parietal lobe",
"probable_diagnosis": "Cerebrovascular Accident (Left MCA Territory)",
"plan_remarks": "Advised MRI Brain and Neurology follow-up"
}
}Index Examinations
Request:
GET /api/v1/clinic_patients/17/derma_examinationsResponse:
200 OK
Content-Type: application/json
[
{
"id": 2,
"clinic_patient_id": 17,
"doctor_id": 8,
"clinic_id": 10,
"event_id": 424,
"event_type": "Appointment",
"examination_site": "generalized",
"lesion_type": "plaque",
"lesion_color": "hyperpigmented",
"lesion_configuration": "scattered",
"surface": "scaly",
"secondary_changes": "lichenification",
"notes": "Chronic plaque psoriasis",
"deleted": false,
"created_at": "2025-11-14T06:15:22.123Z",
"updated_at": "2025-11-14T06:15:22.123Z"
},
{
"id": 1,
"clinic_patient_id": 17,
"doctor_id": 8,
"clinic_id": 10,
"event_id": 424,
"event_type": "Appointment",
"examination_site": "localized",
"lesion_type": "papule",
"lesion_color": "erythematous",
"lesion_configuration": "grouped",
"surface": "smooth",
"secondary_changes": "scaly",
"notes": "Patient presents with acne-like eruptions on the face.",
"deleted": false,
"created_at": "2025-11-14T05:58:14.416Z",
"updated_at": "2025-11-14T05:58:14.416Z"
}
]Delete Examination
Request:
DELETE /api/v1/clinic_patients/17/derma_examinations/1Response:
204 No ContentError Handling
Validation Errors
{
"errors": {
"examination_type": "Could Not Be Saved: Examination site must be localized, generalized, or symmetrical, Lesion type must be macule, papule, vesicle, pustule, plaque, or nodule"
}
}Not Found Errors
{
"errors": {
"examination": "not found"
}
}Key Implementation Details
1. Event-Based Appointment Linking
All examinations support optional linking to appointments through:
event_id: Reference to appointment IDevent_type: Set to 'Appointment'belongs_to :event, polymorphic: true
2. Comprehensive Validation
Each examination type has medical-specific validation rules based on clinical checklists:
- Dermatology: Site, lesion type, color, configuration, surface, secondary changes
- Neurology: Consciousness, orientation, speech, cranial nerves, motor/sensory systems, reflexes, gait, coordination
- Cardiology: General physical, inspection, palpation, percussion, auscultation, additional findings
3. Soft Delete Implementation
- Uses
update_columnsto bypass validations during delete - Manually triggers patient history logging
- Supports audit trail with
deleted_by_user_idanddeleted_reason
4. Patient History Integration
- Automatic logging on create/update via
after_savecallback - Manual logging on delete to ensure consistency
- Structured data organization by examination type
- Deletion status tracking in patient history
5. Error Handling
- Detailed validation error messages with field descriptions
- Consistent error response format across all examination types
- Proper HTTP status codes for different error scenarios
Database Migrations
Key Migration Files
| Migration | File | Purpose |
|---|---|---|
CreateDermaExaminations | backend/parts/patient/migrate/20251113000000_create_prescription_examinations.rb | Creates derma_examinations table (renamed) |
CreateNeuroExaminations | backend/parts/patient/migrate/20251113075535_create_neuro_examinations.rb | Creates neuro_examinations table |
CreateCardioExaminations | backend/parts/patient/migrate/20251113095527_create_cardio_examinations.rb | Creates cardio_examinations table |
RenameExaminationDataToDermaExaminationData | backend/parts/patient/migrate/20251113071647_rename_examination_data_to_derma_examination_data.rb | Updates derma table structure |
Security and Authorization
All controllers use Pundit policies for authorization:
before_action :authorize_action
def authorize_action
authorize ExaminationType, "#{action_name}?"
endPolicies control access based on:
- Doctor-clinic relationship
- Patient assignment
- User roles and permissions
This documentation covers the complete medical examination system implementation including dermatology, neurology, and cardiology examinations with comprehensive API endpoints, database schema, validation rules, and integration patterns.