Перейти к основному содержимому

Бэкенд (Spring Boot)

Стек и зависимости

ТехнологияВерсияНазначение
Java21Язык программирования
Spring Boot4.0.4Основной фреймворк
Spring Data JPAДоступ к БД через репозитории
Spring SecurityJWT-авторизация
PostgreSQL15Реляционная БД
LiquibaseМиграции схемы БД
MapStructГенерация маппер-классов
AWS SDK v2 (S3)Работа с SeaweedFS
CaffeineIn-memory кеш
JJWTГенерация и валидация JWT
Springdoc OpenAPISwagger-документация
FeignHTTP-клиент для 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/

Контроллеры и эндпоинты

Публичные (без авторизации)

КонтроллерЭндпоинтМетодОписание
AuthControllerPOST /api/v1/auth/registerРегистрация
AuthControllerPOST /api/v1/auth/loginВход, возвращает JWT
ProductControllerGET /api/v1/productsСписок товаров (пагинация, фильтры)
ProductControllerGET /api/v1/products/{id}Карточка товара
CategoryControllerGET /api/v1/categoriesВсе категории
CategoryControllerGET /api/v1/categories/treeДерево категорий
CategoryControllerGET /api/v1/categories/homepageКатегории для главной
BrandControllerGET /api/v1/brandsСписок брендов
ReviewControllerGET /api/v1/reviews/activeАктивные отзывы (для витрины)
BannerBlockControllerGET /api/v1/banner-blocks/activeАктивные баннеры
FeatureItemControllerGET /api/v1/feature-items/activeАктивные фичи
AppConfigPublicControllerGET /api/v1/config/publicПубличные настройки сайта
ContactControllerPOST /api/v1/contactsОтправка обращения
ImageControllerGET /api/v1/images/{id}Скачать изображение
CartControllerPOST /api/v1/cart/validateВалидация корзины

Пользовательские (роль USER)

КонтроллерЭндпоинтМетодОписание
OrderControllerPOST /api/v1/ordersОформить заказ
OrderControllerGET /api/v1/orders/{id}Просмотр заказа
OrderControllerGET /api/v1/orders/myМои заказы
AuthControllerPUT /api/v1/auth/profileОбновить профиль
AuthControllerPUT /api/v1/auth/change-passwordСменить пароль

Административные (роль ADMIN / MANAGER)

КонтроллерЭндпоинтОписание
AdminOrderControllerGET/PATCH /api/v1/admin/ordersУправление заказами
AdminOrderControllerPOST /api/v1/admin/orders/{id}/submitПередача в mphone
AdminUserControllerGET/POST/PUT/DELETE /api/v1/admin/usersУправление пользователями
AdminContactControllerGET/PUT/DELETE /api/v1/admin/contactsОбращения клиентов
AdminSyncControllerGET /api/v1/admin/sync/statesСтатус синхронизации
AdminSyncControllerPOST /api/v1/admin/sync/runЗапустить синхронизацию
AppConfigAdminControllerGET/POST/PUT/DELETE /api/v1/admin/configНастройки сайта
ReviewControllerGET/POST/PUT/DELETE /api/v1/reviewsУправление отзывами
ReviewControllerGET /api/v1/reviews/exportЭкспорт отзывов в JSON
ReviewControllerPOST /api/v1/reviews/importИмпорт отзывов из JSON
BannerBlockControllerGET/POST/PUT/DELETE /api/v1/banner-blocksБаннеры
FeatureItemControllerGET/POST/PUT/DELETE /api/v1/feature-itemsФичи
ImageControllerGET /api/v1/imagesСписок изображений
ImageControllerPOST /api/v1/imagesЗагрузить изображение
ImageControllerPUT /api/v1/images/{id}/replaceЗаменить файл (FK сохраняются)
ImageControllerDELETE /api/v1/images/{id}Удалить изображение
ProductControllerPOST/PUT/PATCH/DELETE /api/v1/productsРедактирование товаров
CategoryControllerPUT /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, brandId
  • minPrice, maxPrice
  • search (по названию)
  • active
  • page, 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)

Конфигурационные классы

КлассНазначение
SecurityConfigJWT-фильтр, CORS, разрешения эндпоинтов
JwtServiceГенерация и валидация JWT
JwtAuthFilterServlet-фильтр: читает заголовок Authorization
JwtProperties@ConfigurationProperties("jwt"): secret, expirationMs
S3ConfigСоздаёт бин S3Client (AWS SDK) для SeaweedFS
S3Properties@ConfigurationProperties("storage.s3")
CacheConfigCaffeine: 1000 записей, TTL 30 с
WebConfigCORS (origin из cors.allowed-origins)
ApplicationConfigUserDetailsService, PasswordEncoder
SchedulingConfig@EnableScheduling