Data Privacy and GDPR Compliance Systems
Cumulative GDPR fines reached €5.88 billion by January 2025, with €1.2 billion issued in 2024 alone. France (CNIL), Spain (AEPD), and Italy (Garante) have intensified inspections for dark patterns, pre-loaded analytics cookies, and insufficient consent logs. In this environment, having robust software for GDPR compliance management is no longer optional — it is a business requirement.
In this article we build the fundamental components of a GDPR Compliance System: a Consent Management Platform (CMP), Data Subject Request (DSR) automation, automated data mapping, and privacy by design architectural patterns. Code is in Python (FastAPI backend) and TypeScript/Angular (frontend).
What You Will Learn
- Architecture of a GDPR-compliant Consent Management Platform (CMP)
- Data Subject Requests: access, erasure, portability automation
- Automated data mapping: where is personal data stored?
- Privacy by design: architectural patterns for risk minimization
- Immutable audit trail for demonstrating compliance
- Angular cookie banner and privacy preferences integration
The Legal Framework: GDPR Principles for Developers
Before writing code, it is critical to understand which GDPR principles must be reflected in system architecture. Key principles (Art. 5 GDPR) with direct technical implications:
| GDPR Principle | Technical Implication | Architectural Pattern |
|---|---|---|
| Data minimization | Collect only strictly necessary data | Schema validation, minimal form fields |
| Purpose limitation | Data used only for declared purpose | Purpose tagging, purpose-based access control |
| Accuracy | Data kept current, errors corrected promptly | DSR update workflow, data quality checks |
| Storage limitation | Data deleted/anonymized after purpose ends | Automated retention policies, scheduled deletion |
| Integrity and confidentiality | Protection against unauthorized access | Encryption at rest, RBAC, audit logging |
| Accountability | Demonstrate compliance | Immutable audit trail, DPA agreement tracking |
Consent Management Platform (CMP)
The CMP is the heart of the GDPR system: it collects, stores, and manages user consent for each processing purpose. It must support opt-in (explicit, granular consent), immediate revocation, and verifiable logs.
from dataclasses import dataclass, field
from typing import List, Optional, Dict
from datetime import datetime
from enum import Enum
import uuid
import hashlib
class LegalBasis(Enum):
CONSENT = "consent" # Art. 6(1)(a)
CONTRACT = "contract" # Art. 6(1)(b)
LEGAL_OBLIGATION = "legal_obligation" # Art. 6(1)(c)
LEGITIMATE_INTEREST = "legitimate" # Art. 6(1)(f)
@dataclass
class ConsentRecord:
"""
Immutable consent record.
Every change creates a NEW record (append-only audit trail).
"""
record_id: str
user_id: str
purpose_id: str
granted: bool
version: str # privacy policy version at time of consent
timestamp: datetime
ip_address_hash: str # hashed IP (IP is PII in some jurisdictions)
user_agent_hash: str
collection_point: str # e.g., "cookie_banner", "registration_form"
expires_at: Optional[datetime] = None
class ConsentManagementPlatform:
"""
GDPR consent management.
Immutable pattern: consents are never updated, only appended.
"""
def __init__(self, db_connection, privacy_policy_version: str):
self.db = db_connection
self.policy_version = privacy_policy_version
def record_consent(
self,
user_id: str,
purpose_id: str,
granted: bool,
ip_address: str,
user_agent: str,
collection_point: str
) -> ConsentRecord:
"""Records a consent/withdrawal. Always creates a new record."""
record = ConsentRecord(
record_id=str(uuid.uuid4()),
user_id=user_id,
purpose_id=purpose_id,
granted=granted,
version=self.policy_version,
timestamp=datetime.utcnow(),
ip_address_hash=hashlib.sha256(ip_address.encode()).hexdigest()[:16],
user_agent_hash=hashlib.sha256(user_agent.encode()).hexdigest()[:16],
collection_point=collection_point
)
# Append-only persistence (never update)
self.db.consent_records.insert_one({
'record_id': record.record_id,
'user_id': record.user_id,
'purpose_id': record.purpose_id,
'granted': record.granted,
'version': record.version,
'timestamp': record.timestamp.isoformat(),
'ip_address_hash': record.ip_address_hash,
'collection_point': record.collection_point
})
return record
def get_current_consent(self, user_id: str, purpose_id: str) -> Optional[ConsentRecord]:
"""Returns current consent status using event sourcing pattern (latest record wins)."""
records = self.db.consent_records.find(
{'user_id': user_id, 'purpose_id': purpose_id},
sort=[('timestamp', -1)],
limit=1
)
return records[0] if records else None
def get_all_consents(self, user_id: str) -> Dict[str, dict]:
"""Returns all current consents for a user (for privacy dashboard and DSR access)."""
pipeline = [
{'$match': {'user_id': user_id}},
{'$sort': {'timestamp': -1}},
{'$group': {
'_id': '$purpose_id',
'granted': {'$first': '$granted'},
'last_updated': {'$first': '$timestamp'}
}}
]
results = self.db.consent_records.aggregate(pipeline)
return {r['_id']: {'granted': r['granted'], 'last_updated': r['last_updated']}
for r in results}
Data Subject Requests (DSR) Automation
GDPR grants data subjects several rights (Art. 15-22) that must be fulfilled within 30 days of the request. Automating DSR handling is not just efficient — it is necessary to meet regulatory deadlines at scale.
from enum import Enum
from dataclasses import dataclass, field
from typing import List, Optional
from datetime import datetime, timedelta
import uuid
class DSRType(Enum):
ACCESS = "access" # Art. 15 - right of access
RECTIFICATION = "rectification" # Art. 16 - rectification
ERASURE = "erasure" # Art. 17 - right to be forgotten
RESTRICTION = "restriction" # Art. 18 - restriction of processing
PORTABILITY = "portability" # Art. 20 - data portability
OBJECTION = "objection" # Art. 21 - right to object
@dataclass
class DataSubjectRequest:
request_id: str
dsr_type: DSRType
user_id: str
email: str
received_at: datetime
deadline: datetime
audit_log: List[dict] = field(default_factory=list)
class DSRAutomationService:
DATA_SOURCES = [
'user_profiles', 'orders', 'consent_records',
'analytics_events', 'support_tickets', 'email_logs'
]
def create_request(self, dsr_type: DSRType, email: str, user_id: str = None) -> DataSubjectRequest:
received_at = datetime.utcnow()
return DataSubjectRequest(
request_id=str(uuid.uuid4()),
dsr_type=dsr_type,
user_id=user_id or '',
email=email,
received_at=received_at,
deadline=received_at + timedelta(days=30)
)
async def process_access_request(self, request: DataSubjectRequest, db) -> dict:
"""Art. 15: generate complete personal data report. Reduces 4-week task to minutes."""
personal_data = {}
for source in self.DATA_SOURCES:
try:
records = await db[source].find(
{'$or': [{'user_id': request.user_id}, {'email': request.email}]}
).to_list(length=10000)
# Remove internal metadata before returning
personal_data[source] = [
{k: v for k, v in r.items() if k not in ['_id', 'internal_notes']}
for r in records
]
except Exception as e:
personal_data[source] = {'error': str(e)}
return {
'request_id': request.request_id,
'user_email': request.email,
'generated_at': datetime.utcnow().isoformat(),
'personal_data': personal_data,
'format': 'JSON',
'legal_basis': 'Art. 15 GDPR'
}
async def process_erasure_request(self, request: DataSubjectRequest, db, dry_run: bool = True) -> dict:
"""
Art. 17: delete or anonymize all personal data.
dry_run=True shows what would be deleted without making changes.
Note: orders are anonymized, not deleted, due to legal retention obligations (Art. 17(3)(b)).
"""
deletion_report = {'actions': [], 'errors': [], 'dry_run': dry_run}
for source in self.DATA_SOURCES:
try:
records = await db[source].find(
{'$or': [{'user_id': request.user_id}, {'email': request.email}]}
).to_list(length=10000)
if not records:
continue
action = {
'source': source,
'records_found': len(records),
'action': 'delete' if source != 'orders' else 'anonymize'
}
if not dry_run:
if action['action'] == 'delete':
result = await db[source].delete_many(
{'$or': [{'user_id': request.user_id}, {'email': request.email}]}
)
action['deleted_count'] = result.deleted_count
else:
await db[source].update_many(
{'$or': [{'user_id': request.user_id}, {'email': request.email}]},
{'$set': {'email': 'deleted@anonymized.gdpr', 'name': 'DELETED', 'phone': None}}
)
action['anonymized'] = True
deletion_report['actions'].append(action)
except Exception as e:
deletion_report['errors'].append({'source': source, 'error': str(e)})
return deletion_report
GDPR-Compliant Cookie Banner with Angular
The frontend is often the most critical compliance point: dark patterns, pre-selected consent, and friction-heavy rejection flows are the leading causes of GDPR fines in 2024-2025.
// cookie-consent.service.ts
import { Injectable, inject, signal } from '@angular/core';
import { HttpClient } from '@angular/common/http';
export interface ConsentPreferences {
necessary: true;
analytics: boolean;
marketing: boolean;
personalization: boolean;
}
@Injectable({ providedIn: 'root' })
export class CookieConsentService {
private http = inject(HttpClient);
private readonly STORAGE_KEY = 'gdpr_consent_v2';
preferences = signal<ConsentPreferences | null>(null);
bannerVisible = signal<boolean>(false);
constructor() { this.loadSavedPreferences(); }
private loadSavedPreferences(): void {
const saved = localStorage.getItem(this.STORAGE_KEY);
if (saved) {
const parsed = JSON.parse(saved);
const savedAt = new Date(parsed.savedAt);
const thirteenMonthsAgo = new Date();
thirteenMonthsAgo.setMonth(thirteenMonthsAgo.getMonth() - 13);
if (savedAt > thirteenMonthsAgo) {
this.preferences.set(parsed);
return;
}
}
this.bannerVisible.set(true);
}
acceptAll(): void {
this.savePreferences({
necessary: true, analytics: true, marketing: true, personalization: true
});
}
rejectAll(): void {
// Rejection must be equally easy as acceptance - GDPR requirement
this.savePreferences({
necessary: true, analytics: false, marketing: false, personalization: false
});
}
private savePreferences(prefs: ConsentPreferences): void {
localStorage.setItem(this.STORAGE_KEY, JSON.stringify({
...prefs, savedAt: new Date().toISOString()
}));
this.preferences.set(prefs);
this.bannerVisible.set(false);
// Send to backend for audit trail
this.http.post('/api/v1/consent', { preferences: prefs }).subscribe();
}
}
Privacy by Design Best Practices
- Pseudonymization by default: in internal databases, use a UUID as user_id and maintain the email-to-UUID mapping in a separate service with restricted access.
- Encryption at rest for sensitive data: special categories (Art. 9 GDPR: health, sexual orientation, ethnicity) must be encrypted at rest with separately managed keys.
- Purpose-based access control: data collected for analytics must not be accessible to marketing modules, and vice versa.
- Personal data access logging: every access to personal data must be logged with who accessed it, when, and for what purpose.
Common Violations That Lead to Fines
- Analytics cookies loaded before consent (most common EU violation)
- Pre-ticked consent boxes or consent bundled with terms of service
- "Reject" button smaller or less visible than "Accept"
- Failure to respond to DSRs within 30 days
- Data transfer to third countries without adequate safeguards
- Insufficient consent logs: unable to prove when/how consent was given
Conclusions
A GDPR-compliant system is not a one-time project — it is an ongoing process requiring maintenance, updates as regulations evolve, and periodic audits. The tools presented here — CMP, DSR automation, retention policies, and compliant cookie banner — are the foundational building blocks of sustainable compliance.
In the coming months, with the EUDI Wallet rollout and intensifying inspections on AI system consent under the EU AI Act, privacy compliance becomes even more critical for any digital product targeting the European market.
LegalTech & AI Series
- NLP for Contract Analysis: From OCR to Understanding
- e-Discovery Platform Architecture
- Compliance Automation with Dynamic Rules Engines
- Smart Contracts for Legal Agreements: Solidity and Vyper
- Legal Document Summarization with Generative AI
- Case Law Search Engine: Vector Embeddings
- Digital Signature and Document Authentication at Scale
- Data Privacy and GDPR Compliance Systems (this article)
- Building a Legal AI Assistant (Legal Copilot)
- LegalTech Data Integration Patterns







