| name | gdpr-data-handling |
| description | Implement GDPR-compliant data handling with consent management, data subject rights, and privacy by design. Use when building systems that process EU personal data, implementing privacy controls, or conducting GDPR compliance reviews. |
GDPR Data Handling
Practical implementation guide for GDPR-compliant data processing, consent management, and privacy controls.
When to Use This Skill
- Building systems that process EU personal data
- Implementing consent management
- Handling data subject requests (DSRs)
- Conducting GDPR compliance reviews
- Designing privacy-first architectures
- Creating data processing agreements
Core Concepts
1. Personal Data Categories
| Category | Examples | Protection Level |
|---|
| Basic | Name, email, phone | Standard |
| Sensitive (Art. 9) | Health, religion, ethnicity | Explicit consent |
| Criminal (Art. 10) | Convictions, offenses | Official authority |
| Children's | Under 16 data | Parental consent |
2. Legal Bases for Processing
Article 6 - Lawful Bases:
├── Consent: Freely given, specific, informed
├── Contract: Necessary for contract performance
├── Legal Obligation: Required by law
├── Vital Interests: Protecting someone's life
├── Public Interest: Official functions
└── Legitimate Interest: Balanced against rights
3. Data Subject Rights
Right to Access (Art. 15) ─┐
Right to Rectification (Art. 16) │
Right to Erasure (Art. 17) │ Must respond
Right to Restrict (Art. 18) │ within 1 month
Right to Portability (Art. 20) │
Right to Object (Art. 21) ─┘
Implementation Patterns
Pattern 1: Consent Management
const consentSchema = {
userId: String,
consents: [
{
purpose: String,
granted: Boolean,
timestamp: Date,
source: String,
version: String,
ipAddress: String,
userAgent: String,
},
],
auditLog: [
{
action: String,
purpose: String,
timestamp: Date,
source: String,
},
],
};
class ConsentManager {
async recordConsent(userId, purpose, granted, metadata) {
const consent = {
purpose,
granted,
timestamp: new Date(),
source: metadata.source,
version: await this.(),
: metadata.,
: metadata.,
};
...(
{ userId },
{
: {
: consent,
: {
: granted ? : ,
purpose,
: consent.,
: metadata.,
},
},
},
{ : },
);
..(, {
userId,
purpose,
granted,
: consent.,
});
}
() {
record = ...({ userId });
(!record) ;
latestConsent = record.
.( c. === purpose)
.( b. - a.)[];
latestConsent?. === ;
}
() {
record = ...({ userId });
record?. || [];
}
}
<div class="consent-banner" role="dialog" aria-labelledby="consent-title">
<h2 id="consent-title">Cookie Preferences</h2>
<p>
We use cookies to improve your experience. Select your preferences below.
</p>
<form id="consent-form">
<div class="consent-category">
<input type="checkbox" id="necessary" checked disabled />
<label for="necessary">
<strong>Necessary</strong>
<span>Required for the website to function. Cannot be disabled.</span>
</label>
</div>
<div class="consent-category">
Analytics
Help us understand how you use our site.
Marketing
Personalized ads based on your interests.
Accept All
Reject All
Save Preferences
Privacy Policy |
Cookie Policy
Pattern 2: Data Subject Access Request (DSAR)
from datetime import datetime, timedelta
from typing import Dict, List, Optional
import json
class DSARHandler:
"""Handle Data Subject Access Requests."""
RESPONSE_DEADLINE_DAYS = 30
EXTENSION_ALLOWED_DAYS = 60
def __init__(self, data_sources: List['DataSource']):
self.data_sources = data_sources
async def submit_request(
self,
request_type: str,
user_id: str,
verified: bool,
details: Optional[Dict] = None
) -> str:
"""Submit a new DSAR."""
request = {
'id': self.generate_request_id(),
'type': request_type,
'user_id': user_id,
'status': 'pending_verification' if not verified else 'processing',
'submitted_at': datetime.utcnow(),
'deadline': datetime.utcnow() + timedelta(days=self.RESPONSE_DEADLINE_DAYS),
: details {},
: [{
: ,
: datetime.utcnow(),
:
}]
}
.db.dsar_requests.insert_one(request)
.notify_dpo(request)
request[]
() -> :
request = .get_request(request_id)
request[] != :
ValueError()
user_data = {}
source .data_sources:
:
data = source.get_user_data(request[])
user_data[source.name] = data
Exception e:
user_data[source.name] = {: (e)}
response = {
: request_id,
: datetime.utcnow().isoformat(),
: (user_data.keys()),
: user_data,
: .get_retention_info(),
: .get_processing_purposes(),
: .get_recipients()
}
.update_request(request_id, , response)
response
() -> :
request = .get_request(request_id)
request[] != :
ValueError()
results = {}
exceptions = []
source .data_sources:
:
can_delete, reason = source.can_delete(request[])
can_delete:
source.delete_user_data(request[])
results[source.name] =
:
exceptions.append({
: source.name,
: reason
})
results[source.name] =
Exception e:
results[source.name] =
response = {
: request_id,
: datetime.utcnow().isoformat(),
: results,
: exceptions
}
.update_request(request_id, , response)
response
() -> :
request = .get_request(request_id)
user_data = .process_access_request(request_id)
portable_data = {
: datetime.utcnow().isoformat(),
: ,
: user_data[]
}
json.dumps(portable_data, indent=, default=).encode()
Pattern 3: Data Retention
from datetime import datetime, timedelta
from enum import Enum
class RetentionBasis(Enum):
CONSENT = "consent"
CONTRACT = "contract"
LEGAL_OBLIGATION = "legal_obligation"
LEGITIMATE_INTEREST = "legitimate_interest"
class DataRetentionPolicy:
"""Define and enforce data retention policies."""
POLICIES = {
'user_account': {
'retention_period_days': 365 * 3,
'basis': RetentionBasis.CONTRACT,
'trigger': 'last_activity_date',
'archive_before_delete': True
},
'transaction_records': {
'retention_period_days': 365 * 7,
'basis': RetentionBasis.LEGAL_OBLIGATION,
'trigger': 'transaction_date',
'archive_before_delete': True,
'legal_reference': 'Tax regulations require 7 year retention'
},
'marketing_consent': {
'retention_period_days': 365 * 2,
'basis': RetentionBasis.CONSENT,
'trigger': 'consent_date',
:
},
: {
: * ,
: RetentionBasis.LEGITIMATE_INTEREST,
: ,
:
},
: {
: ,
: RetentionBasis.CONSENT,
: ,
: ,
:
}
}
():
data_type, policy .POLICIES.items():
cutoff_date = datetime.utcnow() - timedelta(
days=policy[]
)
policy.get():
.anonymize_old_data(data_type, cutoff_date)
:
policy.get():
.archive_data(data_type, cutoff_date)
.delete_old_data(data_type, cutoff_date)
.log_retention_action(data_type, cutoff_date)
():
data_type == :
.db.analytics.update_many(
{: {: before_date}},
{: {
: ,
: ,
: ,
: ,
: datetime.utcnow()
}}
)
Pattern 4: Privacy by Design
class PrivacyFirstDataModel:
"""Example of privacy-by-design data model."""
user_profile_schema = {
'user_id': str,
'email_hash': str,
'created_at': datetime,
'preferences': {
'language': str,
'timezone': str
}
}
user_pii_schema = {
'user_id': str,
'email': str,
'name': str,
'phone': str,
'address': dict,
'encryption_key_id': str
}
analytics_schema = {
'session_id': str,
'pseudonym_id': str,
'events': list,
'device_category': str,
: ,
}
:
() -> :
REQUIRED_FIELDS = {
: [, ],
: [],
: [, , , ],
: [, ]
}
allowed = REQUIRED_FIELDS.get(purpose, [])
{k: v k, v form_data.items() k allowed}
() -> :
geoip2.database
reader = geoip2.database.Reader()
:
response = reader.country(ip_address)
response.country.iso_code
:
Pattern 5: Breach Notification
from datetime import datetime
from enum import Enum
class BreachSeverity(Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
CRITICAL = "critical"
class BreachNotificationHandler:
"""Handle GDPR breach notification requirements."""
AUTHORITY_NOTIFICATION_HOURS = 72
AFFECTED_NOTIFICATION_REQUIRED_SEVERITY = BreachSeverity.HIGH
async def report_breach(
self,
description: str,
data_types: List[str],
affected_count: int,
severity: BreachSeverity
) -> dict:
"""Report and handle a data breach."""
breach = {
'id': self.generate_breach_id(),
'reported_at': datetime.utcnow(),
'description': description,
'data_types_affected': data_types,
'affected_individuals_count': affected_count,
'severity': severity.value,
'status': 'investigating',
'timeline': [{
'event': 'breach_reported',
'timestamp': datetime.utcnow(),
'details': description
}]
}
await self.db.breaches.insert_one(breach)
.notify_dpo(breach)
.notify_security_team(breach)
.requires_authority_notification(severity, data_types):
breach[] = (
datetime.utcnow() + timedelta(hours=.AUTHORITY_NOTIFICATION_HOURS)
)
.schedule_authority_notification(breach)
severity.value [BreachSeverity.HIGH.value, BreachSeverity.CRITICAL.value]:
.schedule_individual_notifications(breach)
breach
() -> :
sensitive_types = [, , , ]
(t sensitive_types t data_types):
severity [BreachSeverity.MEDIUM, BreachSeverity.HIGH, BreachSeverity.CRITICAL]
() -> :
breach = .get_breach(breach_id)
{
: {
: .config.org_name,
: .config.dpo_contact,
: .config.registration_number
},
: {
: breach[],
: breach[],
: breach[],
: .assess_consequences(breach),
: .get_remediation_measures(breach_id),
: .get_proposed_measures(breach_id)
},
: breach[],
: datetime.utcnow().isoformat()
}
Compliance Checklist
## GDPR Implementation Checklist
### Legal Basis
- [ ] Documented legal basis for each processing activity
- [ ] Consent mechanisms meet GDPR requirements
- [ ] Legitimate interest assessments completed
### Transparency
- [ ] Privacy policy is clear and accessible
- [ ] Processing purposes clearly stated
- [ ] Data retention periods documented
### Data Subject Rights
- [ ] Access request process implemented
- [ ] Erasure request process implemented
- [ ] Portability export available
- [ ] Rectification process available
- [ ] Response within 30-day deadline
### Security
- [ ] Encryption at rest implemented
- [ ] Encryption in transit (TLS)
- [ ] Access controls in place
- [ ] Audit logging enabled
### Breach Response
- [ ] Breach detection mechanisms
- [ ] 72-hour notification process
- [ ] Breach documentation system
### Documentation
- [ ] Records of processing activities (Art. 30)
- [ ] Data protection impact assessments
- [ ] Data processing agreements with vendors
Best Practices
Do's
- Minimize data collection - Only collect what's needed
- Document everything - Processing activities, legal bases
- Encrypt PII - At rest and in transit
- Implement access controls - Need-to-know basis
- Regular audits - Verify compliance continuously
Don'ts
- Don't pre-check consent boxes - Must be opt-in
- Don't bundle consent - Separate purposes separately
- Don't retain indefinitely - Define and enforce retention
- Don't ignore DSARs - 30-day response required
- Don't transfer without safeguards - SCCs or adequacy decisions
Resources