In the first place, keep the data normalized (not redundant) as much as you can.
If the data is fully normalized, no single update to the data can make it inconsistent.
You can't always keep the data normalized, in other words you may not be able to eliminate redundancy, in which case it can have inconsistent states.
The thing to do then is tolerate the inconsistency and repair it periodically with some kind of program that sweeps over it and patches it up.
There is a strong tendency to try to manage redundancy tightly by means of notifications.
These are not only difficult to be sure they are correct, but can lead to enormous inefficiencies.
(Part of the temptation to write notifications arises because in OOP they are practically encouraged.)
In general, anything that depends on time-sequence of events, messages, etc., is going to be vulnerable and require tons of defensive coding.
Events and messages are characteristic of data with redundancy, because they are communicating changes from one part to another, trying to prevent inconsistency.
As I said, if you must have redundancy (and chances are pretty good you must), it is best to be able to a) tolerate, and b) repair it.
If you try to prevent inconsistency solely by means of messages, notifications, triggers, etc., you will find it very hard to make it robust.