Files
FlowPilot/docs/多注册流程状态迁移设计.md
T
2026-05-13 00:52:10 +08:00

8.2 KiB
Raw Blame History

多注册流程状态迁移设计

本文是 docs/多注册流程架构边界.md 的落地补充,专门解决“现有扁平状态怎么迁到多 flow 架构”这个最容易把旧逻辑拖垮的问题。

1. 先说结论

当前项目不能直接在 DEFAULT_STATE 上继续堆字段。要支持多个完全不同的注册流程,必须先把“运行态”“持久配置”“共享服务状态”“flow 私有状态”分层,再保留一层 OpenAI 旧步骤兼容视图。

这次迁移的目标不是一步把全部字段搬完,而是先建立新的状态主模型,让旧代码通过 adapter 继续运行。

2. 当前源码里的真实问题

2.1 DEFAULT_STATE 仍然是单流程扁平模型

background.js 里的 DEFAULT_STATE 目前把这些不同层次的状态混在一起:

  • 流程进度:currentStepstepStatuses
  • 通用运行态:automationWindowIdtabRegistrylogs
  • OpenAI OAuth / 平台回调:oauthUrllocalhostUrlsub2apiSessionIdcodex2apiSessionId
  • OpenAI PlusplusCheckoutTabIdplusCheckoutUrlplusBillingAddress
  • OpenAI 接码:currentPhoneActivationsignupPhoneActivationreusablePhoneActivation
  • OpenAI LuckMailcurrentLuckmailPurchase
  • 共享邮箱运行态:registrationEmailState

这会带来两个直接后果:

  1. 新 flow 一接进来,就只能继续往全局 state 加字段。
  2. 任何 reset / retry / stop 都容易误清理别的业务域状态。

2.2 旧步骤数字模型已经渗透到多个模块

当前不只是 background.js 依赖 currentStep / stepStatuses,下列模块也在按“Step 1~13”理解流程:

  • background/auto-run-controller.js
  • background/logging-status.js
  • background/account-run-history.js

所以新状态模型不能只改 background.js,必须给自动运行、日志、账号记录保留兼容出口。

2.3 registrationEmailState 名字看起来通用,内部却仍带 OpenAI 身份假设

background/registration-email-state.js 已经把邮箱运行态单独抽出来了,这是好事;但它的 preserveAccountIdentity 现在默认保留的是“手机号身份”,也就是:

  • accountIdentifierType = phone
  • signupPhoneNumber
  • signupPhoneActivation
  • signupPhoneCompletedActivation

这对 OpenAI 的 add-email 分支是对的,但对未来可能出现的“用户名主身份”“邀请码主身份”“钱包地址主身份”并不通用。

3. 目标状态分层

建议先建立“概念上的标准状态模型”,物理存储可以分阶段迁移。

chrome.storage.session.runtimeState = {
  activeFlowId: 'openai',
  activeRunId: 'run_20260512_xxx',
  currentNodeId: 'submit-signup-email',
  nodeStatuses: {
    'open-chatgpt': 'completed',
    'submit-signup-email': 'running',
  },

  shared: {
    automationWindowId: 123,
    tabRegistry: {},
    sourceLastUrls: {},
    logs: [],
    autoRun: {},
    accountArtifacts: {},
  },

  services: {
    mail: {},
    proxy: {},
    accountPools: {},
  },

  flows: {
    openai: {
      auth: {},
      platformBinding: {},
      plus: {},
      phoneVerification: {},
      luckmail: {},
      identity: {},
    },
  },

  legacyStepCompat: {
    currentStep: 2,
    stepStatuses: { 1: 'completed', 2: 'running' },
  },
};

chrome.storage.local.settings = {
  schemaVersion: 2,

  shared: {
    autoRunDefaults: {},
    logging: {},
  },

  services: {
    mailProviders: {},
    ipProxy: {},
    hotmailPool: {},
    mail2925Pool: {},
    icloud: {},
    customEmailPool: {},
  },

  flows: {
    openai: {
      signupMethod: 'email',
      phoneVerificationEnabled: false,
      plusModeEnabled: false,
      plusPaymentMethod: 'paypal',
      sub2api: {},
      codex2api: {},
      luckmail: {},
      smsProviders: {},
    },
  },
};

4. 四层状态边界

4.1 共享运行态 runtimeState.shared

只放“运行任何 flow 都需要”的内容:

  • activeFlowId / activeRunId / currentNodeId / nodeStatuses
  • automationWindowId
  • tabRegistry
  • sourceLastUrls
  • logs
  • 自动运行轮次、暂停、计时器计划
  • 账号产物总览,如最终身份、最终邮箱、最终手机号、完成时间

这里不要再放 OpenAI 特有概念,例如 plusCheckoutTabIdcurrentPhoneActivation

4.2 共享服务状态 runtimeState.services

放“可被多个 flow 复用的服务运行态”,而不是具体网站流程状态:

  • 邮箱 provider 当前会话
  • 2925 / Hotmail / iCloud / Cloud Mail 等共享邮箱服务上下文
  • IP 代理当前应用结果、探测结果、池游标
  • 可复用的共享账号池游标

注意:LuckMail 目前不进这一层,它仍属于 OpenAI flow 私有能力。

4.3 flow 私有运行态 runtimeState.flows[flowId]

每个 flow 自己保管自己的业务运行态。当前 OpenAI 至少应拆成:

  • authoauthUrllocalhostUrl
  • platformBindingsub2api*codex2api*
  • plusplusCheckoutTabIdplusCheckoutUrlplusBillingAddress
  • phoneVerificationcurrentPhoneActivationsignupPhoneActivationreusablePhoneActivation
  • luckmailcurrentLuckmailPurchasecurrentLuckmailMailCursor
  • identity:OpenAI 特有的登录方式冻结结果、step8VerificationTargetEmail

4.4 持久配置 settings

持久配置必须按“共享 / 服务 / flow 私有”拆开,不再把所有配置都平铺到同一个 namespace。

特别注意:

  • signupMethod 先保留在 flows.openai,不要急着抽成全局通用枚举。
  • plusModeEnabledplusPaymentMethodgopay*paypal* 都属于 OpenAI flow 私有配置。
  • phoneVerificationEnabled 当前也属于 OpenAI flow 私有配置。

5. 旧步骤兼容层怎么做

迁移阶段仍要保留 currentStep / stepStatuses,但它们不再是主数据,只是 legacyStepCompat 的派生视图。

建议规则:

  1. 新的 canonical 状态只写 activeFlowId / currentNodeId / nodeStatuses
  2. OpenAI flow 通过 node-to-step 映射生成 legacyStepCompat
  3. getState() 对旧模块仍返回:
    • currentStep
    • stepStatuses
    • OpenAI 旧字段镜像
  4. setStepStatus(step, status) 内部先更新 node,再回写 legacy step 视图

这样可以保证:

  • background/auto-run-controller.js 先不重写也能跑
  • background/logging-status.js 先不重写也能继续渲染
  • background/account-run-history.js 仍能按旧语义落盘

6. 账号记录与自动运行的兼容策略

6.1 自动运行

background/auto-run-controller.js 当前按数字步骤推断进度、失败点和恢复点。迁移阶段要增加一层统一 selector:

  • getActiveRunProgress(state)
  • getLegacyStepCompat(state)
  • inferResumeNode(state, flowId)

第一阶段可以继续让 OpenAI flow 通过旧 step 恢复;第二个 flow 接入时再真正改成 node-based resume。

6.2 账号记录

background/account-run-history.js 不能只记“失败在第几步”,还要开始记录:

  • activeFlowId
  • activeRunId
  • currentNodeId
  • nodeStatuses 摘要
  • legacyFailedStep(仅 OpenAI 兼容)

否则未来多 flow 下,单看 step7_failed 已经没有意义。

7. 命名约束

仓库里已经存在别的 flow_id 语义,用在 GPC / GoPay 远端任务里。为了避免冲突:

  • 扩展内部运行态统一使用 activeFlowId
  • 当前轮标识统一使用 activeRunId
  • 节点标识统一使用 currentNodeId
  • 不新增裸字段 flowId

flow_id 只保留给外部接口 payload 兼容使用。

8. 第一阶段迁移顺序

  1. 新增状态 selector / patch helper,不改业务步骤行为。
  2. 给 OpenAI flow 建立 flowState.openai 命名空间,同时保留旧字段镜像。
  3. 把日志、自动运行、账号记录改为优先读 selector,不直接拼 stepStatuses
  4. 把新加字段一律放进 shared / services / flows.openai,禁止继续向 DEFAULT_STATE 顶层加 OpenAI 字段。
  5. 第二个 flow 接入前,再清理旧 step 镜像的写路径。

9. 本文对应解决的缺口

本文主要补齐以下缺口:

  • DEFAULT_STATE 扁平模型没有命名空间
  • 旧步骤状态与新 node 状态如何并存
  • 自动运行 / 日志 / 账号记录如何不被状态迁移打断
  • registrationEmailState 当前仍隐含“手机号是唯一可保留主身份”的假设