Очень широкий вопрос, он вполне может быть закрыт, но я постараюсь дать вам несколько руководящих мыслей:
Как правило, вы либо срезаете по горизонтали (как вы это сделали, UI-модуль со всеми представлениями плюс логический модуль со всеми услугами) или по вертикали (как предлагает ваш Product-модуль: представления, представления моделей, услуги для продукта в один модуль, те для пользователя в другом).
Вы можете сделать и то, и другое, но тогда вам нужно «прорезать», так что один модуль для product-ui, один для user-ui, один для product-services, один для user-services ... вы понимаете. Это означает, что много модулей, однако.
Кроме того, при создании своих модулей имейте представление о том, чего вы хотите достичь. Модули могут инкапсулировать компоненты для повторного использования в другом приложении. Или же они могут заключать в себе заменяемые компоненты, так что вы можете создать приложение для совместного использования автомобилей сегодня, а завтра поменять автомобильный модуль на велосипедный модуль и иметь приложение для совместного использования велосипедов. Или же они могут быть использованы для обеспечения разделения кода на основе анализа рисков в регулируемой среде. То, что я пытаюсь передать: не создавайте модули просто для того, чтобы иметь модули, сделайте так, чтобы у каждого модуля было определенное назначение.
Кроме того, определите интерфейсы для модулей. Я не люблю, чтобы модули ссылались друг на друга, поскольку это эффективно уничтожает все сегрегации, которые в противном случае были бы там. Создайте отдельные немодульные сборки, которые содержат только открытые интерфейсы. Затем сделайте так, чтобы ваши модули содержали реализации как внутренние типы. В идеальном мире ни одна сборка модуля не содержит открытый тип. Интерфейсные сборки могут быть либо для модуля, либо для потребителя, либо для связи между модулями (эти флажки на вашей N2-диаграмме есть, не так ли?).
Вы хотите сохранить разумное количество модулей, а также зависимости между ними (не как в «ссылках на сборку», а через интерфейс-сборку).
как мы можем ссылаться на сборки nuget из этого модуля в оболочке (например, для их применения), чтобы избежать ссылок в каждом модуле и оболочке?
Вы должны отделить часть «интерфейса» (например, базовые классы или DTO, а не часть модуля) и фактическую часть служб (это модуль). Пример: unity имеет пакет nuget для интерфейсов ( Unity.Abstractions ) и пакет, содержащий реализацию контейнера ( Unity.Container ). Нет ничего плохого в том, что все ссылаются на интерфейс, в основном это говорит: «Я хочу использовать этот интерфейс».