A little remark, and then a tentative answer.
Use eventual consistency between aggregate's boundaries (before asking whose job it is)
That's aggregate design by definition. We might argue whether this is a good or bad decision, but the Aggregate in Domain-Driven Design is a "unit of consistency". This is not to say that this is "the right way to do things", only that, when we talk about aggregates, this principle is somewhat implicit.
If I'm not mistaken, one of DDD's reasons for being is avoiding spaghetti code, where business logic is scattered all around on, most of times, a fat service layer. Are you not scattering business logic when you use eventual consistency?
DDD doesn't exist for avoiding spaghetti code, but to provide a sensible way of designing code in places where you have frequent evolutions (due to intrinsic domain complexity - code is changed because people learn - or to rapidly evolving domains - code is changed because we are competing with new ideas). However... spaghetti gets in the way when you are pushing for frequent changes. ;-)
"Scattering business logic" per se isn't a good or a bad thing, until you take into account Bounded Contexts and different purposes that the software might serve. If the business logic belongs to different bounded contexts, then it's fine if it's not in the same place. In CQRS/ES for example, coordination logic frequently gets placed into ProcessManagers, reacting to external Domain Events.
Is there any other way to represent the business ubiquitous language other than having a rich domain model? Can't the language be expressed in a fatter service layer?
Another little clarification is needed: there is no such thing as "the business ubiquitous language". There are many languages with different purposes. They can be made ubiquitous and consistent only within the boundary of a Bounded Context, where they will be expressed well... everywhere (that's the ubiquity), from Acceptance Tests to UI labels to database field names.
The need of a fatter service layer often arises from a misconception of what a model is. If the model is principally behavioural, then its behaviour is decoupled from what users need to see. However, this decoupling is not spread evenly: some portions of the system will look CRUD-like, while in other portions the distance between what the software is doing and what a user needs to see might be strong enough to call for distinct models.
Focusing on what users need to see leads invariably to overlapping models: things with the same name that different users use in different ways. That's because the data looks the same, forcing promiscuous sharing. When the data is promiscuous, the obvious place to put the logic is the service layer. But the problem is upstream of that.
One way to view CQRS is that it's commands (messages) all the way down.
Taking your example:
- Application layer send GiveReward command to reward management with a correlation ID.
- Reward management fires a CreateTransaction command to the account bounded context, with the Correlation ID included.
- CreateTransaction finishes and broadcasts a TransactionCompleted event with the correlation ID.
- The Application Layer listens to TransactionCompleted events and connects it back to the original request through the correlation ID.
For your web front-end you can extend this approach to there as well. E.g. in a react/redux approach the command is relayed to the server, which eventually updates the redux store over a websocket feed which relays GiveRewardCompleted events.
Other approaches are returning the correlation ID to the front-end and have it poll the server for updates, or block at the server edge until a TransactionCompleted message is received.
Best Answer
CQRS is a principle, not a dogma. Like all principles, it has its positive and negative aspects in its own right. Departing from "pure CQRS" could just mean that you can't meaningfully call it CQRS.
Quoting Martin Fowler:
In other words, queries crafted this way are idempotent, and therefore provide the same benefits as any other idempotent or "pure" method. cf. functional programming.
Like all techniques, it has a cost:
The questions you need to ask yourself are these: do you need these benefits or not? And are the benefits worth the additional cost?
Fowler discusses the benefits and pitfalls of CQRS in detail here and here.