gdpr
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGDPR Compliance
GDPR合规
Data Subject Rights Implementation
数据主体权利实施
Right to Access (Data Export)
访问权(数据导出)
typescript
app.get('/api/privacy/my-data', auth, async (req, res) => {
const userId = req.user.id;
const data = {
profile: await db.user.findUnique({ where: { id: userId }, select: exportableFields }),
orders: await db.order.findMany({ where: { userId }, select: orderExportFields }),
preferences: await db.preference.findMany({ where: { userId } }),
consents: await db.consent.findMany({ where: { userId } }),
};
res.json(data);
// Or: generate downloadable file
// res.attachment('my-data.json').json(data);
});typescript
app.get('/api/privacy/my-data', auth, async (req, res) => {
const userId = req.user.id;
const data = {
profile: await db.user.findUnique({ where: { id: userId }, select: exportableFields }),
orders: await db.order.findMany({ where: { userId }, select: orderExportFields }),
preferences: await db.preference.findMany({ where: { userId } }),
consents: await db.consent.findMany({ where: { userId } }),
};
res.json(data);
// Or: generate downloadable file
// res.attachment('my-data.json').json(data);
});Right to Erasure (Deletion)
删除权(擦除)
typescript
async function deleteUserData(userId: string): Promise<void> {
// Anonymize where deletion would break referential integrity
await db.order.updateMany({
where: { userId },
data: { customerName: '[deleted]', email: '[deleted]' },
});
// Delete personal data
await db.preference.deleteMany({ where: { userId } });
await db.consent.deleteMany({ where: { userId } });
await db.session.deleteMany({ where: { userId } });
// Anonymize the user record (keep for accounting if legally required)
await db.user.update({
where: { id: userId },
data: {
email: `deleted-${userId}@anonymized.local`,
name: '[deleted]',
phone: null,
deletedAt: new Date(),
},
});
// Log the deletion (audit requirement)
await auditLog.record({
action: 'user.data_deleted',
resource: { type: 'user', id: userId },
actor: { id: userId, type: 'user' },
});
}typescript
async function deleteUserData(userId: string): Promise<void> {
// Anonymize where deletion would break referential integrity
await db.order.updateMany({
where: { userId },
data: { customerName: '[deleted]', email: '[deleted]' },
});
// Delete personal data
await db.preference.deleteMany({ where: { userId } });
await db.consent.deleteMany({ where: { userId } });
await db.session.deleteMany({ where: { userId } });
// Anonymize the user record (keep for accounting if legally required)
await db.user.update({
where: { id: userId },
data: {
email: `deleted-${userId}@anonymized.local`,
name: '[deleted]',
phone: null,
deletedAt: new Date(),
},
});
// Log the deletion (audit requirement)
await auditLog.record({
action: 'user.data_deleted',
resource: { type: 'user', id: userId },
actor: { id: userId, type: 'user' },
});
}Consent Management
同意管理
typescript
interface ConsentRecord {
userId: string;
purpose: string; // 'marketing', 'analytics', 'essential'
granted: boolean;
grantedAt: Date;
ipAddress: string;
version: string; // Policy version at time of consent
}
app.post('/api/consent', auth, async (req, res) => {
const { purposes } = req.body; // { marketing: true, analytics: false }
for (const [purpose, granted] of Object.entries(purposes)) {
await db.consent.upsert({
where: { userId_purpose: { userId: req.user.id, purpose } },
create: {
userId: req.user.id,
purpose,
granted: granted as boolean,
grantedAt: new Date(),
ipAddress: req.ip,
version: CURRENT_PRIVACY_POLICY_VERSION,
},
update: {
granted: granted as boolean,
grantedAt: new Date(),
ipAddress: req.ip,
version: CURRENT_PRIVACY_POLICY_VERSION,
},
});
}
res.json({ updated: true });
});
// Check consent before processing
async function hasConsent(userId: string, purpose: string): Promise<boolean> {
const consent = await db.consent.findUnique({
where: { userId_purpose: { userId, purpose } },
});
return consent?.granted === true;
}typescript
interface ConsentRecord {
userId: string;
purpose: string; // 'marketing', 'analytics', 'essential'
granted: boolean;
grantedAt: Date;
ipAddress: string;
version: string; // Policy version at time of consent
}
app.post('/api/consent', auth, async (req, res) => {
const { purposes } = req.body; // { marketing: true, analytics: false }
for (const [purpose, granted] of Object.entries(purposes)) {
await db.consent.upsert({
where: { userId_purpose: { userId: req.user.id, purpose } },
create: {
userId: req.user.id,
purpose,
granted: granted as boolean,
grantedAt: new Date(),
ipAddress: req.ip,
version: CURRENT_PRIVACY_POLICY_VERSION,
},
update: {
granted: granted as boolean,
grantedAt: new Date(),
ipAddress: req.ip,
version: CURRENT_PRIVACY_POLICY_VERSION,
},
});
}
res.json({ updated: true });
});
// Check consent before processing
async function hasConsent(userId: string, purpose: string): Promise<boolean> {
const consent = await db.consent.findUnique({
where: { userId_purpose: { userId, purpose } },
});
return consent?.granted === true;
}PII Field Handling
PII字段处理
typescript
// Mark PII fields in schema
const PII_FIELDS = {
user: ['email', 'name', 'phone', 'address', 'dateOfBirth'],
order: ['customerName', 'shippingAddress', 'email'],
} as const;
// Encrypt PII at rest
const encryptedFields = ['dateOfBirth', 'phone', 'address'];
// Pseudonymization for analytics
function pseudonymize(userId: string): string {
return createHmac('sha256', PSEUDONYM_KEY).update(userId).digest('hex');
}typescript
// Mark PII fields in schema
const PII_FIELDS = {
user: ['email', 'name', 'phone', 'address', 'dateOfBirth'],
order: ['customerName', 'shippingAddress', 'email'],
} as const;
// Encrypt PII at rest
const encryptedFields = ['dateOfBirth', 'phone', 'address'];
// Pseudonymization for analytics
function pseudonymize(userId: string): string {
return createHmac('sha256', PSEUDONYM_KEY).update(userId).digest('hex');
}Cookie Consent Banner
Cookie同意横幅
typescript
// Express middleware — block non-essential cookies without consent
function cookieConsentMiddleware(req: Request, res: Response, next: NextFunction) {
const consent = req.cookies['cookie-consent'];
if (!consent) {
// Only set essential cookies
req.analyticsEnabled = false;
req.marketingEnabled = false;
} else {
const prefs = JSON.parse(consent);
req.analyticsEnabled = prefs.analytics === true;
req.marketingEnabled = prefs.marketing === true;
}
next();
}typescript
// Express middleware — block non-essential cookies without consent
function cookieConsentMiddleware(req: Request, res: Response, next: NextFunction) {
const consent = req.cookies['cookie-consent'];
if (!consent) {
// Only set essential cookies
req.analyticsEnabled = false;
req.marketingEnabled = false;
} else {
const prefs = JSON.parse(consent);
req.analyticsEnabled = prefs.analytics === true;
req.marketingEnabled = prefs.marketing === true;
}
next();
}Anti-Patterns
反模式
| Anti-Pattern | Fix |
|---|---|
| Hard-deleting all data | Anonymize where referential integrity needed |
| No consent versioning | Track which policy version user consented to |
| PII in log files | Redact or pseudonymize PII before logging |
| Consent as one checkbox | Granular consent per purpose (marketing, analytics) |
| No data processing records | Maintain Article 30 records of processing activities |
| Ignoring third-party data sharing | Document and control all data processors |
| 反模式 | 修复方案 |
|---|---|
| 硬删除所有数据 | 在需要保持引用完整性的地方进行匿名化处理 |
| 无同意版本控制 | 记录用户同意的政策版本 |
| 日志文件中包含PII | 记录前编辑或伪匿名化PII |
| 单一复选框式同意 | 按用途(营销、分析)提供细粒度同意选项 |
| 无数据处理记录 | 维护第30条要求的处理活动记录 |
| 忽略第三方数据共享 | 记录并管控所有数据处理方 |
Production Checklist
生产环境检查清单
- Data subject access request endpoint
- Data deletion/anonymization endpoint
- Consent management with purpose granularity
- Consent versioning (tracks policy version)
- PII inventory documented
- Data retention policies implemented
- Cookie consent banner (EU users)
- Data Processing Agreement with third parties
- Article 30 records of processing activities
- 数据主体访问请求端点
- 数据删除/匿名化端点
- 按用途细分的同意管理
- 同意版本控制(跟踪政策版本)
- 已记录PII清单
- 已实施数据保留政策
- Cookie同意横幅(针对欧盟用户)
- 与第三方签订的数据处理协议
- 第30条要求的处理活动记录