# Руководство Backend-разработчика Magistr Добро пожаловать в проект Magistr! Этот бэкенд построен на **Spring Boot** и имеет сложную **мультитенантную архитектуру**, где одно приложение обслуживает множество независимых университетов, каждый со своей базой данных. В проекте также есть интеграция с Kubernetes для "горячего" управления этими тенантами. Здесь описано, как тут всё устроено, чтобы вы ничего не сломали. --- ## 1. Архитектура мультитенантности Мы используем подход **Separate Database per Tenant** (Отдельная БД для каждого клиента). - **Как приложение понимает, к какой базе обращаться?** Все запросы с фронтенда приходят с заголовком `Host` (например, `swsu.zuev.company`). В классе `TenantInterceptor` (находится в `config/tenant/TenantInterceptor.java`) мы перехватываем этот запрос ДО того, как он дойдёт до контроллеров, вытаскиваем поддомен (`swsu`) и сохраняем его в `ThreadLocal` переменную через класс `TenantContext`. - **Как переключаются базы данных?** Класс `TenantRoutingDataSource` наследуется от спринговского `AbstractRoutingDataSource`. Перед каждым запросом в базу (любой `findById` или `save` из репозитория) Spring спрашивает этот класс: *"Какой сейчас ключ тенанта?"*. Класс берёт имя из `TenantContext` и переключает коннект на нужную БД на лету. > **Важно:** Вся логика переключения абсолютно прозрачна для бизнес-кода. В контроллерах и сервисах вы пишете обычный код (`userRepository.findAll()`), и он сам выполнится в нужной базе. --- ## 2. Динамическое управление тенантами (Kubernetes / ConfigMap) Бэкенд спроектирован для работы в **Kubernetes с несколькими репликами (replicas: 2+)**. Список тенантов не зашит в код: - В K8s он лежит в специальном `ConfigMap`, который монтируется внутрь пода как файл `tenants.json`. - В классе `DatabaseController` находится API для добавления нового тенанта из админки. - Чтобы изменения применились ко **всем подам** без перезагрузки, `DatabaseController` вызывает `ConfigMapUpdater`. Этот класс обращается напрямую к **Kubernetes API** (используя ServiceAccount токен пода) и патчит `ConfigMap`. - В фоне работает планировщик `TenantConfigWatcher` (каждые 30 секунд). Он следит за изменениями `tenants.json` и, если видит нового тенанта, на лету поднимает для него новый `HikariCP` пул соединений и добавляет в маршрутизатор баз данных. --- ## 3. Базы данных и Миграции (Flyway) Мы **НЕ используем** автоматическую генерацию таблиц через Hibernate (`spring.jpa.hibernate.ddl-auto=none`). Структурой баз данных правит **Flyway**. Поскольку баз данных много (они создаются динамически), стандартный Spring Boot Flyway отключён. Вместо этого `TenantConfigWatcher` вызывает Flyway **программно** в момент первого подключения нового тенанта. ### 🛑 ПРАВИЛА ИЗМЕНЕНИЯ СТРУКТУРЫ БД: Если вам нужно добавить новую таблицу, колонку или изменить тип поля: 1. **Запрещено трогать старые файлы миграций!** Запомните: файл `V1__init.sql` (и любые другие V-файлы, которые уже попали в коммит) — **СВЯЩЕНЕН**. Если вы его измените, бэкенд не запустится на сервере с ошибкой `Migration checksum mismatch`. 2. **Как правильно добавить таблицу?** - Зайдите в папку `src/main/resources/db/migration/`. - Создайте новый файл. Название **строго** по формату: `V<Номер>__<Описание>.sql`. Например: `V2__add_student_rating_table.sql`. - Напишите в нём ваш SQL (`CREATE TABLE ...`, `ALTER TABLE ...`). - Сохраните и запустите проект. Flyway **сам** пройдёт по всем базам данных тенантов и накатит этот скрипт. 3. **Что если локально я накосячил в V2?** Пока файл `V2_...` не залит в Git и крутится только у вас на локалке, вы можете его переписывать. Но для этого вам нужно зайти в вашу локальную БД (через DBeaver/pgAdmin), вручную откатить свои кривые изменения (удалить таблицу) и **удалить запись из истории Flyway**: `DELETE FROM flyway_schema_history WHERE version = '2';` Либо, что проще: удалите контейнер с локальной БД (`docker compose down -v`) и поднимите заново пустую. --- ## 4. Как запускать проект локально В корневой папке репозитория (где лежит `docker-compose.yaml`) поднимите инфраструктуру: ```bash docker compose up -d ``` Соберется и запустится: - Фронтенд - Бэкенд - Ваша локальная тестовая PostgreSQL-база данных (на порту 5432, имя базы `app_db`, юзер `myuser`, логин/пароль см. в compose файле). Файл `backend/tenants.json` нужен для локальной разработки. Если вы запускаете бэкенд в Docker Compose, вы можете указать URL `jdbc:postgresql://db:5432/app_db` (где `db` — имя контейнера в compose сети). Либо, если вы тестируете взаимодействие бэкенда с вашим текущим IP-адресом (например, `192.168.1.87`), вы можете использовать этот IP. Оба варианта рабочие! Проект сразу подхватит настройки и накатит таблицы через Flyway. Контроллеры и бизнес-логику пишите как в обычном Spring Boot проекте. Главное, помните: у каждого тенанта — своё изолированное хранилище!