|
|
|
@ -2,11 +2,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
## 目标
|
|
|
|
## 目标
|
|
|
|
|
|
|
|
|
|
|
|
实现“①发送数字货币发行请求”教学页面的后端。学生携带有效的本系统 JWT 后,可以查询商业银行库存、创建并逐步处理发行申请、查看央行端接收结果。接口不区分教师与学生角色。
|
|
|
|
实现“①发送数字货币发行请求”教学页面的后端。学生携带有效的本系统 JWT 后,可以在商业银行端查询库存、创建并逐步处理发行申请,并在中央银行端查看接收结果。接口不区分教师与学生角色。
|
|
|
|
|
|
|
|
|
|
|
|
## 范围
|
|
|
|
## 范围
|
|
|
|
|
|
|
|
|
|
|
|
本期仅覆盖页面的第 1 步:商业银行生成并发送发行请求,以及中央银行显示已接收的请求。第 2 至第 7 步(验签、业务核查、准备金扣减、数字货币生成、确权)不在本期实现范围内。
|
|
|
|
本期仅覆盖页面的第 1 步:商业银行生成并发送发行请求,以及中央银行显示已接收的请求。两个端是独立的接口入口和查询视图,但属于同一教学系统并共享发行申请数据。第 2 至第 7 步(验签、业务核查、准备金扣减、数字货币生成、确权)不在本期实现范围内。
|
|
|
|
|
|
|
|
|
|
|
|
## 限界上下文与分层
|
|
|
|
## 限界上下文与分层
|
|
|
|
|
|
|
|
|
|
|
|
@ -26,7 +26,7 @@ issuance/
|
|
|
|
persistence/ MyBatis-Plus Entity、Mapper、Repository 实现
|
|
|
|
persistence/ MyBatis-Plus Entity、Mapper、Repository 实现
|
|
|
|
crypto/ Bouncy Castle 的 SM3/SM2 实验实现
|
|
|
|
crypto/ Bouncy Castle 的 SM3/SM2 实验实现
|
|
|
|
interfaces/
|
|
|
|
interfaces/
|
|
|
|
rest/ IssuanceRequestController、CentralBankIssuanceController
|
|
|
|
rest/ CommercialBankIssuanceController、CentralBankIssuanceController
|
|
|
|
dto/ 请求与响应 DTO
|
|
|
|
dto/ 请求与响应 DTO
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
@ -36,17 +36,23 @@ issuance/
|
|
|
|
|
|
|
|
|
|
|
|
`IssuanceRequest` 保存机构代码、机构标识、发行金额、面额明细、币种、时间戳、待签名原文、摘要、签名、签名密钥标识、请求报文和当前状态。
|
|
|
|
`IssuanceRequest` 保存机构代码、机构标识、发行金额、面额明细、币种、时间戳、待签名原文、摘要、签名、签名密钥标识、请求报文和当前状态。
|
|
|
|
|
|
|
|
|
|
|
|
状态只能按下列顺序变化:
|
|
|
|
商业银行申请状态只能按下列顺序变化:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
```text
|
|
|
|
DRAFT → MESSAGE_PREPARED → DIGESTED → SIGNED → PACKAGED → SENT → RECEIVED
|
|
|
|
DRAFT → MESSAGE_PREPARED → DIGESTED → SIGNED → PACKAGED → SENT
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
中央银行接收状态独立保存:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
|
|
NOT_RECEIVED → RECEIVED
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- 只有 `DRAFT` 可修改总金额、面额明细和币种。
|
|
|
|
- 只有 `DRAFT` 可修改总金额、面额明细和币种。
|
|
|
|
- 面额数量必须为正整数,`Σ(面额 × 数量)` 必须等于发行总金额。
|
|
|
|
- 面额数量必须为正整数,`Σ(面额 × 数量)` 必须等于发行总金额。
|
|
|
|
- `prepare-message` 只允许从 `DRAFT` 执行,并冻结时间戳和待签名原文。
|
|
|
|
- `prepare-message` 只允许从 `DRAFT` 执行,并冻结时间戳和待签名原文。
|
|
|
|
- `digest`、`sign`、`package` 只允许在前一状态执行。
|
|
|
|
- `digest`、`sign`、`package` 只允许在前一状态执行。
|
|
|
|
- `send` 从 `PACKAGED` 进入 `SENT` 后,在同一事务中立即进入 `RECEIVED`,模拟中央银行已接收;重复发送返回同一请求,不生成第二笔记录。
|
|
|
|
- `send` 从 `PACKAGED` 进入 `SENT` 后,在同一事务中将中央银行接收状态设为 `RECEIVED` 并记录接收时间,模拟中央银行已接收;重复发送返回同一请求,不生成第二笔记录。
|
|
|
|
- 已到达目标状态的重复按钮请求返回当前数据,不重新计算摘要或签名。
|
|
|
|
- 已到达目标状态的重复按钮请求返回当前数据,不重新计算摘要或签名。
|
|
|
|
|
|
|
|
|
|
|
|
待签名原文采用固定字段顺序:
|
|
|
|
待签名原文采用固定字段顺序:
|
|
|
|
@ -70,27 +76,27 @@ ISSUE|{bankCode}|{organizationId}|{totalAmount}|{denominations}|{currency}|{time
|
|
|
|
| 表 | 关键字段 | 用途 |
|
|
|
|
| 表 | 关键字段 | 用途 |
|
|
|
|
| --- | --- | --- |
|
|
|
|
| --- | --- | --- |
|
|
|
|
| `issuance_bank_inventory` | `bank_code`、`current_balance`、`warning_threshold` | 查询库存、预警阈值和建议补充金额。预置 `BKCHCNBJ00001`。 |
|
|
|
|
| `issuance_bank_inventory` | `bank_code`、`current_balance`、`warning_threshold` | 查询库存、预警阈值和建议补充金额。预置 `BKCHCNBJ00001`。 |
|
|
|
|
| `issuance_request` | `id`、`request_no`、`bank_code`、`organization_id`、`total_amount`、`currency`、`request_timestamp`、`message_text`、`digest`、`signature`、`signing_key_ref`、`payload_json`、`status`、审计字段 | 发行申请聚合持久化。 |
|
|
|
|
| `issuance_request` | `id`、`request_no`、`bank_code`、`organization_id`、`total_amount`、`currency`、`request_timestamp`、`message_text`、`digest`、`signature`、`signing_key_ref`、`payload_json`、`status`、`central_receive_status`、`central_received_at`、审计字段 | 发行申请聚合持久化。 |
|
|
|
|
| `issuance_request_denomination` | `request_id`、`denomination`、`quantity` | 发行请求的面额明细,`request_id + denomination` 唯一。 |
|
|
|
|
| `issuance_request_denomination` | `request_id`、`denomination`、`quantity` | 发行请求的面额明细,`request_id + denomination` 唯一。 |
|
|
|
|
|
|
|
|
|
|
|
|
建议补充金额始终计算为 `max(warning_threshold - current_balance, 0)`,不单独持久化。
|
|
|
|
建议补充金额始终计算为 `max(warning_threshold - current_balance, 0)`,不单独持久化。
|
|
|
|
|
|
|
|
|
|
|
|
## REST 接口
|
|
|
|
## REST 接口
|
|
|
|
|
|
|
|
|
|
|
|
所有接口均以 `/api/v1/issuance` 开头,要求有效 JWT,不添加角色限定。
|
|
|
|
所有接口要求有效 JWT,不添加角色限定。商业银行端与中央银行端使用不同的 URL 前缀和 Controller;中央银行端不提供创建、修改、签名或发送操作。
|
|
|
|
|
|
|
|
|
|
|
|
| 方法与路径 | 作用 |
|
|
|
|
| 方法与路径 | 作用 |
|
|
|
|
| --- | --- |
|
|
|
|
| --- | --- |
|
|
|
|
| `GET /inventory?bankCode=BKCHCNBJ00001` | 返回库存余额、预警阈值、建议补充金额。 |
|
|
|
|
| `GET /api/v1/commercial-banks/issuance/inventory?bankCode=BKCHCNBJ00001` | 商业银行端返回库存余额、预警阈值、建议补充金额。 |
|
|
|
|
| `POST /requests` | 创建 `DRAFT` 发行申请,返回申请 ID 与基础数据。 |
|
|
|
|
| `POST /api/v1/commercial-banks/issuance/requests` | 商业银行端创建 `DRAFT` 发行申请。 |
|
|
|
|
| `PUT /requests/{id}` | 仅在 `DRAFT` 更新金额、面额明细和币种。 |
|
|
|
|
| `PUT /api/v1/commercial-banks/issuance/requests/{id}` | 商业银行端仅在 `DRAFT` 更新金额、面额明细和币种。 |
|
|
|
|
| `GET /requests/{id}` | 返回商业银行端完整申请与处理产物。 |
|
|
|
|
| `GET /api/v1/commercial-banks/issuance/requests/{id}` | 商业银行端返回完整申请与处理产物。 |
|
|
|
|
| `POST /requests/{id}/prepare-message` | 冻结时间戳并生成待签名原文。 |
|
|
|
|
| `POST /api/v1/commercial-banks/issuance/requests/{id}/prepare-message` | 商业银行端冻结时间戳并生成待签名原文。 |
|
|
|
|
| `POST /requests/{id}/digest` | 对待签名原文生成 SM3 摘要。 |
|
|
|
|
| `POST /api/v1/commercial-banks/issuance/requests/{id}/digest` | 商业银行端对待签名原文生成 SM3 摘要。 |
|
|
|
|
| `POST /requests/{id}/sign` | 使用 `sm2-key-02` 生成 SM2 签名。 |
|
|
|
|
| `POST /api/v1/commercial-banks/issuance/requests/{id}/sign` | 商业银行端使用 `sm2-key-02` 生成 SM2 签名。 |
|
|
|
|
| `POST /requests/{id}/package` | 生成包含请求号、机构、金额、面额、币种、时间戳、摘要和签名的 JSON 报文。 |
|
|
|
|
| `POST /api/v1/commercial-banks/issuance/requests/{id}/package` | 商业银行端生成请求 JSON 报文。 |
|
|
|
|
| `POST /requests/{id}/send` | 模拟发送至中央银行并返回 `RECEIVED`。 |
|
|
|
|
| `POST /api/v1/commercial-banks/issuance/requests/{id}/send` | 商业银行端模拟发送;申请变为 `SENT`,中央银行接收状态变为 `RECEIVED`。 |
|
|
|
|
| `GET /central-bank/requests/{id}` | 返回中央银行端接收状态和 JSON 报文。 |
|
|
|
|
| `GET /api/v1/central-banks/issuance/requests/{id}` | 中央银行端返回接收状态、接收时间和 JSON 报文。 |
|
|
|
|
|
|
|
|
|
|
|
|
不存在的申请返回 `RESOURCE_NOT_FOUND`;状态不合法或金额校验不通过返回 `VALIDATION_ERROR`;未认证请求沿用既有 Spring Security 的 `UNAUTHORIZED` 响应。
|
|
|
|
不存在的申请返回 `RESOURCE_NOT_FOUND`;状态不合法或金额校验不通过返回 `VALIDATION_ERROR`;未认证请求沿用既有 Spring Security 的 `UNAUTHORIZED` 响应。
|
|
|
|
|
|
|
|
|
|
|
|
|