You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GDPR合规下如何删除/匿名化敏感数据并保障Calcometer应用数据完整性?

符合GDPR要求的Calcometer应用数据处理解决方案

我正在开发Calcometer应用,该应用帮助医护人员及销售人员记录预约间的驾车距离与时长,技术栈为Ruby on Rails、StimulusJS和Bootstrap。当前核心目标是在符合GDPR患者数据删除要求的前提下,不破坏应用核心逻辑。

应用说明

核心模型(5个)

  • address:存储地址信息
  • appointment:存储预约时间、关联用户与患者
  • patient:存储患者敏感信息(姓名等)及关联地址
  • trip:存储两个预约间的驾车距离与时长
  • user:存储应用使用者信息

数据库表结构

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

用户流程

  1. 用户创建患者信息并填写地址;
  2. 用户为当日接诊的所有患者创建n个预约;
  3. 当当日预约数>2时,应用基于起始预约与结束预约计算行程:
    • trip模型中验证起始与结束预约无重叠;
    • appointment模型中验证开始时间早于结束时间;
  4. 每日凌晨1点触发recalculate_trip服务,重新计算前一日行程以保障数据完整性;
    • 删除预约时会触发当日的该服务;
  5. [开发中] 用户可将指定时间段的行程数据导出并发送给客户/雇主。

核心方法

使用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.all? && coordinates2.all?
end

基于驾车距离与瑞士平均车速(50km/h)计算驾车时长的方法:

def calculate_driving_time
   (calculate_driving_distance.to_f / AVERAGE_SPEED * 60).round if calculate_driving_distance  
end

核心问题与解决方案建议

问题1:删除患者账户时的数据完整性

患者数据(姓名、address_id关联的地址详情)属于GDPR定义的敏感数据,删除时需彻底删除或匿名化,但直接操作会破坏行程计算的核心逻辑(trip依赖预约关联的患者地址坐标)。

问题2:calculate_driving_distance方法的适配

当前逻辑依赖appointment -> patient -> address的关联链获取坐标,删除患者后该链断裂,导致行程计算失效,同时影响每日自动触发的recalculate_trip服务。

推荐解决方案组合

针对问题1:采用匿名化+软删除结合方案

放弃单纯的软删除(不符合GDPR"彻底删除敏感数据"的核心要求),也不直接永久删除(破坏业务逻辑),具体实现:

  1. 当用户发起患者删除请求时,先将患者的敏感字段(name等)替换为匿名值(如"匿名患者-XXXXXX",XXXXXX为随机字符串);
  2. 为patients表添加deleted_at软删除字段,业务查询中默认过滤已删除患者,但保留与预约的关联;
  3. 地址表中仅保留经纬度坐标(非敏感数据),删除地址的敏感字段(street、number、zip_code等)——行程计算仅依赖经纬度,无需完整地址信息。

针对问题2:解耦预约与患者的地址依赖

采用备选方案D的优化版,确保行程计算不依赖患者存在:

  1. 在appointments表中添加latitude和longitude字段;
  2. 创建预约时,将患者当前的地址经纬度同步到预约的对应字段;
  3. 修改calculate_driving_distance方法,直接从预约获取坐标:
def calculate_driving_distance
   coordinates1 = [start_appointment.latitude, start_appointment.longitude]
   coordinates2 = [end_appointment.latitude, end_appointment.longitude]
   Geocoder::Calculations.distance_between(coordinates1, coordinates2) if coordinates1.all? && coordinates2.all?
end
  1. 若后续患者地址更新,可根据业务需求选择:历史预约保留当时的坐标,未来预约同步更新坐标。

额外优化建议

  1. GDPR合规审计:在患者删除操作时添加审计日志,记录删除时间、操作人、匿名化/删除的字段,满足GDPR的可追溯要求;
  2. recalculate_trip服务容错:修改服务逻辑,当遇到无法获取坐标的预约时,跳过该行程计算并记录警告日志,避免服务整体失败;
  3. 数据导出脱敏:在开发中的导出功能中,自动过滤已匿名化的患者敏感数据,确保导出的行程数据不包含可识别的患者信息。

内容的提问来源于stack exchange,提问作者Aleks V

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 07:39:56