I realized that user is passed to implement access policy. As a fan of OPA I immediately wondered how an integration would be best devised.
Generically speaking an external agent only can ever interact with the domain through the application service layer.
The necessary metadata to decide upon an access policy:
Identifier of the actor
eventually an elevation token
an instance of the domain entity (to base decisions on domain values)
the command to be executed (probably the most important data point to make a policy decision)
Hence, I'm inclined to thing the policy could be well implemented at the application layer and the domain be freed of any policy decision. Although being part of the business logic, it will be flexibly implemented in the policy service (OPA) based on those data points.
I feel this mental model is advantageous, since the domain logic could be implemented free of any policy considerations.
// StartRecordingHandler knows how to start a recording
type StartRecordingHandler struct {
aggregate domain.Repository
commMgr domain.CommManager // interface
policy app.Policy // policy interface implemented at the application, not the domain layer?
}
// Handle starts a recording
func (h StartRecordingHandler) Handle(ctx context.Context, livecallToStartRecordingFor uuid.UUID, userID uuid.UUID, elevationToken string) error {
err := h.aggregate.Update(ctx, livecallToStartRecordingFor, func(l *livecall.Livecall) error {
if ok := h.policy.Can(ctx, "StartRecording", userID, elevationToken, *l); !ok {
return ErrNotAuthorizedToStartRecording
}
if err := l.StartRecording(h.commMgr); err != nil {
return err
}
return nil
})
if err != nil {
return ErrUnableToStartRecording
}
return nil
}
}
While thinking about https://github.com/ThreeDotsLabs/wild-workouts-go-ddd-example/blob/186a2c4a912e485ac7bb4d18c2892df7617e9ec9/internal/trainings/domain/training/repository.go#L16-L27
I realized that
user
is passed to implement access policy. As a fan of OPA I immediately wondered how an integration would be best devised.I feel this mental model is advantageous, since the domain logic could be implemented free of any policy considerations.