majesticlabs-dev/majestic-marketplace

privacy-reviewer

Review PII handling, encryption, and GDPR/CCPA compliance in Rails applications.

View source
Original skill document

Rendered from the source repository. Headings, examples, code, tables, links, and referenced images are preserved.

Privacy Compliance Review

Review PII identification, encryption, data deletion, and regulatory compliance.

PII Identification Checklist

CategoryExamplesTreatment
Direct identifiersName, email, phone, SSNEncrypt at rest
Indirect identifiersIP address, device IDHash or encrypt
Location dataGPS, address, zip codeEncrypt, retention limits
FinancialCard numbers, bank accountsPCI compliance required
HealthMedical records, conditionsHIPAA compliance required
BehavioralBrowsing history, preferencesConsent required

Encryption for Sensitive Fields

ruby
# Rails 7+ built-in encryption
class User < ApplicationRecord
  encrypts :ssn
  encrypts :date_of_birth
  encrypts :medical_notes, deterministic: false  # Non-searchable
end

# Configuration in credentials
# active_record_encryption:
#   primary_key: <32-byte key>
#   deterministic_key: <32-byte key>
#   key_derivation_salt: <salt>

Right to Deletion (GDPR Article 17)

ruby
# PROBLEM: Hard delete loses audit trail
user.destroy

# SOLUTION: Anonymization with audit preservation
def anonymize!
  transaction do
    update!(
      email: "deleted_#{id}@anonymized.local",
      name: "Deleted User",
      phone: nil,
      address: nil,
      deleted_at: Time.current
    )
    # Keep orders for accounting, anonymize PII
    orders.update_all(
      customer_name: "Anonymized",
      shipping_address: nil
    )
  end
end

Data Retention

ruby
# Automated cleanup job
class PiiRetentionJob < ApplicationJob
  def perform
    # Delete inactive users after retention period
    User.where("last_activity_at < ?", 3.years.ago)
        .find_each(&:anonymize!)

    # Purge old logs
    AuditLog.where("created_at < ?", 7.years.ago).delete_all
  end
end

Audit Trails

ruby
# Track PII access
class PiiAccessLog < ApplicationRecord
  belongs_to :user           # Whose data was accessed
  belongs_to :accessed_by, class_name: 'User'

  # Log: what, when, why, who
  # user_id, accessed_by_id, field_accessed, purpose, created_at
end

# In model
def ssn
  PiiAccessLog.create!(user: self, accessed_by: Current.user, field_accessed: 'ssn')
  super
end

Consent Management

ruby
class UserConsent < ApplicationRecord
  belongs_to :user

  # Track: what consented, when, version, withdrawal
  # consent_type, granted_at, policy_version, withdrawn_at
end

# Check before processing
def can_send_marketing?(user)
  user.consents.active.exists?(consent_type: 'marketing')
end

Data Export (GDPR Article 20)

ruby
def export_personal_data
  {
    profile: attributes.slice('name', 'email', 'phone'),
    orders: orders.map(&:export_data),
    activity: activity_logs.map(&:export_data),
    exported_at: Time.current.iso8601
  }.to_json
end

Review Checklist

  • [ ] All PII fields identified and documented?
  • [ ] Sensitive fields encrypted at rest?
  • [ ] Anonymization method exists for deletion requests?
  • [ ] Data retention policies implemented?
  • [ ] PII access logged for audit?
  • [ ] Consent tracked before data processing?
  • [ ] Data export available for portability requests?

Output Format

markdown
## Privacy Review: [PASS/WARN/FAIL]

### Unencrypted PII
- [model.field]: [PII type, should be encrypted]

### Deletion Compliance
- [issue]: [hard deletes without anonymization option]

### Missing Audit Trails
- [model]: [PII accessed without logging]

### Consent Gaps
- [feature]: [processes data without consent check]

### Recommendations
1. [Prioritized fixes]
from this repository

More skills

All skills