8.3 KiB
8.3 KiB
PRD:UR#73 按运营商实名能力控制复机
Status: ready-for-agent
Problem Statement
当前停复机代码同时存在“行业卡无需实名”和“所有卡都必须实名”的互相冲突分支。卡业务类别被错误当成实名能力,导致相同运营商能力下出现不同复机结果,也使手动复机、设备复机、自动复机和开放接口无法共享同一规则。
七月迭代的数据同步公共方案将卡实名、流量和网络状态收口到统一 DDD 边界。UR#73 不能继续在旧 Service 中补条件,否则会形成第二套卡状态规则和状态写入口。
Solution
复机是否要求实名只由卡所属运营商的 realname_link_type 决定:none 不要求实名,template 和 gateway 要求卡已实名。card_category 仅保留分类展示用途,不再参与任何复机资格判断。
该规则进入数据同步公共 Asset/Card 领域模型,由统一复机 Application UseCase 供后台单卡、设备、自动任务和 OpenAPI 调用。Gateway 成功后的状态收敛、领域事件、Outbox、Audit Event 和同步触发全部复用公共 DDD,不在旧 Service 直接更新卡状态。
User Stories
- 作为运营人员,我希望不支持实名能力的运营商卡即使本地仍为未实名,也可在满足其他条件时复机。
- 作为运营人员,我希望需要实名的运营商卡在未实名时被明确拒绝。
- 作为运营人员,我希望普通卡和行业卡遵循相同的运营商能力规则,卡类别不再造成例外。
- 作为设备操作人员,我希望设备下每张卡独立按其运营商能力判断,不因设备中其他卡的状态被错误放行或拦截。
- 作为 OpenAPI 调用方,我希望复机与后台入口使用同一资格规则。
- 作为维护人员,我希望所有入口只调用一个复机用例,避免轮询、Service 和 Handler 各自维护规则。
- 作为审计人员,我希望成功、拒绝和失败都进入统一审计链路并能关联后续同步观测。
Implementation Decisions
业务规则
realname_link_type=none表示运营商不要求实名;复机资格不检查real_name_status。realname_link_type=template或gateway表示运营商要求实名;仅real_name_status=1可继续复机。card_category=normal/industry只用于分类和展示,不参与手动复机、设备复机、自动复机、套餐触发复机或 OpenAPI 复机判断。周期轮询资格不由 UR#73 调整。realname_policy只描述实名与购买顺序,不替代运营商能力;本需求不得用它决定复机是否要求实名。- 保留所有既有非实名约束,包括风险停机、已销户、机卡分离状态限定、停复机保护期、有效套餐、流量耗尽、网络状态和数据权限。
- 多卡设备逐卡判断。满足条件的卡正常处理,不满足条件的卡跳过或拒绝;不得因其中一张卡无需实名而放行全部卡。
- 未知
realname_link_type、运营商记录缺失或配置读取失败属于配置/内部错误,不得静默按none放行,也不得调用 Gateway。 - 未实名拒绝继续使用统一禁止访问业务错误,并向用户返回中文原因“卡未实名,无法操作”。
DDD 与公共数据同步边界
- 本需求依赖七月“数据同步触发与轮询优化”公共能力先落地;公共能力尚未完成时,不允许先在旧 StopResume Service 中打临时补丁。
- “运营商是否要求实名”和“卡当前是否具备复机资格”属于 Asset/Card 领域规则。领域方法只接收已加载的运营商能力和卡状态,不直接查询 GORM、Redis、Fiber 或 Gateway。
- 后台单卡复机、后台设备复机、自动复机、套餐激活后的复机和 OpenAPI 复机统一调用 Application 复机用例;各入口不得自行判断
card_category、real_name_status或realname_link_type。 - Application 用例负责加载并锁定必要状态、调用领域资格规则、执行 Gateway 端口、记录业务结果并发布可靠事件。
- 旧 Service 如需过渡,只能作为无业务判断的内部门面转发到新用例;不得继续直接写实名、网络状态、停机原因或复机时间。
ApplyCardObservation是上游观测写入卡状态的唯一入口。复机 Gateway 返回成功不授权旧 Service 直接修改本地网络状态。- 复机成功边界发布网络状态同步触发,按公共方案创建立即、3 分钟、5 分钟观测序列;观测结果通过
ApplyCardObservation应用,达到开机预期后剩余任务直接完成。 - 状态变化产生统一领域事件和 Outbox,触发其他业务联动;不得由多个入口重复执行相同副作用。UR#94 本期保持现有轮询调度和重排策略。
- Audit Event 和 Integration Log 使用公共审计设施;不得继续扩展旧资产审计为第二套长期写入系统。
接口与前端
- 后台继续复用
POST /api/admin/assets/{identifier}/start;卡和设备均走统一复机用例。 - OpenAPI 继续复用现有卡复机接口;机卡分离限定仍先于一般复机规则生效。
- 本需求不新增 API,不因规则修正改变成功响应外层结构。
- 前端不读取
card_category预判,不在本地复制运营商能力规则。 - 提交期间禁用重复操作;失败原地展示后端中文业务原因;成功后重新拉取资产详情。
- 详情刷新读取本地状态快照;异步观测尚未收敛时沿用公共同步状态展示,不伪造 Gateway 已确认结果。
发布与兼容
- 删除或改造所有以
card_category=industry跳过实名的生产分支和注释。 - 删除手动单卡、设备批量及自动复机中直接判断“必须已实名”的重复分支,统一转调领域规则。
- 发布前核查
realname_link_type!=none但资产realname_policy=none的冲突数据;修正结果遵循公共数据同步方案,不在运行时静默选边。 - API、Worker 和公共卡状态能力在同一维护窗口切换,不保留新旧复机规则双写或双判定。
Testing Decisions
- 领域单元测试覆盖
none/template/gateway与实名 0/1、普通/行业卡的完整矩阵,并证明卡类别不影响结果。 - Application 测试使用可控 Gateway Adapter,验证不合格时绝不调用 Gateway,合格时只调用一次,并正确发布审计和同步触发。
- HTTP 集成测试覆盖后台卡复机、设备复机和 OpenAPI 入口,穿过真实认证、权限和统一错误处理;PostgreSQL、Redis 使用开发配置,Gateway 使用测试 Adapter,禁止对真实业务卡执行停复机。
- 验证设备内混合运营商能力、混合实名状态时逐卡处理,不发生整设备误放行。
- 回归风险停机、销户、保护期、无有效套餐、流量耗尽、非机卡分离 OpenAPI 卡等既有限制。
- 验证 Gateway 成功后旧 Service 没有直接写状态,公共同步序列生成一次,观测确认后由
ApplyCardObservation更新状态并提前完成剩余任务。 - 验证重复请求、重复事件和重复观测不造成重复 Gateway 调用、重复领域事件或重复审计。
- 人工验收使用明确隔离的联调卡,对三个运营商能力值分别验证;核对 PostgreSQL 状态、Outbox/Audit Event、Integration Log 和同步任务关联链路。
Out of Scope
- 不修改
card_category的存储和展示。 - 不新增实名能力字段,继续使用运营商
realname_link_type。 - 不重新设计风险停机、销户、机卡分离、保护期、套餐或流量规则。
- 不新增显式同步按钮或同步 API。
- 不修改周期轮询的卡资格、卡类别过滤、配置、频率、队列或重排策略;UR#94 只把轮询观测的状态应用收口到公共用例。
- 不在 UR#73 单独实现公共观测、Outbox、审计或 0/3/5 调度的另一份副本。
- 不通过本需求处理运营商回调、事件同步和全部数据同步入口;回调与事件由 UR#94 交付,周期轮询策略本轮保持现状并留待后续设计。
Further Notes
- 推荐实施顺序:数据同步公共 DDD → UR#73 接入统一复机用例 → 前后端联调。
- 当前代码仍存在行业卡豁免、强制实名和直接写网络状态等多套实现;它们是迁移输入,不是目标架构。
- 本 Spec 对数据同步公共 DDD 的复用是硬约束,不得以“先快速修一行”替代。