Learning DDD here.
There is two kind of users Members and Staff. A Member can have a list of subscriptions and are able to purchase additional subscriptions at any time. Staff user can also add a subscription to a member. When staff user adds a subscription to the member system should remember who added this subscription.
Members and staff users are in completely different bounded context. They have the different set of rights and the different group they can attend. So I created a Member aggregate root which contains a list of Subscriptions in separate bounded context "Member". Then i created Staff aggregate root in seprate Bounded context Staff".
When members want to purchase additional subscription it is easy, MemberService just attaches a new Subscription to a member because Subscription is part of the Member aggregate and Member bounded context.
However, when staff user wants to add a new subscription to a user the problem starts because it's not the member who purchase a subscription to itself anymore, it is staff who assign a subscription to a member.
I see multiple solutions here, but none of them seems completely right.
What am I missing here?
Sub question:
Is it allowed to use same DTOs across multiple bounded contexts services?
From what I understand you have indeed at least two bounded contexts but not (only?) those that you identified: Subscriptions bounded context
and Authorization bounded context
.
Subscriptions bounded context
contains the logic that is used when the members get new subscriptions or cancel an existing subscription. The rules are like this: a member can have as many subscriptions he wants. A subscription can be added by somebody else.
Authorization bounded context
contains the rules by which a user
may add subscriptions to a member. If the user is a member then he may add subscriptions only to his member account. If the user is from the staff then he may add subscriptions to other members but not to its own, unless he is also a member (the first rule).
Having two bounded contexts, you need to integrate them. In the use case "adding a subscription to a member" there are used both bounded contexts. You can implement this in the Application service by calling first a query/domain service from the Authorization bounded context
to check if the current authenticated user may add a subscription to the member. If he may not then return with an exception otherwise load the MemberSubscriptions
aggregate, call addSubscription(subscriptionId, idIfTheUserThatAddsTheSubscription, subscriptionType, etc...)
then persist the aggregate in the repository.
Note that the Application service did not instantiated a new Subscription
entity, that is the job of the MemberSubscriptions
aggregate and you must protect its encapsulation. You can even keep the Subscription
entity class as private (protected, package or whatever language mechanism you have in C#). Anyway, any access to a members subscription must be done from the MemberSubscriptions
aggregate root (like addSubscription
, removeSubscription
, hasSubscription
etc).