资讯动态

OpenSEO 托管版 GDPR 用户数据擦除实战:`gdpr:erase-user` 全流程运行手册

发布时间:2026/9/13 15:35:34 来源:尧图企业网站定制
OpenSEO 托管版 GDPR 用户数据擦除实战gdpr:erase-user全流程运行手册【免费下载链接】open-seoOpen source alternative to Semrush and Ahrefs项目地址: https://gitcode.com/GitHub_Trending/op/open-seo本文以 OpenSEO 仓库的 runbooks/gdpr-erasure.md 为核心系统讲解托管hosted部署下如何通过pnpm gdpr:erase-user命令对一个用户的全部 OpenSEO 数据进行盘点与擦除从一次性部署配置、操作者环境变量、dry-run 安全确认到执行阶段的第三方服务清理、Cloudflare 侧存储清理与 Postgres 事务删除再到保留期与合规注意事项。读完本文你将掌握一条可重复、可回执、可安全重试的用户数据擦除操作链路并能对照源码理解其底层实现。一、命令定位一次盘点、多处擦除、默认安全pnpm gdpr:erase-user由 package.json 中的脚本gdpr:erase-user: tsx scripts/erase-user-data.ts注册实际实现位于 scripts/erase-user-data.ts。它面向Postgres 托管部署覆盖的数据面包括应用数据库Postgres 中该用户及其所属组织的全部业务数据Cloudflare 侧状态站点审计 / 排名追踪 Workflow 实例、chat/scratchpad Durable Objects、R2 审计负载、KV 进度记录、MCP OAuth grants/tokensGoogle 授权GSC、GA4 OAuth 连接第三方服务Loops 联系人、PostHog 人员及事件、Autumn 客户及其通过 Autumn 关联的 Stripe 客户。命令默认执行dry run只盘点不删除且拒绝任何“当前成员数大于 1”的组织——因为删除这类工作区会连带抹掉其他成员的数据。遇到此类组织时命令直接报错退出需要人工先解决归属与共享数据保留问题后再重试。二、一次性部署配置2.1 生成并分发 GDPR_ERASURE_SECRET生成一个足够长的随机密钥并在生产 Worker与操作者运行环境中配置为同一个GDPR_ERASURE_SECRETopenssl rand -hex 32该密钥用于启用一个单个HMAC 鉴权的内部端点/api/internal/gdpr-erasure/storage。密钥未设置时端点返回404从而默认隐藏该接口。把GDPR_ERASURE_SECRET加入.env.production后先部署 Worker 再执行擦除命令。密钥要避免进入 shell 历史与日志。2.2 确认 R2 生命周期规则生产 R2 bucket 必须配置dataforseo-cache/前缀的过期lifecycle规则生产生命周期规则由 Cloudflare 控制台管理。后续“保留说明”中的若干保留声明都依赖这条规则兜底。三、操作者环境变量将以下值放入安全、不纳入版本控制的环境文件或密钥管理器中POSTGRES_DATABASE_URLpostgres://... BETTER_AUTH_URLhttps://app.openseo.so GDPR_ERASURE_SECRET... LOOPS_API_KEY... AUTUMN_SECRET_KEY... POSTHOG_API_HOSThttps://us.posthog.com POSTHOG_PROJECT_ID... POSTHOG_PERSONAL_API_KEY...脚本还会从当前工作目录读取.env.local/.env见 scripts/cli-utils.ts 中的loadLocalEnv()所以要在 env 文件内容正确的目录下运行。需要注意PostHog personal key 需要person 的读取与写入权限若项目位于 EU 区域POSTHOG_API_HOST换成 EU 的 API host脚本会去掉末尾/见deletePostHogPerson。AUTUMN_SECRET_KEY的前缀会被用于判断环境见下文 4.4。四、运行步骤先盘点再确认后执行4.1 第一步dry-run 盘点先用邮箱精确盘点目标用户与受影响的各类行 / 资源数量pnpm gdpr:erase-user --email personexample.comdry run 输出一份 JSON 摘要包含mode: dry-run与databaseHost后续执行时必须逐一匹配userid / email / nameorganizations与databaseCountssessions、accounts、onboarding_answers、projects、saved_keywords、audits、rank_snapshots、sam_sessions、attributed_audits、gsc_connections、ga4_connections、api_keys 等cloudflare计数samChats、auditScratchpads、r2Objects、activeAuditWorkflows、activeRankWorkflowsexternalgoogleAccounts、postHogDistinctId、autumnCustomersAndStripeCustomers、autumnEnvironment。4.2 确认关键信号autumnEnvironment 必须为 livedry run 必须打印autumnEnvironment: live。源码autumnEnvironment()scripts/erase-user-data.ts按密钥前缀判断am_sk_live_→liveam_sk_test_→sandbox其他 →unset-or-unknown。如果误用 sandbox 的 Autumn key 对着生产数据执行所有删除请求都会 404真实 Stripe 订阅会继续运行——所以这一步是执行前的硬性检查项。4.3 第二步正式执行用 dry run 打印出的精确归一化邮箱和数据库 host执行pnpm gdpr:erase-user --email personexample.com \ --execute --confirm personexample.com \ --confirm-database-host us-east-3.pg.psdb.cloud参数语义对应 scripts/cli-utils.ts 的parseArgs支持--key value或--keyvalue参数作用--email email选择器按邮箱定位用户脚本会toLowerCase()归一化数据库侧用lower(email)匹配--user-id id可替代--email作为选择器但--confirm仍必须填写盘点输出中的邮箱--execute从 dry run 切换为真正执行--confirm email必须与所选用户邮箱精确一致大小写不敏感比较否则报错--confirm-database-host host必须与 dry run 打印的databaseHost精确一致防止连错库两个选择器只能二选一同时传或都不传都会触发printUsage()报错。4.4 执行顺序为安全重试而设计擦除按三步顺序执行main()中依次调用外部服务先清删除 Loops 联系人、请求 PostHog 人员 / 事件删除、删除 Autumn 客户及其关联的 Stripe 客户deleteAutumnCustomer对每个组织调用autumn.customers.delete({ customerId: organizationId, deleteInStripe: true })404 视为“已不存在”的 no-op。调用 Worker 端点终止运行中的 site-audit 与 rank-check Workflow 实例、撤销 Google 授权、擦除 chat/scratchpad Durable Objects、R2 审计负载、KV 进度记录、MCP OAuth grants/tokens。Postgres 单事务收尾在一个事务内删除组织与用户依赖外键级联清理项目数据随后回读校验根行确实消失。任一步失败修复报错的凭证或服务错误后重跑同一条命令即可。第三方厂商已无对应记录、Workflow 已处于终态均被当作成功的 no-op 处理不会导致整条链路失败。五、Worker 端存储擦除的源码级剖析5.1 端点鉴权HMAC-SHA-256 时间戳防重放端点路由挂在 src/server.tspathname GDPR_STORAGE_ERASURE_PATH时直接交给handleGdprStorageErasure。请求鉴权流程src/server/gdpr/storage-erasure.ts携带x-gdpr-timestamp与x-gdpr-signature两个 header时间戳与服务器当前时间差超过MAX_CLOCK_SKEW_MS 5 * 60 * 10005 分钟直接拒绝签名用共享密钥对${timestamp}.${body}计算 HMAC-SHA-256src/shared/gdpr-erasure.ts并用timingSafeEqual常数时间比较防时序攻击对应签名算法的单元测试见 src/shared/gdpr-erasure.test.ts它用 NodecreateHmac独立复算验证输出。请求体还有一组硬性防护要求content-length头否则 411、体积上限MAX_BODY_BYTES 5MB超出 413、HMAC 校验失败 401、JSON 解析失败 400、payload 结构校验使用 zod schemagdprStorageErasurePayloadSchemasrc/shared/gdpr-erasure.ts每类 id 数组最多MAX_ITEMS_PER_KIND 10_000条、每条 1512 字符googleAccounts只接受 GSC / GA4 两个 OAuth provider。5.2 具体擦除动作eraseStorageeraseStoragesrc/server/gdpr/storage-erasure.ts按“先停活、再删数据”的顺序执行终止 Workflow对activeAuditWorkflowIds与activeRankWorkflowIds逐个workflow.get(id)未知 id 会抛错说明没有需要停止的东西再instance.terminate()已处于终态的实例 terminate 抛错也被吞掉计为已结束。撤销 Google 授权对每个 GSC/GA4 账号通过 Better Auth 取 access token 后调用https://oauth2.googleapis.com/revoketoken 不可用返回token_unavailableGoogle 返回 400invalid_token说明早已撤销也视为成功只有其他非 2xx 才抛错。即使 token 取不到后续 Postgres 事务仍会删除本地加密 token 行。擦除 Durable ObjectsSAM chat 会话调用destroyForErasure()全量销毁审计 scratchpad 调用env.AUDIT_ENGINE.destroyScratchpad(auditId)跨 worker RPC并删除audit-progress:${auditId}的 KV 键。KV 清理删除 Dub 推荐标记dub:referred:user:${userId}与每个组织的dub:referred:org:${organizationId}OAuth KV 中按grant:${userId}:前缀翻页列出并删除 grant同时按token:${userId}:${grantId}:前缀删除其 token。R2 清理按 payload 的r2Keys每 1000 个一批批量删除随后扫描 prompt 缓存前缀PROMPT_CACHE_PREFIX通过对象customMetadata.organizationId匹配目标组织并批量删除。刻意保留autumn:customer-ensuredKV 标记不删——它不携带个人数据org id 为键、值为 124 小时 TTL 自动过期且提前清除反而会让进行中的已鉴权请求在 Postgres 删除落地前重新创建 Autumn 客户。六、Postgres 侧单事务删除与共享数据兜底erasePostgresscripts/erase-user-data.ts在单个事务内完成删除无用户外键的记录按邮箱删除invitation按 identifier/value 匹配用户 id 删除verification重置密码、删除账号令牌等删除gscConnections、ga4ConnectionsconnectedByUserId与apikeyreferenceId它们没有 user FK不会随用户行级联。匿名化审计归属将audits.startedByUserId更新为gdpr-deleted-user保留审计记录本身同时移除可归因到具体用户的信息。重新断言单成员守卫删除组织时用notExists子查询确认该组织没有“非当前用户”的其他成员只要盘点之后有人接受了邀请deletedOrganizations.length就会与预期不符事务整体中止并提示重跑。删除用户根行delete(schema.user)并returning校验恰好删除 1 行。事务提交后verifyPostgres独立回读校验user与organization行数为 0作为擦除回执的一部分。七、保留说明与合规注意回执保存命令输出的 completion JSON 就是擦除回执应存入请求案件request case但不要再写回产品分析PostHog——异常上报特意匿名化见 src/server/gdpr/storage-erasure.ts源码注释明确按 distinct id 打点会重建该 person 画像。异步部分PostHog 事件删除在 person 删除请求之后异步进行已完成的 Workflow 状态与 Workers 日志按 Cloudflare 账号配置的保留期自然过期。必须保留的部分数据库备份与税务、反欺诈、法律义务所需的账单记录应与生产访问隔离按文档化的保留周期自然到期。Prompt 缓存本擦除工具部署后写入的 prompt-response 缓存对象带组织标签会被命令删除更早的无标签缓存对象无法从哈希键归因到某个用户在账号删除后自然不可达最终依赖 bucket 的dataforseo-cache/生命周期规则过期见 2.2。审计 scratchpad创建超过 30 天的审计其 scratchpad Durable Objects 与 progress KV 键早已通过 finalize 路径、7 天 alarm 或 30 分钟 TTL 自毁命令会跳过这些审计对应auditCutoff now - 30 天的 ISO 字符串字典序比较逻辑源码注释说明 30 天对 7 天 alarm 有 4 倍余量并控制单次 Worker 调用在 KV 操作配额内。八、端到端链路一览阶段载体关键实现命令入口pnpm gdpr:erase-userpackage.json → scripts/erase-user-data.ts盘点与守卫Postgres 查询 单成员组织检查buildInventory、findUser外部服务清理Loops / PostHog / Autumn APIdeleteLoopsContact、deletePostHogPerson、deleteAutumnCustomerWorker 存储擦除HMAC 鉴权端点src/server/gdpr/storage-erasure.ts、路由挂载于 src/server.tsPayload 与签名zod schema HMAC-SHA-256src/shared/gdpr-erasure.ts、测试 src/shared/gdpr-erasure.test.tsPostgres 删除与校验单事务 提交后回读erasePostgres、verifyPostgres这条链路从“盘点 → 确认 → 外部服务 → Cloudflare 侧 → Postgres → 回读校验”逐层推进配合 dry-run 默认、双重 confirm、环境前缀识别与事务级守卫为 GDPR 用户擦除提供了可审计、可重试、可留痕的完整工程化方案。操作前请务必确认 Worker 已用同一GDPR_ERASURE_SECRET部署、R2 生命周期规则已就位并妥善保管完成 JSON 作为擦除回执。【免费下载链接】open-seoOpen source alternative to Semrush and Ahrefs项目地址: https://gitcode.com/GitHub_Trending/op/open-seo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价