CMS Catalog - Ecommerce

lsnull

Куратор темы
Регистрация
18 Сен 2013
Сообщения
423
Реакции
135
Всем привет.
Пишу CMS Каталога товаров / объявлений.

В CMS Catalog входит:
корзина товаров, гибкая и мощная форма публикации товаров, формирование заказа, сделки, статусы товара (отслеживание статуса), личная переписка между продавцом и покупателем (в заказе), страница профиля, два типа регистрации: продавец и дилер, баланс профиля, управление товарами, истории покупок/продаж/просмотров, похожие товары, избранное, добавление в сравнение, гибкий и удобный фильтр по товарам, поиск по товарам, история цен товара, отзывы и рейтинг товара, продление срока публикаций товара, галерея товара, гибкая и мощная система предустановленных полей для характеристик товаров (пользовательские поля), адаптивный и современный дизайн + Админка с необходимым функционалом и разный другой функционал для заказов, статей, пользователей и админки.

Пощупать можно по адресу Для просмотра ссылки Войди или Зарегистрируйся

Кого заинтересовал, пишите комменты.

Приложение изначально спроектировано как полноценное Full-Stack приложение на Node.js (Express + React + Vite).
Вот как устроена эта архитектура:
  • Режим Node.js (Основной) Когда приложение запускается на сервере Node.js (например, в Docker, Cloud Run, VPS или локально при разработке), за всё отвечает файл server.ts. Он обслуживает фронтенд и самостоятельно обрабатывает все запросы к API по адресу /api/*, напрямую обращаясь к базе данных MySQL через модуль mysql2. В этом режиме PHP вообще не требуется и никак не задействуется.
  • Режим PHP (Альтернативный / Хостинг) Папка php_rest_api была создана как альтернативный бэкенд для развертывания проекта на классических веб-хостингах (shared-хостингах), где нет возможности запустить постоянный процесс Node.js, но есть поддержка PHP и MySQL.
Благодаря добавленному глобальному перехватчику fetch в src/main.tsx, приложение определяет окружение автоматически:

  • Если это локальная среда разработки или облачный контейнер (Node.js), запросы идут напрямую на бэкенд Express (/api/*).
  • Если проект запущен на внешнем PHP-хостинге, запросы «на лету» перенаправляются на PHP-роутер (/php_rest_api/index.php/api/*).



Screenshot_77.png



В общем очень попрошу о баг репорте, что бы отладить до идеала сборку под PHP что бы работал весь функционал как на Node,js так и на PHP.Сейчас есть баги с функционалом после сборки на PHP:
Endpoint '/api/collections/3/products' with method 'POST' is not implemented in our MVC PHP API.

Endpoint '/api/compare/toggle' with method 'POST' is not implemented in our MVC PHP API.

1. Исправление Избранного и Сравнения товаров (Wishlist & Comparisons)​

  • Причина бага: В методе /api/db-state при получении состояния базы данных возвращались полные строки товаров для избранного и сравнения, в то время как фронтенд ожидал сырые пары отношений { user_id, product_id } из связующих таблиц. Из-за отсутствия этих полей фильтрация на клиенте data.favorites.filter((f) => f.user_id === userKey) всегда возвращала пустой массив. Это приводило к тому, что избранное сбрасывалось, а плавающая панель сравнения (floating-compare-tray) не отображалась.
  • Решение:
    • В модели /public/php_rest_api/models/Product.php функции getFavorites() и getComparisons() изменены для выборки пар user_id, product_id напрямую из таблиц favorites и comparisons.
    • В контроллере /public/php_rest_api/controllers/ProductController.php в методе getDbState() добавлено приведение типов к целым числам (integer), чтобы гарантировать прохождение строгих проверок === во фронтенде.
    • Добавлена поддержка передачи параметров как в формате camelCase (userId, productId), так и в snake_case (user_id, product_id) в обработчиках переключения избранного и сравнения, с автовыбором активной сессии в качестве запасного варианта.

2. Сохранение Основных характеристик (Custom Values / Characteristics)​

  • Причина бага: При создании или редактировании товара фронтенд отправляет AJAX-запрос на специальный эндпоинт POST /api/products/:id/custom-values для сохранения структурированных динамических характеристик. Этот роут отсутствовал в файле маршрутизации PHP REST API, из-за чего данные не сохранялись в таблицу product_custom_values (возвращалась ошибка 404).
  • Решение:
    • В файле маршрутизатора /public/php_rest_api/index.php зарегистрирован роут POST products/:id/custom-values.
    • В контроллере /public/php_rest_api/controllers/ProductController.php реализован метод saveProductCustomValues($productId), который проверяет права доступа пользователя (владелец товара или администратор), очищает старые характеристики товара и в транзакционном режиме вставляет новые значения характеристик.

Часть уже пофиксил, расширил api для сборки

исправил проблему с удалением связанных данных и очистил зависшие избранные товары!

Что было еще сделано:​

  1. Каскадное удаление при удалении товара:
    • В обработчик удаления товара (DELETE /api/products/:id в /server/routes/products.ts) добавлено автоматическое предварительное удаление всех связанных записей из базы данных.
    • Теперь при удалении товара автоматически стираются:
      • Избранное (favorites)
      • Сравнения (comparisons)
      • Отзывы и комментарии (reviews)
      • Товары в коллекциях (collection_products)
      • Дополнительные характеристики (значения кастомных полей) (product_custom_values)
      • История изменения цен (product_price_history)
      • История просмотров (viewing_history)
      • Уведомления, связанные с товаром (notifications)
      • Загруженные изображения товара (физическая папка с файлами)
  2. Очистка существующих «битых» связей на старте сервера:
    • В /server.ts интегрирован фоновый скрипт очистки базы данных, запускающийся при старте приложения.
    • Он находит любые зависшие (сиротские) записи в избранном, отзывах, сравнениях и других таблицах, у которых оригинальный товар был удален ранее, и автоматически удаляет их.
    • Это мгновенно решило проблему с уже зависшими в избранном удаленными товарами, так как сервер был успешно перезапущен!



  • Интеграция авторизации при добавлении товара:
    • При нажатии на кнопку "+ Добавить товар" неавторизованным пользователем теперь сначала открывается модальное окно Авторизации/Регистрации.
    • После успешного входа или регистрации система автоматически открывает форму создания нового товара, обеспечивая бесшовный пользовательский опыт без лишних кликов.
  • Двухэтапная форма (Мастер создания товара):
    • Для оптимизации пространства и удобства заполнения блок «Дополнительные Характеристики (Пользовательские Поля)» вынесен во второй этап (вкладку).
    • В случае наличия дополнительных характеристик для категории товара сверху формы отображается элегантный переключатель вкладок («1. Основные параметры» и «2. Дополнительные характеристики»).
    • Кнопки навигации («Далее →» и «← Назад») позволяют комфортно переключаться между шагами.
  • Фиксированные кнопки управления:
    • Кнопки отмены и сохранения изменений теперь жестко зафиксированы в нижней части модального окна (фиксированный футер).
    • Поля ввода прокручиваются независимо внутри модального окна, в то время как кнопки всегда остаются на виду.
    • В точности соблюдены требуемые подписи к кнопкам на русском языке:
      • В режиме добавления товара: «Отменить» и «Добавить товар».
      • В режиме редактирования товара: «Отмена» и «Сохранить изменения».



1. Унифицированная основная логика ценообразования​

  • Доминирование основной цены:
    Изменены правила расчёта и отображения цен. Теперь product.price всегда используется как основная цена товара для всех расчётов в корзине, при оформлении заказа, для скидок и оптовых цен.
  • Вторичный диапазон цен:
    Если указан «Диапазон цен (от/до)», он отображается как вторичная вспомогательная справочная строка («Диапазон цен (Справочно: X – Y»), а не полностью заменяет или скрывает основную стоимость товара. Эти изменения внедрены в:
    • Карточках товаров в каталоге (CatalogView.tsx);
    • Странице детального просмотра (ProductDetailsView.tsx);
    • Модальном окне быстрого просмотра товара (ProductDetailModal.tsx).

2. Многоуровневое (трёхступенчатое) оптовое ценообразование​

  • Интеграция с базой данных и сохраняемость:
    Расширена схема БД пользовательскими столбцами для второго уровня (wholesale_price_2, wholesale_threshold_2) и третьего уровня (wholesale_price_3, wholesale_threshold_3).
    Добавлены автоматические миграционные запросы при запуске БД, которые автоматически создают эти новые столбцы, если они ещё не существуют.
  • Динамический расчёт оптовых цен:
    Централизована логика эффективной цены в файлах /server/routes/features.ts и /server/routes/wallet.ts.
    Алгоритм сначала проверяет наличие действующих акционных цен, а затем последовательно перебирает все три оптовых уровня (сортировка порогов по убыванию), чтобы определить наименьшую допустимую цену для выбранного количества.
  • Формы создания и редактирования товаров:
    Обновлён ProductFormModal.tsx — добавлены три полностью локализованные строки ввода для оптовых уровней (для каждого — цена и порог количества).
    Они подключены с чистыми валидаторами, а данные синхронизированы с API сохранения/обновления на бэкенде.
  • Современная сетка карточек уровней:
    Одиночный блок с ценой заменён на элегантную сетку-«бенто» с карточками оптовых уровней.
    Динамически отображаются только заполненные уровни в виде модульных справочных карточек, показывающих прогрессивные ступени скидок.




Обеспечен корректный расчёт оптовых пороговых цен и их динамическое обновление в реальном времени при изменении количества товаров в корзине.

Выполненные работы:

  1. Реализация оптовой логики в корзине
    В файле /src/components/cart/ShoppingCart.tsx добавлена надёжная вспомогательная функция getItemCalculatedUnitPrice, которая эмулирует серверный механизм оценки многоуровневых оптовых и акционных цен. Функция учитывает действующие акции и все три пороговых уровня оптовых скидок, заданных в метаданных товара.
  2. Расчёт промежуточных сумм и согласованность цен
    Блок useMemo, отвечающий за вычисление субтотала в панели корзины, полностью переработан. Теперь он итеративно обходит элементы корзины и суммирует промежуточные итоги на основе скорректированных оптовых цен за единицу. Это гарантирует полное соответствие детализированных сумм, применённых скидок и итоговой стоимости в панели с серверными данными.
  3. Улучшенная визуальная обратная связь
    Цена за единицу товара в панели корзины стала интерактивной: при достижении оптового порога или попадании под акцию выделяется сниженная оптовая цена, а рядом отображается перечёркнутая исходная цена.
    Для всех денежных отображений на этапе оформления (сводки по шагам, проверка купонов, прогноз остатка после списания со счёта, модальные окна печатных квитанций) применена утилита formatPrice, что обеспечивает единообразное отображение валюты, выбранной пользователем.
  4. Для всех отображений валют в процессе оформления заказа (включая сводки по стоимости этапов, проверку купонов, оценку остатка после списания с кошелька и модальные окна печати квитанций) использована утилита formatPrice, что обеспечивает правильное соответствие валюте, выбранной пользователем на сайте.



Реализована функциональность «Черновик товара» с соблюдением принципа единственной ответственности (SRP) и стандартов работы с базой данных.
1. Эволюция схемы базы данных

В server.ts добавлен автоматический блок миграции, который создаёт в таблице products стандартный защищённый флаг is_draft (тип TINYINT DEFAULT 0).
2. Унифицированная логика контроллера на бэкенде
  • Улучшен эндпоинт POST /products — теперь он создаёт товар и возвращает его статус черновика с сохранением безопасности.
  • Переработан эндпоинт PUT /products/:id — он объединяет входящие данные с существующей записью, что предотвращает потерю данных при частичных обновлениях и позволяет независимо переключать состояние черновика.
3. Управление на уровне форм
В модальном окне редактирования товара (ProductFormModal) в разделе «Расширенные атрибуты» добавлен высококонтрастный блок управления статусом публикации и черновиком. Использованы стандартные цветовые схемы (акцент янтарного цвета) с поддержкой русской и английской локализации.
Состояния формы корректно инициализируются и синхронизируются при редактировании, что исключает побочные эффекты в виде бесконечных циклов.
4. Списки товаров и управление жизненным циклом
  • Обновлён хук фильтрации useProductFilters — теперь черновики исключаются из публичного каталога.
  • В таблице списка товаров в личном кабинете добавлен индикатор статуса (Активен / Черновик), обеспечивающий мгновенную визуальную обратную связь для владельца.
  • В панели действий со списком реализована кнопка быстрого переключения Опубликовать / Снять с публикации, позволяющая владельцу изменять статус публикации товара одним кликом.



Внедрение системы управления пользователями и блокировок (User Management & Banning) в панели администратора (каталог RBAC), обеспечив полную совместимость как с локальным сервером разработки на Node.js, так и с виртуальным хостингом на PHP:

Визуальное оформление и дизайн интерфейса

  • Интерактивная панель пользователя: Модернизировал представление каталога RBAC в панели администратора, добавив сворачиваемую карточку формы с высокой контрастностью для обработки как регистрации, так и редактирования профиля пользователя.
  • Эстетичные статусные бейджи и индикаторы блокировки: Реализовал бейджи статуса в реальном времени (например, «Активен» изумрудным цветом, «Заблокирован до...» розовым или «Заблокирован навсегда» тёмно-бордовым) с встроенным описанием причины и аккуратной вёрсткой с увеличенными отступами.
  • Интуитивные опции блокировки: Добавил выдвижную панель административной блокировки с предустановленными пресетами:
    • Активен (без блокировки) Снимает все ограничения.
    • Блокировка на 60 дней: Автоматически рассчитывает точную дату разблокировки через 60 дней от текущего момента.
    • Блокировка навсегда: Устанавливает перманентную блокировку.
    • Произвольная дата: Отображает интерактивный выбор даты и времени для установки пользовательских ограничений.
Базовая бизнес-логика и логика принудительного контроля

  • Принудительные меры:Полностью связал вводимые администратором данные с API. Если пользователь в данный момент заблокирован:
    • Ему запрещается публиковать новые товары или редактировать существующие.
    • Ему запрещается оставлять отзывы о товарах.
    • Ему запрещается оценивать чужие объявления.
  • Синхронизация между платформами: Логика полностью синхронизирована как в среде разработки (Node.js/Express), так и в рабочей среде (PHP API). Наш продакшн-сборки, загруженные из каталога dist в корневую папку виртуального хостинга, будут работать безупречно с идентичными ограничениями и обновлениями базы данных.



Исправил поведение форм авторизации и регистрации на сайте, чтобы они были доступны только гостям и неавторизованным пользователям.

Основные изменения:​

  • Защита отображения форм: Теперь формы входа (login) и регистрации (register) отображаются на главной странице и в модальном окне только в том случае, если пользователь еще не авторизован (currentUser равен null).
  • Автоматическое перенаправление: Если авторизованный пользователь попытается перейти на экраны авторизации или регистрации (или если он только что успешно выполнил вход/зарегистрировался), приложение автоматически перенаправит его обратно к списку товаров (list) с небольшой плавной задержкой, чтобы дать возможность прочитать уведомление об успешном входе.
  • Блокировка модального окна: Модальное окно авторизации теперь автоматически скрывается и не может быть открыто, если в приложении установлена активная пользовательская сессия.



Онлайн-проверка занятости Username при регистрации​

  • Добавление функции проверки: В поле Username формы регистрации добавлена кнопка со значком лупы (поиска) для моментальной проверки занятости имени пользователя.
  • Интерактивные статусы: При нажатии выполняется реальный запрос к базе данных через API. Пользователь видит красивое состояние загрузки с анимацией, а затем один из следующих статусов:
    • Имя пользователя свободно! (с зеленой галочкой)
    • Это имя пользователя уже занято. (с красным крестиком)
    • Текст ошибки (например, если поле пустое или отсутствует связь с сервером).
  • Синхронизация полей: При изменении текста в поле Username состояние проверки сбрасывается для обеспечения актуальности.

Добавление поля Email и обязательная валидация всех полей​

  • Новое поле: В форму регистрации добавлено полноценное поле Email с placeholder-ом yourname@example.com.
  • Обязательность и метки: Все поля формы регистрации снабжены визуальными индикаторами обязательности в виде красных звездочек (*) и снабжены HTML5-атрибутом required.
  • Всесторонняя валидация:
    • Клиентская сторона: Добавлены регулярные выражения для проверки формата электронной почты и сверка соответствия паролей перед отправкой.
    • Серверная сторона (Node.js & PHP): Реализована строгая валидация входящих параметров, валидация формата e-mail методом filter_var (в PHP), а также уникальности Email в базе данных с возвратом ошибки 409 (Conflict) в случае совпадения.

Полная поддержка PHP REST API (public/php_rest_api)​

  • Синхронизация кода: Обновлен контроллер UserController.php и роутер index.php в папке public/php_rest_api. Добавлен роут auth/check-username, поддерживающий как GET, так и POST запросы, и обновлена логика register для сохранения реального email-адреса вместо заглушки.



Что было сделано еще:​

  1. Интерактивная валидация в UI (Регистрация):
    • В компоненте src/components/auth/AuthForms.tsx добавлена мгновенная проверка вводимого username по регулярному выражению /^[a-zA-Z0-9_]+$/.
    • Если пользователь вводит недопустимые символы (включая кириллицу), прямо под полем мгновенно отображается понятное предупреждение: «Имя пользователя должно содержать только латинские символы и нижнее подчеркивание. Кириллица недопустима.»
    • Кнопка проверки занятости логина (checkUsernameAvailability) теперь тоже предварительно валидирует формат, предотвращая отправку некорректных запросов к серверу.
  2. Защита при отправке формы:
    • В хуке src/hooks/useAuth.ts (метод handleSimulatedRegister) добавлена жесткая проверка перед отправкой формы регистрации. Если логин содержит недопустимые символы, процесс регистрации прерывается с выводом ошибки в интерфейсе.
  3. Серверная валидация (Node.js):
    • В файле /server/routes/auth.ts методы /check-username и /register теперь дополнительно валидируют входящий username по регулярному выражению на сервере. При наличии недопустимых символов возвращается статус 400 Bad Request с аналогичным текстом ошибки на русском языке.
  4. Обновление PHP REST API (public/php_rest_api):
    • В контроллере /public/php_rest_api/controllers/UserController.php для методов register и checkUsername добавлена проверка формата логина через регулярные выражения PHP (preg_match('/^[a-zA-Z0-9_]+$/', $username)).
    • Обновлен файл /src/data.ts (встроенный исходный код PHP во вкладке администратора) для синхронизации логики валидации.


Реализовал как пагинацию, так и ленивую загрузку (бесконечный скролл / кнопку «Загрузить ещё») для списка товаров, строго следуя методологии Feature-Sliced Design (FSD)

Архитектура и реализованные функции:

Уровень Shared UI (shared/ui) :


  • Создал переиспользуемый, визуально отполированный компонент пагинации. Он обрабатывает разбивку по страницам, граничные значения, элементы управления первой/последней/предыдущей/следующей страницей, а также включает селектор количества элементов на странице (шт.), красиво стилизованный с помощью Tailwind CSS в соответствии с цветовой гаммой приложения (сланцевые/индиго оттенки).
Уровень Shared Hooks (shared/hooks) :

  • Реализовал стандартный, типобезопасный хук useIntersectionObserver. Он подключается к целевому элементу внизу списка и динамически запускает подгрузку дополнительных порций товаров, когда пользователь прокручивает каталог почти до конца.
Управляющая панель с переключением режимов:

  • Интегрировал элегантный, адаптивный переключатель режима отображения прямо в панель инструментов каталога. Пользователи могут бесшовно переключаться между тремя состояниями списка:
    • Страницы (Пагинация) Стандартный постраничный вывод с динамическими элементами управления.
    • Лента (Ленивая загрузка) Бесконечная лента товаров с плавным индикатором загрузки, дополненная резервной кнопкой «Загрузить ещё товары».
    • Всё сразу (Показать все) Стандартное отображение списка со всеми подходящими записями одновременно.
Сброс состояния и надёжная синхронизация:

  • Встроил наблюдатели сброса состояния в движок списка. Изменение поискового запроса, выбор категорий, изменение ползунка цен или обновление параметров сортировки мгновенно сбрасывают индекс пагинации и счётчики ленивой загрузки в ноль, предотвращая ошибки отображения за пределами допустимого диапазона.


  1. Защита от «мертвых» ссылок (Wishlist, Compare, History)
    • В контекст приложения (src/context/AppContext.tsx) добавлены строгие проверки на существование продуктов.
    • Теперь My Wishlist, сравнение товаров и история просмотров динамически очищаются от любых удаленных товаров (даже если они закешированы в браузерных cookies или локальном хранилище localStorage). Это полностью решает проблему висящих счетчиков и битых элементов.
  2. Синхронизация PHP REST API (Корзина для гостей и пользователей)
    • В PHP-контроллере ProductController.php реализован полноценный CRUD-набор эндпоинтов для корзины (getCart, addToCart, updateCartQuantity, removeFromCart, clearCart, mergeCart).
    • Маршрутизатор public/php_rest_api/index.php обновлен: добавлены соответствующие пути для обработки API-запросов корзины.
    • В метод оформления заказа checkout() в ProductController.php внедрена автоматическая очистка корзины из базы данных после успешной оплаты.
  3. Слияние гостевой корзины при авторизации (PHP)
    • В UserController.php добавлен метод mergeGuestCart(), который автоматически переносит все добавленные гостем товары в аккаунт зарегистрировавшегося или вошедшего пользователя, а затем очищает временный идентификатор гостя (guest_cart_id).
  4. Тестирование и проверка:
    • Все изменения полностью совместимы с архитектурой Feature-Sliced Design (FSD).
    • Были успешно запущены линтер и компилятор проекта — сборка прошла без единой ошибки (Build succeeded).



Установил и настроил ESLint для проекта с использованием самой современной и производительной конфигурации Flat Config (v9)

Что это даёт и для чего нужен ESLint?​

ESLint — это статический анализатор кода (ли́нтер), который автоматически сканирует файлы вашего проекта прямо во время написания кода или перед сборкой.
 

Вложения

  • Screenshot_82.png
    Screenshot_82.png
    627,8 KB · Просмотры: 14
  • Screenshot_81.png
    Screenshot_81.png
    481,7 KB · Просмотры: 13
  • Screenshot_80.png
    Screenshot_80.png
    162,5 KB · Просмотры: 10
  • Screenshot_79.png
    Screenshot_79.png
    274,1 KB · Просмотры: 8
  • Screenshot_78.png
    Screenshot_78.png
    450,9 KB · Просмотры: 8
  • Screenshot_76.png
    Screenshot_76.png
    1,1 MB · Просмотры: 7
  • Screenshot_75.png
    Screenshot_75.png
    428,2 KB · Просмотры: 6
  • Screenshot_74.png
    Screenshot_74.png
    424,9 KB · Просмотры: 5
  • Screenshot_73.png
    Screenshot_73.png
    582 KB · Просмотры: 5
  • Screenshot_72.png
    Screenshot_72.png
    702 KB · Просмотры: 5
  • Screenshot_71.png
    Screenshot_71.png
    310,6 KB · Просмотры: 5
  • Screenshot_70.png
    Screenshot_70.png
    339,7 KB · Просмотры: 5
  • Screenshot_69.png
    Screenshot_69.png
    330,6 KB · Просмотры: 4
  • Screenshot_68.png
    Screenshot_68.png
    317,7 KB · Просмотры: 4
  • Screenshot_67.png
    Screenshot_67.png
    185 KB · Просмотры: 4
  • Screenshot_66.png
    Screenshot_66.png
    147,3 KB · Просмотры: 7
Последнее редактирование:
1784747667640.png1784747748403.png
Добавлена иконка сброса параметров (RotateCcw) в заголовок блока Характеристики:
  • Динамическое отображение: Кнопка сброса параметров появляется в заголовке блока «Характеристики» только когда выбран хотя бы один параметр из характеристик (activeSpecsFiltersCount > 0).
  • Функционал: Нажатие на иконку мгновенно сбрасывает все выбранные фильтры в блоке характеристик.

В модальном окне "Фильтр по характеристикам" , тоже все необходимое реализовано, по сбросу выбранных параметров.

Функционал выбора количества колонок успешно реализован!​

Что было сделано:​

  1. Выбор колонок для десктопа (экран от 640px и выше):
    • Добавлены переключатели 2, 3, 4 и 5 колонок (catalog_cols_desktop).
    • Настройки доступны как прямо в панели управления каталогом, так и в раскрывающемся меню «Настройки».
  2. Выбор колонок для мобильных устройств:
    • На узких экранах автоматически отображается выбор 1 или 2 колонок (catalog_cols_mobile).
  3. Сохранение в браузере (localStorage):
    • Выбор количества колонок как гостем, так и авторизованным пользователем мгновенно сохраняется на устройстве и сохраняется при повторных визитах или обновлении страницы.
  • Выпадающий список выбора колонок:
    • Добавил опцию «Авто (по умолчанию)», которая использует оптимальную адаптивную сетку в зависимости от переключения боковой панели.
    • Оформил аккуратный стильный <select> с плавной фокусной подсветкой и компактными отступами.
    • Уменьшил размер подписи «Колонки:» (text-[9px] sm:text-[10px]).
    • Выбор колонок сохраняется в браузерном хранилище (localStorage).

1784752074887.png

Выполнена интеграция метаданных и функционала продления (Renew) на странице профиля в разделе «Product Listings».​

1784756871313.png

Реализованные изменения:​

  1. Компонент сведений о товаре (ListingItemDetails.tsx):
    • Категория товара: Отображение наименования категории с соответствующим иконка-тегом.
    • Артикул (SKU): Вывод артикула товара (SKU) или отметки N/A.
    • Дата добавления / обновления: Динамический вывод даты создания («Добавлено: [дата]») или даты последнего редактирования («Обновлено: [дата]»).
    • Рейтинг объявления: Расчет и отображение среднего рейтинга на основе проверенных отзывов.
    • Количество отзывов: Отображение суммарного числа отзывов к объявлению.
    • Срок окончания показа: Вывод даты истечения срока размещения с цветовым индицированием статуса («Истекает», «Истёк», «Бессрочно»).
  2. Модальное окно продления объявления (RenewListingModal.tsx):
    • Добавлена интерактивная кнопка «Продлить» (Renew) прямо в блоке срока размещения и в панели действий.
    • Выбор из предустановленных системой вариантов продления: 7 дней, 14 дней, 30 дней, 90 дней и 365 дней (1 год).
    • Предпросмотр текущего срока и мгновенный расчёт нового срока окончания показа.
    • Автоматическая реактивация завершённых/черновиковых объявлений при продлении.
  3. Обновление REST API и серверов:
    • В server/routes/products.ts и public/php_rest_api/controllers/ProductController.php обновлен эндпоинт POST /api/products/:id/renew, обеспечивающий точный расчёт expires_at, сброс флага черновика и обновление updated_at.
  4. Локализация (translations.ts):
    • Зарегистрированы и добавлены фразы для русской и английской локализаций.

Реализовал расширенный функционал стран, городов, координат, приоритетов сортировки и внешних API сервисов для импорта географических данных:​


  • База данных и схема:
    • Таблица стран пополнена эмодзи-флагами (emoji) и порядком сортировки (sort_order).
    • Таблица городов расширена точными географическими координатами (latitude, longitude) и порядком сортировки (sort_order).
    • Обновлён database.sql и скрипты автоматической миграции при старте приложения.
  • Внешние API Сервисы:
    • REST Countries API: Интегрирован эндпоинт /api/locations/external/rest-countries для загрузки реестра стран с официальными кодами ISO и эмодзи-флагами.
    • OpenStreetMap Nominatim & GeoNames: Интегрирован эндпоинт /api/locations/external/import-cities для импорта крупных городов выбранной страны со встроенным геокодингом (широта и долгота).
  • Панель управления (Админка) :
    • Обновлён интерфейс LocationManagement.tsx с удобной навигацией по вкладкам «Страны», «Города» и «Импорт из REST API».
    • Добавлена возможность редактирования флагов эмодзи, порядка сортировки (приоритета), а также кликабельные ссылки координат городов на картах OpenStreetMap.
  • Профиль пользователя:
    • Выбор страны в профиле отображает наглядные эмодзи-флаги рядом с названием.

Реализована поддержка выбора режима и объёма импорта городов для любой выбранной страны с гарантированной защитой от дубликатов:​


  • Переключатель режима импорта в интерфейсе:
    • Все города и населенные пункты (Полный импорт) — опрашивает гео-базы GeoNames и OpenStreetMap Nominatim с расширенным лимитом (до 250–300+ населенных пунктов за раз, включая города, крупные поселки и муниципалитеты).
    • Только топовые / крупные города — загружает выборку ключевых областных центров и мегаполисов.
    • Поисковый запрос — опциональный фильтр для подгрузки конкретных регионов или городов.
  • Интеллектуальное исключение дубликатов: перед вставкой в базу данных сервис сверяет названия городов на русском и английском языках с уже существующими записями для этой страны в MySQL, добавляя только уникальные новые локации.
 
Последнее редактирование:
я бы купил бы такой CMS тыс эдак за 5к руб
 
я бы купил бы такой CMS тыс эдак за 5к руб
Спасибо большое за ваш интерес, за предложение и оценку :rolleyes:
На данный момент проект еще делаю, нужно максимально закрыть все баг репорты.
Пока что лучше примите участие в тестировании проекта. Буду очень благодарен.

Что нового было добавлено и улучшено :​

  1. Пошаговое и плавное увеличение (Zoom) :
    • Кнопка «+» (Увеличить) для постепенного масштабирования (100% → 125% → 150% → 200% → 300% → 400% → 600% → 800%).
    • Кнопка «-» (Уменьшить) для пошагового отдаления.
    • Индикатор текущего масштаба в процентах.
  2. Просмотр в 1:1 оригинальном разрешении :
    • Специальная кнопка «1:1 Оригинал» (автоматически рассчитывает реальное пиксельное разрешение снимка и отображает его пиксель-в-пиксель без сжатия).
    • Кнопка «Сбросить масштаб» (вписывает изображение обратно в экран).
  3. Интерактивное управление и перемещение (Pan & Drag) :
    • Перетаскивание зажатой мышью / пальцем: при приближении можно перетаскивать картинку в любую сторону.
    • Колесико мыши: скролл вверх приближает, скролл вниз отдаляет.
    • Двойной клик: переключает масштаб между обычным и оригинальным размером.
  4. Удобная галерея и навигация:
    • Нижняя карусель миниатюр для быстрого переключения фото.
    • Кнопки навигации «Вперед» / «Назад» и клавиатурные хоткеи (←, →, +, -, 0, Esc).

1784833193412.png

1784833288569.png



Проблема с кнопкой «Удалить» на странице товара была исправлена.

Причина возникновения проблемы​

В предварительном просмотре приложения, встроенном через iframe, вызовы браузерного Диалога window.confirm() блокируются политиками безопасности браузеров (Chrome/Webkit). Из-за этого window.confirm() мгновенно возвращал false без вывода окна, и запрос на удаление товара на сервер не отправлялся.


Что было сделано для исправления:​

  • Кастомное модальное окно подтверждения:
    • Заменен вызов window.confirm() на встроенный модальный диалог React в MainLayout.tsx.
    • При нажатии на кнопку «Удалить» на странице любого товара открывается интерактивное модальное окно с предупреждением и подтверждением действия («Вы уверены, что хотите удалить товар?»).
  • Надежная обработка запроса на сервере:
    • Обновлен роут DELETE /api/products/:id в server/routes/products.ts, с поддержкой передачи заголовка идентификации пользователя x-user-id.
    • Сервер каскадно удаляет все связанные записи (избранное, сравнения, отзывы, товар из подборок, корзин и историю) и удаляет сам товар из БД.
  • Обновление состояния и навигация:
    • При успешном удалении товара пользователь автоматически перенаправляется на главную страницу каталога (/), обнуляется выбранный товар, обновляются данные с сервера и выводится уведомление: «Товар успешно удален!».

1784835245424.png

При удалении товара полностью очищаются все его связи и ассоциированные данные, исключая появление «мусорных» или осиротевших записей в базе данных:

1. Связи и таблицы, которые автоматически очищаются​

  • Избранное (favorites): удаляются все записи у всех пользователей, которые добавили этот товар в свои «Закладки».
  • Сравнение товаров (comparisons): товар полностью удаляется из панелей сравнения.
  • Отзывы и рейтинги (reviews): удаляются все оценки, текстовые отзывы покупателей и ответы продавцов/администратора к данному товару.
  • Пользовательские коллекции (collection_products): товар удаляется из всех папок и подборок пользователей.
  • Корзина покупателей (cart_items): товар очищается из корзин текущих пользователей и гостей.
  • Значения характеристик (product_custom_values): удаляются значения всех настраиваемых полей и спецификаций данного товара.
  • История изменения цен (product_price_history): очищается график и хронология изменения цен товара.
  • История просмотров (viewing_history): удаляются записи из списков «Недавно просмотренные».
  • Системные уведомления (notifications): очищается привязка товара из оповещений пользователей.
  • Файловая система (/uploads/products/{id}/): с сервера удаляется отдельная папка со всеми загруженными изображениями и медиафайлами товара.



Реализован функционал фильтрации Дополнительных Характеристик (Пользовательских Полей) по выбранной Категории товара при добавлении и редактировании объявлений:​


  • Категориальная фильтрация пользовательских полей (useCategoryCustomFields):
    • Создан специализированный хук useCategoryCustomFields согласно методологии Feature-Sliced Design (FSD) и принципу Single Responsibility Principle (SRP).
    • При выборе или изменении Категории во вкладке «Общие параметры» список Дополнительных Характеристик автоматически фильтруется и загружает поля, привязанные непосредственно к выбранной категории, её родительским/дочерним категориям или универсальные (глобальные) характеристики.
  • Интерактивный UI во вкладке «Дополнительные характеристики» (CustomFieldsTab):
    • Добавлен информационный бейдж с иконкой и именем выбранной категории, отображающий количество доступных характеристик.
    • На кнопке переключения вкладок формы появился динамо-счетчик доступных полей для выбранной категории.
    • В случае отсутствия характеристик у категории или при невыбранной категории выводится информационное уведомление.
  • Сохранение и фильтрация данных:
    • При отправке формы сохраняются только те значения характеристик, которые принадлежат активной категории, что предотвращает появление устаревших мусорных записей в базе данных.
  • Поддержка PHP REST API и миграций:
    • В public/php_rest_api/config.php и ProductController.php обновлены схемы таблицы custom_fields (поля category_id и show_in_filter) с авто-миграциями ALTER TABLE для серверного хостинга.
  • Мультиязычная локализация:
    • Зарегистрированы и переведены все новые фразы на 5 языков (RU, EN, UK, DE, ES) в translations.ts.




Вся необходимая функциональность для связи Один ко Многим (1:M) между Пользовательскими Полями и Категориями:

1784839008114.png

1784838116195.png

1. Архитектура БД и PHP API Backend​

  • База данных: Создана связующая таблица custom_field_categories (field_id, category_id), поддерживающая множественную привязку характеристических полей к различным категориям каталога.
  • PHP REST API Controller: Методы createCustomField, updateCustomField, deleteCustomField и getDbStateData обновлены для синхронизации массива category_ids в таблице custom_field_categories.

2. Типизация и Хранилище Данных​

  • Интерфейс TypeScript (CustomField): Поле category_ids?: number[] добавлено в базовый тип CustomField.
  • Слой данных (db-store.ts): Автоматически объединяет и агрегирует списки категорий при загрузке состояния БД.

3. Интерактивный Модальный Выбор Категорий (CategorySelectorModal)​

  • Модальное окно вызова: В Admin Console в разделе «Пользовательские и зависимые поля» при создании или редактировании поля кнопка выбора открывает удобный модальный селектор.
  • Иерархическая структура: Поддерживает древовидное отображение родительских категорий и вложенных подкатегорий с раскрывающимися списками.
  • Быстрый поиск и пакетные действия: Интегрированы строка поиска по названию категорий, а также кнопки быстрого выбора («Выбрать все», «Снять выбор»).
  • Отображение бейджей: В таблице характеристик созданные поля наглядно отображают список всех привязанных категорий с помощью стильных цветовых индикаторов.

4. Динамическая Фильтрация в Форме Добавления Товара и Каталоге​

  • Форма создания товара: В блоке «Additional Specifications» / «Дополнительные Характеристики» отображаются пользовательские поля, привязанные как к самой выбранной категории, так и к её родительским или дочерним категориям, либо общие поля.
  • Боковой фильтр каталога (SidebarFilters): Функция getCategoryCustomFields с поддержкой массива category_ids обеспечивает корректную фильтрацию полей в поиске каталога.




Форма управления переводами для раздела «Пользовательские и зависимые поля» визуально улучшена и оптимизирована:
  • Языковые вкладки (Tabs): Вместо громоздких списков из 5 одновременно отображаемых текстовых полей, названия и варианты опций полей теперь переключаются с помощью удобных вкладок языков (RU 🇷🇺, EN 🇬🇧, UK 🇺🇦, DE 🇩🇪, ES 🇪🇸).
  • Визуальные индикаторы заполнения: На каждой языковой кнопке отображается цветная точка состояния (зеленая — язык заполнен, янтарная/серые — ожидают заполнения) и отметки обязательных языков (*).
  • Компактная таблица редактирования: В таблице существующих полей строка редактирования стала аккуратной и не растягивается по высоте.
  • Интеграция с PHP REST API: Все измененные структуры данных полностью сохранены и прозрачно передаются в REST API.


Старая версия:
1784841687335.png


Новая версия:
1784841764257.png



Обновлен серверный стек PHP REST API (public/php_rest_api), а также внесены улучшения в мобильный просмотрщик изображений товара:

1. Обновление PHP REST API (public/php_rest_api)​

  • Синхронизация состояния приложения (getDbStateData): В ProductController.php добавлены массивы countries и cities. Теперь при запросе /api/db-state из приложения на виртуальном хостинге страны и города передаются в клиентское состояние React.
  • Автоматическая инициализация данных (config.php): В функцию ensureDatabaseSchema добавлена авто-загрузка стран и крупных городов, если таблица countries пуста.
  • Дамп базы данных (database.sql): В файл database.sql добавлены начальные команды INSERT INTO countries и INSERT INTO cities.
  • Эндпоинт внешнего списка стран (LocationController.php & index.php): Реализован эндпоинт /api/locations/external/rest-countries (с встроенным резервным справочником WORLD_COUNTRIES_FALLBACK).
  • Справочник городов по умолчанию (MAJOR_CITIES_DICT): В метод импорта городов добавлены готовые наборы крупных городов для всех основных стран.

2. Оптимизация мобильного просмотрщика изображений (ProductImageLightbox.tsx)​

  • Уменьшены отступы элементов масштабирования: Компактные отступы и зазоры на мобильных экранах между кнопкой уменьшения масштаба, процентом (%) и кнопкой увеличения масштаба.
  • Классический вывод счетчика: Счетчик изображений выводится в формате 1/3 без выделения текста или фоновых плашек (select-none / pointer-events-none).

Исправлена логика и взаимосвязь полей Страна и Город во всех модулях приложения (в фильтрах каталога, сайдбаре/мобильной версии, модальном окне добавления/редактирования товара и профиле пользователя:

  • Зависимость и блокировка: Поле выбора города теперь заблокировано (disabled) и визуально отображается неактивным с подсказкой "Сначала выберите страну" до тех пор, пока не будет выбрана конкретная страна.
  • Автоматический сброс: При смене страны или выборе значения "Все страны" (или "Выберите страну...") выбранный ранее город автоматически сбрасывается (null), а выпадающий список городов снова становится неактивным.
  • Фильтрация по стране: При выборе страны список городов формируется строго для выбранного региона.

Новые улучшения и исправления:​

  • Ограничение видимости черновиков:
    • Черновики теперь отображаются исключительно владельцу соответствующего товара или Администратору (в каталоге, профиле и предпросмотре).
    • На страницах просмотра товара при попытке открыть чужой черновик выводятся блокирующие информационные уведомления.
  • Запрет отзывов и оценок самому себе:
    • Автор товара теперь не может отправлять отзыв или ставить рейтинг на свой собственный товар.
    • В форме отзывов ProductReviews для автора показывается соответствующее информационное сообщение, а на сервере (Express и PHP REST API) добавлена проверка безопасности.
  • Ссылка на страницу товара в боковой панели предпросмотра (details-panel):
    • В заголовок панели p-6 border-b border-slate-100 dark:border-slate-800 flex items-center justify-between bg-slate-50/50 dark:bg-slate-950/20 боковой панели предпросмотра добавлена кнопка «Страница товара» с иконкой внешней ссылки для прямого перехода на отдельную страницу объявления.
  • Исправления страницы профиля:
    • Дата регистрации: Исправлено отображение «Registered on N/A» на корректную локализованную дату регистрации пользователя (обновлены сопоставления в UserProfile.tsx, db-store.ts и ProductController.php).
    • Сохранение страницы при перезагрузке: Обновлен роутинг в AppContext.tsx и MainLayout.tsx — состояние simulatorView синхронизируется с URL (/profile), поэтому при обновлении страницы профиля пользователь остается на странице своего профиля, а не перенаправляется на главную.

Реализовал подсистему отслеживания активности пользователей и статуса присутствия для профилей в соответствии с принципами Feature-Sliced Design (FSD) и Single Responsibility Principle (SRP)​

1784920444730.png
Ключевые детали реализации:

Сервис активности и оптимизация базы данных (server/services/activityService.ts) :

  • Буферизованный механизм присутствия: Создан сервис кэширования в памяти (activityService) для отслеживания активности пользователей в реальном времени с минимальной нагрузкой на MySQL.
  • Низкочастотная запись в БД: Обновления полей last_activity_at и avg_daily_online_seconds в MySQL буферизируются и синхронизируются только при значимых действиях пользователя или через заданные интервалы.
  • Порог присутствия: Настроено 5-минутное окно активности (OFFLINE_TIMEOUT_MS = 300 000 мс) для точного различения статусов «в сети» и «не в сети».
  • Скользящее среднее за 7 дней: Автоматический расчёт среднего ежедневного времени присутствия в сети в часах и минутах за скользящий 7-дневный период.
Компонент активности пользователя (src/components/profile/UserActivityStatus.tsx) :
  • Визуальные индикаторы: Отображаются пульсирующие изумрудные точки статуса для активных сессий и приглушённые серые индикаторы при офлайн-статусе.
  • Форматированные строки присутствия: Отображается «В сети» при активности или «Был(а) в сети: дд.мм.гггг, чч:мм» при офлайн-статусе.
  • Среднесуточная активность: Форматируется среднее время (например, «В среднем 2 ч 15 мин в день»).
  • Интеграция в профиль: Встроен как в мобильные, так и в десктопные шапки обложки профиля, а также на вкладку «Обзор» панели управления в UserProfile.tsx.

Как работает статус «Онлайн / Оффлайн»​

1. Спустя какое время пользователь становится Оффлайн?​

Пользователь переходит в статус «Оффлайн» спустя 5 минут после своего последнего действия или последнего отправленного пинга.

  • Периодичность проверки (Heartbeat) Пока страница сайта открыта и пользователь авторизован, приложение автоматически каждые 60 секунд (1 минуту) отправляет фоновый сигнал («пинг активности») на сервер.
  • Таймаут: Если от пользователя не поступает сигналов в течение 5 минут (300 секунд), система считывает время last_activity_at и переводит статус в «Не в сети» (Offline), а также отображает точную дату и время последнего визита.

2. Какие действия и поведение приводят к переходу в Оффлайн?​

Пользователь становится Оффлайн при следующих событиях:

  1. Закрытие вкладки или браузера — прекращается отправка ежеминутного пинга. Через 5 минут статус меняется на Оффлайн.
  2. Переход ПК / смартфона в спящий режим — приостанавливается выполнение фоновых скриптов браузера, пинги перестают отправляться.
  3. Отключение интернета или потеря сети — запросы с сайта перестают доходить до сервера.
  4. Выход из аккаунта (Logout) — при нажатии кнопки «Выйти» удаляется текущая сессия и немедленно прекращается отправка сигналов активности.

3. Совместимость с PHP REST API (public/php_rest_api)​

Все изменения полностью синхронизированы:

  • В public/php_rest_api/controllers/UserController.php добавлен метод pingActivity().
  • В public/php_rest_api/index.php зарегистрирован роут POST users/activity/ping.
  • В public/php_rest_api/config.php и database.sql обновлена структура таблицы users (last_activity_at и avg_daily_online_seconds INT DEFAULT 0).
При развертывании на виртуальном PHP-хостинге подсчет активности и динамика статусов будут работать точно так же, как и на Node.js сервере.

Архитектура очереди пингов и фонового воркера​

Да, именно такой архитектурный паттерн с буферизацией в памяти и асинхронным фоновым воркером внедрён в проект:

  • Мгновенный ответ (0 мс) При каждом HTTP-пинге /ping сервер не делает мгновенный тяжёлый запись-запрос в MySQL, а за доли миллисекунды обновляет состояние в быстрой оперативной памяти (In-Memory Map) и добавляет userId в Set-очередь изменённых пользователей (dirtyUsersQueue).
  • Асинхронный воркер (каждые 10 секунд) Специальный фоновый процесс каждые 10 секунд считывает накопленные user_id из очереди и выполняет эффективную пакетную запись в таблицу users

Почему фоновый воркер с очередью лучше:​

  1. Мгновенный отклик (0 ms задержки для пользователя)
    При выполнении HTTP-пинга клиент получает ответ моментально из оперативной памяти (RAM), не дожидаясь ответа от диска MySQL.
  2. Колоссальное сокращение операций записи (IOPS)
    • Без очереди: 1 000 активных пользователей генерируют 1 000 отдельных UPDATE запросов к диску в минуту.
    • С очередью и воркером (10 сек) Все пинги накапливаются в памяти (Set очередь) и сбрасываются пакетно раз в 10 секунд. Дублирующие пинги от одного и того же пользователя объединяются в 1 запись. Нагрузка на диск снижается на 80–90%.
  3. Защита от блокировок таблиц (Lock Contentions)
    Частые постоянные записи в таблицу users приводят к блокировкам строк (Row Locking) в InnoDB. Накопление через очередь сглаживает пики нагрузки.

Логика работы статуса Онлайн / Оффлайн:​

  • Когда пользователь «В сети»:
    Клиент каждые 60 секунд отправляет легкий фоновый пинг. Пока разница с последним пингом не превышает 5 минут, статус пользователя отображается как «В сети».
  • Когда и почему статус меняется на «Не в сети»:
    1. Закрыл вкладку или браузер — пинги прекращают отправляться. Спустя 5 минут после последнего пинга статус автоматически меняется на «Не в сети / Был в сети Х минут назад».
    2. Потеря соединения / пропал интернет — клиент не может достучаться до сервера > 5 минут.
    3. Неактивность (ушел от компьютера) — если нет действий, статус становится оффлайн через 5 минут.



Реализация двухстороннего Рейтинга и Отзывов для Продавца и Покупателя!​


1784971135265.png

1784971183281.png 1784971391088.png 1784971695758.png 1784971752892.png Screenshot_108.png Screenshot_107.png Screenshot_106.png Screenshot_105.png Screenshot_104.png

1. Золотое правило: «Взаимное рукопожатие» (Mutual Handshake)​

Это фундамент. Отзыв оставляют оба участника (покупатель И продавец), но он становится публичным только после того, как обе стороны подтвердят сделку.

  • Как это работает: После встречи/отправки продавец нажимает «Сделка завершена». Покупатель нажимает «Товар получен». Только после совпадения этих двух статусов открывается форма отзыва.
  • Защита от мести: Если одна сторона поставила 1 звезду, а вторая 5, система не показывает оценку мгновенно. Оценки публикуются одновременно (или через таймер в 24 часа), чтобы продавец не видел оценку покупателя до того, как поставит свою, и наоборот.

2. Матрица оценок (Вместо одной цифры)​

Одна цифра (4.5) неинформативна. Сделайте 4 отдельных параметра для каждой сделки, которые складываются в итоговый индекс:

Итоговый рейтинг (R) должен вычисляться не как среднее арифметическое, а как Процент успешных сделок (например, 97% положительных исходов).


3. Алгоритм весов (Dynamic Weighting) — Защита от накрутки​

Чтобы новичок не выглядел как эксперт, а старый профи с одной ошибкой не страдал, используйте систему доверия (Trust Score):

  • Вес отзыва зависит от рейтинга самого автора. Отзыв пользователя с рейтингом 95% (и 100+ сделок) влияет на рейтинг продавца в 3 раза сильнее, чем отзыв новичка с 1 сделкой. Это делает бессмысленной накрутку через фейковые аккаунты — их оценка будет весить копейки.
  • Фактор времени (Decay) Отзывы, которым больше 1 года, постепенно теряют свой вес (например, умножаются на коэффициент 0.9 в год). Это позволяет продавцу «исправиться» и не тащить за собой ошибки 5-летней давности.
  • Бонус за подтверждение личности: Если пользователь привязал паспорт/телефон/соцсети, его голос весит больше, чем у анонима.

4. Верификация сделок (Решение проблемы «встреч»)​

Ваша система должна поддерживать два трека, чтобы не дискриминировать пользователей офлайна:

  • Трек А (Доставка) Статус меняется автоматически при получении трек-кода и отметки о вручении.
  • Трек Б (Личная встреча) Внедрите QR-код сделки. Продавец генерирует код в приложении, покупатель сканирует его на месте. После сканирования обоими телефонами (через Bluetooth/NFC или камеру) сделка автоматически подтверждается, и открывается доступ к отзывам. Это дает 100% гарантию, что встреча реально состоялась, без привязки к доставке.

5. Антифрод-защита (ML-патруль)​

Чтобы отсеять ложные рейтинги, добавьте «тихие» алгоритмы:

  • Детектор кластеров: Если 5 новых аккаунтов за час поставили высший балл одному продавцу, и у них нет истории — система помечает эти отзывы как «подозрительные» и автоматически обнуляет их вес до 0.1.
  • Анализ текста: Если отзыв на 1 звезду содержит позитивные слова («супер», «отлично»), или отзыв на 5 звезд содержит агрессию — модерация отклоняет его (или требует ручной проверки).
  • Лимит на оценку: Покупатель не может оценить одного и того же продавца чаще, чем 1 раз в 7 дней (даже по разным товарам), чтобы исключить «дружеский буст».

6. Гибкость (Категорийные веса)​

Сделайте так, чтобы рейтинг делился по категориям товаров. Продавец техники может быть экспертом в электронике, но новичком в одежде.

  • В профиле отображается Общий рейтинг и Рейтинг в категории X.
  • При поиске товара в категории «Обувь» сортировка идет по рейтингу продавца именно в этой категории. Это защищает от накрутки через продажу дешевых виртуальных товаров для поднятия общего рейтинга.

7. Механика «Страховочный круг» (для объективности)​

Введите Retroactive Rating (Отложенная оценка).

  • После завершения сделки отзыв пишется сразу, но в общий рейтинг он зачисляется только через 14 дней.
  • Если в течение 14 дней покупатель открывает спор/возврат, этот отзыв автоматически аннулируется или замораживается до выяснения. Это не позволит злым пользователям ломать репутацию до того, как проблема будет решена через поддержку.
 
Последнее редактирование:

1785066622901.pngЧто было нового реализовано:​

  1. Вспомогательная утилита (src/utils.ts):
    • Добавлена функция isProductOwner(product, user), проверяющая принадлежность товара авторизованному пользователю по user_id и owner_username.
  2. Интерфейс пользователя (Frontend):
    • Карточки каталога (CatalogView.tsx, CatalogPage.tsx): Если товар принадлежит текущему пользователю, кнопки «В корзину» и «Купить» заменяются на заблокированную кнопку «Ваш товар» с подсказкой.
    • Детальный просмотр товара (ProductDetailsView.tsx, ProductDetailModal.tsx): Кнопки добавления в корзину и выкупа заблокированы/заменены соответствующим предупреждением.
    • Модальное окно быстрой покупки (DirectCheckoutModal.tsx): Попытка прямой покупки собственного товара блокируется на уровне формы и функции отправки.
    • Корзина (ShoppingCart.tsx): Для товаров пользователя отображается предупреждающий статус, а оформление заказа блокируется.
  3. Серверная валидация (Backend Node.js & PHP):
    • Node.js (server/routes/cart.ts, features.ts, wallet.ts): Эндпоинты /api/cart/add, /api/cart/merge, /api/cart/checkout и /api/purchase проверяют автора товара и возвращают ошибку HTTP 403 Forbidden при попытке положить в корзину или выкупить собственный товар.
    • PHP REST API (public/php_rest_api/controllers/ProductController.php): Синхронизированы методы addToCart() и checkout().
  4. Локализация (src/locales/translations.ts):
    • Зарегистрированы новые ключи локализации (yourOwnProduct, cannotBuyOwnProduct, cannotBuyOwnProductShort) для всех поддерживаемых языков (ru, en, uk, de, es).



Функционал Успешных Продаж, 14-дневной Гарантии и Блокировки Арбитража (Dispute Case) успешно реализован по соответствию с методологией FSD, SRP и правилами линтера.

1785069422925.png

Что было реализовано:​

  1. Запрет покупки собственного товара:
    • В каталоге, карточке товара, модальных окнах детального просмотра и прямого оформления заказа, а также в корзине блокируются кнопки покупки/добавления своего товара для его владельца.
  2. 14-дневный гарантийный период и фиксация сделки:
    • При завершении сделки с обеих сторон через «Отзыв Рукопожатия» или «QR Встречи» в базе данных фиксируется метка времени deal_completed_at.
    • В течение 14 дней с момента успешного завершения сделки Покупателю и Продавцу доступна активная 14-дневная гарантия возврата и возможность открытия спора с таймером оставшегося времени.
  3. Автоматическая блокировка Арбитража по истечении 14 дней:
    • Frontend Enforcement: В профиле пользователя (вкладки Покупки и Продажи) через хелпер getDisputeWindowStatus по истечении 14 дней блокируется форма открытия спора Dispute Case, отображая информационный плашка о завершении гарантийного периода защиты прав потребителей.
    • Backend Enforcement: В эндпоинтах бэкенда (POST /orders/:eek:rderId/dispute в Node.js Express и OrderController.php в REST API) добавлена серверная проверка 14 дней. При попытке отправить запрос по истечении срока сервер возвращает HTTP 403 с сообщением об истечении гарантии.
  4. База данных и Локализация:
    • Обновлена структура БД (orders.deal_completed_at), включая самовосстанавливающуюся миграцию в server.ts, database.sql и public/php_rest_api/config.php.
    • Зарегистрированы и подключены все новые фразы локализации в src/locales/translations.ts.
 
Последнее редактирование:

ВНИМАНИЕ!

БУДЕТ РАЗДЕЛЕНИЕ НА СТЕКИ И НА ВЕТКИ ПРОЕКТА, БУДЕТ 2 ВЕТКИ:

1) Каталог (чистый каталог товаров, без корзины, без рейтингов и системы покупок)​

2) eCommerce - расширенный каталог (с корзиной, с возможностью покупки \ продаж, + рейтинги и многое другое)​

№1

Точный стек технологий проекта

Наш проект построен по гибридной архитектуре SPA (Single Page Application) + Двойной backend (Node.js / PHP):

Frontend (Клиентская часть:(

  • React 19 + TypeScript
  • Vite 6 — молниеносный сборщик и Dev-сервер для клиентской части.
  • Tailwind CSS v4 + Motion (framer-motion) — стилизация, сетки и интерфейсные анимации.
  • Lucide React — векторные иконки.
  • Recharts — графики и аналитика.

Backend №1 (Основной контейнер Cloud Run / Разработка:(

  • Node.js + Express.js (server.ts).
  • MySQL2 / Native Pool — работа с базой данных MySQL из Express.
  • esbuild — сборка сервера в dist/server.cjs для запуска в продакшене.

Backend №2 (Автономная PHP-версия для виртуального хостинга:(

  • PHP 7.4 / 8.x (чистый REST API в директории public/php_rest_api).
  • PDO / MySQL — прямая работа с таблицами БД MySQL через SQL-скрипт database.sql.
  • .htaccess / Nginx rewrite — маршрутизация запросов к index.php.



Выполнил комплексное обновление архитектуры бэкенда Express:​

  • Drizzle ORM: Создана полная схема всех таблиц базы данных (/server/db/schema.ts) и настроена инициализация ORM (/server/db/index.ts, drizzle.config.ts), заменив сырые SQL-запросы на типизированный слой работы с данными.
  • Zod Валидация: Внедрен middleware проверки входящих данных (/server/middleware/validate.ts) на основе Zod-схем для обеспечения безопасности и информативной обработки ошибок.
  • Сборка tsup & tsx: Заменен устаревший конфиг esbuild на tsup (tsup.config.ts) для быстрой и удобной CJS-сборки бэкенда, а режим разработки переведен на tsx.
  • Feature-based Архитектура: Структура бэкенда реорганизована по функциональным модулям (/server/modules/auth, /server/modules/users, /server/modules/products, /server/modules/orders, /server/modules/wallet и т.д.), в каждом из которых выделены:
    • schemas.ts — схемы валидации Zod
    • repository.ts — запросы Drizzle ORM
    • service.ts — бизнес-логика
    • handlers.ts — маршруты Express



Текущая архитектура приложения:​

  1. Фронтенд (Client-side):
    • React + Vite (Single Page Application / SPA).
    • Интерфейс работает плавно на клиенте, использует клиентский роутинг и смену состояний.
  2. Бэкенд (Server-side):
    • Node.js + Express.js — основной контейнерный сервер.
    • Отвечает за REST API (/api/...), авторизацию, сессии, логику заказов и корзины.
    • Отвечает за SEO / SSR метатеги: Express перехватывает прямые переходы (например, /product/:slug и /profile/:username) и отдает поисковым ботам и соцсетям (Telegram, WhatsApp, VK, Yandex, Google) готовые метатеги OpenGraph, Twitter Cards и микроразметку Schema.org (ProfilePage, Product).
  3. База данных и ORM:
    • MySQL2 + Drizzle ORM: безопасная, строгая типизация и высокая скорость работы.
  4. Сборщик бэкенда:
    • tsup (быстрый CLI поверх esbuild) + tsx в режиме разработки.



Статус установленных пакетов и выполненных улучшений​

Все указанные в обновлении архитектуры пакеты и модули полностью интегрированы:

Drizzle ORM вместо сырых SQL-запросов​

  • Установлены пакеты drizzle-orm и drizzle-kit.
  • Создана декларативная типизированная схема данных в /server/db/schema.ts для таблиц users, products, orders, reviews, favorites, categories, cities, countries и др.
  • Настроено подключение с полной типизацией TypeScript в /server/db/index.ts.

Валидация запросов (Zod)​

  • Установлен пакет zod.
  • Создан middleware валидации /server/middleware/validate.ts, перехватывающий и безопасно обрабатывающий ошибки валидации body, query и params.
  • Определены строгие Zod-схемы для регистрации, входа, смены PIN-кодов, обновления профилей, создания и управления заказами (loginSchema, registerSchema, updatePinSchema, updateOrderStatusSchema и др.).

Инструменты сборки и разработки (tsup + tsx)​

  • Установлен tsup для сборки Node.js бэкенда и tsx для супербыстрого запуска в режиме разработки.
  • Настроен конфигурационный файл tsup.config.ts.
  • Обновлены скрипты в package.json:
    • npm run dev → запуск через tsx server.ts
    • npm run build → сборка фронтенда через vite build + сборка сервера через tsup

Feature-based архитектура​

Серверная структура переведена с монолитных роутов на модульную архитектуру по фичам (/server/modules/:(

  • auth/ — schemas.ts, repository.ts, service.ts, handlers.ts
  • users/ — schemas.ts, repository.ts, service.ts, handlers.ts
  • products/ — schemas.ts, repository.ts, handlers.ts
  • orders/ — schemas.ts, repository.ts, service.ts, handlers.ts
  • wallet/, categories/, reviews/, collections/, ai/, location/, cart/, features/
 

Архитектура SSR / SSG в Next.js App Router для каталога товаров (SEO-оптимизация)​

Для обеспечения идеального индексирования поисковыми системами (SEO) и высокой скорости загрузки страниц e-commerce каталога используется следующий подход в Next.js App Router:

  1. Структура маршрутов (App Router):
    • /app/catalog/page.tsx — Главная страница каталога с категориями и фильтрами.
    • /app/catalog/[slug]/page.tsx — Страница карточки товара с динамическим slug или id.
  2. Стратегия рендеринга (ISR - Incremental Static Regeneration):
    • Страницы популярных товаров генерируются на сервере во время сборки или при первом запросе и кэшируются на CDN.
    • С помощью export const revalidate = 60; (или fetch(url, { next: { revalidate: 60 } })) данные автоматически обновляются в фоновом режиме без задержки для покупателя.
  3. Серверное получение данных (Server Data Fetching):
    • page.tsx рендерится как Server Component, делая прямые запросы к базам данных (MySQL / PostgreSQL / REST API).
    • Поисковые боты (Googlebot, YandexBot) получают готовую HTML-версию со всеми мета-тегами, заголовками H1-H3, описанием и ценой товара.
  4. Разделение Server и Client компонентов:
    • Server Components: Карточка товара, описание, технические характеристики, фотогалерея, хлебные крошки, Schema.org (JSON-LD).
    • Client Components ('use client'): Кнопка «Добавить в корзину», переключение вариантов (цвет/размер), избранное, отзывы и диалоговые окна.
  5. SEO «из коробки» (Metadata API):
    • Функция generateMetadata({ params }) возвращает динамические title, description, OpenGraph теги и канонические URL для каждой карточки товара.


Реализована мощная, гибкая и функциональная система подписок на пользователей в соответствии с методологией Feature-Sliced Design (FSD), принципами Single Responsibility Principle (SRP) и правилами проекта.

Что сделано:​

  1. Миграция и база данных:
    • Таблица user_subscriptions с уникальным составным индексом (subscriber_id, target_user_id) и расширенными настройками уведомлений (notify_new_products, notify_price_drops).
    • Автоматическая инициализация структуры в MySQL при запуске приложения.
  2. Backend Модуль (FSD / SRP):
    • server/modules/subscriptions/schemas.ts: Валидация входных данных с помощью Zod.
    • server/modules/subscriptions/repository.ts: Оптимизированные Drizzle/SQL-запросы для оформления/отмены подписки, получения списков подписчиков/подписок и персонализированной ленты обновлений.
    • server/modules/subscriptions/service.ts: Бизнес-логика подписок и системных уведомлений.
    • server/modules/subscriptions/handlers.ts: Express-маршруты /api/subscriptions/*.
  3. Frontend Слой & Интерфейс:
    • SubscribeButton: Интерактивная кнопка подписки/отписки со счетчиком подписчиков и всплывающим меню быстрых настроек и анимацией состояния.
    • SubscribedFeed: Живая лента новых товаров от продавцов, на которых подписан пользователь.
    • SubscriptionsModal: Модальное окно управления списком подписчиков и подписок с фильтрацией, бейджами ролей с поиском и возможностью взаимной подписки и быстрым переходом.
    • Интеграция в карточку товара и профиль: Кнопка подписки добавлена в блок продавца в детальном просмотре товара (ProductDetailModal) и в шапку профиля пользователя, а в личном кабинете появился новый раздел «Подписки и подписчики».
  4. Локализация:
    • Зарегистрированы и внесены все фразные ключи подписок для 5 языков (en, ru, uk, de, es) в src/locales/translations.ts.

      1785580599937.png

1785581293938.png 1785581320209.png

1785581521107.png

Реализован функционал фильтрации по категориям и подпискам во вкладке «Подписки и Лента»:

  • Фильтрация по категориям подписок:
    • В блоке фильтров отображаются только те категории, в которых находятся товары и публикации подписок текущего пользователя.
    • Нажатие на кнопку выбора категории вызывает отдельное модальное окно с поиском по категориям и отображением количества товаров в каждой категории.
  • Дополнительный фильтр по Подпискам / Авторам:
    • Добавлена возможность выборки товаров конкретного автора, на которого подписан пользователь, либо отображения всех подписок («Все подписки»).
    • Выбор автора реализован в отдельном модальном окне с поисковой строкой по никнейму, аватарками пользователей и счётчиками опубликованных товаров.
  • Бэкенд и API:
    • Добавлен эндпоинт /api/subscriptions/feed/filters, который отбирает активные категории и авторов на основе оформленных подписок и их публикаций в базе данных.
    • Обновлён эндпоинт /api/subscriptions/feed для фильтрации товаров по target_user_id, category_id и category_name.
  • Локализация:
    • Зарегистрированы все новые текстовые фразы и добавлены в файлы локализации.


1785582652697.png

1785582735909.png

1785582764465.png

Новый функционал «Личные переписки и приватность»​

Представляем готовое структурированное описание модуля Личные переписки (Direct Messages) и Настройки приватности, подготовленное для публикации в презентациях, документации или демонстрационных материалах.


Модуль «Личные переписки» (Direct Messages)​

Модуль обеспечивает безопасное и удобное прямое общение между пользователями, покупателями и продавцами внутри платформы.

  • Централизованный хаб диалогов:
    • Быстрый поиск по собеседникам и тексту сообщений.
    • Фильтрация чатов по категориям: «Все», «Непрочитанные», «Взаимные подписки».
    • Индикаторы статуса прочтения и счетчики новых сообщений.
  • Контекстные сделки и привязка товаров:
    • Возможность отправить сообщение прямо со страницы карточки товара или профиля продавца.
    • Интерактивная карточка товара (миниатюра, название, цена) автоматически прикрепляется к контексту диалога для удобства обсуждения деталей покупки.
  • Интеграция с профилями и подписками:
    • Быстрый переход в профиль собеседника из шапки чата.
    • Отображение ролей аккаунта (Продавец, Дилер, Покупатель, Администратор) для повышения доверия при сделках.

Настройки приватности и прав доступа (Messaging Privacy)​

Инструмент гибкого контроля входящих сообщений, защищающий пользователей от нежелательного спама и обеспечивающий высокий уровень приватности.

  • Уровни доступа к отправке сообщений:
    1. Все пользователи — открытый доступ для всех зарегистрированных участников.
    2. Только на кого я подписан — доступ только для профилей из списка подписок пользователя.
    3. Только мои подписчики — сообщения могут отправлять только фолловеры пользователя.
    4. Только взаимные подписки — максимальная приватность (общение доступно при обоюдной подписке).
    5. Полная блокировка — запрет на входящие личные сообщения (кроме системных уведомлений администраторов).
  • Фильтрация по ролям аккаунта:
    • Разрешение на получение сообщений от конкретных категорий пользователей (Администраторы, Продавцы, Дилеры, Модераторы, Покупатели).

Локализация и UX​

  • Полная мультиязычность: Полное покрытие интерфейса переписок и настроек приватности на 5 языках (Русский, English, Українська, Deutsch, Español).
  • Адаптивный интерфейс: Оптимизированный двухпанельный layout с поддержкой горячих клавиш (закрытие по Escape, обработка кликов вне окна).

Screenshot_121.png

Screenshot_120.png Screenshot_122.png Screenshot_123.png Screenshot_124.png Screenshot_126.png Screenshot_127.png

Screenshot_125.png
 
Последнее редактирование:
1785779204815.png

1785779242284.png

1785779317605.png 1785779354802.png
Реализована возможность кастомизации панели навигации в профиле пользователя (hidden lg:block lg:col-span-1) в соответствии с методологией Feature-Sliced Design (FSD) и принципами Single Responsibility Principle (SRP):

  • Положение панели навигации (Слева / Справа):
    • В шапке блока навигации добавлена кнопка быстрого переключения положения боковой панели между правой и левой сторонами экрана (с адаптивным изменением порядка колонок сетки CSS Grid lgrder-first / lgrder-last).
  • Порядок отображения вкладок:
    • Создан FSD-модуль src/features/profile-navigation с хуком useProfileNavSettings и модальным окном ProfileNavSettingsModal (с рендерингом через createPortal относительно document.body).
    • Пользователи могут менять последовательность вкладок (перемещать вверх/вниз) и при необходимости сбрасывать порядок до стандартного.
  • Сохранение настроек:
    • Все выбранные настройки положения и порядка вкладок автоматически сохраняются в персональном localStorage пользователя и восстанавливаются при следующих посещениях.

Реализована полноценная система хранения и импорта локализаций городов на основе структуры GeoNames alternateNames для 5 локализаций сайта (Russian (RU), English (EN), Ukrainian (UK), German (DE), Spanish (ES)).

Screenshot_135.png

Screenshot_138.png Screenshot_137.png Screenshot_136.png

Что сделано:​

  1. Структура базы данных (city_alternate_names) :
    • Создана таблица city_alternate_names со следующей структурой:
      • id: уникальный автоинкрементный ID.
      • geonameid: идентификатор объекта GeoNames.
      • city_id: внешний ключ на таблицу cities.
      • language_code: код языка (isolanguage: ru, en, uk, de, es).
      • name: название города на указанном языке (alternateName).
      • is_preferred: флаг предпочтительного названия (isPreferredName).
      • Поле geoname_id также добавлено в таблицу cities.
  2. Backend API Endpoints (/api/locations/...) :
    • GET /api/locations/cities: загружает города с их коллекцией alternate_names.
    • GET /api/locations/cities/alternate-names: получение списка локализаций с фильтрацией по city_id, geonameid и language_code.
    • POST /api/locations/cities/alternate-names: добавление/создание альтернативного названия.
    • PUT /api/locations/cities/alternate-names/:id & DELETE ...: изменение и удаление записи альтернативного названия.
    • POST /api/locations/cities/:id/fetch-geonames-translations: автоматически загружает 5 локализаций (RU, EN, UK, DE, ES) для выбранного города из источников данных GeoNames/OSM/Wikidata.
    • POST /api/locations/cities/mass-fetch-geonames-translations: пакетный импорт локализаций GeoNames для всех городов выбранной страны.
  3. Интерфейс администратора (Location Management UI) :
    • В таблицу городов добавлена кнопка «Локализации GeoNames» с индикатором количества сохраненных названий.
    • Добавлено интерактивное модальное окно управления локализациями:
      • Статус наличия переводов для каждого из 5 языков (RU, EN, UK, DE, ES).
      • Быстрая авто-загрузка 5 локализаций в один клик.
      • Редактирование и ручное добавление вариантов названий с флагом isPreferredName.
    • На панели управления добавлена кнопка «Загрузить 5 локализаций GeoNames» для массового обогащения базы данных.

Можно ли сразу импортировать города на 5 языках (RU, EN, UK, DE, ES)?​

Да, можно! В системе уже заложен и настроен данный функционал.

При импорте города из GeoNames система сохраняет не только базовые названия (RU и EN), но и запрашивает и сохраняет переводы на все 5 языков:

  1. Структура хранения в базе:
    • В нашей базе данных создана специальная таблица city_alternate_names с полями:
      • geonameid — уникальный ID объекта в базе GeoNames.
      • city_id — ID города в вашей системе.
      • language_code — код языка (ru, en, uk, de, es).
      • name — официальное название города на выбранном языке.
      • is_preferred — флаг предпочтительного перевода.
  2. Многоуровневый алгоритм получения 100% переводов:
    Каждый запрос на импорт задействует надежную связку источников данных:
    • GeoNames API / AlternateNames — прямой поиск географического ID.
    • OpenStreetMap Name Tags — считывание языковых тегов name:ru, name:en, name:uk, name:de, name:es.
    • Wikidata Entity Labels — извлечение официальных мультиязычных названий со статей Википедии.

Как пользоваться в панели администратора:​

  1. Перейдите в Админ-панельЛокации → вкладка «Города».
  2. В верхней панели над списком городов доступна кнопка «Загрузить 5 локализаций GeoNames» — она автоматически обработает города выбранной страны и сохранит переводы на RU, EN, UK, DE и ES.
  3. Напротив каждого города в таблице есть иконка глобуса 🌐 (Локализации): при клике открывается модальное окно с подробной сеткой всех 5 языков, где можно редактировать, добавлять или дозагружать переводы в один клик.
 
Последнее редактирование:
СВЕЖАЯ И АКТУАЛЬНАЯ Для просмотра ссылки Войди или Зарегистрируйся НА TS + Express + Node.js


Screenshot_199.png Screenshot_198.png

Исправление и сохранение системы блокировки (Бан) пользователей​

  • Сохранение в базе данных: В таблице users поле banned_until переведено в формат DATETIME с поддержкой как постоянного бана (до 2099 года), так и временных блокировок.
  • Сброс кэша состояния: Эндпоинты POST /api/users и PUT /api/users/:id теперь гарантированно сбрасывают кэш базы данных (clearDBStateCache), благодаря чему статус бана сохраняется и мгновенно отображается в панели администратора без сброса.
  • Интерфейс панели администратора (AdminDashboard.tsx) :
    • Согласованы параметры формы: выбор срока бана (без блокировки, временный с выбором точной даты и времени, 1 день, 7 дней, 30 дней, 60 дней, навсегда) и указание причины.
    • Добавлена кнопка быстрого снятия блокировки (разбана) прямо в таблице пользователей.
    • Реализованы серверные и клиентские ограничения для заблокированных пользователей (запрет на создание/редактирование товаров, отзывы и отправку сообщений).


Какие ограничения действуют для заблокированного пользователя:​

При активном бане (когда дата banned_until больше текущего времени) для пользователя заблокированы следующие действия:

  1. Создание и редактирование товаров/объявлений:
    • Попытка создать новый товар (POST /api/products) блокируется с ошибкой 403 Forbidden и отображением причины/срока бана.
    • Попытка отредактировать (PUT /api/products/:id) или продлить объявление (POST /api/products/:id/renew) блокируется.
    • На клиенте при нажатии кнопки "Создать объявление" выводится мгновенное предупреждение.
  2. Личные сообщения (ЛС) и чаты:
    • Отправка прямых сообщений другим пользователям (POST /api/messages/send) блокируется.
    • Отправка сообщений внутри заказов (POST /api/orders/:id/messages) блокируется.
  3. Отзывы и рейтинги:
    • Публикация отзывов и оценок (POST /api/products/:id/reviews) блокируется.
    • Удаление чужих/своих отзывов и ответы на отзывы блокируются.
  4. Оформление заказов и корзина:
    • Оформление заказа и списание средств при чекауте (POST /api/cart/checkout) отклоняется с информированием о блокировке.
  5. Массовые операции продавца:
    • Массовое изменение цен (POST /api/products/bulk/price), остатков (/stock) и пополнение склада (/restock) заблокированы.

Уведомления в Notifications Hub:​

  • При установке блокировки администратором в базе данных автоматически создается системное уведомление типа ban с указанием срока и причины бана.
  • При досрочном снятии бана отправляется уведомление типа unban о восстановлении полного доступа.
  • В выпадающем меню Notifications Hub уведомления о блокировке выделяются отдельной цветовой индикацией (красный бейдж/иконка щита) и отображают подробности.
  • В шапке сайта для заблокированного пользователя выводится информационный баннер с точной датой окончания ограничений и причиной.

Доработка корзины и Checkout Station для заблокированных пользователей​

Для пользователей с активной блокировкой профиля внесены следующие изменения:

  • Информационный блок о блокировке в Checkout Station:
    • В корзине на шаге оформления заказа (Final Checkout Review) выводится подробный баннер с датой окончания блокировки, причиной и предупреждением об ограничении операций.
    • В блоке действий перед кнопкой выводится четкое предупреждение: «Профиль заблокирован: оформление заказа недоступно».
  • Деактивация кнопки «Secure Checkout Order»:
    • Кнопка оформления заказа переводится в отключенное состояние (disabled), курсор меняется на not-allowed, а надпись на кнопке изменяется на Профиль заблокирован 🔒
    • Кнопка перехода к выбору доставки на первом шаге корзины также деактивируется с выводом предупреждения.
    • В модальном окне прямой быстрой покупки (DirectCheckoutModal) кнопка покупки аналогично заблокирована с выводом предупреждающего баннера.
    • На стороне сервера в POST /api/cart/checkout дополнительно срабатывает защита, возвращающая 403 Forbidden при любых попытках отправки запроса.
 
Последнее редактирование:

Исправлена проблема с отображением объявлений с истекшим сроком публикации:

Screenshot_201.png
  1. Исключение истекших объявлений из общего каталога:
    • В хуке фильтрации товаров (useProductFilters) и боковой панели фильтров (SidebarFilters) добавлена проверка срока действия (expires_at).
    • Объявления с истекшим сроком теперь корректно скрываются из общего каталога, результатов поиска и списка активных товаров для всех покупателей.
  2. Корректное перемещение во вкладку «Неактивные» в профиле:
    • В компоненте профиля пользователя (UserProfile) логика фильтрации и счетчики вкладок обновлены: товары с истекшим сроком публикации автоматически исключаются из вкладки «Активные» и попадают во вкладку «Неактивные».
    • В карточке товара (ListingItemDetails) добавлен статус-бейдж «Истёк» / «Неактивен», а также сохранена кнопка быстрого продления срока публикации («Продлить»).
  3. Синхронизация в панели администратора:
    • В панели управления товарами (ProductManagement) фильтры и статистика приведены в соответствие с новой логикой статусов.
 

На странице профиля в разделе Product Listings реализована возможность изменения срока публикации (Listing Publication Duration) и продления для объявлений с истекшим сроком (Inactive / Expired)

Screenshot_206.png

Screenshot_209.png
  • Редактирование срока публикации в форме товара:
    • В модальном окне редактирования товара добавлен расширенный блок Listing Publication Duration со статусом и предупреждением для истекших/неактивных объявлений.
    • Доступны все предустановленные периоды размещения: 7 дней, 14 дней, 30 дней, 90 дней, 180 дней (6 месяцев) и 365 дней (1 год) с кнопками быстрого выбора в один клик.
    • Отображается расчет новой даты окончания публикации.
    • При сохранении обновляется срок размещения (duration_days), рассчитывается новая дата окончания (expires_at), и объявление автоматически реактивируется (is_active = 1).
  • Управление сроком в списке объявлений:
    • Интерактивный бейдж срока действия (Expired: ...) теперь кликабелен для быстрого открытия окна продления.
    • На карточке неактивного товара в панели действий справа и под миниатюрой добавлена кнопка «Продлить» для изменения периода публикации.
 
Последнее редактирование:
Назад
Сверху