How delete/anonymize sensitive data and keep its integrity?

94 views Asked by At

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

  1. User creates a patient and inputs their address.
  2. User creates n appointments for all patients they met during the current_day.
  3. 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).
  4. 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
  5. [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.

0

There are 0 answers