1.0.0
“Ambient Context & Pluggable Metadata”
BREAKING
1.0 把 event metadata 從固定的 external: [String:String]? 字串字典通道,
全面改成型別安全的 ambient context 機制。Domain 層
(AggregateRoot / DomainEvent / Usecase)完全不受影響。
🚀 新增
EventMetadata— 新的 marker protocol(Codable & Sendable, 不規範任何欄位)。應用層自訂 metadata schema 時 conform 它。EventMetadataContext<M>—TaskLocal-backed 的 ambient carrier。在 Usecase 入口用withValue(_:operation:)設一次,巢狀的repository.save透過 structured concurrency 自動繼承。- 型別化 metadata 通道 —
EventStore新增associatedtype Metadata: EventMetadata;append收型別化的metadata: Metadata?。
⚠️ 破壞性變更
| 項目 | 0.x | 1.0 |
|---|---|---|
| 儲存抽象 protocol | EventStorageCoordinator | EventStore |
| Repository/Projector 型別參數 | associatedtype StorageCoordinator | associatedtype Store |
| Repository/Projector 儲存屬性 | var coordinator | var store |
| append metadata 通道 | external: [String:String]? | metadata: Metadata? |
| Kurrent 儲存實作泛型 | KurrentStorageCoordinator<S> | KurrentStorageCoordinator<S, Metadata> |
| In-memory 儲存實作泛型 | InMemoryStorageCoordinator | InMemoryStorageCoordinator<Metadata> |
| save / delete | save(aggregateRoot:external:) | save(aggregateRoot:) + ambient |
| userId 便利方法 | save(…userId:) / delete(…userId:) | 已移除 |
| 事件型別判斷 | RecordedEvent.mappingClassName | RecordedEvent.eventType |
RecordedEvent.userId | 便利 accessor | 已移除 |
CustomMetadata 結構 | { className, external } | { operatorId } |
✓ 不受影響
DomainEventprotocol — 仍有associatedtype Metadata與var metadata。AggregateRoot/Usecase/DomainEventBus/ReadModel— 介面未動。EventSourcingProjector.apply(readModel:events:)— 簽章不變。EventStore.fetchEvents— 仍回傳(events:, latestRevision:)tuple。
升級你的專案?
若有專案依賴 swift-ddd-kit,完整的逐項遷移步驟、多圖表說明,以及給 AI agent 的
機器可讀遷移清單(JSON manifest)都在專屬的 Migration Guide。
開啟 0.x → 1.0 Migration Guide →
開啟 0.x → 1.0 Migration Guide →
為什麼做這次重構?
0.x 用 external: [String:String]? 字串字典把 audit metadata
帶到儲存層,造成三個問題:(1) Domain 抽象被基礎設施 metadata 汙染;(2) schema 被鎖死成
dict,無型別安全的擴充空間;(3) 跟既有的 DomainEvent.Metadata 機制重複。
1.0 用 ambient context + pluggable schema 一次解決——詳見 Migration Guide 的「為什麼要改」。