Background
I'm designing a simple app that lets users sign in via an external OAuth service, and add products to their account, rename them or remove them from their account.
There are two outgoing ports:
- a user account service which handles login, logout, remembering the last logged in user etc. It works with a
UserAccount
with an email address inside as the ID, used throughout in the domain to identify a customer. - a product registration service which accepts the
SerialNumber
of a product and aDeviceOwner
(with only one field: the email address), then adds this info to the database for later retrieval.
Per DDD / hexagonal architecture principles, the implementation of these two services should be entirely separate. Therefore I created two interfaces, and the data structures are also not shared.
Problem
If these are two totally different backend databases, all is OK. But imagine for a moment that both of them need to access the same database. In particular the product registration service needs to add details to the user's own account, which requires the OAuth token of the logged in user as received from the login service.
This poses a problem because the domain is not aware of these details, e.g. the fact that a logged in UserAccount
received from the login service is actually a derived class that adds an internal token
field.
Now, when the registration service wants to add a product to the user's account, they'll only receive the DeviceOwner
with an email address inside, but in converting from one service's output UserAccount
to another service's input DeviceOwner
, the domain has lost the OAuth token.
So my question is, how can we keep the domain independent of these infrastructure details, while still be able to pass on implementation-level data from one service to another?
Related problem
In the same vein, looking at the login service itself, right now I use OAuth which doesn't require any UI in my app. But say we want to replace it with our own ID provider. This would now require a username and a password before the login request can be sent. The UI, domain, and service provider all need to be aware of this. Which means the domain will need to change both its incoming port and outgoing port to now require these 2 additional fields. Whereas conceptually in the domain, I don't care what the customer required to login to the app (my UserAccount
object just needs to have an email address as a way to identify the customer). How to avoid depending on such infra details in the domain?