Add docker

This commit is contained in:
Evgenii Saenko
2025-12-17 11:52:18 +03:00
parent 2d5b329b36
commit ea390b1533
38 changed files with 1359 additions and 165 deletions

119
docs/db-structure.md Normal file
View File

@@ -0,0 +1,119 @@
# Структура БД и модель данных
Документ описывает схемы PostgreSQL, которые используются приложением, а также слой абстракции на базе Ktorm ORM.
## Технологический стек
- **PostgreSQL** основная СУБД. Подключение выполняется через HikariCP (см. `app/Database.kt`), параметры берутся из переменных окружения `DB_*`.
- **Ktorm ORM** легковесная ORM, которая:
- предоставляет интерфейсы `Entity` для объектного представления строк;
- описывает таблицы через `object Table<T>` (например, `object NewsT : Table<News>("t_news")`);
- дает `Database.sequenceOf(Table)` для CRUD-операций и построения SQL через DSL.
Каждая доменная сущность имеет:
1. `interface <Entity> : Entity<<Entity>>` декларация полей.
2. `object <Table> : Table<<Entity>>("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<ServiceEntity>("t_services") {
val title = varchar("title").bindTo { it.title }
val category = long("category_id").references(ServiceCategories) { it.category }
}
```
- **Расширения Database** в каждом модуле есть свой `val Database.<entities>` (например, `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`) дополняет данное описание визуальным представлением потока данных.