用户说“把我的数据删干净”:vibe 项目的 DSR 请求响应实战(GDPR/个保法)
当用户说“把我的数据删干净”,一人团队必须在法定期限内闭环。本篇实战指南覆盖六种权利的 DSR 类型矩阵、身份验证流程、数据资产地图模板、删除与匿名化决策、级联删除清单、机器可读导出包,以及五节点 30 天响应 SOP 与话术模板。

开场:当用户说"删干净",你不是在做客服,是在跑合规
先声明一句:本指南是独立开发者的实务经验分享,不是法律意见。涉及具体合规义务,请以你业务所在地的现行法规和律师意见为准。
任何一个 vibe 项目跑到有真实用户、有真实付费那天,都会收到这样一封邮件:"请删除我的账号和所有数据。"发件人语气客气,但这封邮件不是客服工单——它是数据主体权利请求(Data Subject Request,简称 DSR)。在 GDPR 语境下,用户依法行使的是第 15 条的访问权、第 17 条的删除权(被遗忘权)、第 20 条的数据可携带权;在《个人信息保护法》语境下,个人同样享有查阅、复制、删除等权利。本篇不展开中欧法规对比,只解决一个问题:请求来了,30 天(GDPR 口径为"无不当迟延,最迟一个月")内,你这个一人团队要按什么顺序、用什么交付物,把这件事闭环。
已发的《法律三件套》解决的是"纸面合规"(隐私政策、用户协议、Cookie 文案写什么),《数据备份》解决的是"灾难恢复"(数据丢了怎么恢复)。本篇是中间缺失的那一公里:用户依法要数据时,你的运营动作。纸面写得再漂亮,删除请求来了你 30 天没动静,等于没合规。
一、DSR 类型矩阵:六种权利,各自的期限与交付物
先把"用户到底在要什么"翻译成"你的交付物是什么"。下表覆盖最常见的六种请求类型,期限按 GDPR 口径(无不当迟延,最迟一个月;案情复杂可再延长两个月,但必须在一个月内先告知用户延期及理由):
| 权利 | 依据 | 用户典型说法 | 法定期限 | 你的交付物 |
|---|---|---|---|---|
| 访问权 | GDPR 第 15 条 | "你们存了我哪些数据?" | 最迟一个月 | 数据副本 + 处理说明(目的、类别、接收方、留存期) |
| 更正权 | GDPR 第 16 条 | "我的名字/邮箱写错了,改一下" | 无不当迟延 | 更新后的记录确认 |
| 删除权(被遗忘权) | GDPR 第 17 条 | "把我的数据删干净" | 无不当迟延 | 删除确认书 + 例外保留清单(如有) |
| 限制处理权 | GDPR 第 18 条 | "先别用我的数据,等你们查清楚" | 无不当迟延 | 处理冻结确认(数据留存但标记为不可用) |
| 数据可携带权 | GDPR 第 20 条 | "把我的数据导出来,我要带走" | 最迟一个月 | 结构化、通用、机器可读的导出包(JSON/CSV) |
| 反对权 | GDPR 第 21 条 | "别再给我做画像/营销了" | 无不当迟延 | 停止处理的确认(营销名单移除等) |
三条实战经验:第一,用户不会用法律术语,他们说"删干净""导出来""别烦我",你要自己映射到上表。第二,收到请求先分类再计时——期限从"你收到可识别的请求"那一刻起算,不是你"想清楚怎么做"才起算。第三,免费响应是原则,只有明显无根据或过度重复的请求才可以收费或拒绝,且举证责任在你。
关于中国《个人信息保护法》:个人同样享有查阅、复制、更正、补充、删除等权利,处理者应当及时响应。具体时限与程序以当地法规和监管口径为准,本篇的 SOP 骨架(验证—执行—复核—回复)同样适用。
二、第一关:身份验证——别把数据交到冒充者手里
DSR 流程里最容易被忽视、后果最严重的一步,是第一步。访问和导出请求交付的是用户全部数据,验证错了人,等于你亲手把用户数据送给了社工攻击者。验证强度必须和请求敏感度匹配:
| 请求类型 | 数据敏感度 | 最低验证强度 | 示例做法 |
|---|---|---|---|
| 反对营销 / 退订 | 低 | 弱:请求邮箱与账户邮箱一致 | 点击退订链接即可 |
| 更正非敏感字段 | 低-中 | 弱-中 | 登录态内操作,或邮箱验证码 |
| 访问 / 数据导出 | 高 | 强 | 登录态 + 邮箱/手机二次确认 |
| 删除整个账户 | 极高(不可逆) | 最强 | 登录态 + 二次确认 + 冷却说明(见下文) |
验证 SOP(四步)
- 确认请求渠道可信。优先接受"登录态内提交"(应用内设置页的"导出我的数据/删除账户"按钮)——这是最强的身份证据。邮件请求的,发件地址必须与账户注册邮箱一致。
- 二次确认敏感操作。导出和删除必须有第二步确认:登录态内的二次弹窗、或向注册邮箱发送带时效的确认链接(建议 24 小时过期)。不要接受"我换了邮箱,请把数据发到新邮箱"这类要求,除非走完完整的换绑验证。
- 记录验证过程。谁、在什么时间、用什么方式验证的,写进请求工单。这是你未来证明"已尽合理努力"的证据。
- 存疑时宁可多问一句。无法确认身份时,回复要求补充验证信息——这不算拖延,GDPR 允许在身份存疑时要求提供必要信息,且期限可以从信息补齐起算。
防社工冒领检查单
- 请求邮箱是免费邮箱且与注册邮箱不一致?→ 拒绝,要求登录态内操作。
- 对方"记不清密码"但要求直接导出?→ 先走找回密码流程,不在 DSR 流程里开后门。
- 语气紧急、施压"今天必须删"?→ 按正常时限走,紧急不是降低验证的理由。
- 要求把导出包发到第三方地址或网盘?→ 只交付到账户绑定的渠道。
三、数据资产地图:先画清"用户数据到底散在哪里"
90% 的 DSR 翻车,根因都是同一句:"我以为删完了。"你的数据库删了,但日志里还有、备份里还有、邮件服务商那里还有、分析工具那里还有。没有资产地图,删除就是玄学。下面这张盘点表,建议你第一次收到 DSR 之前就填好——它是你整个响应流程的地基:
用户数据资产盘点表(模板)
用户标识:user_id / 邮箱 / 手机号(列出你用作主键关联的全部键)
表名 → 含 PII 的字段 → 关联键 → 删除策略(硬删/匿名化/保留)
例:users → email, name, phone → id → 硬删;orders → 金额, 商品 → user_id → 匿名化保留统计;invoices → 发票抬头 → user_id → 法律义务保留应用日志 / 错误追踪(Sentry 类)/ 访问日志 → 是否含 user_id、邮箱、IP → 留存期 → 清理方式
支付(Stripe 类:customer 对象)/ 邮件(Resend 类:收件人列表、发送记录)/ 数据分析(PostHog/GA 类)/ 客服工单 / 对象存储(用户上传文件)→ 各自的数据删除入口与 API
数据库备份周期 → 备份保留期 → 删除请求在备份中的处理策略(见第五节)
Redis 缓存键 / 搜索索引(Algolia/ES 类)→ 是否含 PII → 失效/删除方式

填这张表时最容易漏的三个角落:一是日志,错误追踪里经常带着请求参数和用户邮箱;二是分析工具,事件属性里可能塞了 user_id;三是客服/邮件历史,用户跟你来往的每一封邮件都是他的个人数据。vibe 项目早期表不多,趁现在把这张表建起来,成本最低。
四、删除 vs 匿名化 vs 必须保留:三叉路口决策表
"删干净"不等于"把所有行都 DELETE 掉"。有些数据你删了是违法(税务发票),有些数据你留着是违规(早该删的日志)。决策逻辑是三层过滤:
| 情形 | 处理方式 | 理由与实操 |
|---|---|---|
| 账户资料、偏好设置、用户上传内容 | 硬删 | 纯粹为服务用户而存的数据,请求删除即无保留依据。从主库物理删除,并级联清理关联表。 |
| 订单统计、行为分析用的聚合数据 | 匿名化后保留 | 业务需要趋势,但不需要"是谁"。把 user_id 替换为不可逆的匿名标识,或聚合到无法识别个人的粒度。 |
| 发票、交易记录(税务/会计义务) | 必须保留 | 法律义务优先于删除权。保留最小必要字段,限制访问权限,并在删除确认书中明确告知用户"因税务合规保留 X 类数据至 Y 年"。 |
| 风控/反欺诈记录(设备指纹、封禁名单) | 评估后保留 | GDPR 第 17 条第 3 款列明了删除权的例外,包括"为确立、行使或抗辩法律主张"。保留需有成文的内部依据,并做访问隔离。 |
| 用户公开发布的内容(评论、作品) | 删除 + 通知下游 | 第 17 条第 2 款:已公开的个人数据,控制者应采取合理步骤通知其他处理者删除。实操中至少做到站内全删,并给转载/缓存留处理记录。 |
关于匿名化,多说一句狠的:把 user_id 换成哈希不叫匿名化,那叫假名化——只要你手里还留着映射表,它依然是个人数据,GDPR 照样管。真正的匿名化是不可逆的:删除映射、聚合粒度粗到无法回溯、或直接丢弃明细只留统计。一人团队最稳妥的做法是:能硬删就硬删,统计需求用"删除时同步生成聚合快照"来解决,而不是事后去"洗"数据。
五、级联删除实现:从数据库到备份的完整清单
这是本篇最实战的一节。按下面这张清单逐项打勾,缺一项,"删干净"就是一句空话:
- 外键级联策略先定好。建表时就决定:用户主表删除时,关联表是
ON DELETE CASCADE(如会话、偏好)还是先匿名化再保留(如订单)。最危险的是"没设外键、靠应用层删"——漏一条关联就是一次合规事故。 - 软删除必须能转硬删。很多 vibe 项目用
deleted_at软删除做"可恢复"。DSR 删除请求下来,软删除只是第一步:确认无恢复需求后(建议冷却期 7–14 天并明确告知用户),必须执行物理删除,并把软删除期间的访问权限锁死。 - 备份里的"已删除"数据要有说法。备份不可能为一个人重写。业界通行做法是:备份按固定周期轮转(如 30 天),删除请求记录在案,过期备份自然淘汰;同时确保备份恢复流程不会把已删除数据恢复回生产库——恢复演练时要验证这一点。这是监管机构普遍接受的方案,但前提是你的备份保留期是"必要的最短期限"。
- 日志里的 PII 要定期洗。应用日志、错误追踪里的 user_id、邮箱、IP,设留存期(如 30–90 天)自动滚动清理。不要为了一次 DSR 去全文检索日志——靠留存策略让它自然过期,并在资产地图里写明。
- 第三方子处理器连带删除。这是清单里最容易被忘的一整块:支付服务商的 customer 对象、邮件服务商的联系人列表与发送记录、分析工具的用户画像、客服系统的工单、对象存储里的用户文件。每个子处理器都要有对应的删除入口(API 或后台操作),执行后保留操作记录截图/日志。
- 缓存与搜索索引同步清。Redis 里以 user_id 为键的缓存、搜索索引里的用户文档,删除后要主动失效或重建索引。否则用户会看到"删了账号还能搜到自己"的灵异事件。
- 防"删除后又被写回来"。删除用户的 webhook 处理器、定时任务、数据同步脚本里,必须加"已删除用户跳过"守卫。真实翻车案例:删完账户,第二天 Stripe 的 webhook 把 customer 更新又写回了数据库。删除脚本跑完后,用原 user_id 全库
SELECT一遍做最终验证。

六、导出包格式:机器可读不是口号,是结构
GDPR 第 20 条对可携带权的要求是"结构化的、通用的、机器可读的格式"。翻译成一人开发者的实现清单:
- 格式选 JSON 为主、CSV 为辅。JSON 给嵌套结构(订单含明细、设置含多层偏好),CSV 给扁平表格(交易流水)。不要只给 PDF 截图——那不叫机器可读。
- 结构示例(JSON 顶层约定):
{
"export_version": "1.0",
"exported_at": "2026-10-11T09:00:00Z",
"user": { "id": "usr_123", "email": "user@example.com", "created_at": "..." },
"profile": { "name": "...", "preferences": { "...": "..." } },
"orders": [ { "id": "...", "amount": 0, "items": [ "..." ], "created_at": "..." } ],
"uploads": [ { "file_id": "...", "download_url": "...", "expires_at": "..." } ],
"notes": "因税务合规保留的发票数据未包含在本次导出中,详见随附说明。"
}
- 字段要自解释。键名用英文全称,避免只有你自己懂的缩写;时间统一用 ISO 8601 带时区;金额带币种。
- 交付方式:有时效的下载链接。导出包放对象存储,生成签名 URL,建议过期时间 7 天,到期自动失效。不要用邮件附件直接发大文件,也不要给永久链接。
- 大包分片。用户上传了几个 G 的文件?导出包里放"文件清单 + 分片下载链接",而不是试图打成一个 zip。
- 随附说明文件。包里放一份
README:导出范围、字段说明、未包含的数据及原因(如税务保留)、联系方式。用户看不懂的导出包,等于没交付。
七、30 天响应时间线:五节点 SOP 与话术模板
一人团队没有法务部,但必须有时间线。把下面五个节点做成你的 DSR 工单模板(Notion / Linear / 甚至一个 markdown 文件都行),每个请求建一单:
| 节点 | 负责人 | 时限(自收到起) | 产出 |
|---|---|---|---|
| 1. 受理与分类 | 你(创始人即客服) | 24 小时内 | 工单建立:请求类型、渠道、收到时间戳 |
| 2. 身份验证 | 你 | 3 天内完成 | 验证方式记录;存疑则发出补充信息请求 |
| 3. 执行 | 你 + 脚本 | 验证通过后 14 天内 | 导出包 / 删除执行记录 / 第三方处理回执 |
| 4. 复核 | 你(换视角) | 执行后 3 天内 | 按资产地图逐项核对:全库 SELECT 验证、第三方确认 |
| 5. 回复用户 | 你 | 总计 30 天内 | 正式回复:做了什么、没删什么及原因、申诉渠道 |
时限设计留了缓冲:执行和复核压缩在 20 天内完成,剩下 10 天应对"第三方子处理器响应慢""案情复杂需延期"等意外。需要延期时,必须在第一个月内先告知用户延期原因和预计时间——沉默是最差的合规策略。
话术模板一:受理确认(24 小时内发出)
"已收到您关于[删除/导出]个人数据的请求(工单号 #___)。我们将在验证您的身份后处理,整个流程通常在 30 天内完成。如需补充身份验证信息,我们会另行联系。"话术模板二:删除完成确认
"您的删除请求已执行完毕:账户资料、偏好设置、上传内容已从生产系统删除;备份中的数据将随 30 天轮转周期自然淘汰;以下数据因[税务合规]依法保留至 [日期]:[清单]。如有疑问请回复本邮件。"话术模板三:需要延期
"因您的请求涉及 [第三方数据调取/数据量较大],我们需要延长处理时间,预计在 [日期] 前完成。给您带来的不便敬请谅解。"
八、常见坑位:这八个地方最容易翻车
- 备份里的"已删除"数据。生产库删得干干净净,备份里躺着全量快照。对策:固定轮转周期 + 删除登记 + 恢复演练验证"不回写"(见第五节第 3 条)。
- 日志里的 PII。错误追踪带着用户邮箱,访问日志带着 IP。对策:日志留存期自动滚动,不为单次 DSR 全文检索。
- 子处理器的连带义务。你删了,Stripe/Resend/分析工具那边还留着。对策:资产地图里每个第三方都写明删除入口,执行后留操作记录。
- 删除后又被 webhook 写回来。支付/同步回调把已删用户复活。对策:所有写入路径加"已删除用户跳过"守卫,删完后全库 SELECT 验证。
- 软删除当硬删交差。
deleted_at打了标记就以为完事,数据还在库里可查。对策:冷却期后必须物理删除,期间锁死访问。 - 导出包缺胳膊少腿。只导了主表,关联表、上传文件、设置项全漏。对策:导出脚本按资产地图全表遍历,交付前抽样核对。
- 验证走过场。来封邮件就导出全部数据。对策:第二节的强度矩阵是底线,不是可选项。
- 超期沉默。30 天没回复,用户转头就去监管机构投诉。对策:工单模板 + 日历提醒;搞不定时先发延期通知,永远不要让用户猜进度。
收尾:把 DSR 做成一条脚本,而不是一次救火
这篇指南的八节可以压缩成一句话:资产地图是地基,验证是门锁,级联清单是施工图,时间线是deadline。一人团队做 DSR 的终极形态,是把它变成半自动化:应用内自助导出按钮(覆盖 80% 的访问/可携带请求)、删除账户流程(覆盖 70% 的删除请求)、只剩疑难 case 走人工工单。你今天花一下午填好资产地图、写好删除脚本,未来每一次"删干净"都是一次例行操作,而不是一次凌晨救火。
最后再重申一次:本文是实务经验分享,不是法律意见。GDPR 与《个人信息保护法》的具体义务以法规原文和属地监管口径为准,复杂情形请咨询律师。
评论 (0)
相关文章

第二个客户是 vibe 项目的成人礼:单租户代码里藏着全局单用户、硬编码配置、无租户边界三个隐性假设,一碰就塌。本文给出三种隔离模型的六维决策表(共享表/Schema-per-tenant/DB-per-tenant),手把手落地 Postgres RLS(三件套:Next.js 中间件解析租户、CREATE POLICY 行级策略、Prisma 扩展自动过滤),对比子域名/路径前缀/自定义域名三种路由,附 10 项跨租户泄露负向测试清单、5 步不停机迁移 SOP(含每步回滚点),以及按租户计量用量的最小实现。

vibe coding 的迭代速度是 API 契约的十倍快,这正是一个人做项目最容易翻车的地方。本文补上 API 治理缺失的那块拼图:vibe 项目 API 的 3 种真实死法、版本策略 5 维度决策表(URL 路径版 vs 请求头版本 vs 无版本)、12 条破坏性变更判定清单(可直接贴墙上)、废弃 SOP 四步(Deprecation/Sunset 响应头、双语废弃公告模板、双跑观察看板、下线执行检查表)、可直接复制的一页纸迁移指南模板,以及一人版本治理的最小配置:CHANGELOG 驱动 + CI 用 openapi-diff 自动卡住 breaking change。

敢收费不敢退费的心态是错的:清晰的退款政策是最便宜的信任广告,处理得当的退款用户有 30% 会回来,而一次处理失当的 Chargeback 可能吃掉一整月利润。本指南覆盖三档退款政策设计与话术模板、Stripe 手动与 API 退款实战、charge.refunded 的 webhook 自动化闭环、挽留还是秒退决策树、争议证据包 6 类材料、Stripe Radar 防欺诈规则,以及 Paddle/Lemon Squeezy 代扣代缴的跨境税务细节。