Skip to content

四类事实形态与域模型 ​

平台不是「所有数据都进事件流」,也不是「每个业务一套机制」。 统一的是寻址、因果、权限三个契约;存储形态按事实形态选择。


为什么需要这个模型 ​

企业里同一个对象在各系统中状态不同步,根源不是系统太多,是写入路径太多。

所以平台的做法是:每个事实只有一个可写路径,且每次写入都留下带因果的证据。 但不同事实的形态差异很大——订单需要因果链,库存需要原子扣减,物料需要唯一约束。

把它们塞进同一种存储,必然有地方别扭。于是按形态分四类。


四类事实 ​

形态用来存存储为什么
事件订单、期间、交付、审批state_events + state_entries有「谁在何时做了什么」,需要因果与定责
余额资源库存、配额、积分ledger_accounts + ledger_movements要 O(1) 读余额 + 原子扣减
主数据物料、供应商、客户master_entities + master_aliases要唯一约束 + 实体合并
计算定价、MRP、排程computation_runs是算法,不是状态;只存运行证据

四类共享同一个访问契约:

typescript
interface IDomainStore {
  read(path) / write(path, value, actor) / history(path) / list(namespace)
}

所以「加一个业务域」= 选一种存储 + 一份声明,而不是再写一套因果与审计。


域与命名空间 ​

/tasks/{taskId}/deliveries/{id}     domain=tasks       namespace=/tasks/{taskId}
/orders/{orderId}/lines/{id}        domain=orders      namespace=/orders/{orderId}
/periods/{periodId}/entries/{id}    domain=periods     namespace=/periods/{periodId}
/master/{entityType}/{code}         domain=master      namespace=/master/{entityType}
概念定义作用
域path 第一段治理单位:权威、期间策略、写入白名单
命名空间path 前两段串行单位:序号单调、复放边界

一个域下可以有多个命名空间(每个实体一个),同一实体的写入串行、不同实体并行。


域声明与默认拒绝 ​

每个域必须显式声明:

字段作用
factClass选哪种存储;声明后不可更改(换类别 = 数据迁移级事件)
authoritynative(我们说了算)/ mirrored(外部说了算)/ federated
periodPolicy这个域是否参与期间结账
writers域级写入白名单

未声明的顶层域写入被拒——新增域必须是显式决策,不是偶然结果。


越权在机制上不可能 ​

三条约束都在存储层执行,不在应用层:

约束强制点绕得过吗
谁能写哪种事实写入权威表绕不过(写入口唯一)
已关闭期间不接受新分录期间门禁绕不过(在 writeMany 里)
已合并的主数据不会读错主数据存储内部解析绕不过(读路径统一)
余额不会被扣成负数数据库条件更新绕不过(原子操作)

不靠调用方自觉,靠机制拒绝。


一条业务串起四类 ​

① 物料(主数据)      /master/material/M-001
② 算价(计算)        pricing v1 → 100000
③ 订单(事件)        /orders/{orderId}
④ 预留库存(余额)    /ledger/stock/M-001  debit 1 → 余额 99
⑤ 交付 / 验收(事件)  /tasks/{taskId}/deliveries|acceptance
⑥ 结算(事件)        escrow.settle
⑦ 分录(账务)        /periods/task:{taskId}/entries/{entryId}

这条链路可以用一条命令跑完并打印试算平衡表:

bash
npm run case:reference -- --commit

同一事实只有一个权威 ​

这是跨四类的最重要规则:

✅ 订单行存 materialCode
❌ 订单行再存一份 materialName(物料改名时两边就漂移了)

✅ 分录存 sourceEventId,需要金额时回查
❌ 分录冗余存订单金额(除非是结账时点快照,且带 snapshotAt)

违反它就等于把多系统的问题搬进同一个数据库。


边界 ​

不做原因
通用会计引擎只做托管池内部怎么分;多准则、税务不在范围
全量数据集成 / 数据中台会变成 ETL 产品,且没有实体解析能力
主数据自动概率匹配相似度阈值需要真实数据才能调
计算的分布式执行当前算法足够轻

继续读 ​

Released under the MIT License.