12 KiB
财务服务边界设计
范围说明:本文只作为 Finance 独立服务/独立数据库的技术边界依据。文中的钱包、充值、发票、费用分析和利润属于长期模型,不属于订单与客户;订单与客户唯一产品范围以《财务核心五页产品与接口验收契约》为准。
决策日期:2026-08-10
决策状态:技术已确认
决策结论:Finance 采用独立服务和独立数据库
适用范围:财务 F0-F4 全量建设
一、正式结论
财务域新增独立 finance-service,拥有独立财务数据库。不得把应收、应付、对账单、收付款、核销、客户账户、发票、费用分析或利润继续放入 firstleg-service。
身份与主体边界补充确认:产品层只有“平台、客户”两种身份。平台可以管理平台角色和平台用户;客户可以在本客户范围内管理客户角色和客户用户。客户用户是财务操作人,不因创建或操作财务单据而成为新的财务主体。
Finance 中必须分开建模:
- 客户企业/客户范围:业务数据归属和客户侧结算对象,服务端从登录授权上下文确定,不能由前端任意切换;
- 平台财务主体/账套:平台收款、付款、开票和核算的法律/账务主体;即使当前只有一个,也保留独立对象;
- 客户用户/成员:仅作为客户范围内的操作人,保存
userId/memberId和当时的姓名快照;账单、应收、余额和核销归属客户企业,不归属成员。成员停用只撤销访问和权限,不触发财务单据转交。 - 角色与权限:平台角色由平台维护,客户角色由客户在允许的权限目录内维护,任何角色都不能越过客户范围。
已确认首期采用“一客户企业=一个对客结算对象”。这里的客户是业务数据归属和应收结算对象,不等同于平台收付款、开票和核算的法律主体;平台财务主体/账套仍单独建模。首期不支持一个客户配置多个对客结算对象或独立账套。
firstleg-service 保持现有业务边界,只负责:
- 入库单、测量、称重和审核;
- FBA/头程计费规则匹配与费用计算;
- 业务费用快照、费用版本、发布、调整和作废;
- 向 Finance 发布不可变费用来源事件;
- 提供 Finance 核验完整费用来源的内部查询接口。
finance-service 负责:
- 财务主体、往来单位引用、币种、汇率、财务期间和单据编号;
- 财务费用来源池;
- 客户对账单、应收单、收款单、核销和反核销;
- 供应商对账单、应付单、付款单、付款核销和反核销;
- 客户账户、充值、冻结、解冻、扣款、退款和账户流水;
- 发票申请、开票登记、红冲、作废和附件关联;
- 成本台账、费用分析、利润分析和期间快照;
- 财务权限、幂等、Outbox、版本和审计记录。
二、为什么拆服务
拆库本身不强制拆服务,但当前财务范围已经形成独立业务域,具备独立服务的必要条件:
- 财务拥有独立状态机。计费状态不能代替账单、应收、收款和核销状态。
- 财务拥有独立事务边界。入库完成不能与收款、核销或开票放在同一个事务中。
- 财务需要更严格的权限和审计。反核销、付款、关账和红冲不应复用入库费用编辑权限。
- 财务数据生命周期更长。已出账、已核销和已开票记录不能随着业务订单调整被覆盖。
- 财务同时消费 Firstleg、Order、Warehouse、IAM、File 等业务信息,不属于 Firstleg 的单一履约职责。
- 后续应付、客户账户、发票和利润会持续扩展,放入 Firstleg 会形成不可控耦合。
三、目标拓扑
Admin / Client
|
v
Gateway
|
+-----------------------+
| |
v v
firstleg-service finance-service
firstleg 数据库 finance 数据库
| |
| 费用事件 / 内部查询 | 财务单据与台账
+---------------------->|
|
+--> file-service(凭证/发票附件)
+--> iam-service(身份、客户与权限核验)
+--> warehouse-service(供应商/往来单位核验)
禁止:
- Finance 跨库 Join Firstleg、Warehouse、IAM 或 Order 数据库;
- Finance 直接引用其他服务 Entity;
- Firstleg 直接写 Finance 数据库;
- 前端传入客户 ID 后绕过服务端客户范围校验;
- 通过修改 Firstleg 费用状态代替财务调整、冲销或反核销。
3.1 实现标识预留
经现有 Maven 聚合工程、服务端口表、Nacos 配置和部署清单核对,Finance 实施时统一使用以下标识:
| 项目 | 规划值 | 当前状态 |
|---|---|---|
| 后端模块目录 | baiyue-firstleg/finance/ |
规划,尚未创建 |
| Maven artifactId | finance-service |
规划,尚未创建 |
| Nacos 注册服务名 | finance-service |
规划,尚未注册 |
| 服务端口 | 9203 |
规划预留;现有 11 个服务未占用 |
| 独立数据库 | baiyue_finance |
规划,尚未创建 |
9203 仅作为当前架构下的默认预留端口;若部署环境端口占用情况变化,可由配置调整,但仓库内默认值、部署映射和文档必须保持一致。
四、数据归属
| 数据 | 归属服务 | 说明 |
|---|---|---|
| 入库单、测量、重量、体积 | Firstleg | 业务履约事实 |
| 计费规则、价格版本、计费快照 | Firstleg | 业务费用计算依据 |
| 已发布费用来源版本 | Firstleg | Finance 的不可变上游来源 |
| 财务来源池 | Finance | 保存来源引用、版本、哈希和财务入池状态 |
| 客户/供应商对账单 | Finance | 不回写业务费用表 |
| 应收、应付、收款、付款 | Finance | 财务余额和状态唯一来源 |
| 核销、反核销 | Finance | 不允许物理删除 |
| 客户账户和流水 | Finance | 与应收台账分开,抵扣必须产生核销记录 |
| 发票台账 | Finance | 文件内容仍由 File 保存 |
| 成本、分摊、利润和期间快照 | Finance | 只能基于财务台账计算 |
| 客户身份和权限资源 | IAM | Finance 只引用和核验 |
| 公共往来单位/供应商资料 | Warehouse | Finance 保存引用和历史名称快照 |
五、Firstleg 到 Finance 的契约
5.1 事件
Firstleg 通过本地 Outbox 发布:
FIRSTLEG_FEE_PUBLISHEDFIRSTLEG_FEE_ADJUSTEDFIRSTLEG_FEE_VOIDED
以上是目标事件名。当前 Firstleg 已存在 FIRSTLEG_FEE_SENT 和 FIRSTLEG_FEE_ADJUSTED;实施时将 FIRSTLEG_FEE_SENT 兼容映射为 FIRSTLEG_FEE_PUBLISHED,并补充明确的作废事件,不能把规划事件误写成当前已上线能力。
事件采用“统一信封 + 轻量来源引用”,不直接承载完整金额和计费明细。至少包含:
eventId
eventType
eventVersion
occurredAt
producer
tenantId
inboundId
sourceFeeId
sourceFeeVersion
sequence
idempotencyKey
payloadHash
traceId
Finance 以 eventId 做投递幂等,并以 sourceType + sourceFeeId + sourceFeeVersion 做业务唯一约束。重复相同事件返回第一次处理结果;同一业务键对应不同哈希时拒绝处理并记录冲突。金额、币种、方向、业务日期、费用明细和业务快照必须通过内部快照接口核验后保存,不能只信任事件载荷。
5.2 内部查询
Finance 接收事件后,通过服务令牌调用 Firstleg 内部接口核验完整来源快照。内部接口返回 DTO,不返回或共享 Entity。接口路径、信封字段、重试和兼容规则以《Firstleg-Finance 跨服务契约》为准。
Finance 保存来源快照后,不依赖 Firstleg 当前表数据实时计算历史账单。已出账来源发生调整时,Finance 生成补差或冲销来源,不覆盖原账单明细。
六、Finance 服务内部模块
建议 finance-service 内部先按业务域分包,不在首期继续拆成多个微服务:
finance-service/
foundation/ 财务主体、币种、汇率、期间、编号
source/ 费用来源接入与校验
receivable/ 对账单、应收、收款、核销
payable/ 供应商对账、应付、付款、核销
account/ 客户账户和流水
invoice/ 发票生命周期
costing/ 成本和分摊
reporting/ 费用分析和利润
audit/ 财务操作日志
当前只拆一个 Finance 服务,不把应收、应付、钱包、发票和报表各自拆成独立微服务。只有将来出现独立团队、独立扩缩容或明显不同的可用性需求时,才重新评估二次拆分。
七、开发顺序
F0:finance-service 骨架、独立数据库、主体/币种/期间/编号、来源接入、幂等和审计
-> F1:客户对账、应收、收款和核销
-> F2:供应商对账、应付、付款和核销
-> F3:客户账户和发票
-> F4:成本、费用分析和利润
F1 与 F2 可以在 F0 契约冻结后并行开发;F3/F4 可以并行做页面和契约设计,但生产数据链路必须依赖前序财务台账。
八、技术验收标准
finance-service可以独立构建、部署和回滚;- Finance 数据库不存在对其他服务数据库的跨库外键或 Join;
- Firstleg 发布费用后,Finance 能幂等生成一条财务来源;
- 重复事件、乱序事件和失败重试不会重复入账;
- 已出账费用调整不会覆盖历史账单;
- 所有财务写操作有幂等键、乐观锁、权限和审计;
- 长整型 ID 以前端字符串传输,金额使用定点小数和 ISO 三位币种;
- 跨客户、跨主体、跨币种和关闭期间操作由服务端拒绝;
- Admin/Client 使用正式 Finance API,不依赖
/prototype/finance/*页面或模拟数据。
九、进入实现时的仓库改造清单
以下是 Finance 开发阶段必须完成的技术工作,不属于产品待确认项。本轮只形成规划,不创建服务、不建库、不修改部署环境。
| 范围 | 实施时需要新增或修改 | 验证重点 |
|---|---|---|
| Maven 聚合 | 根 pom.xml 增加 finance module;新增 finance/pom.xml |
mvn -pl finance -am test 可独立构建 |
| 服务配置 | 新增 config/nacos/local/finance-service.yml、config/nacos/cn/finance-service.yml |
服务名、端口、数据源、内部令牌与环境变量约定一致 |
| 数据库 | 新增 Finance 自有迁移目录,并同步统一增量 SQL 入口 | 只创建/访问 baiyue_finance,无跨库外键或 Join |
| 部署映射 | 更新 deploy/service-map.yml、deploy/docker-compose.yml 和部署脚本 |
生成独立 JAR、镜像、容器,可单独部署/回滚 |
| Gateway | 增加 Finance 平台端/客户端路由和 Swagger/OpenAPI 聚合 | 前端仍只通过 /api 访问;平台端与客户端访问域隔离 |
| CI/CD | 更新 Jenkins 增量构建、受影响服务识别和部署映射 | 修改 Finance 只构建相关单元;公共模块变更包含 Finance |
| 服务契约 | Firstleg 增加费用 Outbox 事件及受保护内部快照查询;Finance 增加 Inbox/消费结果 | 重复、乱序、重试、冲突事件均可验证 |
| 权限与审计 | IAM 增加 Finance 权限资源;Finance 接入公共鉴权与审计能力 | 服务端校验客户范围、高风险权限和操作留痕 |
| 架构文档 | 更新服务总览、端口/数据库表和调用拓扑 | 可运行服务口径由 11 个变为 12 个 |
实施时必须先冻结 Finance 与 Firstleg 的事件/查询契约,再并行建设 Finance 内部 F1/F2 模块;不得先由前端或数据库表反推跨服务契约。
十、复核结论
当前仓库采用 Maven 多模块单仓、服务独立 JAR/镜像/容器、服务独立数据库、DTO/事件协作的架构。Finance 独立服务与这一模式一致,不需要因为代码处于同一 Git 仓库而并回 firstleg-service。
因此本技术决策保持不变:新增一个 finance-service 和一个 baiyue_finance 数据库,服务内部按财务子域分包,当前不继续拆成多个财务微服务。