| 项目 | 内容 |
|---|---|
| 文档版本 | v1.1(2026-09-22)· 流程改造:把「修改手机号」从「输入新号 → 验新号 → 直接换绑」改为「先验证原手机号 → 再验证新手机号」。v1.1 已按客户 Figma 设计稿(section「我的-修改手机号」11 个画板)逐屏对齐:版式、文案、错误提示形式(iOS 系统弹窗)、成功/失败弹窗全部照设计稿 |
| 功能模块 | 我的 → 编辑 → 编辑资料 → 手机号(页面标题:更改号码) |
| 适用端 | iOS / Android(同一个 App,一套规则)。Web / Desktop 本期不做,原因见第八章 |
| 演示页 | 同目录 index.html(17 屏可点击:设计稿已有 11 屏 + 本次补充 6 屏) |
| 设计稿 | Figma 6dsI4eKdAoZr4RP0uILIBq(U8 Chat 2.0)· PAGE「iOS端」· SECTION「我的-修改手机号」node 1076:34256 —— 11 个画板(更改号码 / 输入当前手机号验证码 / 输入新手机号 / 已被占用 / 位数不正确 / 输入新手机号的验证码 / 验证码时返回提示 / 验证码错误 / 更改成功 / 更改失败 / 我的-编辑),演示页 M2–M12 与它们一一对应 |
| 实机截图 | 客户另给的 5 张实机图(「我的」页、编辑资料、更改号码、新号码、输入验证码短信)—— 用于核实设计稿没画到的细节(如「我的」页的全貌);演示里 M1 按实机截图还原 |
| 参照产品 | Telegram「Change Number」(两步验证的流程形态与它同源,但换绑规则按 U8 的账号体系定义) |
| 一句话需求 | 修改手机号时,先通过验证码验证原手机号,再验证新手机号,两者都通过才能换绑 |
本 PRD 做了什么:设计稿已经把界面定完了(11 个画板,连错误提示弹窗都画了),缺的是开发照着画板做不出来的判定规则 —— 两次验证的先后顺序靠什么保证、验证码的位数/时长/次数、中途退出怎么办、换绑之后旧号还能不能登录、失败会不会改到一半、接口怎么保证幂等。 这些补齐在第六、七章;第九、十章给出可直接落地的文案与接口顺序;需要拍板的 7 个点在第十一章。 演示页与设计稿的关系:M2–M12 一一对应 11 个画板(版式、文案、弹窗样式 1:1);M1 与 M13–M17 是设计稿没画、但不做就不闭环的 6 屏,屏上都标了「本次补充」(逐条交代见第十二章)。
一、背景与目标
1.1 背景
U8 Chat 的账号体系里,手机号就是登录账号:注册、登录、找回、加好友都围绕它。用户可以换绑,入口在「我的 → 手机号 → 更改号码」。
现状流程(本次要改掉的):
我的 → 更改号码(截图 1)
↓ 点「更改号码」
新号码(截图 2)── 填新号 ──▶ 验证码 ── 验证码正确 ──▶ 号码当场就换了
整个过程中,原手机号只被展示、从未被验证:用户只要手上有一台已登录的设备,就能把账号挪到任意一个自己能收到短信的号码上。
1.2 现状问题(本次要解决的)
| # | 问题 | 后果 |
|---|---|---|
| 1 | 换绑不验证原号码,只验证新号码 | 账号一旦在别人手里(捡到未锁屏的手机、共享设备的登录态、被诱导登录),对方可以无声地把账号改绑到自己控制的号码上,原号主从此登不进来;连"找回"都要走原号验证,而原号已经被换掉了 |
| 2 | 换绑不可逆,且没有"这是你本人吗"的确认 | 用户输错一位数字(133 输成 138),账号就绑到了一个陌生号上,且原号主无法自救 |
| 3 | 换绑后没有留痕 | 原号码收不到任何通知(连一条"你的账号手机号已变更"的短信都没有),用户发现账号没了时已经过去很久 |
| 4 | 两次验证的异常口径不明 | 验证码几位、多久有效、错几次会怎样、中途退出怎么办 —— 现状没有定义,每个端各做一套 |
1.3 目标
业务目标
- 把"账号被悄悄换绑"这一类不可逆的账号风险堵住:换绑必须同时持有原号(收得到短信)与新号。
- 降低与换绑相关的客诉("我号怎么没了"/"我改错了号找不回来")。
用户目标
- 换绑过程看得懂:清楚知道现在验的是旧号、下一步验的是新号。
- 换绑不会改错:改错了能立刻发现(新号填错时就在第二步被拦住)。
- 换绑后知道发生了什么:成功页明确写出新号码;原号码收到一条变更通知。
成功指标(上线首月,目标值需与数据侧对齐后锁定)
| 指标 | 目标 |
|---|---|
| 换绑流程完成率(进入「更改号码」→ 提交成功) | ≥ 65%(改造前基线需先取数) |
| 因"号码被改成陌生号"产生的账号找回 / 客诉 | 降到 ≈ 0 |
| 换绑中途放弃率(进入第 1 步旧号验证后离开) | ≤ 30%(超过就要看是否被"多一步"劝退) |
| 原号码收到变更通知的到达率 | ≥ 99% |
| 旧号验证步骤的首次校验通过率 | ≥ 90%(低于此值说明用户困惑"为什么要验旧号",见待确认 ②) |
二、范围
2.1 本期做
| 模块 | 内容 | 演示屏 |
|---|---|---|
| 入口 | 我的 → 右上角「编辑」 → 编辑资料 → 「手机号」行(右侧显示当前号码),点进「更改号码」 | M1、M2 |
| 入口页 | 「更改号码」页(设计稿 02,1:1),点按钮进入换绑流程 | M3 |
| 旧号验证(本次新增) | 短信发到当前号码,5 位验证码,填在 5 个方框里;通过后服务端下发一次性 change_token | M4 |
| 新号码填写 | 「新号码」页(设计稿 04,1:1),填 11 位号码 | M5 |
| 新号验证 | 短信发到新号码,5 位验证码,填在 5 个方框里;输满 5 位自动提交换绑 | M6(设计稿 07) |
| 结果 | 更改成功弹窗(设计稿 10)+ 失败弹窗(设计稿 11) | M7、M12 |
| 异常与边界 | 验证码错误 / 过期 / 重发 / 次数超限 / 新号已被占用 / 新号=旧号 / 提交中 / 提交失败 | M8–M12 |
2.2 本期不做(明确划出,防止开发自由发挥)
| 不做的事 | 原因 |
|---|---|
| 国家 / 地区选择 | 截图里的「🇨🇳 中国」是展示态,本期只支持 +86。国际号涉及运营商、计费、格式校验一整套,单独立项 |
| 邮箱 / 第三方账号绑定 | 与本功能无关;账号体系里只有手机号一个登录标识 |
| 旧号验证的白名单(比如"常用设备免验") | 一旦有例外,这个例外就是攻击面。换绑永远要验旧号,没有例外 |
| 弹窗二次确认("确定要更改吗?") | 只增加点击不增加安全性;安全性由旧号验证码保证 |
| 断点续传(中途退出后接着上次继续) | 换绑是低频高危操作,流程状态不落盘,退出即重来(见 7.5) |
| 换绑后强制所有设备下线 | 本期保持原登录状态,只推送安全通知(见 7.4)。是否强制下线见待确认 ⑥ |
| 自动解绑原号码 / 注销原号码 | 不触碰用户的号码归属,只解绑与本账号的关系 |
| 换绑历史记录页 | 本期只在设备/安全消息里留一条通知,不做专门的记录页 |
| Web / Desktop 端的换绑 | 见第八章 |
| 深色模式、超大字号的适配 | 随全局一起排期 |
2.3 端一致性
本期只有移动端。iOS 与 Android 同一套规则、同一套文案、同一套验证码参数(位数、时长、次数)。唯一差异是按系统习惯的键盘唤起与短信自动填充(iOS 支持"从短信中填入验证码",Android 走 sms_retriever)。
三、名词定义(务必与开发对齐,避免和现有功能混名)
| 名词 | 定义 |
|---|---|
| 原手机号 / 旧号 | 当前绑定在该账号上的手机号(示例:+86 183 1134 8215)。就是当前的登录账号 |
| 新手机号 / 新号 | 用户希望绑上来的号码(示例:+86 133 4455 6678) |
| 旧号验证 | 把验证码短信发到原手机号、由用户回填的这一步(M4)。本次新增 |
| 新号验证 | 把验证码短信发到新手机号、由用户回填的这一步(M6)。现状已有,本次位置不变 |
change_token | 旧号验证通过后,服务端下发的一次性凭证(有效期 10 分钟)。新号验证码的发送与最终提交都必须带它 —— 这是"顺序不可颠倒、不可跳过"的技术保证 |
| 换绑 / 更号 | 把账号与手机号的绑定关系从旧号改到新号。账号本身没有变(账号 ID 不变) |
| 数据转移 | 截图里"你的账号和所有数据都将转移到新的手机号"是用户视角的说法。技术上不存在数据迁移:账号 ID 不变,聊天记录、联系人、群关系、资产本来就在这个账号上,改的只是登录标识(见 7.4) |
| 登录验证码 | 登录时用的短信验证码。与换绑验证码是两套用途,不可互相顶替(见 6.8) |
| 锁定 | 验证码错误次数超限后,对该号码/账号暂停换绑一段时间(不是封号) |
⚠️ 开发注意:「数据转移」不要真的写迁移逻辑。换绑 = 更新账号的
phone字段 + 写一条安全日志 + 发通知。任何"把 A 账号的数据搬到 B 账号"的实现都是错的。
四、用户与场景
角色只有两类:账号持有者与拿到账号的他人(这是本功能的存在理由)。
场景 A · 换手机号(主场景,正常用户)
用户换了运营商号码,从 183 换到 133。他进「我的 → 右上角编辑 → 编辑资料 → 手机号 → 更改号码」, 先收到旧号(183)的验证码并在 M4 填入 → 进入 M5 填新号(133)→ 收到新号(133)的验证码并在 M6 填入 → M7 弹出「手机号码已更改」,点「完成」回「我的」,手机号已经是 133 了。
场景 B · 旧号已经不能用了(最尴尬的真实情况)
用户想把号换掉,是因为旧号卡已经丢了 / 停机了 —— 他收不到旧号的验证码。 这是本次改造必须正面回答的场景:走账号找回流程(申诉 / 人工),不在本流程里开免验证的口子。 ⚠️ 本期没有客服入口,所以这个场景目前没有可点的出口 —— 这正是待确认 ⑤ 必须先拍板的地方。
场景 C · 账号被盗后,攻击者试图换绑
攻击者拿到了用户的登录态(共享设备 / 未锁屏的手机)。他进「更改号码」→ 需要旧号的短信验证码 → 他收不到(短信只发到用户的旧号)→ 流程停在 M4。用户毫无察觉,但账号没有被挪走。 这就是本次改造的全部价值。
场景 D · 用户把新号填错一位
用户在 M5 把 133 输成 138 并继续。因为新号验证码要发到那个错误的号码上,他收不到 → 停留在 M6,可以点「返回」回去改号。账号始终没变。
场景 E · 用户在 M4 反复输错
用户手边没有旧号卡,猜了几次验证码 → 5 次后进入 M15:换绑锁定 24 小时, 但登录、收发消息完全不受影响。文案必须把这一点写出来,否则用户以为账号被封。
场景 F · 换绑中途退出 App
用户在 M6 直接杀掉 App。流程状态不保留:下次进来从「更改号码」(M3)重新开始, 旧号要重新验证一次。理由见 7.5(不做断点续传)。
五、功能总览
我的(M1 · 实机截图 5)
└─ 右上角「编辑」→ 编辑资料(M2 · 设计稿 01)
└─ 手机号 +86 183 1134 8215 ›
└─ 更改号码(M3 · 设计稿 02)
└─【新增】输入验证码短信(M4 · 设计稿 03)★ 验证当前手机号
│ └─ 通过 → 服务端下发 change_token(10 分钟)
└─ 新号码(M5 · 设计稿 04)── 填 11 位新号
└─ 输入验证码短信(M6 · 设计稿 07)★ 验证新手机号
└─ 提交 → 更改成功弹窗(M7 · 设计稿 10)/ 失败弹窗(M12 · 设计稿 11)
异常与边界(M8–M12)
验证码错误 M8 · 重新发送 M13 · 验证码已过期 M14 · 次数超限(锁定 24h)M15
新号已被占用 M10 · 新号=当前号 M17 · 提交中 M16 · 更换失败 M12
一条主线(演示页的「▶ 走一遍主流程」就是这个顺序): 我的 → 右上角「编辑」→ 编辑资料 → 手机号 → 更改号码 → 验证当前号码 → 新号码 → 验证新号码 → 更换成功。
六、功能详情
6.1 入口与页面结构
| 项 | 规则 |
|---|---|
| 入口路径 | 我的 → 右上角「编辑」 → 编辑资料 → 「手机号」行(设计稿 01 + 客户实机截图 5 确认)。三屏连起来才是入口:M1「我的」→ M2「编辑资料」→ M3「更改号码」 |
| 入口为什么藏在「编辑」里 | 手机号属于资料,与头像 / 姓名 / 简介 / 出生日期 / 账号名同属一页;「编辑资料」里「手机号」这一行右侧直接显示当前号码 + ›,与「账号名」是同一类行(点进去才能改) |
| 「我的」页不放入口行 | 「我的」页顶部那行 +86 183 1134 8215 · @Bosaidong 只做展示、不可点。不要在「我的」页另加「电话 / 手机号」行 |
| 导航样式(全流程统一) | 二级页左上角统一是白色圆形返回按钮(设计稿 01/02/03/04/07 都是它);「编辑资料」右上角另有一个紫色圆形 ✓ |
| 页面标题 | 「更改号码」(与设计稿一致,不改) |
| 流程图 | 见第五章。改造后的顺序固定为:验证当前手机号 → 新号码 → 验证新手机号 → 提交,两次验证之间不可插入、不可跳过 |
| 返回行为 | M2 返回 → M1;M3 返回 → M2;M4 返回 → M3;M5 返回 → M4;M6 返回 → M5。<br>验证码页返回要先弹确认(M11「取消手机验证」/ 继续 · 取消),因为它意味着放弃这次换绑;返回不回退验证状态:M4 通过后返回 M3 再进来,要重新验证旧号(change_token 作废) |
6.2 入口三屏(M1 我的 / M2 编辑资料 / M3 更改号码)
M1「我的」· 客户实机截图 5
| 元素 | 规则 |
|---|---|
| 右上角「编辑」(紫色文字) | 进「编辑资料」页(M2)—— 这是本功能真正的入口按钮 |
左上二维码图标 + 居中大头像(紫光环)+ 昵称 + +86 … · @… | 纯展示,都不可点 |
| 五组卡片(更改个人资料照片 / 我的资料 / 我的收藏 / 通知和声音 · 隐私和安全 · 语言 / 网络诊断 · 关于我们) | 既有功能,本次不动 |
| 底部 Tab | 聊天(红角标 1)/ 联系人 / 通话 / 我的 —— 是「通话」不是「资产」,未读角标是 1 不是 146 |
M2「编辑资料」· 设计稿 01,1:1
| 元素 | 规则 |
|---|---|
| 结构 | 圆形返回 + 紫色圆形 ✓ + 头像(紫光环)+「设置新照片」+ 五张卡片(姓名 / 简介 / 出生日期 / 手机号 + 账号名 / 退出登录),每张卡片下面一行灰色说明 |
| 「手机号」行 | 左侧文案「手机号」+ 右侧当前号码 + ›;点击 → 「更改号码」(M3)。本功能的入口就是这一行 |
| 行样式 | 与「账号名」一致(当前值 + ›,点进去才能改);「出生日期」显示「添加」;这三行都不做就地编辑 |
| ⚠️ 与实机截图的差异 | 实机截图 4 的导航是「取消 / 完成」文字,设计稿改成了「圆形返回 + 紫色 ✓」。演示按设计稿画(见待确认 ①) |
M3「更改号码」· 设计稿 02,1:1
页面结构:圆形返回按钮 + 居中标题「更改号码」+ 插图(黄鸭抱蓝色 SIM 卡 + 紫框绿屏手机)+ 当前号码 + 两行灰字说明 + 白色胶囊按钮「更改号码」。
| 元素 | 规则 |
|---|---|
| 当前号码 | 完整显示、不脱敏(+86 183 1134 8215):这一页本来就是给本人看的 |
| 说明文案 | 「你可以在这里更改手机号。你的账号和所有数据都将转移到新的手机号。」一字不改(设计稿原话)——已经把代价讲清楚了 |
| 按钮 | 白底紫字(设计稿原样)。点它 → 进入 M4(验证当前手机号),不直接进新号码页 |
6.3 【新增】验证当前手机号(M4 · 设计稿 03 · 本次改造的核心)
这一屏就是本次需求要加的那一步,设计稿已经画好了。
| 项 | 规则 |
|---|---|
| 进入方式 | M3 点「更改号码」后自动发送一条验证码到当前手机号并进入本屏 |
| 版式 | 圆形返回 + 灰色气泡插图 + 居中标题「输入验证码短信」+ 居中号码 + 一行灰色小字「这是你当前的登录手机号」+ 5 个方框 + 右下「30s后再试」+ 底部圆角数字键盘 |
| 那行灰字的作用 | 旧号验证与新号验证的版式完全一样,只靠这一行区分"这次验的是旧号"。这一行是设计稿画的,必须保留 |
| 输入 | 5 位数字,填在 5 个方框里:当前要填的框是紫边框,已填数字在框内 |
| 提交 | 输满 5 位自动校验:页面上没有确认按钮,所以不做按钮(这是从设计稿反推的交互) |
| 校验时机 | 输满自动提交一次;失败弹系统弹窗(M8),关掉后焦点回第 1 个框 |
| 通过后 | 服务端下发一次性 change_token(10 分钟有效)→ 进 M5 |
| 重发 | 右下「30s后再试」是冷却态(不可点);归零后变紫色可点的「重新发送验证码」(M13) |
| 键盘 | 系统数字键盘(仅数字),进页面自动唤起;iOS 支持从短信直接填充 |
| 短信文案 | 必须与登录验证码、新号验证码可区分(见 9.2) |
为什么这一步不能省:M5/M6 验证的是"新号能不能收到短信",只有 M4 验证的是"正在操作的人是不是账号的主人"。
6.4 新号码(M5 · 设计稿 04,1:1)
| 元素 | 规则 |
|---|---|
| 版式 | 圆形返回 + 大标题「新号码」+ 说明「我们将发送一条含验证码的短信到你的新号码。」+ 国家行 + 号码行 + 底部按钮 |
| 国家 / 地区行 | 「🇨🇳 中国」是展示态、不可点(本期只支持 +86,见 2.2) |
| 号码行 | 区号 +86 固定;占位 000 0000 0000;输入后按 3-4-4 分组显示 |
| 按钮态 | 空输入 = 浅灰置灰(设计稿 04);有输入 = 紫色实心(设计稿 05/06)。注意:不是"输满 11 位才变紫" |
| 点「继续」的三条出路 | ① 合法 → 请求新号验证码 → 进 M6;② 位数不对 → 弹窗 M9;③ 号码已被其它账号绑定 → 弹窗 M10(在发短信之前拦) |
| 返回 | 回 M4(change_token 未过期时不必重验旧号;过期则回 M3 重来) |
6.5 验证新手机号(M6 · 设计稿 07,1:1)
| 项 | 规则 |
|---|---|
| 版式 | 与 M4 完全相同,只有两处不同:号码是刚填的新号;没有「这是你当前的登录手机号」那行,改为右下「← 修改手机号」 |
| 输入与提交 | 同 M4:5 个方框、输满 5 位自动提交 |
| 「← 修改手机号」 | 回「新号码」页(M5)改号;改号后需重新发送新号验证码 |
| 提交结果 | 成功弹窗(M7)或失败弹窗(M12),都盖在本屏之上;设计稿没有单独的"提交中"页(实现口径见 M16) |
| 返回 | 同 M4:先弹「取消手机验证」确认(M11) |
6.6 更改成功(M7 · 设计稿 10,弹窗)
| 项 | 规则 |
|---|---|
| 形式 | 盖在验证码页之上的弹窗(不是独立页面):整页加深色遮罩,弹窗居中 |
| 弹窗内容 | 紫色圆形 ✓ + 标题「手机号码已更改」+ 新号码 + 两行说明「你的账号和所有数据都已转移到新号码;之后请用新号码 + 验证码登录」+ 紫色胶囊按钮「完成」 |
| 「完成」 | 回「我的」页(号码已更新)—— 这是弹窗唯一出口。不做自动跳转、不提供"改回去"入口 |
| 同时发生的事 | 原号码收到一条变更通知短信;所有在线设备收到一条安全通知(见 7.4) |
6.7 错误与提示:统一用 iOS 系统弹窗(设计稿口径,不要再做行内红字)
| 场景 | 弹窗文案 | 按钮 | 屏 |
|---|---|---|---|
| 验证码不正确 | 验证码不正确,请重新输入 | 好 | M8 |
| 手机号位数不正确 | 手机号位数不正确,请检查后重新输入 | 好 | M9 |
| 新号已被占用 | 该手机号已被其他账号绑定,请更换其他手机号 | 好 | M10 |
| 验证码页退出确认 | 取消手机验证 | 继续 | 取消(右加粗) | M11 |
| 换绑失败 | 手机号码更改失败(+「网络异常,手机号没有发生改变,请检查网络后重试」) | 确定(胶囊按钮) | M12 |
统一要求:所有错误都在弹窗里说,不用行内红字、不用 toast;弹窗出现时整页加遮罩;「好 / 确定」关掉后回到可重试状态,用户输入的内容保留。
6.8 两次验证的关系(本章是开发最容易做错的地方)
| 规则 | 说明 |
|---|---|
| 顺序不可颠倒 | 必须"旧的先、新的后"。新号验证码的发送与最终提交,都要求携带旧号验证产出的 change_token —— 顺序由服务端保证,不靠前端自觉 |
| 不可跳过任一步 | 没有 change_token 的"发送新号验证码 / 提交换绑"请求一律拒绝(403),客户端收到 403 即回 M3 重走 |
| 凭证不互通 | 两次验证的验证码不互通,也与登录验证码不互通:服务端按 purpose 区分(change_phone_old / change_phone_new / login),用错用途直接判错并计入错误次数 |
| 两步之间的时间窗 | 旧号验证通过后有 10 分钟完成新号验证与提交;超时回到 M4 重新验证旧号 |
| 重复提交 | 提交接口必须幂等(客户端带 request_id,服务端去重):连点、弱网重发都只生效一次 |
| 失败可重试 | 提交失败不消耗验证码,同一验证码在有效期内可重试同一请求(M12 → 关掉弹窗再点一次) |
七、异常与边界
7.1 状态对照表(验收时逐条走)
| # | 场景 | 触发方式 | 界面 | 号码是否变化 | 是否消耗错误次数 |
|---|---|---|---|---|---|
| 1 | 验证码错误 | 在 M4 / M6 输满 5 位自动校验后 | M8(弹窗「验证码不正确,请重新输入」) | 否 | 是 |
| 2 | 验证码过期 | 超过 5 分钟才提交 | M14(弹窗「验证码已失效,请重新获取」) | 否 | 否 |
| 3 | 重发倒计时中 | 点「重新发送」 | 停留本屏,灰字不可点 | 否 | 否 |
| 4 | 重新发送 | 倒计时归零后点 | 5 个方框清空、焦点回到第 1 个框、重新倒计时(M13 就是这个中间态) | 否 | 否(计发送上限) |
| 5 | 错误次数超限 | 1 小时内错 5 次 | M15(弹窗:请 24 小时后再试) | 否 | — |
| 6 | 新号已被其它账号绑定 | M5 点「继续」(发短信前拦) | M10 | 否 | 否 |
| 7 | 新号=当前号 | M5 点「继续」 | M17 | 否 | 否 |
| 8 | 提交中 | 在 M6 输满 5 位之后 | M16(键盘收起、方框变灰、下方显示「正在更改手机号…」) | 未定 | 否 |
| 9 | 提交失败 | 网络异常 / 超时 / 5xx | M12(弹窗:手机号码更改失败 / 网络异常,手机号没有发生改变) | 否 | 否 |
| 10 | 提交成功 | 服务端返回成功 | M7 | 是 | — |
| 11 | 短信发送失败(运营商侧) | send_code 返回失败 | 停在 M4 / M6 + 弹窗「短信发送失败,请稍后重试」(不消耗错误次数) | 否 | 否 |
| 12 | change_token 过期 | 停留超 10 分钟再操作 | 回 M4 + 提示「本次操作已超时,请重新验证当前号码」 | 否 | 否 |
| 13 | 多设备同时换绑 | 另一台设备正在进行 | 停留本屏 + 提示「这个账号正在另一台设备上更改手机号,请稍后再试」 | 否 | 否 |
| 14 | 账号被风控限制 | 服务端按风险策略拒绝 | 停留本屏 + 提示「账号暂时被限制,请稍后重试」 | 否 | 否 |
验收口径:除第 10 行以外,任何情况下手机号都不能发生变化。这是本功能唯一不可妥协的验收项。
7.2 两次验证的验证码参数(同一张表,两端照做)
| 参数 | 旧号验证(M4) | 新号验证(M6) | 备注 |
|---|---|---|---|
| 位数 | 5 位数字 | 5 位数字 | 与登录验证码位数统一(待确认 ③) |
| 有效期 | 5 分钟 | 5 分钟 | 过期按 M14 处理,不算错 |
| 重发间隔 | 60 秒 | 60 秒 | 倒计时期间按钮不可点 |
| 单次会话重发上限 | 5 次 | 5 次 | 超了提示"请稍后再试" |
| 同一号码每日发送上限 | 10 条 | 10 条 | 防短信轰炸,跨会话累计 |
| 错误上限 | 5 次 / 1 小时 | 5 次 / 1 小时 | 按账号累计(不是按设备) |
| 超限后 | 换绑锁定 24 小时 | 同左 | 只锁换绑,登录不受影响 |
用途隔离(purpose) | change_phone_old | change_phone_new | 与 login 完全隔离 |
| 一次一码 | 每次重发后旧码立即失效 | 同左 | 避免"旧码还能用"的争议 |
7.3 限流与锁定:锁什么、不锁什么
| 项 | 规则 |
|---|---|
| 按什么维度限流 | 账号维度累计错误次数;号码维度限制发送条数;另加 IP / 设备维度的一层粗限流(阈值由安全侧定) |
| 锁定的范围 | 只锁「更换手机号」这一个功能(以及本次流程内的发送验证码) |
| 不锁什么 | 登录、收发消息、加好友、改资料、设备管理 —— 完全不受影响。文案必须写出来(见 M15) |
| 解锁 | 到期自动解锁;本期不做手动解锁 / 申诉入口(客服能力未上线,见待确认 ④⑤) |
| 锁定期内的界面 | M4 / M6 方框禁用、「重新发送」不可点;弹窗告知原因与时长(同 M8/M9 的系统弹窗样式) |
7.4 换绑成功之后(本节是最容易被追问的部分)
| 项 | 口径 |
|---|---|
| 账号本身 | 账号 ID 不变、密码/邮箱等其余字段不变,只更新登录标识(手机号) |
| 聊天数据 | 一条都不会动:会话、消息、联系人、群成员关系、收藏、资产、钱包余额等全部随账号走(因为它们本来就属于这个账号) |
| 「数据转移」的说法 | 界面照截图文案说"转移",但实现上没有任何迁移动作。不要为此写迁移逻辑 |
| 已登录设备 | 保持在线上(本期不强制下线)。所有在线设备收到一条安全通知:「你的账号手机号已于 {时间} 变更为 {新号}。若非本人操作,请及时检查账号安全与登录设备。」 |
| 原号码(旧号) | ① 立刻不能再登录本账号(登录按新号查账号);② 收到一条变更通知短信:「你的账号已解除与本次号码的绑定。若非本人操作,请及时检查账号安全与登录设备。」——这是留痕,必须有 |
| 新号码 | 立刻成为登录标识;下一次登录需要用它 + 验证码(会话内的登录态不受影响) |
| 旧号能否立刻注册新账号 | 建议冷却 30 天(防"换号后旧号被别人拿走再注册、造成混淆与骚扰")—— 见待确认 ⑥ |
| 隐私开关 | 「通过手机号找到我 / 手机号对好友可见」等开关保持原值,值本身变成新号(口径见待确认 ⑦) |
| 安全日志 | 记录一条事件:时间、账号 ID、旧号(掩码)、新号(掩码)、设备名 / IP / 位置 —— 与「设备管理」模块复用同一套安全事件通道 |
7.5 中断、返回与并发
| 场景 | 规则 |
|---|---|
| 中途退出 App / 杀进程 | 流程状态不落盘(本地不存"已验证旧号"这种状态)。下次进来从 M3 重新开始,旧号重新验证一次。理由:换绑是低频高危操作,不做断点续传可以少一个可被利用的状态 |
| 返回上一屏 | M4→M3、M5→M4、M6→M5 都可以返回。返回 M3 会作废 change_token,再进来要重新验证旧号 |
| 停留在 M4 / M6 太久 | 验证码 5 分钟过期(M14);change_token 10 分钟过期(回 M4) |
| 来电 / 短信打断 | 不做特殊处理,回来继续(倒计时按服务端时间算,不按本地) |
| 同一账号多设备并发 | 以"先进入旧号验证"的会话为准:第二台设备发起时提示"正在另一台设备上更改手机号"(见 7.1 #13)。若第一台 10 分钟未完成(token 过期),第二台可继续 |
| 提交中杀进程 | 服务端仍会完成本次换绑(请求已发出)。用户重新打开 App 看到的是新号码 —— 因此提交中的返回拦截很重要(避免用户以为已取消) |
| 重复触发提交(输满自动提交后误触 / 弱网重发) | 幂等(request_id),只生效一次 |
7.6 号码合法性与输入格式
| 项 | 规则 |
|---|---|
| 合法格式 | 11 位、以 1[3-9] 开头(+86 区段) |
| 输入 | 只接受数字;粘贴内容里的 +86、空格、-、()自动清洗 |
| 显示 | 按 3-4-4 分组(133 4455 6678),与截图一致 |
| 不合法时 | 按钮保持置灰,不弹错误提示(输入过程中不打扰)。点了也不发短信 |
| 国际号 | 本期不支持(国家/地区行是展示态) |
| 号码变更后 | 存服务端时统一存 +86 + 11 位纯数字 |
八、跨端差异(Web / Desktop)
| 端 | 本期安排 |
|---|---|
| iOS / Android | 本期做,规则、文案、参数完全一致 |
| Web | 本期不做。Web 的登录形态与移动端不同(扫码 / 密码),换绑入口与验证链路要单独定义 |
| Desktop | 本期不做。如果 Desktop 上已经有"更改手机号"的入口,本期必须先下线或置灰它 —— 安全改造必须同时堵住所有端,否则旧流程仍然是一个可被利用的口子(这条是硬要求,不是建议) |
| 服务端接口 | 按"通用换绑"设计(purpose + change_token + 幂等),未来 Web / Desktop 直接复用,不需要再改协议 |
九、文案(全部按设计稿,逐条可复制)
9.1 界面文案
| 屏 | 位置 | 文案 | 来源 |
|---|---|---|---|
| M1 | 右上角 | 编辑 | 实机截图 5 |
| M2 | 标题行 | 手机号 → +86 183 1134 8215 › | 设计稿 01 |
| M2 | 卡片说明 | 输入您的姓名并添加可选的个人资料照片 / 你可以添加几行关于自己的信息 / 完善生日信息,结识更多有缘的朋友 | 设计稿 01 |
| M3 | 标题 / 说明 / 按钮 | 更改号码 / 你可以在这里更改手机号。你的账号和所有数据都将转移到新的手机号。/ 更改号码 | 设计稿 02 |
| M4 | 标题 / 号码 | 输入验证码短信 / +86 183 1134 8215 | 设计稿 03 |
| M4 | 号码下方灰字 | 这是你当前的登录手机号 | 设计稿 03(旧号验证的专用标识) |
| M4 / M6 | 重发(冷却中) | 30s后再试({n}s后再试) | 设计稿 03 / 07 |
| M4 / M6 | 重发(可点) | 重新发送验证码 | 本次补充(倒计时归零后) |
| M5 | 标题 / 说明 / 占位 | 新号码 / 我们将发送一条含验证码的短信到你的新号码。/ 000 0000 0000 | 设计稿 04 |
| M5 | 按钮 | 继续 | 设计稿 04 |
| M6 | 底部链接 | ← 修改手机号 | 设计稿 07 |
| M7 | 弹窗(成功) | 手机号码已更改 / {新号码} / 你的账号和所有数据都已转移到新号码;之后请用新号码 + 验证码登录 / 完成 | 设计稿 10 |
| M8 | 弹窗(错误) | 验证码不正确,请重新输入 / 好 | 设计稿 09 |
| M9 | 弹窗(错误) | 手机号位数不正确,请检查后重新输入 / 好 | 设计稿 06 |
| M10 | 弹窗(错误) | 该手机号已被其他账号绑定,请更换其他手机号 / 好 | 设计稿 05 |
| M11 | 弹窗(确认) | 取消手机验证 / 继续 | 取消 | 设计稿 08 |
| M12 | 弹窗(失败) | 手机号码更改失败 / 网络异常,手机号没有发生改变,请检查网络后重试 / 确定 | 设计稿 11 |
| M13 | 重发(可点) | 重新发送验证码 | 本次补充 |
| M14 | 弹窗 | 验证码已失效,请重新获取 / 好 | 本次补充 |
| M15 | 弹窗 | 验证码错误次数过多,请 24 小时后再试。你当前的号码仍可正常使用 / 好 | 本次补充 |
| M16 | 进度提示 | 正在更改手机号… / 请不要关闭 App,通常 3 秒内完成。 | 本次补充 |
| M17 | 弹窗 | 这就是你当前的号码,无需更改 / 好 | 本次补充 |
| 通用 | change_token 过期 | 本次操作已超时,请重新验证当前号码 | 本次补充 |
| 通用 | 短信发送失败 | 短信发送失败,请稍后重试 | 本次补充 |
| 通用 | 多设备并发 | 这个账号正在另一台设备上更改手机号,请稍后再试 | 本次补充 |
| 通用 | 风控限制 | 账号暂时被限制,请稍后重试 | 本次补充(无客服入口,文案里不出现「联系客服」) |
9.2 短信模板(三条都必须能互相区分)
| 用途 | 发给谁 | 文案 |
|---|---|---|
| 旧号验证码 | 原手机号 | 【U8 Chat】验证码 {code},用于更改你账号的手机号。5 分钟内有效。若非本人操作,请勿泄露此验证码。 |
| 新号验证码 | 新手机号 | 【U8 Chat】验证码 {code},用于把它绑定为你的新手机号。5 分钟内有效。 |
| 变更完成通知 | 原手机号 | 【U8 Chat】你的账号已解除与本次号码的绑定,当前绑定的手机号为 {新号掩码}。若非本人操作,请及时检查账号安全与登录设备。 |
三条短信的目的不同:前两条是"你要做一件事",第三条是"有人做了一个动作,这是给你留的痕"。第三条是本改造配套的必备项。
⚠️ 本期没有客服功能:短信与通知里的「请联系客服」已统一改为「请及时检查账号安全与登录设备」;等客服入口上线后再补回客服引导(见待确认 ⑤)。
9.3 站内安全通知(所有已登录设备)
你的账号手机号已于 {时间} 变更为 {新号}。若非本人操作,请及时检查账号安全与登录设备。
十、接口顺序、幂等与埋点
10.1 接口顺序(顺序即安全边界)
| # | 接口(建议命名) | 入参要点 | 出参要点 | 备注 |
|---|---|---|---|---|
| 1 | POST /account/change_phone/old/send_code | 账号 ID(从登录态取,不接受客户端传号码) | 掩码后的旧号、倒计时秒数 | 短信只发到服务端记录的当前号码 |
| 2 | POST /account/change_phone/old/check_code | code | change_token(10 分钟)、过期时间 | 校验通过才发 token;失败返剩余次数 |
| 3 | POST /account/change_phone/new/check_number | change_token、new_phone | 可用 / 已被占用 / 与当前号相同 | 发短信前先拦(M10 / M17) |
| 4 | POST /account/change_phone/new/send_code | change_token、new_phone | 倒计时、掩码新号 | 必须带合法 token,否则 403 |
| 5 | POST /account/change_phone/commit | change_token、new_phone、code、request_id | 成功 / 各类失败码 | 幂等;成功后作废 token、发通知、写安全日志 |
硬性要求:接口 1、2 不接受客户端传入的手机号(一律以服务端的当前绑定为准)。否则"先验旧号"就形同虚设。
10.2 幂等与并发
| 项 | 要求 |
|---|---|
commit 幂等 | 以 request_id(客户端生成 UUID)+ 账号 ID 去重;重复请求返回同一结果 |
change_token 一次性 | 提交成功后立即作废;重复提交返回"已完成"而不是报错 |
| 账号级互斥 | 同一账号同时只允许一个换绑会话(见 7.5) |
| 验证码一次性 | 校验成功后该码立即失效(防重放) |
10.3 埋点
| 事件 | 触发时机 | 关键参数 |
|---|---|---|
change_phone_entry_click | 点「我的 → 电话」 | 来源页 |
change_phone_start | 点「更改号码」 | — |
change_phone_old_code_sent | 旧号验证码下发 | 是否重发、第几次 |
change_phone_old_code_fail | 旧号验证码校验失败 | 剩余次数、错误码 |
change_phone_old_verified | 旧号验证通过 | 耗时(从 start 起) |
change_phone_new_number_submit | M5 点「继续」 | 是否被拦(占用 / 同号 / 格式) |
change_phone_new_code_sent | 新号验证码下发 | 是否重发 |
change_phone_commit | 验证码输满 5 位自动提交(M6) | — |
change_phone_commit_result | 提交换绑返回 | success / fail + 失败码 + 耗时 |
change_phone_done | 到达 M7 | 总耗时、重发次数、错误次数 |
change_phone_locked | 触发锁定 | 错误次数 |
change_phone_abandon | 中途离开(M4 / M5 / M6 退出) | 停在哪个屏、停留时长 |
关键看板:改造前后完成率对比 + 卡在哪一步放弃最多。如果 M4 的放弃率异常高,说明"为什么多一步"没讲清楚(对应待确认 ②)。
十一、待确认(需要产品拍板,开发据此实现)
| # | 问题 | 建议 |
|---|---|---|
| ① | 点「编辑资料」里的「手机号」行后,是跳「更改号码」页,还是像「账号名」那样就地编辑? | 建议跳页(当前设计,与截图 1 一致):换绑要「先验旧号、再验新号」,就地编辑放不下这条流程。入口按截图 4 不动:路径=我的 → 编辑 → 手机号,行内文案就叫「手机号」 |
| ② | M3 是否需要一行"为什么要先验旧号"的说明? | 建议加:「为保护账号安全,需要先验证你当前的手机号。」这是新增步骤唯一的解释入口,缺了会有"怎么多一步"的困惑 |
| ③ | 换绑验证码用几位?验证码页要不要「确认按钮」? | 位数与登录验证码一致(演示按 5 位画;若登录是 6 位就同步改 6 位,同一套验证码服务)。截图 3 上没有确认按钮,因此按输满 5 位自动提交实现 —— 若产品希望「输满后还要再点一下」,需要改截图 3 的版式:这是本 PRD 唯一一处从截图反推的交互,请先确认 |
| ④ | 错误次数上限与锁定时长? | 建议 5 次 / 1 小时 → 锁定 24 小时;本期不做申诉通道(没有客服入口),到期自动解锁 |
| ⑤ | 旧号已经停机 / 丢失、收不到旧号验证码的用户走哪条路? | 走账号找回(申诉 + 人工核验),不在换绑流程里开免验证口子。⚠️ 本期没有客服功能:M4 只能先给「没收到?请检查信号与短信拦截」这类自助提示;等客服 / 申诉入口上线后,再补「旧号收不到验证码怎么办」的引导(这件事必须先有结论,否则这部分用户会卡死在 M4) |
| ⑥ | 换绑成功后:① 原号码能否立即注册新账号?② 已登录设备是否强制下线? | ① 建议冷却 30 天;② 建议不强制下线,只推送安全通知(强制下线会让"在别的设备上正常使用"的用户突然被踢,体验代价大) |
| ⑦ | 换绑后,「通过手机号找到我 / 手机号对好友可见」等隐私开关如何取值? | 建议开关保持原值,值变为新号;但要在成功页或通知里提醒一句"新号码现在可以被搜到"(若开关是开着的) |
十二、相对设计稿改了什么(逐条交代,没有偷偷加功能)
| # | 改动 | 性质 |
|---|---|---|
| 1 | 「更改号码」按钮的下一步:从「新号码」页改成「验证当前手机号」页 | 本次唯一的功能改动(就是需求本身)。设计稿已经画好这一屏(画板 03) |
| 2 | 新增 M1「我的」页(按实机截图 5 还原) | 补齐入口路径的第一屏;设计稿 section 里没有这一屏 |
| 3 | 新增 M13–M17:重新发送可点态 / 验证码已过期 / 次数超限锁定 / 提交中 / 新号=当前号 | 设计稿未画。属于"必须有但不能只是瞬时一闪"的实现细节与安全边界,按 PRD 第七、十章执行;屏上标注了「本次补充」 |
| 4 | 弹窗样式按设计稿(iOS 系统弹窗 + 成功/失败结果弹窗) | 上一版我自造的"行内红字提示条 / 独立成功页"已全部删掉 |
| 5 | 上一版自造的「我的 → 电话」入口行已删除 | 入口以设计稿 01 为准:我的 → 编辑 → 手机号 |
| 6 | 截图 1 / 2 / 3 / 5 与设计稿 01–11 的版式、文案、按钮位置:一字未改 | 视觉零改动(唯一例外:演示里的插图与头像用 SVG / 首字占位重绘,不是设计稿的位图素材) |
| 7 | 去掉所有「联系客服」入口,短信与通知里「请联系客服」的表述一并改掉 | 本期没有客服功能,先隐藏 |
| 8 | 短信模板从 1 条变成 3 条(旧号验证码 / 新号验证码 / 变更通知) | 配套改造(见 9.2) |
| 9 | Desktop 端若已有换绑入口,本期必须先下线 | 配套改造(见第八章) |
附:演示页怎么用
- 打开同目录
index.html。 - 点页面上的虚线框(鼠标悬停会显示它会跳到哪一屏),就能沿真实流程一步步走;也可以用 <kbd>←</kbd> <kbd>→</kbd> 切屏、按 <kbd>H</kbd> 显示 / 隐藏热区。
- 左栏可以按「设计稿已有 / 本次补充」筛屏:
- 设计稿已有(11 屏,M2–M12):与 Figma 设计稿的 11 个画板一一对应(更改号码 / 输入当前手机号验证码 / 输入新手机号 / 已被占用 / 位数不正确 / 输入新手机的验证码 / 返回提示 / 验证码错误 / 更改成功 / 更改失败 / 我的-编辑),版式、文案、弹窗样式 1:1;
- 本次补充(6 屏,M1、M13–M17):设计稿没画、但不做就不闭环的部分(入口路径第一屏 + 重新发送 / 过期 / 锁定 / 提交中 / 新号=当前号),屏上都标了「本次补充」。
- 点「▶ 走一遍主流程」自动按顺序演示:我的 → 编辑资料 → 更改号码 → 验证当前手机号 → 新号码 → 验证新手机号 → 更改成功。
- 每一屏右侧的说明面板里,「待确认」黄框就是需要拍板的问题(与第十一章一一对应)。