Privacy & Compliance
Compliance is not just legal obligation โ it's about building systems users can trust.
Regulatory Landscapeโ
| Regulation | Scope | Key Requirements |
|---|---|---|
| GDPR | EU/EEA personal data | Consent, right to erasure, DPO, breach notification 72h |
| CCPA/CPRA | California residents | Right to know, right to delete, opt-out of data sale |
| PCI-DSS | Payment card data | Cardholder data protection, vulnerability management |
| HIPAA | US health data (PHI) | Safeguards, minimum necessary, BAA agreements |
| SOC 2 | SaaS trust criteria | Security, availability, confidentiality, privacy controls |
Data Classificationโ
| Class | Examples | Controls |
|---|---|---|
| Public | Marketing copy, product catalog | No special controls |
| Internal | Employee emails, internal docs | Access control |
| Confidential | Business strategies, contracts | Encryption, need-to-know |
| Restricted / PII | Names, emails, IPs | Encrypt at rest + transit, audit log |
| Sensitive PII | SSN, health data, biometrics | All above + masking, separate storage |
| Regulated | PCI card data, PHI | Strict compliance controls, isolated environments |
@PiiField(category = PiiCategory.CONTACT)
private String email;
@PiiField(category = PiiCategory.FINANCIAL)
@Encrypted
private String bankAccountNumber;
@PiiField(category = PiiCategory.IDENTITY, regulated = Regulation.HIPAA)
@Encrypted
@AccessControlled(roles = {"CLINICIAN", "ADMIN"})
private String diagnosisCode;
GDPR Key Requirementsโ
Right to Erasureโ
@Service
@Transactional
public class ErasureService {
public void eraseUser(Long userId) {
// 1. Anonymize PII
User user = userRepository.findById(userId).orElseThrow();
user.setEmail("deleted_" + userId + "@deleted.invalid");
user.setName("Deleted User");
user.setPhoneNumber(null);
user.setErasedAt(Instant.now());
userRepository.save(user);
// 2. Delete non-essential data
activityRepository.deleteByUserId(userId);
sessionRepository.deleteByUserId(userId);
consentRepository.deleteByUserId(userId);
// 3. Retain legally required records (billing, legal disputes)
orderRepository.anonymizeUserReference(userId);
// 4. Invalidate all sessions and tokens
tokenRepository.invalidateAllForUser(userId);
// 5. Notify downstream services via event
eventPublisher.publishEvent(new UserErasedEvent(userId));
}
}
// Downstream services clean up their own data
@KafkaListener(topics = "user-erased")
public void onUserErased(UserErasedEvent event) {
searchIndexService.removeUser(event.getUserId());
analyticsService.anonymize(event.getUserId());
}
Data Minimizationโ
// โ
Use projections โ only return what the feature needs
public interface OrderSummaryProjection {
String getOrderId();
BigDecimal getTotal();
String getStatus();
// No PII returned
}
Data Retention Policyโ
@Scheduled(cron = "0 0 1 * * ?") // Daily at 1 AM
public void enforceRetentionPolicy() {
Instant cutoff = Instant.now().minus(90, ChronoUnit.DAYS);
activityRepository.deleteByCreatedAtBefore(cutoff);
orderRepository.anonymizeOlderThan(Instant.now().minus(7 * 365, ChronoUnit.DAYS));
}
PCI-DSSโ
What You Must NEVER Storeโ
// โ NEVER store (even encrypted)
String cvv;
String fullMagneticStripe;
String pin;
// โ
Store only tokenized reference
@Entity
public class PaymentMethod {
String providerToken; // e.g., Stripe: pm_1234...
String last4; // "1234" โ OK for display
String cardBrand; // "Visa"
String expiryMmYy; // "12/26"
// CVV never stored, ever.
}
Best practice: Use Stripe.js / Braintree โ card data never hits your servers, only tokens do. Drastically reduces PCI scope.
Audit Loggingโ
@Entity
@Immutable // Append-only โ never update
public class AuditLog {
@Id UUID id = UUID.randomUUID();
String eventType; // USER_LOGIN, DATA_ACCESSED, ROLE_CHANGED
String actorId;
String targetType;
String targetId;
String action; // READ, WRITE, DELETE, EXPORT
String ipAddress;
String outcome; // SUCCESS, FAILURE, DENIED
String details; // JSON context
Instant occurredAt;
String correlationId;
}
// Security events that MUST be logged
log.warn("LOGIN_FAILED user={} ip={} reason={}", username, ip, reason);
log.info("LOGIN_SUCCESS user={} ip={} mfa={}", username, ip, mfaUsed);
log.warn("ACCESS_DENIED user={} resource={}", user, resource);
log.warn("PRIVILEGE_ESCALATION_ATTEMPT user={} role={}", user, role);
log.info("DATA_EXPORT user={} records={}", username, count);
// NEVER log these
// log.info("Password: {}", password); โ Credential leak
// log.info("Token: {}", jwtToken); โ Token leak
// log.info("Card: {}", cardNumber); โ PCI violation
Data Masking & Pseudonymizationโ
public static String maskEmail(String email) {
if (email == null) return null;
int at = email.indexOf('@');
return email.charAt(0) + "***" + email.substring(at);
}
public static String maskCard(String card) {
return "****-****-****-" + card.substring(card.length() - 4);
}
Breach Notification Requirementsโ
| Regulation | Notify Authority | Notify Users |
|---|---|---|
| GDPR | Within 72 hours | If high risk to individuals |
| CCPA | N/A | If unencrypted PII exposed |
| HIPAA | Within 60 days | If PHI of 500+ individuals affected |
Interview Questionsโ
- What is GDPR and what are the 6 lawful bases for processing personal data?
- How do you implement the Right to Erasure in a microservices system?
- What is PCI-DSS and what card data must never be stored?
- What is the difference between anonymization and pseudonymization?
- What data should appear in an audit log?
- How do you implement data retention policies at scale?
- What is data minimization and how do you apply it to API design?
- What is a Data Protection Officer (DPO) and when is one required?
- How do you mask PII in logs without losing debugging ability?
- How do you handle Subject Access Requests (SAR) in a system with 10+ microservices?