The domain:
I have an InventoryItem aggregate and a Kit aggregate. An InventoryItem may be added to one (and only one) Kit. An InventoryItem has a Type property, which is an enum of various item types the business uses. A Kit will have multiple InventoryItems.
I am using event sourcing. Each InventoryItem aggregate is stored in its own event stream, and each Kit aggregate is stored in its own event stream.
The problem:
An InventoryItem must know whether it is part of a Kit in order to enforce invariants such as blocking deletion if it is, and not allowing it to be added to another Kit.
A Kit must know how many and what type of InventoryItems have been added to it in order to enforce invariants such as not allowing shipment until the Kit requirements are completely satisfied.
However, one transaction is supposed to affect only one aggregate. So, when an InventoryItem is added to a Kit, I'm unable to use one transaction to update both the Kit and the InventoryItem with the required information. I've been thinking through several solutions, and each one seems to present several issues.
Using a process manager/saga to model the operation as a long-running process.
This feels wrong to me, as the operation is really not a long-running process. It also runs the risk of a stage failing and requiring rollback of the previous stage. All in all, it feels like a lot of overhead for something that should be a simple operation.
Using domain events to update either the Kit or InventoryItem.
I could update one of the aggregates with the initial transaction, then dispatch a domain event to update the second aggregate. However, this runs the risk of an out-of-sync domain model if for some reason the dispatched event fails. Such a case would also introduce the possibility of another user adding the InventoryItem to another Kit before the out-of-sync model is noticed and fixed. Once again, it feels like there are a lot of potential problems and complexity for what is a very simple operation.
Creating another aggregate.
I've considered introducing another aggregate such as KitItem. This aggregate would essentially store the Kit/Inventory Item relationship, and the Kit and InventoryItem aggregates would hold references to it. This seems to me to be the most reasonable approach, and yet it once again introduces the possibility of an out-of-sync model. For example, what if a Kit is deleted? We could use a domain event to delete all KitItems with a relationship to the Kit, but what if that fails for some reason? Additionally, if the Kit is only allowed to hold a reference to the KitItem, how would the Kit know what types of InventoryItems have been added to it?
Does anyone have any advice on what approach to take here, or if there's another approach I haven't considered?