# Структура БД и модель данных Документ описывает схемы PostgreSQL, которые используются приложением, а также слой абстракции на базе Ktorm ORM. ## Технологический стек - **PostgreSQL** – основная СУБД. Подключение выполняется через HikariCP (см. `app/Database.kt`), параметры берутся из переменных окружения `DB_*`. - **Ktorm ORM** – легковесная ORM, которая: - предоставляет интерфейсы `Entity` для объектного представления строк; - описывает таблицы через `object Table` (например, `object NewsT : Table("t_news")`); - дает `Database.sequenceOf(Table)` для CRUD-операций и построения SQL через DSL. Каждая доменная сущность имеет: 1. `interface : Entity<>` – декларация полей. 2. `object : Table<>("table_name")` – описание колонок/ключей и связей через `bindTo`/`references`. 3. DTO для сериализации в API. ## Таблицы ### `t_admins` | Колонка | Тип | Описание | |----------------|------------------|---------------------------------------| | `id` | `bigint` (PK) | Идентификатор администратора | | `username` | `varchar` | Уникальное имя пользователя | | `password_hash`| `varchar` | Хеш пароля (bcrypt) | | `created_at` | `timestamp` | Дата регистрации | | `last_login_at`| `timestamp` nul. | Время последней авторизации | Сущность: `AdminEntity`, таблица: `AdminUsers`. Используется модулем `admin` для регистрации, логина, смены паролей и удаления аккаунтов. ### `t_news` | Колонка | Тип | Описание | |----------------|------------------|--------------------------------------------------| | `id` | `bigint` (PK) | Идентификатор новости | | `title` | `varchar` | Заголовок | | `slug` | `varchar` | Уникальный slug для ссылок | | `summary` | `varchar` | Краткое описание | | `content` | `text` | Основной текст | | `status` | `varchar` | `DRAFT` \| `PUBLISHED` \| `ARCHIVED` | | `published_at` | `timestamp` nul. | Дата публикации | | `image_url` | `varchar` nul. | Ссылка на изображение | | `created_at` | `timestamp` | Дата создания | | `updated_at` | `timestamp` | Дата последнего обновления | Сущность: `News`, таблица: `NewsT`. Репозиторий использует фильтры по статусу и slug для публичных и админских запросов. ### `t_service_categories` | Колонка | Тип | Описание | |---------|---------------|-------------------------| | `id` | `bigint` (PK) | Идентификатор категории | | `name` | `varchar` | Название | | `slug` | `varchar` | Уникальный slug | Сущность: `ServiceCategoryEntity`, таблица: `ServiceCategories`. Используется как справочник категорий услуг. ### `t_services` | Колонка | Тип | Описание | |--------------|-------------------|----------------------------------------------------| | `id` | `bigint` (PK) | Идентификатор услуги | | `title` | `varchar` | Название | | `slug` | `varchar` | Уникальный slug | | `description`| `text` | Подробное описание | | `price_from` | `decimal` nul. | Нижняя граница стоимости | | `image_url` | `varchar` nul. | Изображение | | `status` | `varchar` | `PUBLISHED` \| `DRAFT` \| `ARCHIVED` | | `category_id`| `bigint` FK | Ссылка на `t_service_categories.id` (может быть `NULL`) | | `created_at` | `timestamp` | Дата создания | | `updated_at` | `timestamp` | Дата обновления | Сущность: `ServiceEntity`, таблица: `Services`. Поле `category` смоделировано через `references(ServiceCategories)` и возвращает `ServiceCategoryEntity?`. Сервис объединяет услуги и категории для публичного и админского API. ### `t_users` (лиды) | Колонка | Тип | Описание | |-------------|-----------------|------------------------------------------| | `id` | `bigint` (PK) | Идентификатор лида | | `full_name` | `varchar` | Имя и фамилия | | `email` | `varchar` | Контактный email | | `phone` | `varchar` nul. | Телефон | | `created_at`| `timestamp` | Дата поступления заявки | Сущность: `LeadEntity`, таблица: `Leads`. Несмотря на название таблицы `t_users`, фактически хранит только заявки. Админский модуль использует пагинацию и поиск по `full_name`/`email`. ## Связи между сущностями - **Service → ServiceCategory (многие к одному)**: `Services.category_id` ссылается на `ServiceCategories.id`. Ktorm позволяет навигировать через `ServiceEntity.category`. При выборе услуг можно жадно загружать категорию и формировать вложенный DTO. - **Admin, News, Leads** – независимые сущности без внешних ключей на другие таблицы (в текущей версии). - **Status/enum поля** находятся в бизнес-логике: нет отдельных таблиц для статусов, их значения валидируются сервисами. ## Использование Ktorm - **Entity интерфейсы** – объявляют свойства и их типы. Экземпляры создаются через `Entity.Factory`. - **Table объекты** – задают имя таблицы, колонки и связи. Пример: ```kotlin object Services : Table("t_services") { val title = varchar("title").bindTo { it.title } val category = long("category_id").references(ServiceCategories) { it.category } } ``` - **Расширения Database** – в каждом модуле есть свой `val Database.` (например, `Database.news`) для получения `sequenceOf(Table)`: ```kotlin val Database.news get() = this.sequenceOf(NewsT) ``` Это скрывает детали доступа к данным и дает типобезопасные операции (`filter`, `sortedBy`, `take`, `drop`, `insert`, `update` и т.д.). - **DTO слой** – отделяет Ktorm-entity от сериализуемых объектов (например, `NewsDTO`, `ServiceDTO`). Преобразование выполняется в сервисах. ## Итог База данных состоит из пяти основных таблиц, объединенных единым пулом соединений и общими практиками (таймстемпы, статусы, slug). Слабое связывание между сущностями делает схему гибкой, а Ktorm обеспечивает лаконичный и типобезопасный доступ к данным без тяжелых ORM-схем. Диаграмма CRUD-слоя (`docs/crud-model.svg`) дополняет данное описание визуальным представлением потока данных.