行业: 金融服务
MongoDB 产品: MongoDB Atlas、MongoDB 聚合管道、Change Streams
解决方案概述
核心银行业务是银行运行的引擎。它管理客户数、帐户、余额、付款和财务事件,每个下游渠道、产品和报告系统都依赖于它。
正是这种核心地位使得核心系统难以现代化。许多银行仍然依赖于碎片化数据、固定模式、批处理窗口和点对点集成。随着新产品、渠道和监管要求的出现,复杂性通常会增加。
解决方案?使用银行业架构网络 (BIAN) 和 MongoDB 实现核心银行业务现代化。
BIAN 定义业务架构。MongoDB 将其实现为可组合、事件驱动、域所有的数据平台。
BIAN:目标架构
银行业架构网络 (BIAN) 定义 BIAN 框架—一个银行业标准,将功能模拟为服务域。
将银行操作定义为服务域,可为每个团队赋予一组范围合理的责任,从而产生:
更清晰的绑定上下文:每个服务域都有定义的范围和目的。
更清晰的数据所有权:一个域拥有每个业务对象及其数据。
更清晰的API边界:域通过标准合同而不是共享数据库访问进行交互。
语义漂移较少:共享词汇可以使各团队和系统之间的术语保持一致。
MongoDB:实现数据平台
MongoDB 在实践中实现 BIAN 服务域模型。每个银行需求都对应一个原生 MongoDB 功能:
document model 适用于分层银行数据,例如客户数、帐户和嵌套的 KYC 记录。
多文档 ACID 事务在单次提交中执行同步资金运动。
变更流可以实时传播金融事件,无需轮询。
模式验证器和聚合管道在数据附近实施会计规则。
该解决方案展示了如何在不中断交付管道的情况下逐渐实现核心银行的现代化。
参考架构
该解决方案分为三个 FastAPI 后端服务。每个服务在端到端资金流中都承担着不同的职责。
帐户服务拥有客户数和帐户省/市/自治区。它公开了针对当事人参考数据和当前帐户功能的BIAN对齐操作。
事务服务拥有支付发起和支付执行。它将操作支付结果同步写入为一个 MongoDB ACID transaction。
分类账服务拥有会计管道。它对已执行的事务作出异步反应,并提取子分类账和日志过帖所需的财务侧记录。
这种分离是架构的核心。付款执行、账户状态和会计真相是相关的,但它们并不是同一个问题。该设计通过数据衍生使它们保持连接,同时允许每个服务在其自身范围内发展。
图 1。高级架构:使用 BIAN 和 MongoDB 的核心银行业。
渠道通过应用程序和服务边界进入。
用户通过 Web 用户界面与解决方案交互。前端充当渠道层,并通过基于路径的路由将请求路由到相关的后端服务。服务公开 BIAN 风格的终结点,因此接口层与业务功能保持一致,而不会泄露数据库结构。
帐户服务拥有客户和帐户真实情况。
帐户服务读取和写入
customers和accounts集合。它是客户主数据、KYC相关帐户上下文、余额和帐户生命周期操作的信息来源。这是用于帐户和余额检索的同步读取路径。事务服务同步执行付款。
发起支付时,事务服务会将其处理为一个 MongoDB 多文档 ACID transaction。在该解决方案中,该工作单元会在一次提交中扣除源账户余额、信用目的账户余额、插入事务记录、更新支付状态以及写入相关通知或状态变更。
操作账户余额会立即在事务流中更新,而分类账流会异步更新总账。总账在过账窗口结束时分批处理单独过账。
MongoDB 成为会计传播的事件源。
分类帐本路径不会拉取变更,也不依赖解决方案中的外部消息总线。相反,分类帐本服务通过 MongoDB 变更流监视
transactions集合。每个新插入的事务都会成为异步会计处理的 trigger。这是运行执行与财务处理之间的架构交接。
图 2。分类帐服务。
点击放大分类帐本服务的阶段 1 写入会计边界对象。
第一个分类工作人员消耗事务变更流,并为每笔付款写入一个
ledgerEvent文档。该文档包含业务事件的会计解释,包括借记和信用分录以及下游所需的过帐上下文。在写入事件之前,工作人员会验证借记和信用分录是否平衡。此控制很重要,因为
ledgerEvents是流程中的第一个不可变的会计集合。写入此处的数据必须准确,然后才能传播到下游的subLedgerEntries和journalEntries。从架构上看,
ledgerEvents是支付域和财务域之间的边界集合。它将支付速度与会计速度解耦,同时保留回溯到发起支付的行程。分类帐本服务的阶段 2 项目实体级别会计分录。
第二个分类帐务工作人员会监视
ledgerEvents,并将每个事件项目到两个subLedgerEntries:一个借记和一个信用。它在 ACID transaction 中将这些条目一起写入,并重新验证事件平衡且两个总分类帐户在分类帐户图表中均为有效的过帐叶。此阶段创建用于客户声明和日内头寸头寸视图的实体级会计真相。
分类帐本服务的阶段 3 帖子总分类帐本。
批处理工作人员会定期对待处理的子分类账分录进行对账,并将其转变为平衡的
journalEntries。如果对账失败,则跳过过帖周期。如果成功,工作人员会写入日志分录,将生成的日志 ID 记录回源记录,并切换其过帖状态。即使是实时付款,总帐也是批处理帖子的。分类帐户(而非 GL)是日内余额的准确来源。该模式支持选择按事务帖子的机构的 REALTIME 帖子模式,但此解决方案使用批处理 GL 帖子,这与标准行业实践一致。
该平台保留端到端、双向可追溯性,使设计可审核。
数据流在业务和会计层之间双向完全可追溯。付款从付款移动到事务,然后移动到
ledgerEvents,然后移动到subLedgerEntries,最后移动到journalEntries。每个日志条目都可以通过该链追溯到发起付款。该双向血统支持管道追踪用户界面、可审计性和下游消费者的架构清晰性。
数据模型方法
数据模型遵循与服务相同的架构分离。每个集合的存在都是为了向流程中独特的业务或会计目的提供服务。
操作集合
customers存储客户数主记录和嵌套的 KYC 上下文。accounts存储当前账户省/市/自治区,并作为余额的可信来源。payments存储付款说明和生命周期省/市/自治区,例如 PENDING 和 SETTLED。transactions存储付款事实,并成为分类帐本管道的事件源。
这些集合支持架构的运行侧。它们直接为客户和帐户工作流提供服务,并由帐户和事务服务同步更新。
会计集合
glAccounts存储账户图表并验证可以发布帖子。ledgerEvents每笔事务存储一条会计边界记录。subLedgerEntries存储实体级别的借记和信用过帖。journalEntries存储平衡的总帐分录。
数据流
流程是细致的,以下步骤总结了集合如何参与过程流:
付款指令将在付款中落地。
同步付款执行会将执行的事实事务写入
transactions,并更新操作账户余额。事务上的变更流会触发分类帐本管道。
分类帐分阶段为每个事务写入一个
ledgerEvent。分类帐事件包含两个腿和过帐模式,用于确定其下游路径。
示例文档:分类帐本事件
{ "eventId": "LE-20260415-000042", "idempotencyKey": "PAY-20260415-0042", "groupId": "GRP-20260415-000042", "eventType": "PAYMENT_PRINCIPAL", "debitLeg": { "glAccountCode": "1001", "controlAccountCode": "1000", "amount": { "$numberLong": "100000" }, "currency": "USD", "entityReference": { "entityType": "ACCOUNT", "entityId": "ACC-001234" } }, "creditLeg": { "glAccountCode": "2100", "controlAccountCode": "2000", "amount": { "$numberLong": "100000" }, "currency": "USD", "entityReference": { "entityType": "ACCOUNT", "entityId": "ACC-001235" } }, "postingMode": { "type": "BATCH" }, "postingStatus": "PENDING", "sourceReference": { "sourceCollection": "transactions", "sourceId": "PAY-20260415-0042", "sourceSystem": "LEDGER_PIPELINE" } } 投影阶段为每个事件写入两个
subLedgerEntries。投影工作人员将一个
ledgerEvent分成两个subLedgerEntries,每条腿一个,在 ACID transaction 中一起写入。每个都可以作为完整的发布单元独立存在;journalEntryId携带""守卫直到gl_batch盖章真实 ID。示例文档:子分类账分录
{ "subLedgerId": "SLE-20260415-000042-D", "idempotencyKey": "LE-20260415-000042:DEBIT", "controlAccountCode": "1000", "side": "DEBIT", "amount": { "$numberLong": "100000" }, "currency": "USD", "periodCode": "2026-04", "status": "POSTED", "journalEntryId": "", "entityReference": { "entityType": "ACCOUNT", "entityId": "ACC-001234" }, "sourceReference": { "sourceCollection": "ledgerEvents", "sourceId": "LE-20260415-000042", "sourceSystem": "LEDGER_PIPELINE" } } 其平衡信用边是第二个文档— 与
sourceId相同,但side和controlAccountCode相反,entityId:ACC-001235。journalEntryId($gt: "") 上的部分索引会排除两者,直到批处理填充真实的日志ID。批处理路径写入平衡的
journalEntries。批处理会将子分类账分录聚合到一个日志中,其平衡行位于嵌入式数组中。
示例文档:日志分录
{ "journalId": "JNL-20260623-EOD-1001", "idempotencyKey": "BATCH-20260623-EOD:1000:2026-06", "periodCode": "2026-06", "journalType": "LEDGER_EVENT_POSTING", "status": "POSTED", "totalAmount": { "$numberLong": "1000000" }, "entries": [ { "lineNumber": 1, "accountCode": "1000", "side": "DEBIT", "amount": { "$numberLong": "1000000" }, "currency": "USD" }, { "lineNumber": 2, "accountCode": "2000", "side": "CREDIT", "amount": { "$numberLong": "1000000" }, "currency": "USD" } ] } 验证器实施会计不变量
三个集合验证器将会计规则推入数据库,因此,跳过服务层的写入仍然不会损坏账簿。
ledgerEvents验证器要求业务字段,并将postingStatus锁定到已知的enum。_LEDGER_EVENTS_VALIDATOR = {"$jsonSchema": { "bsonType": "object", "required": ["eventId", "idempotencyKey", "groupId", "occurredAt", "valueDate", "eventType", "debitLeg", "creditLeg", "postingStatus", "sourceReference", "mappingVersion"], "properties": { "postingStatus": {"bsonType": "string", "enum":["PENDING", "POSTED", "FAILED"]}, "debitLeg": _LEG_SCHEMA, "creditLeg": _LEG_SCHEMA, }, }} subLedgerEntries验证器将side锁定到DEBIT或CREDIT,并将status锁定到POSTED或FAILED,并要求每个文档上都有journalEntryId—""前站可以满足这一要求,直到gl_batch打上真实 ID,因此条目不会超出该生命周期。journalEntries验证器直接实施 Pacioli 平衡不变量:借记行的总和必须等于信用行的总和,在每次写入时使用$expr进行检查。_JOURNAL_BALANCE_VALIDATOR = {"$expr": {"$eq": [ {"$sum": {"$map": {"input": {"$filter": {"input": "$entries", "as": "e", "cond": {"$eq": ["$$e.side", "DEBIT"]}}}, "as": "e", "in": "$$e.amount"}}}, {"$sum": {"$map": {"input": {"$filter": {"input": "$entries", "as": "e", "cond": {"$eq": ["$$e.side", "CREDIT"]}}}, "as": "e", "in": "$$e.amount"}}}, ]}} 会计集合支持架构的财务侧。它们源自运营事件,而不是由账户或事务服务直接写入。
该链条可为您提供运营速度和会计控制。支付执行不会等待完整的 GL 过账,但每笔支付仍会解决为可审计的会计追踪。
为什么 MongoDB 是天然的选择?
客户数和账户数据是分层的,并会随着时间的推移而发生变化。支付记录通过轨道和渠道携带可变元数据。分类账目将相关会计事实分组为单一业务文档。
在 MongoDB 中,您可以存储帐户省/市/自治区、生命周期详情、KYC 上下文、付款事实和嵌入式过帖行,其形状与服务生产和消费数据的方式相匹配。您可以避免关系模型所需的重复平坦和重新组装。
构建解决方案
本节将向您展示如何使用 MongoDB 实现 BIAN,然后如何复制 Leafy Bank BIAN 解决方案。有关完整实现指南,请克隆存储库并按照 GitHub README 中的设置说明执行操作。
使用 MongoDB 实现 BIAN
复制 Leafy Bank BIAN 解决方案
克隆存储库并按照设置说明操作。
Go 到 Github 存储库 并按照 README 中的说明执行以下操作:
准备先决条件
克隆存储库并安装依赖项
预配 MongoDB 数据库
配置后端服务
配置前端代理
创建索引和验证器
播种示例数据
启动服务
验证端到端流程
运行容器化路径(如有需)
关键要点
在此解决方案库中,您了解了如何:
使用 BIAN 框架定义目标架构:服务域创建更清晰的业务边界、数据所有权和 API 合同。
使支付执行与分类账分开:该架构同步更新操作省/市/自治区,异步更新会计省/市/自治区。
在两个流程中使用 MongoDB:ACID 事务、变更流、验证器和聚合管道在一个平台中支持完整模式。
将 ledgerEvents 视为控制边界:在数据进入不可变的财务流程之前验证平衡的会计分录。
模型集合围绕过程流:每个集合都应支持不同的阶段,并保留整个架构的血统。
逐步现代化:从高价值域开始,在不完全替换核心的情况下扩展平台。
作者
Doina Brestoiu
Kiran Tulsulkar
Ainhoa Mugica
Andrea Alaman Calderon