SA入驻App流程需求

1. 文档定位

本文定义 PocketBuy SA App 侧入驻流程,从手机号注册、身份 KYC、资料填写、收款账户、人脸验证、提交审核,到审核、培训、后台门店分配和办单资格生效的完整逻辑。

原型参考:https://demo.at.lltech.dev/pocketbuy_sa/home?docs=0&canvas=1

2. 总体流程

SA 入驻完整链路:

手机号注册 + OTP
-> Identity KYC
-> Personal Profile
-> Bank account
-> Face verification
-> Submitted
-> 后台入职审核
-> 线下培训
-> 管理后台选择并绑定门店
-> 初始登录密码下发
-> 可正式办单

页面边界:

  • App 页面展示文案使用英文,需求文档使用中文。
  • 不新增 Work setup、Job role、Background check。
  • 不向 SA 展示 Dojah/AWS 明细、设备定位采集结果、风控规则、审核内部原因或后台判断阈值。
  • SA 前端只展示当前步骤、可操作按钮、可理解状态和后续安排。

3. 页面与操作逻辑

整个操作流程不允许app内录屏

3.1 注册

路由:/pocketbuy_sa/register

功能:

  • 输入 Nigeria 手机号和 OTP。
  • 手机号格式通过后点击 Get code;OTP 校验通过后,服务端在创建草稿前查询该手机号是否已存在 SA 账号或未完成入驻记录。
  • 存量手机号不得静默创建第二个 SA 账号;前端根据服务端返回的业务类型展示英文弹窗:已激活账号提示 Phone number already registered,提供 Go to login;存在未完成草稿提示 Onboarding already in progress,直接进入对应入驻步骤。
  • 存量手机号查询结果只返回可行动的业务提示,不返回账号内部 ID、审核人、风控命中规则等内部信息。
  • 注册手机号作为 SA 账号手机号,不重复录入。
  • 注册成功后自动跳转 /pocketbuy_sa/onboarding/kyc

后端要求:

  • OTP 发送、校验、频控和风险限制由后端处理。
  • OTP 验证通过后,按手机号查询 active_accountin_progress_onboardingnone;查询和弹窗决策均由后端结果驱动,前端不得仅凭本地缓存判断是否存量。
  • active_account 不创建新草稿;in_progress_onboarding 返回原草稿的可恢复入口;none 才创建新草稿。所有分支记录 trace_id 和审计事件。
  • 后端创建 SA 草稿时记录手机号、注册时间、注册渠道、设备摘要和 trace_id。

3.2 Identity KYC

路由:/pocketbuy_sa/onboarding/kyc

功能:

  • 页面内容使用英文。
  • 录入 Full legal name 和 11 位 BVN。
  • 页面不提供单独 BVN Check 按钮。
  • 点击 Continue 后由后端先校验 BVN 格式、当前 BVN 是否已关联其他 SA、是否已关联当前草稿,再调用 BVN KYC;只有全部通过才进入 Personal Profile。
  • 存量 BVN 或身份异常使用英文弹窗:当前账号已绑定时提示 BVN already linked to this account;已绑定其他账号时提示 BVN already linked to another account;姓名不一致时提示 Details do not match 并允许返回修改;服务不可用时提示 Identity check unavailable,允许重试。
  • 存量 BVN 不允许通过更换姓名、手机号或重复提交绕过;服务端以 BVN 的规范化值和唯一约束为准。
  • KYC 失败时前端只展示可理解的失败提示,不展示供应商原始返回。

设备与定位:

  • 进入 KYC 页面时弹出定位授权提示,并采集设备信息。
  • SA 授权后采集设备型号、系统、设备指纹、定位、精度和操作时间。
  • SA 拒绝授权或采集失败不阻断流程,但后端必须记录失败原因,作为审核材料。
  • SA 前端不展示经纬度、精度、设备指纹等采集结果。

后端要求:

  • 提交时先校验当前 BVN 是否已有有效绑定:绑定当前草稿时幂等返回;绑定其他 SA 时返回 BVN_ALREADY_USED;无绑定时调用 Dojah BVN Lookup 验证姓名并拉取 BVN 照片保存。
  • BVN 唯一性检查、姓名比对和第三方调用结果必须落库并审计;并发请求通过数据库唯一约束或幂等键避免重复绑定。
  • BVN、BVN KYC 结果属于强实名信息,后续后台不可手动修改。

3.2.1 存量校验弹窗 UI 设计图

下图为注册和 Identity KYC 环节的全量存量校验弹窗,App 页面文案保持英文;弹窗居中展示,背景加遮罩,主按钮使用品牌色,次要操作使用无边框文字按钮。

SA 入驻存量手机号与 BVN 校验弹窗 UI 设计图

弹窗触发条件主操作次要操作是否允许继续入驻
Phone number already registeredOTP 通过后命中已激活 SA 账号Go to loginUse another phone number否;不得创建新账号
Onboarding already in progressOTP 通过后命中未完成入驻草稿Resume onboardingUse another phone number不新建;进入原草稿
BVN already linked to this accountBVN 已绑定当前草稿/账号CloseGo to login否;按幂等或恢复原流程处理
BVN already linked to another accountBVN 已绑定其他 SACloseGo to login否;不得泄露对方账号信息
Details do not matchBVN 返回姓名与用户输入不一致Review and try again否;返回 KYC 表单并保留可编辑输入
Identity check unavailableBVN 服务超时、不可用或系统异常Review and try again否;保留输入,不写入 KYC 通过状态

原型中使用以下测试数据可触发各类弹窗:

  • 手机号 8012340001:已激活账号

  • 手机号 8012340002:未完成入驻

  • BVN 11111111111:当前账号已绑定

  • BVN 22222222222:其他账号已绑定

  • BVN 33333333333:姓名不一致

  • BVN 44444444444:服务不可用

3.3 Personal Profile

路由:/pocketbuy_sa/onboarding/profile

功能:

  • 录入基础资料:性别、生日、地址、State、City、教育信息、紧急联系人。
  • 基础资料可以在提交前由 SA 修改。
  • 提交审核后,只有后台在特定状态下可修改基础信息,App 不直接开放后台改写能力。

后端要求:

  • State、City 使用后端字典或配置。
  • 紧急联系人手机号需做格式校验。
  • 后端保存每次草稿更新的更新时间和 trace_id。

3.4 Bank account

路由:/pocketbuy_sa/onboarding/payout

功能:

  • 录入收款银行、10 位 NUBAN 和备注。
  • 页面展示脱敏账户摘要。
  • Bank account 与 Face verification 是两个独立步骤。

后端要求:

  • 银行名称、NUBAN、银行校验结果属于资金相关信息。
  • SA 提交银行名称和 10 位 NUBAN 后,由服务端调用 Paystack 账户校验接口;前端不得直接调用 Paystack,也不得接触供应商密钥。
  • 使用接口:GET https://api.paystack.co/bank/resolve?account_number={NUBAN}&bank_code={BANK_CODE}(Resolve Account Number)。BANK_CODE 由后端银行字典提供;服务端读取返回的 account_nameaccount_numberbank_id 等字段,用于校验账号存在性、账户名称和账户归属。
  • 账户校验通过条件:Paystack 返回成功、账号和银行代码与请求一致、账户名非空、且账户名与 BVN KYC 法定姓名满足配置的匹配规则;仅“账号存在”不能视为归属验证通过。
  • 后端保存请求 trace_id、校验时间、脱敏账号、返回账户名摘要、匹配结果和错误码映射;原始响应按敏感数据留存策略加密或脱敏。
  • 提交后后台不可手动修改银行名称、NUBAN 或银行校验结果;如需变更必须走单独银行卡变更流程。
  • 提交审核前服务端复验 NUBAN 格式、银行账户验证状态和账户归属匹配状态,验证过期或账户信息发生变更时必须重新校验。

Paystack 官方文档:Verify Account Number

3.5 Face verification

路由:/pocketbuy_sa/onboarding/face

功能:

  • 人脸验证是入驻提交前最后一步。
  • 只有 OTP、BVN KYC 和银行账户均满足条件后,才能进入最终提交判断。
  • 人脸验证通过后才允许点击 Submit application。

后端要求:

  • 参照现有进件流程人脸校验逻辑

3.6 Submitted

路由:/pocketbuy_sa/onboarding/submitted

功能:

  • 展示入驻申请已提交。
  • 告知后续会进行审核和线下培训。
  • 提供返回 Home 入口。

后端要求:

  • 提交时状态进入 pending_review
  • 服务端提交前必须复验 OTP、BVN KYC、人脸比对、银行账户校验状态、NUBAN 格式和审核材料完整性。
  • 重复提交需要幂等处理,不允许生成多条并行审核单。

4. 首页状态与办单拦截

Home 根据后端返回状态展示 SA 当前资格:

状态App 展示办单入口
未提交正常展示入驻入口不允许正式办单
pending_review入驻审核中拦截 New Application / Calculator
rejected入驻未通过不允许办单
approved_pending_training待培训确认不允许办单
training_passed,等待后台分配门店或密码下发Getting ready不允许办单;不展示后台处理细节
training_passed 且已绑定有效门店、已下发密码可正式开始办单允许
disabled账号停用阻断登录或办单

办单资格条件:

review_status == approved
AND training_result == passed
AND at least one store binding active
AND login_password_issued == true
AND account_status == active

门店分配规则:

  • SA App 入驻流程不展示 Merchant / Store 页面,不采集、选择或展示门店信息。
  • 培训通过后,管理后台才可为该 SA 选择并绑定一个或多个有效门店;后台保存 sa_store 关系、操作人、时间、变更前后值和审计记录。
  • 后台完成至少一个有效门店绑定后写入 store_assignment_status=assigned;门店被解绑、停用或全部失效时,该状态应回退为不可办单。
  • sa办单过程也需要对sa权限进行校验,如扫码是权限外的门店,弹窗提示:“You currently do not have the application permission for this store. If you need it, please contact your manager.”
  • 培训已通过但尚未完成门店分配或初始密码下发时,App 首页只显示英文 Getting ready / We are preparing your account,并拦截办单入口;不得向 SA 说明后台门店分配、审核或密码下发的内部处理状态。

5. 登录与密码

  • 登录页支持 Password/OTP 切换。
  • 培训通过后系统下发初始登录密码。
  • Reset Password 支持旧密码重置和 OTP 重置。
  • 旧密码重置不要求手机号;OTP 重置才要求手机号和验证码。
  • 密码下发、登录、重置均由服务端校验和审计。

5.1 OTP 重置密码节点

路由:/pocketbuy_sa/reset-password

  1. SA 输入注册手机号,点击 Get code
  2. 服务端校验手机号格式、账号状态和发送频控;为避免账号枚举,账号不存在、停用或不可重置时前端统一展示“验证码已发送或请联系客服”的结果,不返回具体账号是否存在。
  3. SMS 服务发送 4 位一次性验证码;验证码有效期 5 分钟,单次使用,最多连续输错 5 次,重新发送后旧验证码立即失效。
  4. SA 输入验证码并点击页面上的 Verify code 按钮;服务端校验手机号、验证码、用途 password_reset、有效期、错误次数和设备/风险上下文。验证码未验证通过前,新密码和确认密码输入框保持不可用。
  5. 验证通过后服务端签发一次性 password_reset_token,有效期 10 分钟,仅允许修改该手机号对应账号的密码,不得直接登录或调用其他业务接口。
  6. SA 输入新密码和确认密码;服务端校验密码复杂度、两次输入一致、不能复用最近密码,并使用 reset token 完成密码更新。
  7. 更新成功后撤销旧登录会话和未使用的重置 token,记录审计日志,并返回登录页;验证码、token 和新密码不得写入普通日志。

重置密码短信模板:

Your PocketBuy SA verification code is {otp}. It expires in {minutes} minutes. Do not share this code.

uSpeedo 报备信息:

Template NameTemplate IDuSpeedo 模板内容变量映射预估长度长度判断
PB_SA_OTP_CODEUTA260807TZK1RTYour PocketBuy SA verification code is {1}. It expires in {2} minutes. Do not share this code.{1}=otp, {2}=minutes93OK: 1 segment

模板变量和发送规则:

  • {otp} 为服务端生成的 4 位数字验证码;{minutes} 固定为 5,避免模板动态文案与实际有效期不一致。
  • 短信发送成功后才允许进入验证码输入态;发送失败不启动倒计时,前端提示重试。
  • 验证码发送间隔建议 60 秒,单手机号、设备、IP 均需要频控;命中频控时不创建新验证码。
  • 验证成功、过期、输错、达到最大错误次数、重发失效和密码更新结果均记录 trace_id 与审计事件。

初始密码短信模板:

Welcome to PocketBuy. Your SA account is approved. Login phone: {phone}. Initial password: {password}. Please change it after login.

uSpeedo 报备信息:

Template NameTemplate IDuSpeedo 模板内容变量映射预估长度长度判断
PB_SA_ACCOUNT_APPROVED_APPUTB260807D1JWO2Welcome to PocketBuy. Your SA account is approved. Login phone: {1}. Initial password: {2}. Please change it after login.{1}=phone, {2}=password142OK: 1 segment

模板规则:

  • {phone} 使用 SA 注册手机号,建议展示完整手机号或业务约定的脱敏格式。
  • {password} 为服务端生成的一次性初始密码。
  • 仅在培训通过、账号满足开通条件且密码未下发时发送。
  • 发送成功后写入 login_password_issued=true;发送失败时保留待重试状态并写审计日志。

6. 接口草案参考

接口用途
POST /api/sa/register/otp/send发送注册 OTP
POST /api/sa/register/otp/verify校验 OTP,并返回存量手机号分支或创建入驻草稿
GET /api/sa/register/existing-check按已验证手机号查询账号/入驻草稿状态
POST /api/sa-onboarding/kyc/verify-bvnIdentity KYC Continue 时触发 BVN KYC
POST /api/sa-onboarding/draft保存入驻草稿
POST /api/sa-onboarding/face/verify最终人脸验证
POST /api/sa-onboarding/submit提交入驻审核
GET /api/sa-onboarding/status首页查询入驻、培训、账号状态
POST /api/sa-onboarding/store-assignment培训通过后由管理后台选择并绑定 SA 门店,非 SA App 调用
POST /api/sa/login/password密码登录
POST /api/sa/login/otpOTP 登录
POST /api/sa/password/reset/otp/send发送重置密码验证码
POST /api/sa/password/reset/otp/verify验证重置密码验证码并签发 reset token
POST /api/sa/password/reset/complete使用 reset token 更新密码
POST /api/sa/password/reset重置密码

注册 OTP 验证接口返回:status=nonestatus=active_accountstatus=in_progress_onboarding;存量分支只返回恢复/登录所需的短期 token 或路由信息。BVN 接口返回:BVN_ALREADY_USEDBVN_ALREADY_LINKED_TO_CURRENT_DRAFTBVN_NAME_MISMATCHKYC_SERVICE_UNAVAILABLE 或成功结果。

7. 异常与提示

  • OTP 超时、频控、错误次数过多:前端提示稍后重试,后端记录风险事件。
  • 重置密码验证码发送失败:不启动倒计时,保留手机号并提示重试。
  • 重置密码验证码错误、过期或超过最大错误次数:不签发 reset token;达到上限后要求等待或重新发送。
  • reset token 过期、重复使用或与手机号不匹配:阻断密码更新并返回重置密码起始页。
  • BVN 格式错误:前端本地拦截。
  • 手机号已注册且账号有效:弹窗引导登录,不创建新草稿。
  • 手机号存在未完成入驻:弹窗引导恢复原草稿,不创建新草稿。
  • BVN 已绑定当前账号:按幂等成功处理或提示恢复已有入驻,不重复创建绑定关系。
  • BVN 已绑定其他账号:弹窗提示不可复用,阻断继续,不展示被绑定账号信息。
  • BVN 与姓名不一致:弹窗提示检查并返回当前页修改;不得进入下一步。
  • BVN 查询服务不可用:弹窗提示稍后重试,保留当前输入,不标记为 KYC 通过。
  • BVN KYC 未通过:前端展示身份校验失败,不展示供应商原始原因。
  • 设备/定位拒绝或失败:不阻断流程,后台审核材料记录采集失败。
  • 人脸验证失败:不允许提交,可提示重试。
  • 银行账户格式无效:不允许提交。
  • 银行账户不存在、账户名为空或账户归属与 BVN 姓名不匹配:停留在 Bank account,展示可理解的英文错误提示,不允许进入最终提交。
  • Paystack 超时或不可用:展示重试提示,保留银行输入,不标记账户验证通过。
  • 账号停用:登录和新进件入口阻断,已提交的处理中订单继续由服务端推进;代办单用户仍可查看进度、补充资料和完成不依赖 SA 实时操作的步骤。未生成订单的草稿不可继续创建订单,需联系平台或转派其他有效 SA。

8. 验收口径

  • 注册成功后进入 /pocketbuy_sa/onboarding/kyc
  • 输入已激活存量手机号并完成 OTP 后,展示登录引导弹窗;输入存在未完成草稿的手机号后,展示恢复入驻弹窗。
  • 输入已绑定其他账号的 BVN 后,展示阻断弹窗且不能进入 Personal Profile;姓名不一致和服务不可用均有可关闭/重试弹窗。
  • Identity KYC 页面内容为英文,不展示 KYC 结果,不含 BVN Check 按钮。
  • 设备/定位采集失败不阻断入驻提交,但审核材料可见失败原因。
  • SA 入驻流程不包含 Merchant / Store 步骤;Bank account 与 Face verification 独立。
  • Bank account 必须完成 Paystack GET /bank/resolve 账户校验;需要确认归属时必须完成 BVN 与账户匹配校验,不能仅依赖 NUBAN 格式校验。
  • 人脸验证在最后一步,通过后才允许提交。
  • Submitted 页面为英文,并提示后续审核和线下培训。
  • Home 能展示审核中、拒绝、待培训、可办单、停用状态。
  • 审核通过但培训未通过时不能办单。
  • 培训通过后由管理后台完成至少一个有效门店绑定;门店绑定和密码下发均完成、账号启用后才可办单。