Серверная часть интернет-магазина музыкальных инструментов и виниловых пластинок, построенная на Ktor и Kotlin.
- Язык: Kotlin 1.9.22
- Фреймворк: Ktor 2.3.7
- База данных: H2 Database (in-memory)
- ORM: Exposed 0.44.1
- Сериализация: Kotlinx Serialization
- Логирование: Logback
- Сборка: Gradle 8.x
- JDK 17 или выше
- Gradle 8.x (или использовать wrapper)
git clone <repository-url>
cd music-store-backend# Сборка проекта
./gradlew clean build
# Запуск
./gradlew runСервер запустится на http://localhost:8080
curl http://localhost:8080/api/productssrc/main/kotlin/com/musicstore/
├── Application.kt # Точка входа приложения
├── models/
│ ├── Database.kt # Инициализация H2 БД
│ └── Tables.kt # Схемы таблиц (Exposed DSL)
├── repositories/
│ └── UserRepository.kt # Бизнес-логика
├── routes/
│ ├── AuthRoutes.kt # Авторизация
│ ├── ProductRoutes.kt # Товары
│ ├── OrderRoutes.kt # Заказы
│ ├── AdminRoutes.kt # Админ панель
│ └── StatisticsRoutes.kt # Статистика
├── plugins/
│ ├── Routing.kt # Регистрация маршрутов
│ └── Serialization.kt # JSON + CORS
└── seed/
└── DatabaseSeeder.kt # Тестовые данные
- users - Пользователи (3 записи)
- categories - Категории товаров (6 категорий)
- products - Товары (50 товаров)
- warehouses - Склады (3 склада)
- stores - Магазины (4 магазина)
- employees - Сотрудники (4 человека)
- clients - Клиенты (4 клиента)
- orders - Заказы (7 заказов)
- order_products - Связь заказов и товаров
| Username | Password | Role |
|---|---|---|
| admin | admin | ADMIN |
| john | password | USER |
| maria | password | USER |
POST /api/auth/register
Content-Type: application/json
{
"username": "newuser",
"email": "user@example.com",
"password": "password123",
"fullName": "Иван Иванов"
}Ответ 200:
{
"user": {
"id": 4,
"username": "newuser",
"email": "user@example.com",
"fullName": "Иван Иванов",
"role": "USER"
},
"token": "fake-jwt-token"
}POST /api/auth/login
Content-Type: application/json
{
"username": "john",
"password": "password"
}GET /api/auth/user/:idPUT /api/auth/user/:id
Content-Type: application/json
{
"username": "john",
"email": "newemail@example.com",
"fullName": "John Doe Updated"
}GET /api/products # Все товары
GET /api/products?categoryId=2 # По категории
GET /api/products?search=guitar # Поиск по названиюОтвет 200:
[
{
"id": 11,
"article": "ART-00011",
"name": "Fender Stratocaster American Professional II",
"description": "Легендарная электрогитара...",
"categoryId": 2,
"categoryName": "Гитары",
"price": 189990,
"quantityInStock": 5,
"imageUrl": "data:image/svg+xml...",
"warehouseId": 1
}
]GET /api/products/:idPOST /api/products
Content-Type: application/json
{
"article": "ART-00051",
"name": "Новый товар",
"description": "Описание товара",
"categoryId": 2,
"price": 50000,
"quantityInStock": 10,
"imageUrl": "https://example.com/image.jpg",
"warehouseId": 1
}PUT /api/products/:id
Content-Type: application/json
{
"name": "Обновленное название",
"price": 55000,
"quantityInStock": 15
}DELETE /api/products/:idGET /api/ordersОтвет 200:
[
{
"id": 1,
"orderDate": "2025-12-10",
"orderStatus": "COMPLETED",
"totalCost": 190889,
"totalWeight": 3500,
"itemCount": 2,
"employeeName": "Иванов Иван Иванович",
"storeName": "Москва, ул. Тверская, д. 12",
"clientName": "Алексей Смирнов",
"clientPhone": "+7 (916) 111-22-33",
"userId": 2
}
]GET /api/orders/user/:userIdGET /api/orders/:idGET /api/orders/:id/itemsОтвет 200:
[
{
"productId": 11,
"productName": "Fender Stratocaster American Professional II",
"quantity": 1,
"price": 189990
}
]POST /api/orders
Content-Type: application/json
{
"userId": 2,
"fullName": "Джон Доу",
"phone": "+7 999 123-45-67",
"email": "john@example.com",
"address": "Москва, ул. Ленина, д. 1",
"notes": "Позвонить за час до доставки",
"items": [
{ "productId": 11, "quantity": 1 },
{ "productId": 40, "quantity": 2 }
]
}PATCH /api/orders/:id/status?status=COMPLETED
PATCH /api/orders/:id/status?status=CANCELLEDДопустимые статусы: PENDING, COMPLETED, CANCELLED
DELETE /api/orders/:idGET /api/admin/categories # Получить все
POST /api/admin/categories # Создать
DELETE /api/admin/categories/:id # УдалитьPOST Body:
{
"name": "Аудиотехника",
"slug": "audio",
"description": "Описание категории",
"imageUrl": "https://example.com/image.jpg"
}GET /api/admin/warehouses
POST /api/admin/warehouses
DELETE /api/admin/warehouses/:idPOST Body:
{
"address": "Новосибирск, ул. Ленина, д. 1",
"phone": "+7 383 555-55-55"
}GET /api/admin/stores
POST /api/admin/stores
DELETE /api/admin/stores/:idGET /api/admin/employees
POST /api/admin/employees
DELETE /api/admin/employees/:idPOST Body:
{
"fullName": "Петров Петр Петрович",
"storeId": 1,
"phone": "+7 999 888-77-66",
"hireDate": "2025-12-20"
}GET /api/admin/clients
POST /api/admin/clients
DELETE /api/admin/clients/:idGET /api/admin/users
DELETE /api/admin/users/:idGET /api/statistics/summaryОтвет 200:
{
"totalProducts": 50,
"totalOrders": 7,
"totalRevenue": 1221822,
"totalUsers": 3,
"lowStockCount": 2,
"pendingOrders": 2,
"completedOrders": 5
}GET /api/statistics/revenueGET /api/statistics/top-products# Сборка проекта
./gradlew clean build
# Запуск сервера
./gradlew run
# Запуск с автоперезагрузкой
./gradlew run --continuous
# Проверка кода
./gradlew check
# Создание JAR
./gradlew jar
# Список зависимостей
./gradlew dependenciesЛоги настроены через Logback. Уровень логирования по умолчанию: INFO.
Для изменения уровня отредактируй src/main/resources/logback.xml.
По умолчанию сервер использует порт 8080. Изменить можно в Application.kt:
embeddedServer(Netty, port = 8080, host = "0.0.0.0")- База данных H2 работает in-memory и сбрасывается при перезапуске
- CORS настроен для
localhost:3000(фронтенд) - Все пароли хранятся в открытом виде (для демо)
- JWT токены не реализованы (возвращается fake-token)
MIT License
MusicStore Backend Team