Skip to content

09 — Consent & Compliance Layer

GDPR-First Design

Designing for GDPR ensures compliance with HIPAA, India DPDP Act, UAE data protection by default.

Purpose Required For Default
clinical_data_processing Any clinical data handling Required
cross_border_transfer Sending data to destination country Required
provider_sharing Sharing records with matched providers Required
analytics De-identified analytics and reporting Optional
sms_transactional SMS notifications Optional
sms_marketing Marketing communications Optional
  • Records are immutable — new versions created, never updated
  • Processing blocked without active consent for relevant purpose
  • Consent expiry tracked with 30-day automated warnings
  • Separate consent versions per privacy policy version
CREATE TABLE consent_records (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    patient_id UUID NOT NULL REFERENCES patients(id),
    tenant_id VARCHAR(100) NOT NULL,
    purpose VARCHAR(50) NOT NULL,
    granted BOOLEAN NOT NULL,
    policy_version VARCHAR(20) NOT NULL,
    ip_address VARCHAR(45),
    user_agent TEXT,
    expires_at TIMESTAMPTZ,
    created_at TIMESTAMPTZ DEFAULT NOW()
    -- No updated_at: immutable records
);

Data Classification

Classification Examples Protection
PII Name, email, phone, passport Field-level encryption at rest, audit-logged access
PHI Medical records, diagnoses, imaging Field-level encryption, tenant-isolated, consent-gated
Operational Preferences, language, budget Standard encryption, tenant-scoped

Data Subject Request Handler (GDPR Article 17)

Cascade delete across all data stores: 1. PostgreSQL: patient records, FHIR resources, events, consent, documents 2. Neo4j: patient node and all relationships 3. Qdrant: patient embeddings 4. R2: all uploaded files for this patient 5. Redis: cached data

Generates deletion certificate with affected record counts.

Audit Logging

CREATE TABLE audit_log (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    actor_id VARCHAR(100) NOT NULL,
    action VARCHAR(50) NOT NULL,          -- 'read', 'create', 'update', 'delete', 'export'
    resource_type VARCHAR(50) NOT NULL,
    resource_id VARCHAR(100),
    tenant_id VARCHAR(100) NOT NULL,
    ip_address VARCHAR(45),
    user_agent TEXT,
    correlation_id VARCHAR(100),
    details JSONB,
    created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Append-only. Super admins cannot delete.