GDPR コンプライアンス
ルール
- データ削除エンドポイント(忘れられる権利)を実装する:すべてのユーザー PII をリクエストに応じて削除または匿名化する
- 明示的な同意をタイムスタンプ付きで追跡する:ユーザーが何に同意したか、いつ、どのバージョンのポリシーに同意したか
- 分析とログ内の PII を匿名化する — 不透明な ID を使用し、生のメールアドレスや名前は使用しない
- データエクスポートエンドポイント(データポータビリティの権利)を実装する:すべてのユーザーデータを JSON または CSV として返す
- Cookie 同意バナーを表示する:ユーザーがオプトインするまでトラッキングスクリプトを読み込まない
- データ収集フォームのあるすべてのページからプライバシーポリシーにリンクする
- PII アクセスの監査ログを維持する — 誰がどの個人データをいつ閲覧したか
- 72時間以内の侵害通知:文書化されたプロセスと連絡先リストを準備しておく
app.delete("/api/user/data", requireAuth, async (req, res) => {
const userId = req.user.id;
await db.transaction(async (tx) => {
await tx.delete(userProfiles).where(eq(userProfiles.userId, userId));
await tx.delete(userSessions).where(eq(userSessions.userId, userId));
await tx.update(users).set({
email: `deleted_${userId}@anonymized.local`,
name: "Deleted User",
deletedAt: new Date(),
}).where(eq(users.id, userId));
});
await auditLog("user_data_deleted", { userId, requestedBy: userId });
res.json({ success: true });
});
const consentSchema = z.object({
marketing: z.boolean(),
analytics: z.boolean(),
policyVersion: z.string(),
});
app.post("/api/consent", requireAuth, async (req, res) => {
const consent = consentSchema.parse(req.body);
await db.insert(consentRecords).values({
userId: req.user.id,
...consent,
consentedAt: new Date(),
ipAddress: req.ip,
});
res.json({ success: true });
});
回避すべきこと
- PII を実際に削除せずにユーザーデータをソフトデリートする — 「削除済み」ユーザーのメールアドレスがデータベースに残っている
- Cookie 同意前に Google アナリティクスやトラッキングピクセルを読み込む
- 分析イベントやアプリケーションログに生のメールアドレスを保存する
- データエクスポートメカニズムがない — ユーザーは自分のデータに対する法的権利がある
- GDPR は EU 拠点の企業のみに適用されると仮定する — EU ユーザーにサービスを提供するすべてのアプリに適用される