Files
Jyotisha/docs/tasks/PROGRESS-account-deletion-20260930.md
T
Jesse_ChenandClaude Opus 5.5 96adbce3a9 feat(account): self-service deletion with a 7-day cooling-off period
Request signs out everywhere and freezes paid routes (423 + DB triggers);
signing in within 7 days shows the pending gate with 撤销注销. A periodic
idempotent worker purges personal content afterwards and keeps finance
rows against a tombstoned identity. Read-only admin list.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
2026-09-30 09:42:11 +08:00

4.4 KiB
Raw Blame History

PROGRESS — 自助注销账号 + 7 天冷静期(2026-09-30)

分支 codex/account-deletion-20260930,基线 codex/compliance-base-20260930(2cd37720,含 lib/legal-entity.ts 占位主体)。产品决定:注销 = 7 天冷静期后删除;联系方式先用占位。

做了什么

部分 位置
迁移(只加) frontend/supabase/migrations/20260930020000_account_deletion_requests.sql:表 account_deletion_requests、函数 request_account_deletion / cancel_account_deletion / account_deletion_scheduled_for / purge_deleted_account / mark_account_deletion_attempt_failed、扣点拦截触发器
API GET/POST/DELETE /api/account/deletion(POST 同源校验 + 必须 confirm:"注销";管理员账号 403)
冻结 咨询、报告、校正 agent、打开校正、合盘五条付费路由认证后先查,注销中返回 423 account_deletion_pending;数据库层 usage_reservations、birth_time_rectification_billing、credit_transactions(amount < 0)BEFORE INSERT 触发器同码拒绝
前端 通用设置底部「注销账号」区;(app) 布局的「账号注销中」全屏门(撤销注销 / 退出登录)
后台 /admin/account-deletions 只读列表(admin.customers.read,不显示邮箱)
清除任务 lib/account-deletion-worker.ts,由 instrumentation.ts 启动

删除 vs 去标识

  • 删除:public 下所有以 user_id 指向 auth.users 的表(外键自动发现 + 带 uuid user_id 列的表),以及 profiles(按 id)。包括对话、星盘档案、个人报告及其任务/分节、校正 case、合盘、记忆等。created_by / updated_by 这类运营配置列不算用户内容,不删。
  • 保留并去标识(account_deletion_kept_tables(),前后端同一份名单,测试比对):payment_orders、credit_transactions、usage_ledger、usage_reservations、user_subscriptions、user_product_redemptions、redemption_attempts、redemption_codes、credit_request_cancellations、birth_time_rectification_billing、consultation_requests、pricing_experiment_events、account_deletion_requests、admin_* 三张。
  • 身份墓碑:identity.users / auth.users 行保留(财务表外键是 cascade,删身份会连带删账),邮箱改为 deleted+<id>@deleted.invalid,姓名「已注销用户」,封禁;sessions、accounts、two_factors、verifications 删除。
  • 全部在一个事务里:删不干净(多轮重试外键顺序后仍有剩余)就整体回滚,记 purge_incomplete,下次再试。

清除任务怎么跑

进程启动 60 秒后第一次,之后每 30 分钟一次(unref 定时器,globalThis 防重)。每次取最多 20 条到期、attempt_count < 5 的 pending 申请,逐条调 purge_deleted_account;函数对未到期 / 已撤销 / 已完成返回 skipped,可重复执行。失败记错误码与次数,满 5 次停止重试,后台列表可见。日志只写计数,不写 id 或邮箱。

验证

项 结果
tsc --noEmit 0 错
npm run lint 0 error / 126 warning(与基线同)
新单测 tests/account-deletion.test.tsx 8/8
新 DB 测 tests/database-account-deletion.test.ts 本机无 Docker,skipped
全量 npm test 4427 项,fail 25 = 基线 24 条环境失败(同名)+ 1 条合同测试;改后该条通过
next build 通过,/ ○ Static
首屏 gzip 648,688 B(基线约 646,480,+0.34%)

改动的既有断言(frontend/tests/settings-mvp-contract.test.ts):

原值 新值 原因
renderGeneral() { return <ThemePreferencePanel />; return <><ThemePreferencePanel /><AccountDeletionSection /></>; 注销入口放通用设置底部,头像菜单不加入口

未验证 / 待办

  • DB 测试(请求→会话清空→扣点被拒→撤销→到期清除→内容删、流水留、身份墓碑→重复执行无副作用)需 Docker 跑 npm run test:db。
  • 迁移只在 staging 部署时首次真实应用;清除任务真实执行需等 7 天或在 staging 库手工把 scheduled_for 调早。
  • 无受控 staging 账号,端到端(注销→退出→重登见门→撤销)未走。
  • 与 fork C(反馈表)若新增带 user_id 的表,会被自动归入删除;如需保留投诉记录,需加入保留名单。