25 KiB
账号注销后端接口需求
2026-08-28 已被新范围替代: 本次迭代改为使用旧
account-deregister接口,仅注销当前store_user身份,不实施本文的主账号注销、新接口或恢复专用 Token 方案。当前接入情况见 门店身份注销接入说明。下文保留为历史讨论记录。
更新日期:2026-08-27 适用端:随心瞰商家版 iOS;后端账号状态应同时约束 Android、旧版本客户端及其他登录入口。 文档性质:接口需求建议稿,以下新增路径和字段尚未与后端确认,不代表线上已有接口。
1. 需要后端提供什么
需要 5 个注销接口、现有登录与鉴权流程改造,以及服务端到期处理任务。
| 类型 | 建议接口 / 能力 | 用途 |
|---|---|---|
| 新增 | GET /api/app/account-deletion/precheck |
返回真实资产、注销影响说明及阻断原因 |
| 新增 | POST /api/app/account-deletion/send-sms-code |
向主账号绑定手机号发送注销专用验证码 |
| 新增 | POST /api/app/account-deletion/submit |
校验验证码和用户确认,提交注销申请 |
| 新增 | GET /api/app/account-deletion/status |
查询当前账号的服务端注销状态及截止时间 |
| 新增 | POST /api/app/account-deletion/cancel |
冷静期内由用户明确确认后取消注销 |
| 修改 | POST /api/app/v9/login |
身份验证通过后区分正常登录、待注销恢复和不可恢复状态 |
| 修改 | POST /api/app/v9/set-user 与统一鉴权 |
禁止待注销或已注销账号取得、使用业务 Token |
| 服务端任务 | 到期注销、失败重试、会话失效 | 不依赖客户端在线或再次打开 App |
如果已有等价能力,可以复用后端现有路径,但需覆盖本文的数据和行为要求,不必重复建设。
当前客户端状态
- 已有设置入口、资产核验页、短信验证页、成功页、密码登录时的恢复确认和冷启动检查。
- 当前为
AccountDeletionMockService:资产是固定示例,验证码固定为123456,注销记录保存在本机UserDefaults。 - 目前不会发送真实短信,也不会注销后端账号或删除后端数据。
- 接入真实接口后,服务端状态为唯一依据;本机时间、手机号输入值及本地记录不能作为注销结果或操作权限的依据。
2. 账号范围与统一约定
2.1 注销对象
当前功能意图是注销手机号登录对应的主账号及其关联业务身份,不是仅退出当前登录,也不是只停用当前选中的景区或门店身份。
- 后端根据 Token 解析稳定的主账号 ID,并据此聚合所有关联景区、门店身份的数据。
- 请求不接受客户端指定待注销的
user_id、username、phone、scenic_id或store_id;短信收件人也由后端确定。 - 当前业务身份资料里的手机号可能与主账号绑定手机号不同,不能直接用业务身份手机号发送注销短信。
- “解除景区、门店账号”指解除该用户的关联身份;不应删除景区、门店实体,也不能误删其他用户、门店或客户共同拥有的数据。
- 若存在管理员、负责人或共享资产,需明确移交、保留或阻断策略,不能因为客户端勾选“放弃资产”就直接删除。
2.2 请求和响应
沿用当前 App 网络层约定:
Content-Type: application/json
Accept: application/json
token: <当前请求所需的凭证>
X-APP-VERSION: <客户端版本>
X-OS-TYPE: <客户端现有平台标识>
当前工程使用 token 请求头,不是 Authorization: Bearer ...。恢复专用凭证也建议放在同一请求头,由服务端识别凭证类型和权限。
{
"code": 100000,
"msg": "success",
"data": {}
}
- 成功业务码沿用
100000;新增失败码由后端统一分配,见第 6 节。 - JSON 字段使用
snake_case;布尔值使用true/false,空列表使用[]。 - ID 建议统一返回字符串,客户端不依赖数据库自增 ID 或 UUID 的内部格式。
- 时间统一使用带时区的 ISO 8601 字符串,例如
2026-08-27T08:00:00Z;客户端负责本地化显示。 - 时间相关响应返回
server_time;冷静期截止、验证码到期和取消资格全部由服务端判断。
2.3 状态及七天冷静期
建议在真实服务中区分“不可再取消”和“数据已处理完成”,避免定时任务尚未完成就展示为永久删除成功。
state |
含义 | 允许恢复 | 允许进入业务 |
|---|---|---|---|
none |
没有注销申请 | 不适用 | 是 |
pending |
在冷静期内,待用户取消或到期 | 是,且服务端当前时间必须早于截止时间 | 否 |
canceled |
最近一次申请已取消 | 不适用;可以重新申请 | 是,需重新取得有效业务 Token |
processing |
已到截止时间,正在执行最终处理 | 否 | 否 |
completed |
服务端已完成约定的注销处理 | 否 | 否 |
流转:none/canceled → pending → processing → completed;仅 pending 且未到期时允许转为 canceled。
- 建议默认冷静期为提交成功后
7 × 24小时,后端返回准确的scheduled_deletion_at,客户端不自行推算。 - 恰好到达截止时刻即不可取消;即使定时任务尚未运行,接口也必须立即按不可恢复处理。
- 任务失败保持不可恢复状态,记录原因并重试,不能重新开放登录或重置冷静期。
- 当前 Mock 没有
processing状态;接入真实后端时客户端需同步扩展。
3. 五个接口的详细需求
3.1 注销前置核验
GET /api/app/account-deletion/precheck
使用有效业务 Token,无查询参数。返回整个主账号范围内的资产快照、当前绑定手机号的脱敏值、注销后果,以及是否允许提交。
成功响应示例(资产数值仅为示例):
{
"code": 100000,
"msg": "success",
"data": {
"precheck_id": "precheck_example_001",
"expires_at": "2026-08-27T08:10:00Z",
"server_time": "2026-08-27T08:00:00Z",
"masked_phone": "138****0000",
"can_submit": true,
"blocking_reasons": [],
"assets": [
{"kind": "wallet", "title": "钱包余额", "value": "0.00", "unit": "CNY", "value_text": "¥0.00"},
{"kind": "works", "title": "作品与相册", "value": "36", "unit": "item", "value_text": "36个"},
{"kind": "projects", "title": "项目", "value": "4", "unit": "item", "value_text": "4个"},
{"kind": "cloud_files", "title": "云盘文件", "value": "8589934592", "unit": "byte", "value_text": "8 GB"}
],
"consequences": [
"本人关联的景区与门店身份将解除",
"个人作品和云盘文件将按已确认的规则处理",
"提交后7天内再次登录并确认恢复,可取消注销"
],
"acknowledgement_version": "account-deletion-v1"
}
}
| 字段 | 要求 |
|---|---|
precheck_id / expires_at |
后端生成的核验快照标识及有效期,绑定当前主账号,用于确认用户看到的资产和后果 |
masked_phone |
主账号实际绑定手机号的脱敏值;不返回短信验证码 |
can_submit |
是否满足注销条件;客户端据此禁止或允许继续 |
blocking_reasons |
不可提交时返回 [{"reason_code":"WALLET_NOT_SETTLED","message":"请先处理钱包余额或结算中的款项"}],可有多项 |
assets |
当前页面需要 wallet、works、projects、cloud_files 四类;零资产也返回对应项 |
value / unit / value_text |
原始值统一为字符串;金额为元且保留两位小数,计数、字节为整数字符串;value_text 供页面直接展示 |
consequences |
由后端按最终业务规则返回,不能宣称会删除实际需要保留的数据 |
acknowledgement_version |
本次注销说明版本,随提交保存确认记录 |
要求:
- 核验不得触发删除、资金扣除、身份解绑或短信发送。
- 作品、相册、项目及云盘文件的统计口径和去重方式由后端明确,不能把共享资产全部算成该用户可删除的资产。
- 余额、冻结款、提现中、未完成订单、未补缴收款等是否阻断,由产品和后端确认。在规则确认前,建议未结清资金类问题阻断注销,不直接照搬 Mock 的“放弃余额”。
- 提交时必须再次校验条件。资产或影响范围发生需要重新确认的变化时,返回“请重新核验”,不得默默沿用旧快照。
3.2 发送注销短信验证码
POST /api/app/account-deletion/send-sms-code
使用有效业务 Token,请求体为 {}。只发送给当前主账号绑定手机号,不接受任意手机号参数。
{
"code": 100000,
"msg": "success",
"data": {
"verification_id": "verification_example_001",
"masked_phone": "138****0000",
"expires_in": 300,
"retry_after": 60,
"server_time": "2026-08-27T08:01:00Z"
}
}
verification_id是验证码会话标识,绑定主账号、当时的绑定手机号及“账号注销”用途,提交时一并携带。expires_in、retry_after单位为秒;示例为 5 分钟有效、60 秒后可重发,实际值由后端配置并返回。- 使用 6 位数字验证码;不在响应、日志或埋点中返回明文验证码。
- 设置账号、手机号、IP 等维度的频率限制及错误次数限制;重发后旧验证码失效。
- 与登录、提现、实名认证等验证码用途隔离。可复用短信基础设施,不可混用验证码。
- 主账号换绑手机号后,旧手机号对应的验证码会话及核验快照失效,要求重新开始。
- 缺少绑定手机号、发送失败或触发限流时返回明确错误;前端不能在失败时显示“已发送”。
3.3 提交注销申请
POST /api/app/account-deletion/submit
使用有效业务 Token。请求示例:
{
"client_request_id": "709277cb-2085-49c1-b80f-042476c7c36b",
"precheck_id": "precheck_example_001",
"verification_id": "verification_example_001",
"sms_code": "482951",
"acknowledged_asset_kinds": ["wallet", "works", "projects", "cloud_files"],
"acknowledgement_version": "account-deletion-v1"
}
| 字段 | 必填 | 说明 |
|---|---|---|
client_request_id |
是 | 客户端为本次提交生成的 UUID 字符串;网络重试沿用同一个值 |
precheck_id |
是 | 当前主账号的有效核验快照,不接受其他账号的快照 |
verification_id / sms_code |
是 | 验证码会话及用户输入的真实短信码;示例不是固定验证码 |
acknowledged_asset_kinds |
是 | 用户已确认的资产类别,须与快照中要求确认的集合一致 |
acknowledgement_version |
是 | 用户确认的注销说明版本 |
成功响应示例:
{
"code": 100000,
"msg": "success",
"data": {
"state": "pending",
"can_cancel": true,
"server_time": "2026-08-27T08:02:00Z",
"request": {
"id": "deletion_example_001",
"client_request_id": "709277cb-2085-49c1-b80f-042476c7c36b",
"status": "pending",
"submitted_at": "2026-08-27T08:02:00Z",
"scheduled_deletion_at": "2026-09-03T08:02:00Z",
"canceled_at": null,
"completed_at": null,
"acknowledged_asset_kinds": ["wallet", "works", "projects", "cloud_files"],
"acknowledgement_version": "account-deletion-v1"
}
}
}
处理要求:
- 服务端重新校验身份、验证码、快照、确认版本以及资金和未完成业务条件。
- 原子保存申请及用户确认记录、消耗验证码,并使该主账号所有设备上的业务 Token、旧登录临时 Token 和刷新凭证失去业务访问权限。
- 冷静期内保留可恢复的身份及数据,不提前执行不可逆删除;状态必须限制新建订单、上传、提现等业务操作。
- 同一主账号同一时刻最多有一条有效申请。已成功的同一
client_request_id重试应返回原申请,不因验证码已消费而重复报错;同一幂等键不能承载不同请求内容。 - 账号已有待处理申请时,不创建第二条,也不延长原截止时间;返回原状态或可识别的“已有申请”错误,客户端转查询状态。
- 成功页使用服务端返回的截止时间。客户端收到成功响应后应立即清理业务登录态;即使用户尚未点击成功页“退出”,后端也已禁止业务访问。
响应丢失的处理: 提交可能已成功且原 Token 已失效。此时客户端重新完成身份验证,通过登录接口取得恢复专用凭证,再查 status;不得把网络超时直接当成提交失败,也不得为了查询结果自动取消注销。
3.4 查询注销状态
GET /api/app/account-deletion/status
- 无查询参数,以凭证定位主账号。
- 接受有效业务 Token、正常登录临时 Token,或第 4 节定义的恢复专用 Token;不能提供匿名按手机号查询。
- 原业务 Token 已被注销操作撤销时,不重新赋予其查询权限,应先重新验证身份取得恢复专用 Token。
- 用于启动检查、回到前台、多设备状态校准,以及提交/取消请求超时后的结果确认。
响应 data 与提交接口一致,包含 state、can_cancel、server_time、request。无申请时:
{
"code": 100000,
"msg": "success",
"data": {
"state": "none",
"can_cancel": false,
"server_time": "2026-08-27T08:00:00Z",
"request": null
}
}
canceled返回最近取消的申请和canceled_at;completed返回实际完成时间completed_at。can_cancel由后端计算,只能在状态为pending且未到截止时刻时为true。- 查询不得取消注销或延长冷静期。到期任务尚未完成时返回
processing,不能仅凭时间到了就返回completed。 - 状态查询失败时,不应默认账号正常;客户端提示重试或重新登录,业务接口仍由后端鉴权保护。
3.5 取消注销申请
POST /api/app/account-deletion/cancel
token: <恢复专用 Token>
只有重新验证身份且用户点击“恢复账号并登录”后调用:
{
"request_id": "deletion_example_001"
}
成功响应示例:
{
"code": 100000,
"msg": "success",
"data": {
"request_id": "deletion_example_001",
"state": "canceled",
"canceled_at": "2026-08-28T01:00:00Z",
"server_time": "2026-08-28T01:00:00Z",
"login": {
"token": "new-account-selection-token",
"scenic_users": [],
"store_users": []
}
}
}
login结构复用现有 v9 登录响应;示例数组省略业务内容,实际需返回恢复后当前可选的景区、门店身份。- 返回的
login.token为新生成的正常账号选择临时 Token;客户端继续走原有单账号自动选择、多账号选择及/v9/set-user流程,不复用注销前的旧凭证。 request_id必须与凭证绑定的主账号和注销申请一致,不能取消别人的申请或该账号下一次新申请。- 与到期任务通过事务或等效并发控制互斥;按服务端时间决定取消是否成功,不能出现既恢复又删除的结果。
- 对同一已取消申请的重试,不重复改变状态或产生副作用。若凭证仍有效,可返回原取消结果和有效登录上下文;若凭证已撤销或过期,重新登录确认状态,不要求用户再次取消。
- 到期、
processing、completed均拒绝恢复,返回可识别错误;不得重新启用旧 Token。
4. 登录、会话与多端配合
4.1 调整现有 /api/app/v9/login
保留现有手机号密码登录参数。必须先完成密码/验证码等身份验证,再返回该主账号的注销状态,避免泄露任意手机号是否注册或注销。
| 状态 | 登录接口行为 |
|---|---|
none / canceled |
沿用当前 token、scenic_users、store_users;可附带最新注销状态 |
未到期的 pending |
不签发正常账号选择或业务 Token;返回申请信息和恢复专用 Token,等待用户决定 |
processing / completed |
返回明确的不可登录、不可恢复业务错误,不签发可登录凭证 |
待注销登录建议使用成功 Envelope 承载“验证身份成功但尚未登录”的结果:
{
"code": 100000,
"msg": "success",
"data": {
"token": "",
"scenic_users": [],
"store_users": [],
"account_deletion": {
"state": "pending",
"request_id": "deletion_example_001",
"submitted_at": "2026-08-27T08:02:00Z",
"scheduled_deletion_at": "2026-09-03T08:02:00Z",
"server_time": "2026-08-28T01:00:00Z",
"can_cancel": true
},
"recovery_token": "opaque-recovery-token",
"recovery_token_expires_at": "2026-08-28T01:10:00Z"
}
}
恢复专用 Token 要求:
- 短时有效,并绑定主账号、当前注销申请和允许的操作;示例有效期为 10 分钟,实际由后端配置。
- 仅可查询注销状态和取消该申请,不能调用
/v9/set-user、订单、钱包、文件下载等业务接口,也不能兑换或刷新成业务 Token。 - 不能通过改请求参数变成其他用户的凭证;不记录到普通日志、埋点或 URL。
- 用户选择“暂不登录”只结束本次登录,不调用取消接口;重新登录或查询本身不得自动恢复账号。
- 取消完成后撤销该申请的恢复操作权限;新登录凭证按取消接口约定返回。
4.2 修改 /api/app/v9/set-user 和统一鉴权
- 无论客户端是否接入新功能,待注销及不可恢复账号都不能通过旧临时 Token、刷新 Token、账号切换或其他登录入口继续使用业务。
- 校验“凭证属于谁、凭证可做什么、账号当前是什么状态”,不能只检查签名或过期时间。
- 提交注销需要覆盖同一主账号的全部设备和全部关联业务身份,不仅让提交申请的 iPhone 退出。
- Android 当前有
/v9/login的密码和短信两种登录方式;所有方式执行相同的状态检查。iOS 短信登录入口目前仍待接入,不能因此遗漏后端约束。 - 冷静期取消后签发新凭证,不恢复旧凭证的有效性;业务身份列表以取消时的最新数据为准。
4.3 与客户端接入的关系
当前本地 loginState、cancelDeletion 是同步方法,接入网络后需改为异步;不能只替换 Mock 类名。
客户端还需扩展登录返回模型、恢复专用 Token 上下文、processing 状态、短信倒计时、阻断原因和核验快照处理。当前 Mock 使用登录输入框中的手机号取消注销,真实接口必须改用受验证的主账号/申请上下文,不能继续依赖可编辑输入值。
当前 Mock 申请 ID 使用 Swift UUID,资产枚举原始值包含 cloudFiles;本文建议接口使用字符串 ID 和 cloud_files。客户端需通过网络 DTO 显式映射,不能把本地 Mock 模型直接序列化后当作请求契约。
5. 服务端必须负责的后台处理
- 提交成功后持久保存申请,App 卸载、退出或长期离线都不影响到期处理。
- 冷静期内不执行不可逆清理;到期后先禁止恢复,再按最终确认的规则解除身份、处理个人资产和第三方关联。
- 共享资产、资金账务、交易记录、客户已购买内容等分别制定处理方案;需要保留的记录与可删除的个人数据应区分,保留范围及周期由相关负责人确认。
- 处理任务可重复执行且有重试机制;只有约定的必需处理步骤完成后才标记
completed,部分失败不能假报成功。 - 保留可审计的申请、确认说明版本、时间、取消记录、处理进度及失败原因;审计中不保留明文验证码或 Token。
- 到期删除与取消操作必须有统一的并发保护;业务鉴权和后台任务读取一致的主账号状态。
- 需要测试环境的可控时间或缩短冷静期能力,以便验证到期边界及失败重试;不得在生产开放客户端任意修改截止时间的接口。
6. 错误返回要求
沿用整数 code 和可直接展示的中文 msg。以下名称是待后端分配业务码的语义清单,不是现有错误码。
| 错误语义 | 典型场景 | 客户端处理 |
|---|---|---|
ACCOUNT_IDENTITY_REQUIRED |
主账号没有可用于验证的绑定手机号 | 提示先处理账号信息 |
DELETION_BLOCKED |
资金未结清、订单未完成、负责人未移交等 | 展示阻断原因,禁止提交 |
PRECHECK_EXPIRED / PRECHECK_CHANGED |
快照过期、资产或说明版本发生变化 | 重新核验并要求再次确认 |
ACKNOWLEDGEMENT_REQUIRED |
缺少必需资产确认或确认版本不匹配 | 返回资产核验页 |
SMS_SEND_FAILED / SMS_RATE_LIMITED |
短信发送失败或限流 | 提示重试;限流返回重试秒数 |
SMS_CODE_INVALID / SMS_CODE_EXPIRED / SMS_ATTEMPTS_EXCEEDED |
验证码错误、过期、尝试超限 | 提示重输或重新发送 |
DELETION_ALREADY_PENDING |
已有有效申请 | 查询原申请,不重复创建 |
NO_PENDING_DELETION |
申请不存在或并非当前可取消申请 | 查询最新状态 |
DELETION_NOT_CANCELABLE |
已到截止时间或正在最终处理 | 不再提供恢复入口 |
ACCOUNT_DELETION_COMPLETED |
已完成注销 | 禁止登录和恢复 |
RECOVERY_TOKEN_INVALID / RECOVERY_TOKEN_EXPIRED |
恢复凭证失效 | 重新验证身份,不自动取消 |
IDEMPOTENCY_CONFLICT |
同一幂等键用于不同请求内容 | 停止自动重试,提示重新操作 |
错误响应继续采用现有 Envelope。后端如需在 data 中返回 blocking_reasons、retry_after 等结构化详情,需同时给出字段契约;当前 iOS APIClient 对失败响应只暴露 code/msg,接入时需要补充详情解析。
与现有全局登录失效处理区分: 当前 iOS 会将 HTTP 401/403 及业务码 180024、100091、100090、100060 视为登录失效。资产阻断、验证码错误、快照过期等业务问题不要复用这些码,避免误触发全局退出。真实凭证失效仍沿用项目鉴权规则。
7. 联调验收清单
- 主账号关联多个景区、门店时,核验范围完整;切换业务身份不会变成另一个注销对象;不能查询、提交或取消其他主账号的申请。
- 无手机号、无资产、存在余额/冻结款/未完成业务时,分别返回约定的正常或阻断结果。
- 正确验证码可提交;错误、过期、重发前旧码、其他用途码、其他账号验证码都不可提交。
- 资产确认不完整、核验过期、资产发生变化、说明版本不一致时,后端拒绝并要求重新确认。
- 成功申请返回准确截止时间;重复请求不产生新申请、不重置冷静期;请求超时后可重新验证身份并查到真实结果。
- 提交成功后所有设备及旧版本业务访问受限;旧 Token、账号选择、短信登录等不能绕过注销状态。
- 冷静期登录只显示恢复确认;点“暂不登录”保持待注销,点“恢复账号并登录”后取消并取得新的账号选择凭证。
- 恢复专用 Token 只能查询状态和取消绑定申请;不能访问业务或取消其他申请。
- 截止前可取消、恰好截止不可取消;取消与到期任务并发时只产生一个一致结果。
- 未运行 App 也会按期处理;任务部分失败会重试,处理期间保持不可恢复,未完成时不返回
completed。 - 已取消账号可再次发起新申请;旧申请和旧恢复凭证不能影响新申请。
- 完成注销后不能登录或恢复;共享数据、客户内容和需保留记录按确认的方案处理,没有越权删除。
8. 请后端与产品确认并回传
- 账号及数据边界: 主账号映射、关联身份范围;作品与相册/项目的统计口径;共享资产和已售内容的处理方式。
- 准入规则: 余额是否允许放弃;冻结资金、提现中、未完成订单、线下未补缴款及负责人身份是否阻断,如何解除阻断。
- 时限和最终处理: 七天是否按 168 小时计算;到期处理内容、记录保留范围与周期;注销后同手机号能否重新注册,且不得恢复旧账号数据。
- 接口契约: 最终路径、字段类型、完整正常/异常响应、业务码、短信频控、恢复凭证权限及有效期。
- 联调交付: 测试环境地址、测试账号及各状态样例、到期和失败重试验证方式、预计可联调时间。
上述规则确认前,客户端中的“永久删除”“放弃资产”等 Mock 文案不能直接作为最终业务承诺,应随实际后端处理规则调整。