# 财务服务边界设计 > 决策日期:2026-08-10 > 决策状态:技术已确认 > 决策结论:Finance 采用独立服务和独立数据库 > 适用范围:财务 F0-F4 全量建设 ## 一、正式结论 财务域新增独立 `finance-service`,拥有独立财务数据库。不得把应收、应付、对账单、收付款、核销、客户账户、发票、费用分析或利润继续放入 `firstleg-service`。 身份与主体边界补充确认:产品层只有“平台、客户”两种身份。平台可以管理平台角色和平台用户;客户可以在本客户范围内管理客户角色和客户用户。客户用户是财务操作人,不因创建或操作财务单据而成为新的财务主体。 Finance 中必须分开建模: - **客户企业/客户范围**:业务数据归属和客户侧结算对象,服务端从登录授权上下文确定,不能由前端任意切换; - **平台财务主体/账套**:平台收款、付款、开票和核算的法律/账务主体;即使当前只有一个,也保留独立对象; - **客户用户/成员**:制单、复核、确认、收款登记等操作人,保存 `userId/memberId` 和当时的姓名快照; - **角色与权限**:平台角色由平台维护,客户角色由客户在允许的权限目录内维护,任何角色都不能越过客户范围。 若业务口语中的“客户就是主体”是指“客户是业务数据主体/结算对象”,可以采用;若指“财务法律主体/账套”,则不能直接等同,需由 F0-02 单独确认。 `firstleg-service` 保持现有业务边界,只负责: - 入库单、测量、称重和审核; - FBA/头程计费规则匹配与费用计算; - 业务费用快照、费用版本、发布、调整和作废; - 向 Finance 发布不可变费用来源事件; - 提供 Finance 核验完整费用来源的内部查询接口。 `finance-service` 负责: - 财务主体、往来单位引用、币种、汇率、财务期间和单据编号; - 财务费用来源池; - 客户对账单、应收单、收款单、核销和反核销; - 供应商对账单、应付单、付款单、付款核销和反核销; - 客户账户、充值、冻结、解冻、扣款、退款和账户流水; - 发票申请、开票登记、红冲、作废和附件关联; - 成本台账、费用分析、利润分析和期间快照; - 财务权限、幂等、Outbox、版本和审计记录。 ## 二、为什么拆服务 拆库本身不强制拆服务,但当前财务范围已经形成独立业务域,具备独立服务的必要条件: 1. 财务拥有独立状态机。计费状态不能代替账单、应收、收款和核销状态。 2. 财务拥有独立事务边界。入库完成不能与收款、核销或开票放在同一个事务中。 3. 财务需要更严格的权限和审计。反核销、付款、关账和红冲不应复用入库费用编辑权限。 4. 财务数据生命周期更长。已出账、已核销和已开票记录不能随着业务订单调整被覆盖。 5. 财务同时消费 Firstleg、Order、Warehouse、IAM、File 等业务信息,不属于 Firstleg 的单一履约职责。 6. 后续应付、客户账户、发票和利润会持续扩展,放入 Firstleg 会形成不可控耦合。 ## 三、目标拓扑 ```text 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_PUBLISHED` - `FIRSTLEG_FEE_ADJUSTED` - `FIRSTLEG_FEE_VOIDED` 以上是目标事件名。当前 Firstleg 已存在 `FIRSTLEG_FEE_SENT` 和 `FIRSTLEG_FEE_ADJUSTED`;实施时将 `FIRSTLEG_FEE_SENT` 兼容映射为 `FIRSTLEG_FEE_PUBLISHED`,并补充明确的作废事件,不能把规划事件误写成当前已上线能力。 事件采用“统一信封 + 轻量来源引用”,不直接承载完整金额和计费明细。至少包含: ```text 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` 内部先按业务域分包,不在首期继续拆成多个微服务: ```text finance-service/ foundation/ 财务主体、币种、汇率、期间、编号 source/ 费用来源接入与校验 receivable/ 对账单、应收、收款、核销 payable/ 供应商对账、应付、付款、核销 account/ 客户账户和流水 invoice/ 发票生命周期 costing/ 成本和分摊 reporting/ 费用分析和利润 audit/ 财务操作日志 ``` 当前只拆一个 Finance 服务,不把应收、应付、钱包、发票和报表各自拆成独立微服务。只有将来出现独立团队、独立扩缩容或明显不同的可用性需求时,才重新评估二次拆分。 ## 七、开发顺序 ```text 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` 数据库,服务内部按财务子域分包,当前不继续拆成多个财务微服务。**