Would it be ok to have events in the event stream that does not effect any aggregate in the domain state?
Take for instance an event such as AllCompletedTodosPurged that does nothing more than change a read model with active todos by removing all completed todos.
No, it wouldn't be ok. A Domain event is generated when the aggregate state changes. If nothing changed, there is no domain event.
You can use events outside the domain as well, but they wouldn't be part of the domain and obviously not part of the event stream.
In your scenario, if the event isn't generated as an effect of aggregate change, why it should be contained by any aggregate? And technically speaking, in what event stream will you add that event if it doesn't belong to anything? Will you add that event for all involved ToDos? It makes no sense.
I'm not sure that purge is part of your Domain, but if it is, it means that all completed todos are alreay 'deleted' i.e each involved aggregate already has the ToDoDeleted
event in its collection. AllCompletedTodosPurged
is just an event that is useful to update the read model, but that's it. It shouldn't affect the domain model.
By not affecting the aggregate, I'm assuming you mean private variables inside the aggregate class itself? If you meant something else, ignore this answer.
I find that developers who are implementing ES for the first time tend to struggle with this question. The first time I did an end-to-end reference implementation, I had the exact same question.
I was actually surprised to find that local aggregate state was not as useful as I thought it would be--that state was almost always more naturally expressed in the form of projected read models. The only time you really need local state is when it is required to process an individual event (e.g. for validation).
So I would say it's not only acceptable to support events that don't change local aggregate state, these types of events are arguably more common than events that do change local state.