Как правильно разделять бэкенд и фронтэнд в сложных веб-приложениях?
SPA - полноценное самодостаточное приложение, а потому вынести это добро в отдельный репозиторий - вполне себе нормальное решение. Аналогия - разработка мобильных приложений и бэкэнда к оному. Вести такую разработку в одном репозитории как минимум будет неудобно.
И если с мобильными приложениями все понятно, то с фронтэндом могут быть замуты. Например, вы хотите сделать страничку логина просто на Symfony/Django, и потом редиректить уже на SPA после того, как будет получен аутентификационный токен.
опять же я не вижу никаких проблем в этом случае держать все в разных репозиториях и использовать фронтэнд как зависимость к бэкэнду (что бы уже собранное фронтэнд приложение подключалось).
или еще интереснее. Какой-то прелоад данных. Например мы можем захотеть заинлайнить в html какие-то данные, которые генерит бэкэнд. Чтобы эти данные были доступны клиенту еще до того, как загрузится ангуляр. В этом случае опять же мы можем генерить точку входа при помощи готового html шаблона, поставляемому нам со стороны фронтэнда и силами какого-нибудь twig/jninja инлайнить json в тело страницы:function data() {
    return {{data | json}};
}
Но это оооочень редкие кейсы.
1 подход - 2 репозитория, один для фронтенда, другой для бэкенда.
2 подход - фронт внутри бэкенд проекта. Единственное что будет, в одном репозитории коммиты для обоих частей, но я не могу сказать что это большая проблема, в конце концов фильтровать, индексировать коммиты для определенных частей и.т.д. Я так работал, не могу сказать что это было не удобно. Просто у вас появляется возможность поднять весь проект целиком и сразу. Иначе нужно настраивать роутинг и.т.д.