Чтобы не получить преждевременную «универсальность» и не размыть ответственность слоёв, мы придерживаемся практики «локально
до последнего». Если модуль используется в рамках одной страницы
— он остаётся внутри страницы. Если появляется второй потребитель
— тогда принимаем решение о переносе.
Практически мы используем такие критерии:- переносим в shared, если это универсальный компонент/утилита без жёсткой привязки к домену страницы и его можно использовать в других контекстах;
- переносим в features, если это полноценный пользовательский сценарий уровня продукта (например, авторизация), который логически живёт «над страницами»;
- оставляем/переносим в app, если речь про инфраструктуру и сквозную конфигурацию приложения.
Так у нас формируется контролируемое переиспользование: shared растёт только за счёт действительно общих вещей, а features остаётся слоем про сценарии, а не «свалкой всего полезного».