A Merkle-tree data structure + an append only log with checkpoints + a command processor would provide a basic foundation.
Your data can be represented in a Merkle-tree. You provide operations add-node, delete-node, move-node etc., on the Merkle-tree and build a command processor that takes as input a checkpointed Merkle-tree snapshot (could be empty when you start) and a log of operations (essentially an sequence of operations). The command processor then applies the series of tree operations in the log to build the final state of the tree. The special checkpoint operation saves a snapshot of the Merkle-tree.
This basic set of operations should allow you to do unlimited undo/redo/transaction playback capabilities.
Your data can be represented in a Merkle-tree. You provide operations add-node, delete-node, move-node etc., on the Merkle-tree and build a command processor that takes as input a checkpointed Merkle-tree snapshot (could be empty when you start) and a log of operations (essentially an sequence of operations). The command processor then applies the series of tree operations in the log to build the final state of the tree. The special checkpoint operation saves a snapshot of the Merkle-tree.
This basic set of operations should allow you to do unlimited undo/redo/transaction playback capabilities.
Also see: Command Pattern, https://en.wikipedia.org/wiki/Command_pattern