# Каталог: товары, бренды, атрибуты

## Товары (`/admin/shop/products`)

### Структура страницы

- **4 таба** по статусу публикации: все / активные / черновики / архив.
- **Поиск** по id, SKU, названию или slug-у.
- **Селекты**: категория, производитель, сортировка (8 вариантов: по дате обновления, цене, названию, остатку, рейтингу), кол-во на странице.
- **Доп. фильтры** (раскрывающаяся панель): остаток (любой / в наличии / заканчивается 1–5 / нет), диапазон цены, только избранные, без картинки.

### Карточка товара

В форме редактирования 6 вкладок:

1. **Общая** — название, slug, цена, старая цена (для скидки), SKU, штрихкод, остаток, категория, бренд, статус (active/draft/archived), флаг «избранный», краткое и полное описание (HTML-редактор).
2. **Фото** — единая галерея: первое фото — главное (видно в каталоге и поиске). Drag-and-drop для перестановки, ⭐ — сделать главным, ✕ — удалить. Поддержка multi-upload. На сервере `cover` всегда синхронизируется с `images[0]` — серверный гард на случай несинхронизированного клиента.
3. **Вариации** — варианты товара с собственной ценой, скидкой, остатком, SKU и фото. Опции (например, «Цвет»: Красный/Синий, «Размер»: S/M/L) → матрица комбинаций. JS-генерируемая таблица, сохранение в JSON-полях `options` и `variations` товара.
4. **Атрибуты** — типизированные характеристики. Каждый атрибут имеет тип (text/number/select/multiselect/boolean/color), единицу измерения, флаг `is_filterable` (показывать в фасетных фильтрах каталога).
5. **SEO** — SEO Title, SEO Description. Кнопка «Заполнить через ИИ» работает с активным AI-провайдером.
6. **Доп. поля** — кастомные поля, добавленные через ядерный модуль «Доп. поля» с сущностью `shop_product`.

### Вариации vs атрибуты — в чём разница

- **Вариации** — то, что покупатель **выбирает на сайте**. У каждой комбинации своя цена/остаток/фото. Пример: футболка → выбрал цвет и размер → 3500₴ + 5 шт. на складе.
- **Атрибуты** — описывают **сам товар**, покупатель их не выбирает, они работают как фасетные фильтры в каталоге («только Bosch», «вес до 2 кг»). Пример: дрель → бренд Bosch, мощность 700 Вт.

### Просмотры

Счётчик `views` инкрементится при каждом GET `/shop/product/{slug}` от не-бота (фильтр по User-Agent `bot|crawl|spider|slurp|fetch|preview|monitor`). В админ-таблице — кликабельная ссылка на публичную страницу товара.

### Удаление

Удаляет товар и связанные записи `celena_custom_field_values` и `shop_attribute_values`. История заказов сохраняется (в `shop_order_items` остаётся снимок названия и SKU на момент покупки).

## Производители (`/admin/shop/manufacturers`)

CRUD: название, slug, логотип, страна, сайт, sort_order, is_active. Поле `manufacturer_id` в товаре — внешний ключ (без жёсткого FK; при удалении бренда товары отвязываются автоматически).

## Атрибуты (`/admin/shop/attributes`)

Визуальный конструктор. Для типов `select / multiselect / color` — встроенный редактор вариантов значений с drag-reorder. Slug генерируется автоматически из названия (с транслитерацией кириллицы), используется в URL фасетных фильтров: `?attr_brand=bosch`.

### Типы

| Тип | Поведение | Пример |
|---|---|---|
| `text` | Свободный ввод | Артикул производителя |
| `number` | Число + единица измерения | Вес, мощность |
| `select` | Один вариант из списка | Бренд |
| `multiselect` | Несколько значений | Теги: «беспроводной», «компактный» |
| `boolean` | Да/Нет | «Влагозащищённый» |
| `color` | Цвет (один из списка) | Совместим с фильтром цветов |

Значения хранятся в `shop_attribute_values` (product_id, attribute_id, value). Multiselect сохраняется как JSON-массив строк.

## Категории

Категории товаров живут в общей таблице ядра `celena_categories` с фильтром `entity_type = 'shop_product'`. Управление — через стандартный модуль «Категории». Это позволяет одной категории привязываться к нескольким сущностям (например, «Электроника» — и товар, и новость).
