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
4.4 KiB
4.4 KiB
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的表(外键自动发现 + 带 uuiduser_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的表,会被自动归入删除;如需保留投诉记录,需加入保留名单。