I am working on Calcometer, an app that helps healthcare workers (and sales people) keep track of the distance and time they spend driving between appointments.
Tech stack: Ruby on Rails, StimulusJS and Bootstrap.
Goal
Be GDPR compliant about patient data deletion while not breaking main app logic
Description
Models (5): address, appointment, patient, trip, user. Schema
create_table "addresses", force: :cascade do |t|
t.string "street"
t.string "number"
t.string "zip_code"
t.string "city"
t.string "state"
t.string "country"
t.float "latitude"
t.float "longitude"
[...]
end
create_table "appointments", force: :cascade do |t|
t.datetime "start_time"
t.datetime "end_time"
t.bigint "user_id"
t.bigint "patient_id"
[...]
end
create_table "patients", force: :cascade do |t|
t.string "name"
t.bigint "client_id", null: false
t.bigint "address_id", null: false
[...]
end
create_table "trips", force: :cascade do |t|
t.bigint "start_appointment_id", null: false
t.bigint "end_appointment_id", null: false
t.float "driving_distance"
t.integer "driving_time"
[...]
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "name"
t.string "last_name"
[...]
end
User flow
- User creates a patient and inputs their address.
- User creates n appointments for all patients they met during the current_day.
- App calculates a trip based on a start_appointment and an end_appointment (whenever >2 appointments exist in the current_day) 3a. in the trip model, start_appointment and end_appointment are validated to avoid overlapping. 3b. in the appointment model, start_time and end_time are validated (and latter must be after the first).
- A recalculate_trip service is triggered every day at 1am to recalculate trips of previous day for data integrity purposes. 4a. Deleting an appointment will trigger the service for the same day
- [WIP] User can export (email) trips data for a given time range for their client/employer.
Main methods
Method to calculate driving distance using Geocoder
def calculate_driving_distance
coordinates1 = start_appointment.patient.address.latitude, start_appointment.patient.address.longitude
coordinates2 = end_appointment.patient.address.latitude, end_appointment.patient.address.longitude
Geocoder::Calculations.distance_between(coordinates1, coordinates2) if coordinates1 && coordinates2
end
Method to calculate driving time based on driving_distance and average speed in Switzerland (50 km/h)
def calculate_driving_time
(calculate_driving_distance.to_f / AVERAGE_SPEED \* 60).round if calculate_driving_distance
end
Issues
#1 Data integrity when deleting Patient account
Patient data is name, last_name and address_id; as this is sensitive data, I want to make sure the app is GDPR compliant, therefore whenever a user wants to delete patient data, it is deleted/anonymised.
#2 Updating method calculate_driving_distance
Currently, whenever a patient is deleted, this will cause issues in the distance_calculation method as coordinates are fetched from the patient through the appointment (coordinates1 = start_appointment.patient.address.latitude); so when a patient is deleted, the patient becomes nil and no more coordinates
I already checked this (old) answer, however it seems outdates (9+ yo) and I would like to know more recent best practices for database design.
For issue 1, I thought about these two mutually exclusive options:
Proposed solution A: implement a soft delete solution with paper_trail gem
Proposed solution B: permanently delete patient data.
For issue 2, I also thought about the following two options:
Proposed solution C: implement soft delete and never have this issue
Proposed solution D: whenever an appointment is created, set address_id = patient.address_id; and updated coordinates fetching
from
coordinates1 = start_appointment.patient.address.latitude
to
coordinates1 = start_appointment.address.latitude
Thanks for reading so far, I am happy to read your proposed solutions and feedback.