From dd9ab4459018638f0ba51d62b6e38f535fadf489 Mon Sep 17 00:00:00 2001 From: chenyuan Date: Tue, 18 Aug 2026 10:25:07 +0800 Subject: [PATCH] docs: define downstream wallet prerequisite projection --- ...m-wallet-prerequisite-projection-design.md | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 docs/superpowers/specs/2026-08-18-downstream-wallet-prerequisite-projection-design.md diff --git a/docs/superpowers/specs/2026-08-18-downstream-wallet-prerequisite-projection-design.md b/docs/superpowers/specs/2026-08-18-downstream-wallet-prerequisite-projection-design.md new file mode 100644 index 0000000..9e2ad28 --- /dev/null +++ b/docs/superpowers/specs/2026-08-18-downstream-wallet-prerequisite-projection-design.md @@ -0,0 +1,127 @@ +# 模块 4/5 下游按需读取钱包前置数据设计 + +## 目标 + +建立模块 1 至模块 5 的真实业务数据关联,同时保持模块边界:模块 3 只记录钱包开通实验事实,不提前创建模块 4 或模块 5 的操作数据;模块 4、模块 5 在用户实际进入时主动读取前置模块结果。 + +## 已确认的业务边界 + +- 模块 3 完成钱包申请、证书生成、央行备案、合约生成、钱包激活和最终确认,只写 `walletopening` 模块自己的结果表。 +- 模块 4 的付款用户必须完成模块 1、模块 2、模块 3;模块 4 从模块 2 读取商业银行币串库存,从模块 3 读取已开通钱包资料。 +- 模块 5 的付款方必须已经通过模块 4 取得数字货币币串;模块 5 的收款方只需要完成模块 3 并拥有已激活钱包。 +- 下游读取必须按 `user_id + school_id + class_id` 隔离。按银行编码查询机构标识时也必须保留该隔离范围。 +- 进入模块页面只能加载或初始化前置资源,不得创建兑换订单、支付订单或对应步骤记录。 + +## 数据所有权 + +### 模块 3 实验事实 + +以下表继续由模块 3 独占写入: + +- `wallet_application` +- `bank_received_wallet_application` +- `wallet_verification_record` +- `wallet_identifier_generation` +- `wallet_registration_request` +- `central_wallet_registration` +- `smart_contract_generation` +- `central_wallet_activation` + +模块 4、模块 5 对这些表只读,不反向修改。 + +### 共享钱包运行态 + +以下表定义为模块间共享的、可交易的钱包运行态,不属于模块 4 或模块 5 的步骤数据: + +- `digital_wallet` +- `wallet_certificate` +- `wallet_contract` +- `simulated_bank_account` +- `wallet_bank_binding` + +共享运行态只在模块 4 或模块 5 首次需要该钱包时,由下游按模块 3 最终结果幂等初始化。后续余额、冻结金额和额度累计值由真实兑换、支付业务更新,初始化逻辑不得覆盖已有值。 + +## 读取与初始化流程 + +新增一个共享的前置钱包读取服务,供模块 4 和模块 5 调用。 + +1. 接收当前主体 `userId`、`schoolId`、`classId`;按钱包标识读取收款人时,先定位钱包所属主体,再使用其完整主体范围校验。 +2. 查询模块 3 同一主体的最新一轮结果,所有组成数据必须来自同一用户、学校和班级。 +3. 验证以下完成条件: + - `central_wallet_activation.wallet_activated = true`; + - `central_wallet_activation.final_sent = true`; + - `central_wallet_activation.cb_final_signature` 非空; + - `central_wallet_registration.cb_root_signature` 非空且备案流程已完成; + - `wallet_identifier_generation.status = 'CERT_ISSUED'`,证书公钥、私钥和序列号完整; + - `smart_contract_generation.status = 'SENT'`,合约标识和额度字段完整; + - `wallet_application.status = 'SUBMITTED'`,银行卡、开户行、钱包类型和账户余额完整。 +4. 任一条件不满足时返回业务校验错误,错误信息指出尚未完成的钱包开通前置步骤,不创建任何共享运行态记录。 +5. 条件全部满足时,在一个事务内按依赖顺序插入缺失的共享记录:银行卡账户、钱包、证书、合约、绑定关系。 +6. 如果共享钱包已经存在,只验证其归属与模块 3 结果一致,然后返回;不得更新余额、冻结金额、额度累计值、证书密钥或绑定关系。 +7. 初始化完成后,模块 4、模块 5 继续使用现有共享运行态仓储完成签名、冻结、扣款、限额累计和余额更新。 + +## 字段来源 + +| 共享字段 | 模块 3 来源 | +|---|---| +| 钱包标识 | `central_wallet_activation.wallet_id` | +| 钱包类型 | `smart_contract_generation.wallet_type` | +| 央行最终确认签名 | `central_wallet_activation.cb_final_signature` | +| 钱包开户时间 | `central_wallet_activation.final_time`,无法解析时使用共享记录初始化时间 | +| 证书序列号、公私钥 | `wallet_identifier_generation` 对应字段 | +| 央行根签名 | `central_wallet_registration.cb_root_signature` | +| 合约标识、额度、摘要 | `smart_contract_generation` 对应字段 | +| 银行编码 | 当前主体对应的 `institution_identifier_application.bank_code` | +| 银行名称、银行卡号、银行账户初始余额 | `wallet_application` 对应字段 | +| 钱包初始余额、冻结金额 | `0.00` | +| 银行账户冻结金额 | `0.00` | + +共享银行账户标识使用稳定、可重复生成的值,保证重复初始化不会产生多条账户记录。银行卡末四位由完整卡号计算。 + +## 模块调用关系 + +### 模块 4 + +`GET /api/v1/exchanges/context` 在读取兑换上下文前调用共享前置钱包读取服务。成功后继续通过现有 `JdbcExchangeResourceRepository` 读取钱包、证书、合约、银行卡账户及模块 2 币串库存。只有创建兑换请求时才写 `currency_exchange_order` 等模块 4 表。 + +### 模块 5 + +支付上下文加载时分别处理双方: + +- 付款方:读取或初始化其模块 3 钱包运行态,并继续校验模块 4 形成的 `WALLET/AVAILABLE` 币串;没有币串时拒绝支付。 +- 收款方:按收款钱包标识读取模块 3 最终结果并初始化运行态,不要求其完成模块 4。 + +模块 5 查询机构标识时使用钱包所属用户、学校、班级和银行编码共同限定,禁止只按 `bank_code` 取最新记录。 + +## 并发与幂等 + +- 初始化方法使用事务。 +- 共享表已有唯一键继续作为并发保护;出现并发插入时重新读取并验证归属,不覆盖先写入的数据。 +- 初始化只执行“缺失则插入”,不能使用会更新已有余额或额度字段的 upsert。 +- 如果发现共享记录与模块 3 的钱包标识、用户或银行卡绑定不一致,返回冲突错误,不自动修正。 + +## 错误处理 + +- 模块 3 未完成:返回业务校验错误,并指出需要先完成个人数字钱包开通实验。 +- 模块 1 机构标识缺失或主体不匹配:返回业务校验错误,不允许跨用户或跨班级回退。 +- 模块 4 币串库存不足:沿用模块 4 现有库存错误。 +- 模块 5 付款方没有模块 4 形成的钱包币串:返回余额或币串不足错误。 +- 模块 3 数据与已存在共享运行态冲突:返回数据冲突错误,保留双方数据供排查。 + +## 测试与验收 + +1. 模块 3 未完成时访问模块 4,接口拒绝,并且五张共享运行态表没有新增记录。 +2. 模块 3 完成后访问模块 4,能够读取钱包、合约、证书、银行卡和模块 2 库存;模块 4 订单仍为空。 +3. 重复访问模块 4 不覆盖已发生变化的钱包余额、银行卡余额和额度累计值。 +4. 模块 5 付款方完成模块 3 但未取得模块 4 币串时,支付被拒绝。 +5. 模块 5 收款方只完成模块 3 时,可以作为合法收款钱包被读取。 +6. 相同银行编码下存在其他用户、学校或班级数据时,不会读取到错误机构标识或钱包结果。 +7. 模块 4/5 读取和交易后,模块 3 的八张实验事实表内容不被修改。 +8. 现有模块 2→4 币串权属和模块 4→5 支付币串链路继续通过定向集成测试。 + +## 不在本次范围 + +- 不修改模块 3 页面步骤、接口顺序或评分逻辑。 +- 不把模块 3 的历史轮次迁移到共享运行态。 +- 不重构模块 4/5 的交易流水、签名或央行权属模型。 +- 不处理当前全量测试中与本关联改动无关的错误码断言差异。