You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
digital-rmb-backend/docs/superpowers/specs/2026-08-03-issuance-request...

7.8 KiB

数字货币发行请求模块设计

目标

实现“①发送数字货币发行请求”教学页面的后端。学生携带有效的本系统 JWT 后,可以在商业银行端查询库存、创建并逐步处理发行申请,并在中央银行端查看接收结果。接口不区分教师与学生角色。

范围

本期仅覆盖页面的第 1 步:商业银行生成并发送发行请求,以及中央银行显示已接收的请求。两个端是独立的接口入口和查询视图,但属于同一教学系统并共享发行申请数据。第 2 至第 7 步(验签、业务核查、准备金扣减、数字货币生成、确权)不在本期实现范围内。

限界上下文与分层

扩展既有 issuance 限界上下文,不新增顶层模块。IssuanceRequest 是聚合根;库存查询是该上下文的只读查询模型。

issuance/
  domain/
    model/        IssuanceRequest、IssuanceApplicationId、DenominationItem、IssuanceRequestStatus
    repository/   IssuanceRequestRepository
    service/      IssuanceMessageComposer、IssuanceSignatureService
  application/
    command/      CreateIssuanceRequestCommand、UpdateDenominationsCommand
    query/        IssuanceInventoryQueryService、IssuanceRequestQueryService
    service/      IssuanceRequestApplicationService
  infrastructure/
    persistence/  MyBatis-Plus Entity、Mapper、Repository 实现
    crypto/       Bouncy Castle 的 SM3/SM2 实验实现
  interfaces/
    rest/         CommercialBankIssuanceController、CentralBankIssuanceController
    dto/          请求与响应 DTO

依赖方向保持 interfaces → application → domaininfrastructure 只实现领域端口。Controller 不直接调用 Mapper。

聚合与状态机

IssuanceRequest 保存机构代码、机构标识、发行金额、面额明细、币种、时间戳、待签名原文、摘要、签名、签名密钥标识、请求报文和当前状态。

商业银行申请状态只能按下列顺序变化:

DRAFT → MESSAGE_PREPARED → DIGESTED → SIGNED → PACKAGED → SENT

中央银行接收状态独立保存:

NOT_RECEIVED → RECEIVED
  • 只有 DRAFT 可修改总金额、面额明细和币种。
  • 面额数量必须为正整数,Σ(面额 × 数量) 必须等于发行总金额。
  • prepare-message 只允许从 DRAFT 执行,并冻结时间戳和待签名原文。
  • digestsignpackage 只允许在前一状态执行。
  • sendPACKAGED 进入 SENT 后,在同一事务中将中央银行接收状态设为 RECEIVED 并记录接收时间,模拟中央银行已接收;重复发送返回同一请求,不生成第二笔记录。
  • 已到达目标状态的重复按钮请求返回当前数据,不重新计算摘要或签名。

待签名原文采用固定字段顺序:

ISSUE|{bankCode}|{organizationId}|{totalAmount}|{denominations}|{currency}|{timestamp}

denominations 按面额从大到小序列化为 面额:数量,例如 100:400,50:100,20:200,10:50,5:80,1:100

密码学教学实现

服务端使用 Bouncy Castle 提供的 SM3 和 SM2 算法:摘要为 SM3 十六进制文本,签名算法为 SM3withSM2。私钥不通过接口输入或返回。

本期通过 SigningKeyProvider 端口提供 sm2-key-02 实验密钥;基础设施实现仅在服务端生成并缓存密钥对。响应只暴露 signingKeyRef、摘要和签名。后续第 2 步验签可替换为配置化或密钥库实现,不改变聚合和接口契约。

数据模型

基础初始化脚本 src/main/resources/schema.sql 增加以下幂等表和演示数据:

关键字段 用途
issuance_bank_inventory bank_codecurrent_balancewarning_threshold 查询库存、预警阈值和建议补充金额。预置 BKCHCNBJ00001
issuance_request idrequest_nobank_codeorganization_idtotal_amountcurrencyrequest_timestampmessage_textdigestsignaturesigning_key_refpayload_jsonstatuscentral_receive_statuscentral_received_at、审计字段 发行申请聚合持久化。
issuance_request_denomination request_iddenominationquantity 发行请求的面额明细,request_id + denomination 唯一。

建议补充金额始终计算为 max(warning_threshold - current_balance, 0),不单独持久化。

REST 接口

所有接口要求有效 JWT不添加角色限定。商业银行端与中央银行端使用不同的 URL 前缀和 Controller中央银行端不提供创建、修改、签名或发送操作。

方法与路径 作用
GET /api/v1/commercial-banks/issuance/inventory?bankCode=BKCHCNBJ00001 商业银行端返回库存余额、预警阈值、建议补充金额。
POST /api/v1/commercial-banks/issuance/requests 商业银行端创建 DRAFT 发行申请。
PUT /api/v1/commercial-banks/issuance/requests/{id} 商业银行端仅在 DRAFT 更新金额、面额明细和币种。
GET /api/v1/commercial-banks/issuance/requests/{id} 商业银行端返回完整申请与处理产物。
POST /api/v1/commercial-banks/issuance/requests/{id}/prepare-message 商业银行端冻结时间戳并生成待签名原文。
POST /api/v1/commercial-banks/issuance/requests/{id}/digest 商业银行端对待签名原文生成 SM3 摘要。
POST /api/v1/commercial-banks/issuance/requests/{id}/sign 商业银行端使用 sm2-key-02 生成 SM2 签名。
POST /api/v1/commercial-banks/issuance/requests/{id}/package 商业银行端生成请求 JSON 报文。
POST /api/v1/commercial-banks/issuance/requests/{id}/send 商业银行端模拟发送;申请变为 SENT,中央银行接收状态变为 RECEIVED
GET /api/v1/central-banks/issuance/requests/{id} 中央银行端返回接收状态、接收时间和 JSON 报文。

不存在的申请返回 RESOURCE_NOT_FOUND;状态不合法或金额校验不通过返回 VALIDATION_ERROR;未认证请求沿用既有 Spring Security 的 UNAUTHORIZED 响应。

Swagger 文档

Swagger 页面使用中文,所有新增 Java 源文件和 OpenAPI 元数据以 UTF-8 保存,页面不允许出现乱码。发行域接口按以下中文标签分组:

  • 数字货币发行模块 - 商业银行端:库存查询、创建申请、更新申请、生成原文、摘要、签名、封装和发送。
  • 数字货币发行模块 - 中央银行端:查询发行请求接收状态、接收时间和请求报文。

每个接口通过中文 summarydescription 明确说明所属模块、所属端、调用条件、状态变化及返回内容;请求字段和响应字段使用中文 @Schema 描述。OpenAPI 根标题固定为“数字人民币教学仿真后端”,接口分组和接口说明不得使用英文替代中文。

测试标准

  • 领域单元测试覆盖金额守恒、非法状态流转和重复发送幂等性。
  • 应用/持久化测试覆盖库存建议金额、请求与面额明细的保存和读取。
  • MockMvc 测试覆盖学生有效 JWT 下的所有首期接口,以及未认证被拒绝。
  • 密码学测试校验 SM3 输出长度和 SM2 签名可由同一实验公钥验证。
  • 全量 Maven 测试在 JDK 8 下通过;以 dev profile 启动后Swagger 页面可访问。
  • 访问 /v3/api-docs 和 Swagger UI确认“数字货币发行模块 - 商业银行端”“数字货币发行模块 - 中央银行端”标签及中文说明可正常显示,不含乱码字符。

明确约束

  • 使用 JDK 8、Spring Boot 2.7.18、MyBatis-Plus 3.5.17、Spring Security 5.7。
  • 不恢复 Flyway所有基础表变化同步更新幂等 schema.sql 并在 118 测试库验证。
  • 不在日志、接口响应或数据库中保存私钥明文。
  • 不实现真实央行网络调用、准备金扣减或数字货币生成。