Silly question...but why do I need a Domain model at all if I use event sourcing.
I have (an Event Bus of course) and
- Application Services with business operations that each send a Command after basic validation
- Command Handlers which receive Commands perform additional Command validation and publish Events
- Event Handlers which handle Events, update the Read Model, and store the event in a Repository (the Event Source)
- Read Model Services which provide Read Models
- Front ends (UI or otherwise) that consume Read Models from the Read Model Services)...and utilize Application Services for business operations.
Why do I need aggregate roots and domain entities at all? What's the function of the additional layer?
Sounds like you may be doing a bit too much in your command handler. Just to be clear - the role of the command handler is to receive the command, load the appropriate aggregate and to send the command into the aggregate. Finally it grabs any events the aggregate may have generated persists them and finally publishes them. Here is the diagram I have on my blog.
For a fuller step by step overview of a typical CQRS + ES application have a look at my post: CQRS + Event Sourcing - A Step by Step Overview
I hope that clears some things up for you. PS. You may want to take a look at how to create an aggregate root for CQRS and ES. You can find that post here