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

51 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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` 的表,会被自动归入删除;如需保留投诉记录,需加入保留名单。