Бэкенд (Spring Boot)
Стек и зависимости
| Технология | Версия | Назначение |
|---|---|---|
| Java | 21 | Язык программирования |
| Spring Boot | 4.0.4 | Основной фреймворк |
| Spring Data JPA | — | Доступ к БД через репозитории |
| Spring Security | — | JWT-авторизация |
| PostgreSQL | 15 | Реляционная БД |
| Liquibase | — | Миграции схемы БД |
| MapStruct | — | Генерация маппер-классов |
| AWS SDK v2 (S3) | — | Работа с SeaweedFS |
| Caffeine | — | In-memory кеш |
| JJWT | — | Генерация и валидация JWT |
| Springdoc OpenAPI | — | Swagger-документация |
| Feign | — | HTTP-клиент для mphone API |
| Lombok | — | Генерация boilerplate-кода |
Структура пакетов
ru.mbc.studio.dmshop/
├── controller/ # REST-контроллеры
├── service/ # Интерфейсы сервисов
│ └── impl/ # Реализации сервисов
├── repository/ # Spring Data JPA репозитории
│ └── spec/ # JPA Specifications (динамические фильтры)
├── entity/ # JPA-сущности
├── model/ # Внутренние Java records
├── dto/ # HTTP Request/Response records
│ ├── product/
│ ├── order/
│ ├── user/
│ └── ...
├── mapper/ # MapStruct маппер-интерфейсы
├── exception/ # Доменные исключения
├── common/
│ └── exception/ # GlobalExceptionHandler, ApiErrorResponse
├── config/ # Конфигурационные классы Spring
└── sync/ # Интеграция с mphone API
├── client/
├── config/
├── service/
└── jackson/
Контроллеры и эндпоинты
Публичные (без авторизации)
| Контроллер | Эндпоинт | Метод | Описание |
|---|---|---|---|
| AuthController | POST /api/v1/auth/register | — | Регистрация |
| AuthController | POST /api/v1/auth/login | — | Вход, возвращает JWT |
| ProductController | GET /api/v1/products | — | Список товаров (пагинация, фильтры) |
| ProductController | GET /api/v1/products/{id} | — | Карточка товара |
| CategoryController | GET /api/v1/categories | — | Все категории |
| CategoryController | GET /api/v1/categories/tree | — | Дерево категорий |
| CategoryController | GET /api/v1/categories/homepage | — | Категории для главной |
| BrandController | GET /api/v1/brands | — | Список брендов |
| ReviewController | GET /api/v1/reviews/active | — | Активные отзывы (для витрины) |
| BannerBlockController | GET /api/v1/banner-blocks/active | — | Активные баннеры |
| FeatureItemController | GET /api/v1/feature-items/active | — | Активные фичи |
| AppConfigPublicController | GET /api/v1/config/public | — | Публичные настройки сайта |
| ContactController | POST /api/v1/contacts | — | Отправка обращения |
| ImageController | GET /api/v1/images/{id} | — | Скачать изображение |
| CartController | POST /api/v1/cart/validate | — | Валидация корзины |
Пользовательские (роль USER)
| Контроллер | Эндпоинт | Метод | Описание |
|---|---|---|---|
| OrderController | POST /api/v1/orders | — | Оформить заказ |
| OrderController | GET /api/v1/orders/{id} | — | Просмотр заказа |
| OrderController | GET /api/v1/orders/my | — | Мои заказы |
| AuthController | PUT /api/v1/auth/profile | — | Обновить профиль |
| AuthController | PUT /api/v1/auth/change-password | — | Сменить пароль |
Административные (роль ADMIN / MANAGER)
| Контроллер | Эндпоинт | Описание |
|---|---|---|
| AdminOrderController | GET/PATCH /api/v1/admin/orders | Управление заказами |
| AdminOrderController | POST /api/v1/admin/orders/{id}/submit | Передача в mphone |
| AdminUserController | GET/POST/PUT/DELETE /api/v1/admin/users | Управление пользователями |
| AdminContactController | GET/PUT/DELETE /api/v1/admin/contacts | Обращения клиентов |
| AdminSyncController | GET /api/v1/admin/sync/states | Статус синхронизации |
| AdminSyncController | POST /api/v1/admin/sync/run | Запустить синхронизацию |
| AppConfigAdminController | GET/POST/PUT/DELETE /api/v1/admin/config | Настройки сайта |
| ReviewController | GET/POST/PUT/DELETE /api/v1/reviews | Управление отзывами |
| ReviewController | GET /api/v1/reviews/export | Экспорт отзывов в JSON |
| ReviewController | POST /api/v1/reviews/import | Импорт отзывов из JSON |
| BannerBlockController | GET/POST/PUT/DELETE /api/v1/banner-blocks | Баннеры |
| FeatureItemController | GET/POST/PUT/DELETE /api/v1/feature-items | Фичи |
| ImageController | GET /api/v1/images | Список изображений |
| ImageController | POST /api/v1/images | Загрузить изображение |
| ImageController | PUT /api/v1/images/{id}/replace | Заменить файл (FK сохраняются) |
| ImageController | DELETE /api/v1/images/{id} | Удалить изображение |
| ProductController | POST/PUT/PATCH/DELETE /api/v1/products | Редактирование товаров |
| CategoryController | PUT /api/v1/categories/{id} | Обновить категорию |
Фильтрация товаров
ProductRepository использует JPA Specifications (spec/ProductSpecifications):
// Пример динамического фильтра
Specification<ProductEntity> spec = ProductSpecifications
.hasCategory(categoryId)
.and(ProductSpecifications.hasBrand(brandId))
.and(ProductSpecifications.isActive(true))
.and(ProductSpecifications.priceBetween(min, max));
Параметры через GET /api/v1/products:
categoryId,brandIdminPrice,maxPricesearch(по названию)activepage,size,sort
Сервисы
Каждый сервис содержит интерфейс в service/ и реализацию в service/impl/:
ProductService → ProductServiceImpl
OrderService → OrderServiceImpl
AdminOrderService → AdminOrderServiceImpl
AuthService → AuthServiceImpl
UserService → UserServiceImpl
CategoryService → CategoryServiceImpl
ReviewService → ReviewServiceImpl
ImageService → ImageServiceImpl
BannerBlockService → BannerBlockServiceImpl
FeatureItemService → FeatureItemServiceImpl
AppConfigService → AppConfigServiceImpl
ContactRequestService → ContactRequestServiceImpl
SpamProtectionService — защита от спама (без impl)
CartService → CartServiceImpl
SpamProtectionService
Защищает эндпоинт POST /api/v1/contacts от флуда: ограничивает количество обращений с одного IP за заданный промежуток времени.
MapStruct-маппинг
Каждый домен имеет свой маппер. Пример для Product:
@Mapper(componentModel = "spring")
public interface ProductMapper {
ProductModel toModel(ProductEntity entity);
ProductResponse toResponse(ProductModel model);
ProductEntity toEntity(CreateProductRequest request);
}
Поля, которые не заполняются из запроса (например, externalId, productImages), помечаются:
@Mapping(target = "externalId", ignore = true)
@Mapping(target = "productImages", ignore = true)
Конфигурационные классы
| Класс | Назначение |
|---|---|
SecurityConfig | JWT-фильтр, CORS, разрешения эндпоинтов |
JwtService | Генерация и валидация JWT |
JwtAuthFilter | Servlet-фильтр: читает заголовок Authorization |
JwtProperties | @ConfigurationProperties("jwt"): secret, expirationMs |
S3Config | Создаёт бин S3Client (AWS SDK) для SeaweedFS |
S3Properties | @ConfigurationProperties("storage.s3") |
CacheConfig | Caffeine: 1000 записей, TTL 30 с |
WebConfig | CORS (origin из cors.allowed-origins) |
ApplicationConfig | UserDetailsService, PasswordEncoder |
SchedulingConfig | @EnableScheduling |