Compare commits

...

3 Commits

Author SHA1 Message Date
35f2f9b76c Record REV004 late-fee formal-table deployment and canary evidence
This documents that the formal-table deploy SQL has been applied to the
application-dev database, that the previous real-db blocker is resolved,
and that the date-mode late-fee reduce canary now passes against the
test database.

Constraint: Evidence must match the verified dev database and latest canary output
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep evidence updates aligned with the exact environment and command outputs used for verification
Tested: Evidence cross-checked against psql deployment output and fresh canary pass
Not-tested: No additional business flow beyond the documented late-fee date-mode canary
2026-04-15 16:14:03 +08:00
d0ee1cbc17 Align REV004 dictionaries with current interface semantics
Document the minimal dictionary additions and field-binding rules needed to
let REV004 front-end queries and dropdowns use system-managed object and
status semantics while continuing to reuse the existing legacy reason/type
dictionaries.

Constraint: Existing dictionary taxonomy must remain stable for historical pages
Constraint: REV004 needs explicit object/status dictionaries plus a redink reason set for FE binding
Rejected: Rename legacy dictionaries into a new unified taxonomy | too broad for this delivery and risks breaking existing pages
Rejected: Keep object/status values as code-only enums | insufficient for frontend dictionary binding
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: `payment_reason` is only a transitional binding for `WRITTENOFF_ADJUST`; introduce a dedicated writtenoff reason dictionary only when that object stabilizes long-term
Tested: Applied `sql/rev004_account_adjust_dict_seed.sql` to sw_system test DB and verified inserted dict types/data
Not-tested: Frontend page consumption against the new dictionary bindings
2026-04-07 17:53:47 +08:00
9d2ecf1cf6 docs: align planb deployment design with reviewed topology 2026-04-02 17:30:06 +08:00
7 changed files with 683 additions and 212 deletions

View File

@ -117,6 +117,7 @@
> 说明:本表中的历史记录按当时原始表述保留;当前正式数据库口径统一以“达梦数据库 8.0+”为准。
| 2026-03-26 | 方案二整体部署方案独立成文 | 1新增 `docs/design/03_Technical_Design/08_Integrated_Deployment_Design_PlanB.md`,将已采纳 PostgreSQL 16 方案二后的整体部署方案独立成文2结合当前前后端分层部署形态补齐应用、数据库、中间件、静态存储的一体化部署结构3新增软件拓扑图、网络拓扑图、主机角色划分、资源配置建议、网络需求和端口访问建议4`07_PostgreSQL16_DR_Resource_Application.md` 增加独立文档引用说明,在技术专项目录增加入口。 | 用户明确要求不要仅在 `07` 文档内保留方案二内容,而是需要形成独立文件,并作为已采纳数据库方案后的整体部署方案提交评审。 | 正面影响,数据库资源申请专题与整体部署方案实现职责分离;后续甲方可分别评审“数据库容灾资源申请”和“系统整体部署方案”,减少口径混杂并提升部署审批的可读性。 |
| 2026-04-02 | 方案二整体部署文档按网络图口径对齐 | 1`docs/design/03_Technical_Design/08_Integrated_Deployment_Design_PlanB.md` 的网络分区口径统一为“办公区 / 公网区域 / 互联网区DMZ / 内网区”2`Nginx` 入口、业务应用节点、`SFTP/FTP` 文件交换服务器的部署区域说明统一调整为与评审图一致3同步修正网络拓扑图、访问链路、带宽/端口、资源角色及结论段落中的命名与边界表述。 | 用户提供最新部署图,要求正式文档向图片口径靠拢,消除 `内网 Nginx`、应用区/DMZ、办公区等描述不一致问题。 | 正面影响,整体部署方案的图文一致性显著提升,便于甲方按统一网络边界和主机分区口径开展安全评审与资源审批。 |
| 2026-03-18 | REV-005 统计模板补齐 | 1`specs/002-rev005-invoice-flow/verification.md``T055``T060``T061``T062``T063` 新增可直接填写的样本记录模板2将 SC-001 ~ SC-004 的建议统计口径细化为表格字段与待补说明避免后续只剩抽象待办3保持“模板已补齐但实际统计结果仍待联调/测试环境补录”的真实状态,不虚构样本结果。 | 用户继续推进 REV-005希望把剩余统计类待办进一步收敛成可执行模板便于后续直接补录真实样本而不是重新设计统计格式。 | 正面影响REV-005 当前已具备统一的统计与日志抽样记录模板;后续补 `T055``T060 ~ T063` 时可直接按模板填充真实环境数据,减少再次整理验证文档结构的成本。 |
| 2026-03-18 | REV-005 verify 执行入口补齐 | 1`specs/002-rev005-invoice-flow/verification.md` 补齐 `/business/invoice/apply``/query``/query/compensate``/write-back``/customer/query``/customer/download``/customer/push``/invalidate``/red-ink` 的最小请求模板2继续补齐 `T055``T060 ~ T063` 的执行命令草稿与样本采集顺序,明确仅作为测试/联调环境占位模板真实地址、鉴权信息、业务主键与统计结果均待后续替换和回填3同步 `03_Task_Checklist.md`,将 verify 阶段推进到“替换真实环境参数即可执行”的状态。 | 用户继续推进 REV-005希望不要停留在抽象验证建议而是把剩余 verify 工作推进到可直接执行、可直接补样本的程度。 | 正面影响REV-005 当前已具备统一的验证入口、请求模板、命令草稿与采样顺序;后续在测试或联调环境中可直接替换参数发起请求并回填 `T055``T060 ~ T063` 的真实结果,减少重复梳理接口和命令的成本。 |

View File

@ -53,15 +53,15 @@ retrieval_priority: P1
1. 数据库部署方案已采纳 `docs/design/03_Technical_Design/07_PostgreSQL16_DR_Resource_Application.md` 中的方案二,即“同城双可用区主备容灾方案”。
2. 前端继续采用 `Nginx + Vue3` 的静态部署模式。
3. 对外访问经甲方或第三方管理的公网入口进行薄转发,不纳入本方案主机资源范围。
4. 内网 `Nginx` 单独部署,负责将开放 API 端点负载到两台业务应用节点。
5. 两台业务应用节点内均部署 `Spring Boot Gateway`,作为微服务集群统一接入入口,并同时承载业务服务。
4. `Nginx` 入口单独部署在互联网区 `DMZ`,负责承接办公网、公网入口和外部授权链路转发,并将开放 API 端点负载到两台业务应用节点。
5. 两台业务应用节点部署在互联网区 `DMZ`,节点内均部署 `Spring Boot Gateway`,作为微服务集群统一接入入口,并同时承载业务服务。
6. 中间件集中部署在 1 台主机上。
7. 数据库控制组件与中间件部署在同一台主机上。
8. `RustFS` 作为静态存储与对象存储统一入口,与中间件同机部署。
9. 一期口径下,原“数据与中间件节点”和“文件存储节点”合并为 1 台综合节点。
10. 银行文件交换采用独立 `SFTP/FTP` 文件交换服务器,作为银行送盘、回盘、对账文件交换专用前置机。
10. 银行文件交换采用独立 `SFTP/FTP` 文件交换服务器,并部署在互联网区 `DMZ`作为银行送盘、回盘、对账文件交换专用前置机。
11. 当前已知可用于本方案的业务与基础设施主机资源如下:
- 内网 Nginx 入口节点8 核 CPU / 16 GB 内存 / 300 GB 存储,共 1 台
- DMZ Nginx 入口节点8 核 CPU / 16 GB 内存 / 300 GB 存储,共 1 台
- 业务应用节点32 核 CPU / 64 GB 内存 / 300 GB 存储,共 2 台
- 数据、中间件与文件存储综合节点16 核 CPU / 32 GB 内存 / 2300 GB 存储,共 1 台
- 银行文件交换服务器2 核 CPU / 8 GB 内存 / 200 GB 存储,共 1 台
@ -75,8 +75,8 @@ retrieval_priority: P1
2. 中间件集中部署,降低主机数量和运维复杂度。
3. 数据库主备分离部署,避免与中间件、应用节点混部。
4. 数据库控制组件集中部署,通过统一代理地址屏蔽主备切换细节。
5. 网络按公网接入区、内网接入区、应用区、中间件与文件存储区、银行文件交换区、数据区分层隔离
6. 在现有主机数量约束下,优先复用现有业务应用节点、内网入口节点及综合节点资源。
5. 网络按办公区、公网区域、互联网区 `DMZ`、内网区分层隔离;其中数据库、中间件控制与备份归档均落在内网区
6. 在现有主机数量约束下,优先复用现有业务应用节点、DMZ Nginx 入口节点及综合节点资源。
## 软件拓扑图
@ -87,67 +87,71 @@ flowchart LR
classDef source fill:#ecfeff,stroke:#0891b2,stroke-width:1.2px,color:#083344;
classDef access fill:#fff7ed,stroke:#ea580c,stroke-width:1.4px,color:#7c2d12;
classDef app fill:#eff6ff,stroke:#2563eb,stroke-width:1.4px,color:#1e3a8a;
classDef zone fill:#f8fafc,stroke:#94a3b8,stroke-width:1.2px,color:#0f172a;
subgraph OUTER[公网域]
subgraph OFFICE[办公区]
direction TB
U1[PC 端用户<br/>办公网段]:::source
end
subgraph PUBLIC[公网区域]
direction TB
U2[移动端用户]:::source
U3[第三方系统]:::source
G1[公网接入代理]:::access
G1[公网授权入口]:::access
end
subgraph INNER[内部网络域]
subgraph DMZ[互联网区 / DMZ]
direction TB
U1[PC 端用户]:::source
G2[内网 Nginx]:::access
G2[Nginx 入口]:::access
A1[业务应用节点 1<br/>Spring Boot Gateway + 业务服务]:::app
A2[业务应用节点 2<br/>Spring Boot Gateway + 业务服务]:::app
end
subgraph APP1[业务应用节点 1]
direction TB
A1G[Spring Boot Gateway]:::app
A1B[业务服务]:::app
end
class OFFICE,PUBLIC,DMZ zone;
subgraph APP2[业务应用节点 2]
direction TB
A2G[Spring Boot Gateway]:::app
A2B[业务服务]:::app
end
U1 -->|内网访问| G2
U1 -->|办公网访问,内网 IP| G2
U2 -->|HTTPS 443| G1
U3 -->|接口访问| G1
G1 -->|跨公网/内网边界转发| G2
G2 -->|负载到节点 1| A1G
G2 -->|负载到节点 2| A2G
A1G --> A1B
A2G --> A2B
U3 -->|HTTPS / API| G1
G1 -->|授权转发| G2
G2 -->|API 转发| A1
G2 -->|API 转发| A2
```
图说明:
1. 图中已明确区分公网域与内部网络域
2. PC 端用户通过内网直接访问内部网络域中的内网 Nginx
3. 移动端用户和第三方系统位于公网域,先经公网接入代理,再跨边界转发到内部网络域中的内网 Nginx
4. 内网 Nginx 将开放 API 端点负载到两台业务应用节点。
5. 两台业务应用节点内均部署 Spring Boot Gateway作为微服务集群统一接入入口。
6. 每台业务应用节点内的 Gateway 再向本节点业务服务转发请求
1. 图中已明确区分办公区、公网区域和互联网区 `DMZ`
2. PC 端用户位于办公区,经办公网使用内网 IP 直接访问 `DMZ` 内的 `Nginx` 入口
3. 移动端用户和第三方系统位于公网区域,先经公网授权入口,再跨边界进入 `DMZ` 内的 `Nginx` 入口
4. `Nginx` 入口位于互联网区 `DMZ`,负责将开放 API 端点负载到两台业务应用节点。
5. 两台业务应用节点位于互联网区 `DMZ`,节点内均部署 `Spring Boot Gateway`,作为微服务集群统一接入入口。
6. 公网入口后侧涉及的边界路由与 `NAT` 转换属于甲方网络侧能力,本图不展开网络设备细节
**图 4-2 综合服务软件拓扑图**
```mermaid
flowchart TB
classDef zone fill:#f8fafc,stroke:#94a3b8,stroke-width:1.2px,color:#0f172a;
classDef app fill:#eff6ff,stroke:#2563eb,stroke-width:1.4px,color:#1e3a8a;
classDef service fill:#f5f3ff,stroke:#7c3aed,stroke-width:1.4px,color:#4c1d95;
A1[业务应用节点 1<br/>Gateway + Biz]:::app
A2[业务应用节点 2<br/>Gateway + Biz]:::app
subgraph M[综合节点]
direction TB
M2[Redis / Nacos / RustFS]:::service
M3[HAProxy / PgBouncer / Patroni]:::service
subgraph DMZ[互联网区 / DMZ]
direction LR
A1[业务应用节点 1<br/>Gateway + Biz]:::app
A2[业务应用节点 2<br/>Gateway + Biz]:::app
end
subgraph INTRA[内网区]
direction TB
subgraph M[综合节点]
direction TB
M2[Redis / Nacos / RustFS]:::service
M3[HAProxy / PgBouncer / Patroni]:::service
end
end
class DMZ,INTRA zone;
A1 -->|缓存 配置 文件访问| M2
A2 -->|缓存 配置 文件访问| M2
A1 -->|数据库代理访问| M3
@ -156,31 +160,43 @@ flowchart TB
图说明:
1. 综合节点承接缓存、配置、对象存储及数据库控制组件。
2. 两台业务应用节点统一访问综合节点,不直接连接数据库。
1. 综合节点位于内网区,承接缓存、配置、对象存储及数据库控制组件。
2. 两台 `DMZ` 业务应用节点统一访问内网区综合节点,不直接连接数据库。
**图 4-3 数据与备份软件拓扑图**
```mermaid
flowchart LR
classDef zone fill:#f8fafc,stroke:#94a3b8,stroke-width:1.2px,color:#0f172a;
classDef service fill:#f5f3ff,stroke:#7c3aed,stroke-width:1.4px,color:#4c1d95;
classDef data fill:#ecfdf5,stroke:#059669,stroke-width:1.4px,color:#064e3b;
classDef backup fill:#fffbeb,stroke:#d97706,stroke-width:1.4px,color:#78350f;
classDef bank fill:#fef2f2,stroke:#dc2626,stroke-width:1.4px,color:#7f1d1d;
M2[RustFS / 文件归档]:::service
M3[HAProxy / PgBouncer / Patroni]:::service
F1[SFTP / FTP 文件交换服务器]:::bank
D1[(PostgreSQL 主库)]:::data
D2[(PostgreSQL 热备)]:::data
B1[备份归档存储]:::backup
subgraph DMZ[互联网区 / DMZ]
F1[SFTP / FTP 文件交换服务器]:::bank
end
M3 -->|数据库访问| D1
M3 -->|状态感知| D2
D1 -->|同步复制| D2
D1 -->|基础备份 WAL 归档| B1
subgraph INTRA[内网区]
direction LR
subgraph M[综合节点]
direction TB
M1[数据库管理控件 / 中间件]:::service
M2[对象存储 / RustFS]:::service
end
D1[(PostgreSQL 主库)]:::data
D2[(PostgreSQL 热备)]:::data
B1[备份归档存储]:::backup
end
class DMZ,INTRA zone;
M1 -->|5432 数据库访问| D1
M1 -.->|5432 状态探测| D2
D1 -->|主备同步| D2
D1 -->|备份 / WAL 归档| B1
D2 -->|备份副本| B1
M2 -->|对象存储归档| B1
M2 -->|文件归档| B1
F1 -->|银行文件归档| B1
```
@ -188,7 +204,7 @@ flowchart LR
1. 数据库控制组件经由主库提供数据库访问能力。
2. 主库与热备之间通过同步复制保持一致性。
3. 银行文件交换服务器承接送盘、回盘、对账文件交换能力。
3. 银行文件交换服务器位于互联网区 `DMZ`承接送盘、回盘、对账文件交换能力。
4. RustFS 与银行文件交换服务器分别将各自数据归档到备份归档存储。
## 主机部署图
@ -201,14 +217,15 @@ flowchart LR
classDef app fill:#eff6ff,stroke:#2563eb,stroke-width:1.2px,color:#1e3a8a;
classDef middle fill:#f5f3ff,stroke:#7c3aed,stroke-width:1.2px,color:#4c1d95;
classDef data fill:#ecfdf5,stroke:#059669,stroke-width:1.2px,color:#064e3b;
GW[内网 Nginx 入口节点]:::gateway
classDef backup fill:#fffbeb,stroke:#d97706,stroke-width:1.2px,color:#78350f;
GW[DMZ Nginx 入口节点]:::gateway
APP1[业务应用节点 1<br/>内含 Gateway]:::app
APP2[业务应用节点 2<br/>内含 Gateway]:::app
MID[综合节点]:::middle
FTP[SFTP / FTP 文件交换服务器]:::middle
MID[综合节点]:::middle
DB1[(数据库主库服务器)]:::data
DB2[(数据库热备服务器)]:::data
BK[备份归档存储]:::backup
GW --> APP1
GW --> APP2
@ -219,23 +236,26 @@ flowchart LR
MID --> DB1
MID --> DB2
DB1 --> DB2
DB1 --> BK
DB2 --> BK
MID --> BK
```
图说明:
1. 内网 Nginx 入口节点作为我方统一接入入口,承接 API 转发与内部负载均衡能力
2. 业务应用节点 1 和业务应用节点 2 组成应用主机集群,节点内同时部署 Spring Boot Gateway 与核心业务服务
3. 综合节点集中承载 Redis、Nacos、RustFS、HAProxy、PgBouncer、Patroni并同时访问数据库主库与热备服务器
4. 独立的 SFTP/FTP 文件交换服务器承接银行送盘、回盘、对账文件交换,并由业务应用节点直接访问
5. 数据库主库服务器与数据库热备服务器独立部署,满足数据库高可用要求
1. 本图仅表达主机与主机之间的部署关系,不重复展开办公区、公网区域和跨边界访问链路
2. `Nginx` 入口节点、业务应用节点和 `SFTP/FTP` 文件交换服务器部署在互联网区 `DMZ`
3. 综合节点、数据库主库服务器、数据库热备服务器和备份归档存储部署在内网区
4. 业务应用节点经 `DMZ Nginx` 接入,并访问综合节点与 `SFTP/FTP` 文件交换服务器
5. 综合节点统一访问 PostgreSQL 主库与热备;主库、热备和综合节点均向备份归档存储输出数据
主机部署细化说明:
1. 内网 Nginx 入口节点部署 `Nginx`,负责开放 API 转发和内部负载均衡。
2. 两台业务应用节点分别部署 `Spring Boot Gateway` 与业务服务实例。
3. 综合节点部署 `Redis``Nacos``RustFS``HAProxy``PgBouncer``Patroni`,并负责访问数据库主库与热备服务器。
4. SFTP/FTP 文件交换服务器部署银行文件交换服务及送盘、回盘、对账目录,由业务应用节点直接访问。
5. 数据库主库服务器部署 PostgreSQL 主库实例,数据库热备服务器部署 PostgreSQL 热备实例。
1. 互联网区 `DMZ``Nginx` 入口节点部署 `Nginx`,负责开放 API 转发和内部负载均衡。
2. 两台互联网区 `DMZ` 业务应用节点分别部署 `Spring Boot Gateway` 与业务服务实例。
3. 内网区综合节点部署 `Redis``Nacos``RustFS``HAProxy``PgBouncer``Patroni`,并负责访问数据库主库与热备服务器。
4. 互联网区 `DMZ``SFTP/FTP` 文件交换服务器部署银行文件交换服务及送盘、回盘、对账目录,由业务应用节点直接访问。
5. 内网区数据库主库服务器部署 PostgreSQL 主库实例,数据库热备服务器部署 PostgreSQL 热备实例。
## 数据库访问链路图
@ -288,7 +308,7 @@ flowchart LR
## 网络拓扑图
> 说明:如需生成正式网络分区图与网络连接图,统一以 `scripts/generate_planb_diagrams.py` 生成的产物为准;其他脚本仅用于布局试验,不作为正式交付依据。
> 说明:如需生成正式网络分区图,统一以 `scripts/generate_planb_diagrams.py` 生成的产物为准;其他脚本仅用于布局试验,不作为正式交付依据。
**图 4-7 网络分区图**
@ -302,50 +322,47 @@ flowchart LR
classDef bank fill:#fef2f2,stroke:#dc2626,stroke-width:1.2px,color:#7f1d1d;
classDef backup fill:#fffbeb,stroke:#d97706,stroke-width:1.2px,color:#78350f;
U[用户与外部系统]:::user
PGW[公网接入代理]:::edge
subgraph Z1[内网接入区]
IGW[内网 Nginx]
subgraph Z1[办公区]
PC[PC 端用户]
end
subgraph Z2[应用区]
subgraph Z2[公网区域]
PUB[移动端用户 / 第三方系统]
EDGE[公网入口 / 边界路由 / NAT]
BANK[银行系统]
end
subgraph Z3[互联网区 / DMZ]
IGW[Nginx 入口]
APP[业务应用集群]
end
subgraph Z3[综合服务区]
MID[综合节点]
end
subgraph Z4[数据区]
DBM[(PostgreSQL 主库)]
DBS[(PostgreSQL 热备)]
end
subgraph Z6[互联网银行交换区]
FX[SFTP / FTP 文件交换服务器]
end
subgraph Z5[机房接入区]
subgraph Z4[内网区]
MID[综合节点]
DBM[(PostgreSQL 主库)]
DBS[(PostgreSQL 热备)]
BK[备份归档存储]
end
class Z1,Z2,Z3,Z4,Z5,Z6 zone;
class IGW edge;
class APP svc;
class MID svc;
class Z1,Z2,Z3,Z4 zone;
class PC,PUB user;
class EDGE,IGW edge;
class APP,MID svc;
class DBM,DBS data;
class FX bank;
class BK backup;
U --> PGW
U --> IGW
PGW --> IGW
PC --> IGW
PUB --> EDGE
BANK --> IGW
BANK --> FX
EDGE --> IGW
IGW --> APP
APP --> FX
APP --> MID
MID --> DBM
MID --> DBS
MID -.-> DBS
DBM --> BK
DBS --> BK
MID --> BK
@ -353,94 +370,17 @@ flowchart LR
图说明:
1. 公网接入代理不纳入我方主机资源,但作为公网访问进入内网的前置接入层予以保留。
2. 网络分区图按服务器和服务器集群粒度表达,不展开单机内部软件组件。
3. PC 端用户可直接通过内网访问内网 Nginx移动端和第三方系统经公网接入代理后进入内网 Nginx。
4. 业务应用集群、综合服务区、数据区、机房接入区、互联网银行交换区相互隔离,通过授权链路互通。
**图 4-8 网络连接图**
```mermaid
flowchart TB
classDef user fill:#ecfeff,stroke:#0891b2,stroke-width:1.2px,color:#083344;
classDef access fill:#fff7ed,stroke:#ea580c,stroke-width:1.2px,color:#7c2d12;
classDef app fill:#eff6ff,stroke:#2563eb,stroke-width:1.2px,color:#1e3a8a;
classDef middle fill:#f5f3ff,stroke:#7c3aed,stroke-width:1.2px,color:#4c1d95;
classDef data fill:#ecfdf5,stroke:#059669,stroke-width:1.2px,color:#064e3b;
classDef backup fill:#fffbeb,stroke:#d97706,stroke-width:1.2px,color:#78350f;
classDef bank fill:#fef2f2,stroke:#dc2626,stroke-width:1.2px,color:#7f1d1d;
subgraph OUTER[公网域]
direction LR
M[移动端用户]:::user
T[第三方系统]:::user
FX[SFTP/FTP文件交换服务器]:::bank
end
subgraph INNER[内部网络域]
direction TB
subgraph CLIENT[客户端]
PC[PC 端用户]:::user
end
subgraph ACCESS[接入层]
PGW[公网接入代理]:::access
IGW[内网 Nginx]:::access
end
subgraph SVC[应用与中间件层]
APP[业务应用集群<br/>Spring Boot Gateway + Biz]:::app
CACHE[Redis / Nacos / RustFS]:::middle
CTRL[HAProxy / PgBouncer / Patroni]:::middle
end
subgraph DATA[数据层]
DBM[(PostgreSQL 主库)]:::data
DBS[(PostgreSQL 热备)]:::data
end
subgraph STORAGE[存储层]
STORE[备份归档存储]:::backup
end
end
%% 公网访问链路
M -->|HTTPS 443| PGW
T -->|HTTPS 443 / 接口| PGW
PGW -->|请求转发| IGW
%% 内网访问链路
PC -->|内网访问| IGW
IGW -->|网关/应用端口| APP
%% 应用层依赖
APP -->|6379 / 8848 / 9000| CACHE
APP -->|文件传输| FX
APP -->|6432 / 5000| CTRL
CTRL -->|5432| DBM
CTRL -.->|5432 状态探测| DBS
DBM -->|主备同步| DBS
%% 数据备份与归档
CACHE -->|归档文件| STORE
DBM -->|备份 / WAL 归档| STORE
DBS -.->|备份副本| STORE
```
图说明:
1. 图中已明确区分公网域与内部网络域,公网访问通过公网接入代理跨边界进入内部网络。
2. PC 端用户位于内部网络域,直接访问内网 Nginx移动端和第三方系统位于公网域。
3. 内网 Nginx 统一将 API / Gateway 请求负载到业务应用集群。
4. 业务应用集群分别访问综合服务、银行文件交换服务器和数据库控制组件。
5. 综合服务中的数据库控制组件同时访问 PostgreSQL 主库与热备;数据库与综合服务均向备份归档存储输出归档数据。
1. 公网入口、边界路由和 `NAT` 转发不纳入我方主机资源,但作为公网访问进入 `DMZ` 的前置接入层予以保留。
2. 网络分区图按办公区、公网区域、互联网区 `DMZ`、内网区四区模型表达,不展开单机内部软件组件。
3. PC 端用户可直接通过办公网访问 `DMZ` 中的 `Nginx` 入口;移动端和第三方系统经公网入口、边界路由或 `NAT` 转发后进入 `DMZ`
4. `DMZ` 中的 `Nginx` 入口、业务应用集群、银行文件交换服务器与内网区综合节点、数据库、备份归档存储通过授权链路互通。
5. 银行系统除通过 `SFTP/FTP` 目录交换文件外,还可按授权专线或外联链路访问 `DMZ Nginx` 暴露的 API 入口,网络分区图已同步表达这两类授权链路。
## 主机角色与部署内容
| 层级 | 主机角色 | 数量 | 主要部署内容 | 说明 |
|---|---|---:|---|---|
| 接入层 | 内网 Nginx 入口节点 | 1 台 | Nginx、API 转发、内部负载均衡 | 作为我方统一内网接入入口,承接开放 API 转发 |
| 接入层 | DMZ Nginx 入口节点 | 1 台 | Nginx、API 转发、内部负载均衡 | 作为我方统一 DMZ 接入入口,承接办公网访问、公网转发与开放 API 转发 |
| 应用层 | 业务应用节点(主) | 2 台 | Spring Boot Gateway、Spring Boot 业务服务 | 承载微服务集群接入与表务、抄表、收费、账务、发票、报表等核心应用服务 |
| 综合支撑层 | 数据、中间件与文件存储综合节点 | 1 台 | Redis、Nacos、RustFS、HAProxy、PgBouncer、Patroni | 中间件、数据库控制与文件存储同机部署 |
| 银行交换层 | SFTP/FTP 文件交换服务器 | 1 台 | SFTP/FTP 服务、送盘目录、回盘目录、对账目录、归档目录 | 作为银行文件交换专用前置机 |
@ -452,7 +392,7 @@ flowchart TB
| 主机角色 | 数量 | 建议配置 | 备注 |
|---|---:|---|---|
| 内网 Nginx 入口节点 | 1 台 | 8 核 CPU / 16 GB 内存 / 300 GB 存储 | 承载内网 Nginx、API 转发和内部负载均衡 |
| DMZ Nginx 入口节点 | 1 台 | 8 核 CPU / 16 GB 内存 / 300 GB 存储 | 承载 DMZ Nginx、API 转发和内部负载均衡 |
| 业务应用节点(主) | 2 台 | 32 核 CPU / 64 GB 内存 / 300 GB 存储 | 承载 Spring Boot Gateway 及表务、抄表、收费、账务、发票、报表等核心应用服务 |
| 数据、中间件与文件存储综合节点 | 1 台 | 16 核 CPU / 32 GB 内存 / 2300 GB 存储 | 承载缓存、配置治理、数据库控制、图片、附件等非结构化数据 |
| SFTP/FTP 文件交换服务器 | 1 台 | 2 核 CPU / 8 GB 内存 / 200 GB 存储 | 承载银行送盘、回盘、对账、归档文件交换,建议独立部署 |
@ -483,7 +423,7 @@ flowchart TB
| 序号 | 资源名称 | 数量 | 规格 | 部署内容 | 用途说明 | 建议口径 |
|---|---:|---:|---|---|---|---|
| 1 | 内网 Nginx 入口节点 | 1 台 | 8 核 CPU / 16 GB 内存 / 300 GB 存储 | Nginx、API 转发、内部负载均衡 | 我方统一内网接入入口 | 可利旧优先 |
| 1 | DMZ Nginx 入口节点 | 1 台 | 8 核 CPU / 16 GB 内存 / 300 GB 存储 | Nginx、API 转发、内部负载均衡 | 我方统一 DMZ 接入入口 | 可利旧优先 |
| 2 | 业务应用节点(主) | 2 台 | 32 核 CPU / 64 GB 内存 / 300 GB 存储 | Spring Boot Gateway、Spring Boot 核心业务服务 | 承载微服务接入与核心业务服务 | 现有资源纳入正式方案 |
| 3 | 数据、中间件与文件存储综合节点 | 1 台 | 16 核 CPU / 32 GB 内存 / 2300 GB 存储 | Redis、Nacos、RustFS、HAProxy、PgBouncer、Patroni | 承载缓存、配置治理、数据库控制、图片、附件、导出文件等能力 | 现有资源纳入正式方案 |
| 4 | SFTP/FTP 文件交换服务器 | 1 台 | 2 核 CPU / 8 GB 内存 / 200 GB 存储 | SFTP/FTP 服务、送盘/回盘/对账目录、归档目录 | 承载银行文件交换与目录隔离 | 按最节约一期规划建议新增或单独利旧 |
@ -493,7 +433,7 @@ flowchart TB
### 审批建议
1. 业务应用节点、综合节点、内网 Nginx 入口节点可优先按现有资源纳入实施范围。
1. 业务应用节点、综合节点、DMZ Nginx 入口节点可优先按现有资源纳入实施范围。
2. SFTP/FTP 文件交换服务器建议单独审批,以满足银行文件交换隔离和安全要求。
3. PostgreSQL 主库与热备库建议作为单独审批项,避免与现有业务节点混部。
4. 备份归档存储建议作为单独资源项审批,避免后期因备份空间不足影响正式上线。
@ -504,7 +444,7 @@ flowchart TB
|---|---|---|---|---|
| 操作系统 | Linux 发行版 | 银河麒麟Kylin V10X86 | 全部服务器 | 按甲方当前基础环境标准选定 |
| 运行环境 | JDK | 17 | 业务应用节点 | Spring Boot 运行环境 |
| 接入层 | Nginx | 1.20+ | 内网 Nginx 入口节点 | 内网 API 转发、内部负载均衡 |
| 接入层 | Nginx | 1.20+ | DMZ Nginx 入口节点 | 办公网、公网入口转发与内部负载均衡 |
| 网关服务 | Spring Boot Gateway | 3.x | 业务应用节点 | 微服务集群统一接入 |
| 业务服务 | Spring Boot | 3.x | 业务应用节点 | 核心业务服务框架 |
| 银行文件交换 | SFTP/FTP 服务 | 稳定版 | SFTP/FTP 文件交换服务器 | 银行送盘、回盘、对账文件交换 |
@ -531,7 +471,7 @@ flowchart TB
| 组件 | 部署节点 | 建议部署方式 | 是否建议 `host` 模式 | 说明 |
|---|---|---|---|---|
| 内网 Nginx | 内网 Nginx 入口节点 | Docker 部署 | 是,优先建议 | 作为我方统一接入入口,便于端口管理与转发 |
| DMZ Nginx | DMZ Nginx 入口节点 | Docker 部署 | 是,优先建议 | 作为我方统一 DMZ 接入入口,便于端口管理与转发 |
| Spring Boot Gateway | 业务应用节点(主) | Docker 部署 | 否 | 作为微服务统一接入入口,建议与业务服务同节点部署 |
| Spring Boot 应用 | 业务应用节点(主) | Docker 部署 | 否 | 便于发布、回滚、扩容,保留容器网络隔离 |
| SFTP/FTP 服务 | SFTP/FTP 文件交换服务器 | 物理机/虚拟机直接部署 | 否 | 作为银行文件交换专用服务,建议独立部署并做目录隔离 |
@ -548,7 +488,7 @@ flowchart TB
结合当前资源结构,建议优先采用 `Docker + host` 模式的组件如下:
1. `内网 Nginx`
1. `DMZ Nginx`
2. `HAProxy`
3. `PgBouncer`
@ -573,18 +513,18 @@ flowchart TB
| 网络分区 | 部署对象 | 访问要求 |
|---|---|---|
| 公网接入区 | 公网入口薄转发 | 对外提供 HTTPS 访问,不纳入我方主机资源 |
| 应用区 | 业务应用节点 | 仅允许内网接入区与运维区访问 |
| 中间件与文件存储区 | Redis、Nacos、RustFS、数据库控制组件 | 仅允许业务应用节点与运维区访问 |
| 银行文件交换区 | SFTP/FTP 文件交换服务器 | 仅允许业务应用节点、银行专线或授权外联链路访问 |
| 数据区 | PostgreSQL 主库、热备库、备份存储 | 严格限制,仅允许中间件控制主机和运维区访问 |
| 办公区 | PC 端用户办公网段 | 仅允许通过办公网访问 `DMZ Nginx` 入口 |
| 公网区域 | 移动端用户、第三方系统、公网入口薄转发、边界路由 / NAT | 对外提供 HTTPS 访问,不纳入我方主机资源 |
| 互联网区 DMZ | `DMZ Nginx`、业务应用节点、`SFTP/FTP` 文件交换服务器 | 作为对外与跨边界服务区,仅允许按授权链路访问内网区 |
| 内网区 | Redis、Nacos、RustFS、数据库控制组件、PostgreSQL 主库/热备、备份归档存储 | 严格限制,仅允许 `DMZ` 业务应用节点、综合节点控制链路和运维区访问 |
### 2. 带宽与时延要求
| 网络链路 | 建议要求 | 说明 |
|---|---|---|
| 公网入口薄转发到内网 Nginx | 千兆网络 | 满足公网入口转发 |
| 内网 Nginx 到业务应用 | 千兆网络 | 满足开放 API 转发与网关接入 |
| 公网入口薄转发到 DMZ Nginx | 千兆网络 | 满足公网入口转发 |
| 办公网到 DMZ Nginx | 千兆网络 | 满足办公网通过内网 IP 访问 |
| DMZ Nginx 到业务应用 | 千兆网络 | 满足开放 API 转发与网关接入 |
| 业务应用到综合节点 | 千兆网络 | 满足缓存、配置治理、文件访问与数据库代理访问 |
| 业务应用到 SFTP/FTP 服务器 | 千兆网络 | 满足送盘、回盘、对账文件交换 |
| 银行链路到 SFTP/FTP 服务器 | 千兆网络或专线 | 满足银行文件交换与目录投递 |
@ -599,9 +539,11 @@ flowchart TB
| 类别 | 开通要求 | 说明 |
|---|---|---|
| 对外访问 | 开通 443 端口 | 提供统一 HTTPS 入口 |
| 公网入口薄转发访问内网 Nginx | 开通公网入口到内网 Nginx 的转发端口 | 仅授权链路访问 |
| 内网 Nginx 访问应用 | 开通内网 Nginx 到业务应用的 API / 网关端口 | 仅内网访问 |
| 应用访问综合节点 | 开通 Redis、Nacos、RustFS、PgBouncer 相关端口 | 仅应用区访问 |
| 公网入口薄转发访问 DMZ Nginx | 开通公网入口到 DMZ Nginx 的转发端口 | 仅授权链路访问 |
| 办公网访问 DMZ Nginx | 开通办公网到 DMZ Nginx 的内网访问端口 | 仅办公网访问 |
| 银行专线或授权外联链路访问 DMZ Nginx | 开通银行链路到 DMZ Nginx 的 HTTPS/API 端口 | 仅银行授权链路访问 |
| DMZ Nginx 访问应用 | 开通 DMZ Nginx 到业务应用的 API / 网关端口 | 仅 DMZ 内部访问 |
| 应用访问综合节点 | 开通 Redis、Nacos、RustFS9000/9001、PgBouncer 相关端口 | 仅 DMZ 业务应用节点访问 |
| 业务应用访问 SFTP/FTP 服务器 | 开通 SFTP/FTP 相关端口 | 用于银行文件送盘、回盘、对账交换 |
| 银行链路访问 SFTP/FTP 服务器 | 开通 FTP/SFTP 服务端口 | 仅银行授权链路访问 |
| 综合节点访问数据库 | 开通 PostgreSQL 5432 及健康检查相关端口 | 仅综合节点访问 |
@ -612,12 +554,14 @@ flowchart TB
| 源区域/源主机 | 目标区域/目标主机 | 协议/端口 | 用途 | 开通要求 |
|---|---|---|---|---|
| 外部用户 | 公网入口薄转发 | HTTPS/443 | 页面访问、接口入口 | 对外开放 |
| 公网入口薄转发 | 内网 Nginx 入口节点 | HTTP/HTTPS/转发端口 | 公网访问转入内网入口 | 授权链路放通 |
| 内网 Nginx 入口节点 | 业务应用节点(主) | HTTP/HTTPS/网关端口 | 内网 API 转发与微服务接入 | 内网放通 |
| 公网入口薄转发 | DMZ Nginx 入口节点 | HTTP/HTTPS/转发端口 | 公网访问转入 DMZ 入口 | 授权链路放通 |
| 办公网段 | DMZ Nginx 入口节点 | HTTP/HTTPS/内网访问端口 | 办公网用户访问系统入口 | 仅办公网放通 |
| 银行专线或授权外联链路 | DMZ Nginx 入口节点 | HTTPS/API 端口 | 银行系统访问 DMZ API 入口 | 仅授权链路放通 |
| DMZ Nginx 入口节点 | 业务应用节点(主) | HTTP/HTTPS/网关端口 | DMZ API 转发与微服务接入 | DMZ 内部放通 |
| 业务应用节点(主) | 综合节点 | TCP/6379 | Redis 访问 | 内网放通 |
| 业务应用节点(主) | 综合节点 | TCP/8848 | Nacos 访问 | 内网放通 |
| 业务应用节点(主) | 综合节点 | TCP/6432 | PgBouncer 访问 | 内网放通 |
| 业务应用节点(主) | 综合节点 | RustFS 对象存储端口 | RustFS 文件访问 | 内网放通 |
| 业务应用节点(主) | 综合节点 | TCP/9000、9001 | RustFS 文件访问与控制台访问 | 内网放通 |
| 业务应用节点(主) | SFTP/FTP 文件交换服务器 | TCP/21 或 22 | 银行送盘、回盘、对账文件交换 | 内网放通 |
| 银行专线或授权外联链路 | SFTP/FTP 文件交换服务器 | TCP/21 或 22 | 银行文件目录投递与回收 | 仅授权链路放通 |
| 综合节点 | PostgreSQL 主库服务器 | TCP/5432 | 数据库代理与控制访问 | 内网放通 |
@ -631,11 +575,11 @@ flowchart TB
| 服务 | 典型端口 | 访问范围 |
|---|---|---|
| Nginx/HTTPS | 443 | 对外开放 |
| Spring Boot Gateway / 业务应用端口 | 项目自定义端口 | 仅内网 Nginx 与内网调用 |
| Nginx/HTTPS | 443 | 对外开放、办公网授权访问及银行授权链路访问 |
| Spring Boot Gateway / 业务应用端口 | 项目自定义端口 | 仅 DMZ Nginx 与 DMZ/内网授权调用 |
| Redis | 6379 | 仅业务应用与运维可访问 |
| Nacos | 8848 | 仅业务应用与运维可访问 |
| RustFS | 按 RustFS 实际部署端口 | 仅业务应用与运维可访问 |
| RustFS | 9000S3 API、9001Console | 仅业务应用与运维可访问 |
| SFTP/FTP 服务 | 21 或 22 | 仅业务应用节点、运维和银行授权链路可访问 |
| PgBouncer | 6432 | 仅业务应用可访问 |
| HAProxy | 5000 或项目定义端口 | 仅 PgBouncer 与运维可访问 |
@ -645,7 +589,7 @@ flowchart TB
### 1. 基础资源准备
1. 确认内网 Nginx 入口节点、业务应用节点、综合节点是否为利旧资源。
1. 确认 `DMZ Nginx` 入口节点、业务应用节点、综合节点是否为利旧资源。
2. 完成 SFTP/FTP 文件交换服务器、PostgreSQL 主库服务器、热备服务器及备份归档存储审批。
3. 完成各网络分区、IP、域名、SSL 证书、路由及防火墙策略准备。
@ -653,7 +597,7 @@ flowchart TB
1. 安装操作系统并完成安全基线加固。
2. 在业务应用节点安装 JDK、部署业务运行环境。
3. 在内网 Nginx 入口节点安装 Nginx。
3. 在 `DMZ Nginx` 入口节点安装 Nginx。
4. 在综合节点安装 Redis、Nacos、RustFS、HAProxy、PgBouncer、Patroni。
5. 在 SFTP/FTP 文件交换服务器安装 SFTP/FTP 服务并配置目录结构。
6. 在数据库主备节点安装 PostgreSQL 16。
@ -669,7 +613,7 @@ flowchart TB
### 4. 应用与存储部署
1. 在业务应用节点部署 Spring Boot Gateway 和业务应用服务。
2. 在内网 Nginx 入口节点配置 API 转发和内部负载均衡规则。
2. 在 `DMZ Nginx` 入口节点配置 API 转发和内部负载均衡规则。
3. 在综合节点初始化 RustFS 存储桶和访问策略。
4. 在 SFTP/FTP 文件交换服务器配置送盘、回盘、对账、归档目录。
5. 配置业务应用到 Redis、Nacos、RustFS、PgBouncer 的连接参数。
@ -693,7 +637,7 @@ flowchart TB
| 验收项 | 验收标准 | 说明 |
|---|---|---|
| 对外访问 | 用户可通过统一域名正常访问系统 | 公网入口薄转发与内网 Nginx 链路正常 |
| 对外访问 | 用户可通过统一域名正常访问系统 | 公网入口薄转发与 DMZ Nginx 链路正常 |
| 业务应用可用性 | 表务、抄表、收费、账务、发票、报表等核心服务正常 | 业务主流程可执行 |
| Redis 可用性 | 缓存读写正常 | 中间件能力正常 |
| Nacos 可用性 | 配置下发正常 | 配置治理能力正常 |
@ -711,9 +655,9 @@ flowchart TB
本方案的最终结论如下:
1. 公网入口薄转发不纳入我方主机资源;我方实际部署的统一接入入口为内网 Nginx 入口节点。
2. 2 台业务应用节点作为核心业务集群,节点内同时部署 Spring Boot Gateway 和业务服务,承接微服务统一接入与核心业务处理。
3. 综合节点集中承载 Redis、Nacos、RustFS 及数据库控制组件,进一步压缩一期主机数量并降低部署复杂度。
1. 公网入口薄转发、边界路由和 `NAT` 不纳入我方主机资源;我方实际部署的统一接入入口为互联网区 `DMZ``Nginx` 入口节点。
2. 2 台业务应用节点部署在互联网区 `DMZ`,节点内同时部署 `Spring Boot Gateway` 和业务服务,承接微服务统一接入与核心业务处理。
3. 综合节点集中承载 `Redis``Nacos``RustFS` 及数据库控制组件,并部署在内网区,进一步压缩一期主机数量并降低部署复杂度。
## RustFS 产品介绍与选型说明
@ -725,6 +669,6 @@ RustFS 是一款支持私有化部署的 S3 兼容对象存储方案,可用于
2. RustFS 支持私有化部署,适合甲方对自主可控和本地化部署的要求。
3. RustFS 可作为独立对象存储组件部署在综合节点中,与缓存、配置治理和数据库控制能力协同运行。
4. 当前方案中,银行文件交换仍由独立的 SFTP/FTP 文件交换服务器承接RustFS 不承担银行送盘、回盘和对账文件交换职责。
4. 新增 1 台 SFTP/FTP 文件交换服务器,作为银行送盘、回盘、对账文件交换专用前置机。
5. PostgreSQL 16 采用同城双可用区 1 主 1 热备部署,满足高可用要求。
6. 网络采用公网接入区、内网接入区、应用区、中间件与文件存储区、银行文件交换区、数据区分层隔离模式,以满足安全性、可维护性和资源审批要求。
5. 新增 1 台 SFTP/FTP 文件交换服务器,作为银行送盘、回盘、对账文件交换专用前置机。
6. PostgreSQL 16 采用同城双可用区 1 主 1 热备部署,满足高可用要求。
7. 网络采用办公区、公网区域、互联网区 `DMZ`、内网区分层隔离模式,以满足安全性、可维护性和资源审批要求。

View File

@ -0,0 +1,162 @@
# REV004 账务调整统一标准层 — 第一批代码启动证据2026-04-15
## 本轮新增代码
### 标准层 helper
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/accountingadjust/standard/AccountingAdjustSemanticMapper.java`
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/accountingadjust/standard/AccountingAdjustDictResolver.java`
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/accountingadjust/standard/AccountingAdjustStatusResolver.java`
### late-fee reduce formal-table 申请态/审批态基础
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/dal/dataobject/latefeereduce/LateFeeReduceDO.java`
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/dal/dataobject/latefeereducedetail/LateFeeReduceDetailDO.java`
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/dal/mysql/latefeereduce/LateFeeReduceMapper.java`
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/dal/mysql/latefeereducedetail/LateFeeReduceDetailMapper.java`
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/accountingadjust/latefeereduce/LateFeeReduceFormalizationService.java`
### 已接入主链 / 读模型
- `AccountingAdjustProcessServiceImpl`
- `AccountingAdjustActionServiceImpl`
- `AccountingAdjustQueryServiceImpl`
- `AccountingAdjustLogProcessServiceImpl`
- `AccountingAdjustProcessRespVO`
- `AccountingAdjustDetailRespVO`
- `AccountingAdjustLogDetailRespVO`
- `AccountingAdjustPageRespVO`
- `AccountingAdjustLogPageRespVO`
### 对应测试
- `AccountingAdjustSemanticMapperTest`
- `AccountingAdjustDictResolverTest`
- `AccountingAdjustStatusResolverTest`
- `LateFeeReduceFormalizationServiceTest`
- `AccountingAdjustQueryServiceImplTest`
- `AccountingAdjustLogProcessServiceImplTest`
- `AccountingAdjustProcessServiceImplTest`(定向方法)
- `AccountingAdjustActionServiceImplTest`late-fee approval 定向方法)
## 本轮目标
1. 完成 Task-01 标准层 helper 最小实现
2. 将字典/状态 helper 接入 late-fee 相关读模型
3. 接入 late-fee reduce formal-table 申请态写入
4. 接入审批通过后 formal-table 最小更新闭环
5. 补 page / log-page 摘要字段试点
## 新鲜验证证据
### 1. 编译
执行:
```bash
rm -rf sw-business/sw-business-server/target/generated-sources \
sw-business/sw-business-server/target/generated-test-sources
mkdir -p sw-business/sw-business-server/target/generated-sources/annotations
mvn -pl sw-business/sw-business-server -DskipTests compile
```
结果:**PASS**
### 2. 定向测试
执行:
```bash
mvn -pl sw-business/sw-business-server \
-Dtest=AccountingAdjustQueryServiceImplTest,AccountingAdjustLogProcessServiceImplTest,AccountingAdjustProcessServiceImplTest#createUnsoldLateFeeReduce_shouldPassDateModeFieldsToUnifiedChargeService+createUnsoldLateFeeReduce_shouldRejectMixedAmountAndDateMode+batchCreateUnsoldLateFeeReduce_shouldMergeBatchOuterFieldsIntoItems+getProcess_shouldExposeLateFeeDisplayFieldsFromUnifiedSnapshot,AccountingAdjustActionServiceImplTest#approve_lateFeeReduceShouldOnlyUpdateLateFee,LateFeeReduceFormalizationServiceTest,AccountingAdjustSemanticMapperTest,AccountingAdjustDictResolverTest,AccountingAdjustStatusResolverTest \
test
```
结果:**PASS24 tests, 0 fail, 0 error**
## 当前结论
本轮已把第一批试点推进到:
- helper 已落地
- helper 已接入 late-fee 相关读模型
- late-fee formal-table 申请态写入已接入提交主链
- 审批通过后 formal-table 最小更新闭环已接入
- page / log-page 摘要字段试点已补
- compile 通过
- 定向测试通过
## 下一步
1. 继续推进 `lateFeeType=2` 按日期模式真正计算闭环
2. 补 formal-table 中 `before/reduce/after` 的更精确计算与状态更新
## 追加说明date-mode 精确计算规则)
### 当前实现口径
- 使用 `LateFeeDateModeCalculator`
- 所有未缴费用项参与计算
- 逐项通过 `ChargeDetailDO.costComponentCode -> CostComponentDO.penaltyCoefficient` 取系数
- `penaltyCoefficient = 0` 的费用项自然贡献 0
- 每项先四舍五入到分,最后汇总
- `lateFeeBefore` / `lateFeeAfter` 使用区间口径,而不是整账单总值口径
### 已覆盖边界测试
- 多费用项逐项计算并汇总
- 起算日晚于用户选择开始日时自动裁剪有效区间
- 0 系数费用项混合场景
- 计算结果大于当前 `lateFee` 时,`reduceAmount` 按当前 `lateFee` 封顶
- 截止日早于有效起算日时返回 0
## 2026-04-15 补充进展:真实库 canary 拉绿
### 本轮补充代码
- `sw-business/sw-business-server/src/test/resources/sql/rev004/accountprocess/00_reset.sql`
- `sw-business/sw-business-server/src/test/resources/sql/rev004/accountprocess/02_latefee_formal_tables.sql`
- `sw-business/sw-business-server/src/test/resources/sql/rev004/accountprocess/03_latefee_formal_reset.sql`
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/accountingadjust/latefeereduce/LateFeeReduceFormalizationService.java`
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/accountingadjust/AccountingAdjustQueryServiceImpl.java`
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/charge/ChargeServiceImpl.java`
- `sw-business/sw-business-server/src/test/java/cn/com/emsoft/sw/business/integration/rev004/accountprocess/Rev004AccountProcessCanaryQueryIntegrationTest.java`
### 修复点
1. **真实库 SQL fixture 兼容性**
- 去掉 `00_reset.sql` 中会被 Spring `ScriptUtils` 误切分的 `DO $$ ... $$`
- 新增 `03_latefee_formal_reset.sql`,把 late-fee formal table 的清理独立出来
- `02_latefee_formal_tables.sql` 改为无 `DO $$` 的约束重建方式
2. **formal-table 查询兜底**
- 当 `AccountingAdjustQueryServiceImpl` 无法仅从 `biz_operat_log(_detail)` 聚合出 `LATE_FEE_REDUCE` 详情时,
改为继续从:
- `biz_latefee_reduce`
- `biz_latefee_reduce_detail`
回退构造详情对象
3. **request log 的 adjustmentNo 明细一致性**
- `ChargeServiceImpl#recordAccountingAdjustOperatLog(...)` 中,
`adjustmentNo` 改为以 `oldValue = null, newValue = adjustmentNo` 记入日志明细,
避免被“旧值=新值则跳过”逻辑误过滤
### 新鲜验证
#### 定向编译
```bash
mvn -pl sw-business/sw-business-server -DskipTests compile
```
结果:**PASS**
#### 定向单测
```bash
mvn -pl sw-business/sw-business-server \
-Dtest=AccountingAdjustQueryServiceImplTest,LateFeeReduceFormalizationServiceTest,AccountingAdjustActionServiceImplTest#approve_lateFeeReduceDateModeShouldReduceCurrentLateFeeAndUpdateFormalTable \
test
```
结果:**PASS8 tests, 0 fail, 0 error**
#### 真实数据库 canary
```bash
REV004_IT_DB_URL=jdbc:postgresql://192.168.10.130:5436/sw_system \
REV004_IT_DB_USERNAME=sw_system \
REV004_IT_DB_PASSWORD='Em@123456' \
mvn -pl sw-business/sw-business-server clean \
-Dtest=Rev004AccountProcessCanaryQueryIntegrationTest#unsoldLateFeeReduceDateModeApprove_shouldPersistFormalTableSummary \
test
```
结果:**PASS**
### canary 覆盖到的链路
- 未销违约金减免(按日期)提交
- request log 写入 `adjustmentNo`
- `biz_latefee_reduce` / `biz_latefee_reduce_detail` 申请态落单
- 审批通过
- formal table 主表 / 明细表更新为成功态
### 当前结论更新
REV004 late-fee date-mode 这条最小闭环已从:
- **代码与单测通过**
推进到:
- **真实库 canary 通过**
当前剩余风险已不再是“缺表阻塞”,而是后续是否要把更多对象(坏账 / 核销 / 价差)也迁移到 formal-table 路线。

View File

@ -0,0 +1,87 @@
# REV004 late-fee formal-table 真实库阻塞说明2026-04-15
> 状态更新:**该阻塞已于 2026-04-15 当天解除,本文保留为阻塞发生记录。**
## 结论
当前 late-fee reduce 代码侧与定向单测已通过,但真实数据库集成验证被环境缺表阻塞,阻塞点不是代码逻辑,而是目标库未部署 formal-table。
## 已通过的验证
### 编译
```bash
rm -rf sw-business/sw-business-server/target/generated-sources \
sw-business/sw-business-server/target/generated-test-sources
mkdir -p sw-business/sw-business-server/target/generated-sources/annotations
mvn -pl sw-business/sw-business-server -DskipTests compile
```
结果:**PASS**
### 定向测试
```bash
mvn -pl sw-business/sw-business-server \
-Dtest=AccountingAdjustActionServiceImplTest#approve_lateFeeReduceShouldOnlyUpdateLateFee+approve_lateFeeReduceDateModeShouldReduceCurrentLateFeeAndUpdateFormalTable,LateFeeReduceFormalizationServiceTest,AccountingAdjustQueryServiceImplTest,AccountingAdjustLogProcessServiceImplTest,AccountingAdjustProcessServiceImplTest#createUnsoldLateFeeReduce_shouldPassDateModeFieldsToUnifiedChargeService+createUnsoldLateFeeReduce_shouldRejectMixedAmountAndDateMode+batchCreateUnsoldLateFeeReduce_shouldMergeBatchOuterFieldsIntoItems+getProcess_shouldExposeLateFeeDisplayFieldsFromUnifiedChargeService,AccountingAdjustSemanticMapperTest,AccountingAdjustDictResolverTest,AccountingAdjustStatusResolverTest \
test
```
结果:**PASS24 tests, 0 fail, 0 error**
## 真实 DB 阻塞验证
### 执行命令
```bash
REV004_IT_DB_URL=jdbc:postgresql://192.168.10.130:5436/sw_system \
REV004_IT_DB_USERNAME=sw_system \
REV004_IT_DB_PASSWORD='Em@123456' \
mvn -pl sw-business/sw-business-server \
-Dtest=Rev004AccountProcessCanaryQueryIntegrationTest#unsoldLateFeeReduceDateModeApprove_shouldPersistFormalTableSummary \
test
```
### 失败原因
报错核心:
- `relation "biz_latefee_reduce_detail" does not exist`
在测试前置 / 后置 SQL `sql/rev004/accountprocess/00_reset.sql` 中,已经尝试执行:
- `DELETE FROM biz_latefee_reduce_detail ...`
- `DELETE FROM biz_latefee_reduce ...`
这说明:
- 代码侧已经按 formal-table 路径推进
- 测试脚本也已经按 formal-table 假设编写
- 但真实库中尚未存在这些表
## 当前判断
1. 代码逻辑不是当前 blocker。
2. 真实 DB 环境未部署 `biz_latefee_reduce` / `biz_latefee_reduce_detail` 是当前 canary 唯一主要阻塞。
3. 在部署 formal-table 之前,真实库层面的 late-fee canary 无法拉绿。
## 建议下一步
1. 先确认真实库是否允许部署:
- `biz_latefee_reduce`
- `biz_latefee_reduce_detail`
2. 若允许部署,再重跑 canary。
3. 若暂不允许部署,则当前阶段只能以 compile + unit/integration mock/local 证据为主,明确标注“真实库阻塞未消除”。
---
## 后续结果回写(阻塞已解除)
### 已完成动作
1. 补充并执行 `sql/rev004/REV004_latefee_formal_tables_deploy.sql`
2. 修复测试 SQL fixture
- `00_reset.sql`
- `02_latefee_formal_tables.sql`
- `03_latefee_formal_reset.sql`
3. 补充 late-fee formal-table 查询兜底与 request log `adjustmentNo` 明细一致性
### 解除阻塞后的真实库验证
```bash
REV004_IT_DB_URL=jdbc:postgresql://192.168.10.130:5436/sw_system \
REV004_IT_DB_USERNAME=sw_system \
REV004_IT_DB_PASSWORD='Em@123456' \
mvn -pl sw-business/sw-business-server clean \
-Dtest=Rev004AccountProcessCanaryQueryIntegrationTest#unsoldLateFeeReduceDateModeApprove_shouldPersistFormalTableSummary \
test
```
结果:**PASS**
### 更新后的结论
- `biz_latefee_reduce` / `biz_latefee_reduce_detail` 缺表阻塞已消除
- REV004 late-fee date-mode 最小真实库闭环已验证通过
- 本文档现仅作为“阻塞曾发生过”的历史记录,不再代表当前状态

View File

@ -0,0 +1,73 @@
# REV004 late-fee formal table 已应用到 application-dev 测试库2026-04-15
## 目标库
依据:
- `sw-business/sw-business-server/src/main/resources/application-dev.yaml`
解析结果:
- Host`192.168.10.130`
- Port`5436`
- DB`sw_system`
- User`sw_system`
即当前 `application-dev` 指向的测试数据库为:
`jdbc:postgresql://192.168.10.130:5436/sw_system`
## 已执行脚本
- `sql/rev004/REV004_latefee_formal_tables_deploy.sql`
执行命令:
```bash
PGPASSWORD='Em@123456' \
psql -h 192.168.10.130 -p 5436 -U sw_system -d sw_system \
-v ON_ERROR_STOP=1 \
-f sql/rev004/REV004_latefee_formal_tables_deploy.sql
```
## 执行结果
结果:**PASS**
执行输出显示:
- sequence 已存在时跳过
- table 已存在时跳过
- 索引继续补齐/确认
- 外键创建逻辑执行成功
说明该脚本已成功应用到测试库,且具备幂等重放能力。
## 回读校验
### 表
已确认存在:
- `biz_latefee_reduce`
- `biz_latefee_reduce_detail`
### 序列
已确认存在:
- `biz_latefee_reduce_seq`
- `biz_latefee_reduce_detail_seq`
### 索引
已确认存在:
- `uk_biz_latefee_reduce_no`
- `idx_biz_latefee_reduce_case`
- `idx_biz_latefee_reduce_status`
- `idx_biz_latefee_reduce_type`
- `idx_biz_latefee_reduce_detail_main`
- `idx_biz_latefee_reduce_detail_charge`
- `idx_biz_latefee_reduce_detail_cust`
- `idx_biz_latefee_reduce_detail_bill_month`
### 外键
已确认存在:
- `fk_biz_latefee_reduce_detail_main`
- `biz_latefee_reduce_detail(latefee_reduce_id) -> biz_latefee_reduce(id)`
## 当前结论
`application-dev` 指向的测试数据库现在已经具备 REV004 late-fee formal-table 结构,可直接用于:
1. 未销违约金减免申请态落单
2. 审批态 formal-table 更新
3. accountProcess 真实库 canary / 联调验证
## 建议后续
1. 继续保留 `REV004_latefee_formal_tables_deploy.sql` 作为测试库 / 联调库初始化脚本
2. 若后续坏账 / 核销 / 价差也迁移 formal-table应沿用相同“独立 deploy SQL + 回读校验”的方式推进

View File

@ -0,0 +1,131 @@
# REV004 字典绑定矩阵
## 1. 文档目的
本文件用于明确 REV004 当前接口、前端查询条件与下拉口径,应如何绑定到系统字典。
原则:
- 旧字典能承接的继续承接;
- 旧字典承接不了的,仅最小新增;
- 不迁移旧字典体系;
- 不要求所有旧页面一次性切换。
---
## 2. 本轮新增字典
| 字典类型 | 用途 |
|---|---|
| `redink_reason` | 红冲/冲正原因 |
| `account_adjust_object_type` | REV004 当前开放对象类型 |
| `account_adjust_result_status` | REV004 结果状态 |
| `account_adjust_approval_status` | REV004 审批状态 |
| `account_adjust_writeback_status` | REV004 回写状态 |
---
## 3. 继续复用的旧字典
| 字典类型 | 用途 |
|---|---|
| `deposit_reason` | 预付费退款原因 |
| `late_fee_reason` | 违约金减免原因 |
| `price_reason` | 价差调整原因 |
| `separate_reason` | 分账/拆分原因 |
| `separate_type` | 分账调整方式(按水量 / 按费用组成) |
| `knotty_reason` | 呆坏账原因 |
| `knotty_type` | 呆坏账类型(呆账/坏账/纠纷账) |
| `payment_reason` | 已销/核销调整原因(当前作为核销调整过渡复用) |
| `proc_type` | 账务处理方式 |
| `business_type` | 业务大类归属 |
---
## 4. REV004 接口字段绑定矩阵
### 4.1 核心接口字段
| 字段 | 字段语义 | 绑定字典 | 说明 |
|---|---|---|---|
| `objectType` | 调整对象 | `account_adjust_object_type` | 前端对象筛选、标签显示、下拉选择主来源 |
| `resultStatus` | 处理结果状态 | `account_adjust_result_status` | 前端结果状态筛选、展示主来源 |
| `approvalStatus` | 审批状态 | `account_adjust_approval_status` | 前端审批角标/审批筛选主来源 |
| `writeBackStatus` | 回写状态 | `account_adjust_writeback_status` | 前端回写状态展示与筛选主来源 |
| `reasonCode` | 调整原因编码 | **按 objectType 动态绑定** | 不统一绑一个 reason 字典,而是按对象类型切换 |
---
### 4.2 `reasonCode` 动态绑定规则
| objectType | 绑定字典 | 说明 |
|---|---|---|
| `PREPAID_REFUND` | `deposit_reason` | 复用预存调整原因中的退款语义 |
| `REDINK_RECORD` | `redink_reason` | 旧库缺少红冲原因专属字典,本轮新增 |
| `BAD_DEBT_RECORD` | `knotty_reason` | 复用呆坏账原因 |
| `WRITTENOFF_ADJUST` | `payment_reason` | 当前过渡复用;若后续核销长期独立,可再拆专属字典 |
| `PRICE_DIFF_ADJUST` | `price_reason` | 复用价差调整原因 |
| `LATE_FEE_REDUCE` | `late_fee_reason` | 复用违约金减免原因 |
| `SPLIT_ADJUST` | `separate_reason` | 复用分账调整原因 |
---
### 4.3 与辅助类型字段的关系
| 使用场景 | 字段/语义 | 绑定字典 |
|---|---|---|
| 违约金减免二级方式 | 按金额 / 按日期 | `late_fee_type` |
| 分账调整二级方式 | 按水量 / 按费用组成 | `separate_type` |
| 呆坏账细分类型 | 呆账 / 坏账 / 纠纷账 | `knotty_type` |
| 账务结果处理动作 | 转预存 / 转退款 / 转销账 / 线下退款 | `proc_type` |
| 历史业务归类 / 大类筛选 | 预存调整 / 呆坏账 / 违约金减免 / 价差调整 / 已销调整 / 分账调整 | `business_type` |
> 说明:`business_type` 不作为 `objectType` 的替代来源。
> `objectType``account_adjust_object_type` 为主,`business_type` 仅作为旧页面/旧日志/业务大类归类兼容口径。
---
## 5. 前端下拉与查询接入建议
### 5.1 建议读取接口
- 字典数据接口:
- `GET /admin-api/system/dict-data/simple-list`
### 5.2 页面建议
#### REV004 查询页
- 对象类型下拉:`account_adjust_object_type`
- 结果状态下拉:`account_adjust_result_status`
- 审批状态下拉:`account_adjust_approval_status`
- 回写状态下拉:`account_adjust_writeback_status`
#### REV004 办理弹窗
- 原因下拉:根据当前 `objectType` 动态切换字典类型
- 例如:`PRICE_DIFF_ADJUST -> price_reason`
---
## 6. 非目标说明
本轮不做:
- 旧字典批量改名
- 历史页面一次性切换到新字典
- 旧业务表字段语义迁移
- 全账务领域统一字典重构
---
## 7. 当前特别说明
### `WRITTENOFF_ADJUST`
当前建议临时复用:
- `payment_reason`
这是过渡方案,不代表“核销调整”和“已销调整”语义完全等价。
若后续核销调整独立场景长期存在,建议再单独补:
- `writtenoff_reason`
### `REDINK_RECORD`
当前库中无现成“红冲原因/冲正原因”专属字典,故本轮新增:
- `redink_reason`

View File

@ -0,0 +1,73 @@
-- REV004 account adjust dictionaries
-- Target DB: sw_system (PostgreSQL)
-- Purpose:
-- 1) Reuse existing legacy reason/type/proc/business dictionaries
-- 2) Add the minimal new dictionaries needed for REV004 object/status semantics
-- Note:
-- This script is idempotent by (type) and (dict_type, value) checks.
BEGIN;
-- ============================================================
-- 1. Dict types
-- ============================================================
INSERT INTO system_dict_type (name, type, status, remark, creator, updater, category)
SELECT v.name, v.type, 0, v.remark, 'omx', 'omx', 'REV004'
FROM (VALUES
('红冲原因', 'redink_reason', 'REV004 红冲/冲正原因'),
('账务调整对象类型', 'account_adjust_object_type', 'REV004 objectType 字典'),
('账务调整结果状态', 'account_adjust_result_status', 'REV004 resultStatus 字典'),
('账务调整审批状态', 'account_adjust_approval_status', 'REV004 approvalStatus 字典'),
('账务调整回写状态', 'account_adjust_writeback_status', 'REV004 writeBackStatus 字典')
) AS v(name, type, remark)
WHERE NOT EXISTS (
SELECT 1 FROM system_dict_type t WHERE t.type = v.type AND t.deleted = 0
);
-- ============================================================
-- 2. Dict data
-- ============================================================
INSERT INTO system_dict_data (sort, label, value, dict_type, status, color_type, css_class, remark, creator, updater)
SELECT v.sort, v.label, v.value, v.dict_type, 0, v.color_type, v.css_class, v.remark, 'omx', 'omx'
FROM (VALUES
-- redink_reason
(10, '收费错误', '1', 'redink_reason', 'danger', '', 'REV004 红冲原因'),
(20, '用户拒缴', '2', 'redink_reason', 'warning', '', 'REV004 红冲原因'),
(30, '银行撤销', '3', 'redink_reason', 'warning', '', 'REV004 红冲原因'),
(40, '网络异常', '4', 'redink_reason', 'info', '', 'REV004 红冲原因'),
(90, '其它', '9', 'redink_reason', 'default', '', 'REV004 红冲原因'),
-- account_adjust_object_type
(10, '预付费退款', 'PREPAID_REFUND', 'account_adjust_object_type', 'success', '', 'REV004 objectType'),
(20, '红冲记录', 'REDINK_RECORD', 'account_adjust_object_type', 'danger', '', 'REV004 objectType'),
(30, '坏账申请', 'BAD_DEBT_RECORD', 'account_adjust_object_type', 'warning', '', 'REV004 objectType'),
(40, '核销调整', 'WRITTENOFF_ADJUST', 'account_adjust_object_type', 'warning', '', 'REV004 objectType'),
(50, '价差调整', 'PRICE_DIFF_ADJUST', 'account_adjust_object_type', 'info', '', 'REV004 objectType'),
(60, '违约金减免', 'LATE_FEE_REDUCE', 'account_adjust_object_type', 'info', '', 'REV004 objectType'),
(70, '账单拆分', 'SPLIT_ADJUST', 'account_adjust_object_type', 'primary', '', 'REV004 objectType'),
-- account_adjust_result_status
(10, '成功', 'SUCCESS', 'account_adjust_result_status', 'success', '', 'REV004 resultStatus'),
(20, '待审批', 'PENDING_APPROVAL', 'account_adjust_result_status', 'warning', '', 'REV004 resultStatus'),
(30, '失败', 'FAIL', 'account_adjust_result_status', 'danger', '', 'REV004 resultStatus'),
-- account_adjust_approval_status
(10, '无需审批', 'NOT_REQUIRED', 'account_adjust_approval_status', 'default', '', 'REV004 approvalStatus'),
(20, '待审批', 'PENDING_APPROVAL', 'account_adjust_approval_status', 'warning', '', 'REV004 approvalStatus'),
(30, '审批通过', 'APPROVED', 'account_adjust_approval_status', 'success', '', 'REV004 approvalStatus'),
(40, '审批驳回', 'REJECTED', 'account_adjust_approval_status', 'danger', '', 'REV004 approvalStatus'),
-- account_adjust_writeback_status
(10, '已回写', 'UPDATED', 'account_adjust_writeback_status', 'success', '', 'REV004 writeBackStatus'),
(20, '待回写', 'PENDING', 'account_adjust_writeback_status', 'warning', '', 'REV004 writeBackStatus'),
(30, '已跳过', 'SKIPPED', 'account_adjust_writeback_status', 'default', '', 'REV004 writeBackStatus')
) AS v(sort, label, value, dict_type, color_type, css_class, remark)
WHERE NOT EXISTS (
SELECT 1
FROM system_dict_data d
WHERE d.dict_type = v.dict_type
AND d.value = v.value
AND d.deleted = 0
);
COMMIT;