Инструкция · work/classification
Как работают файлы классификации
От старой категории в HTML до нового значения в карточке — каждый шаг, файл и правило.
1. Для чего нужны эти файлы
В старом каталоге одно поле «категории» содержит разные по смыслу вещи: «Бифлекс» описывает вид ткани, «Для платьев» — назначение, «Гипоаллергенные» — свойство, а «Акция» — рекламную подборку. В назначениях тоже встречаются виды ткани, например «Трикотаж».
Папка work/classification задаёт предлагаемое разделение этих значений. Её JSON-файлы работают как промежуточный слой правил: какой старый ключ в какой новый справочник и значение направить. Меняя файл, вы меняете результат предпросмотра для всех товаров с этим источником.
На странице разделения категорий можно увидеть будущие поля товара и проверить происхождение каждого значения. Эта инструкция объясняет механизм, а раздел «Текущие правила» на отдельной странице читает актуальные JSON при каждом открытии.
2. Что происходит при открытии товара
- Составляется список товаров. Приложение обходит
work/raw_pages/ukиwork/raw_pages/ru, включая вложенные папки. В список попадают имена HTML-файлов без расширения. Имя служит ключом товара; числовые имена тоже допустимы. Наличие имени ещё не гарантирует, что внутри действительно карточка товара. - Загружаются правила. Читаются все файлы
*.jsonнепосредственно вwork/classification/rules. Вложенные папки правил не обходятся. JSON проверяется, затем для каждого источника собирается список подходящих новых значений. - Читаются снимки выбранного товара. Например, для
bifleks-rubchikнужныuk/bifleks-rubchik.htmlиru/bifleks-rubchik.html. Всё содержимое каталога при этом не разбирается. Обращения к действующему магазину нет. - Проверяется карточка. Парсеры проверяют признаки страницы товара, заголовок, блок метаданных и, если в canonical распознан slug товара, его соответствие имени файла. Пустой файл, страница каталога или другая карточка не становятся достоверным результатом.
- Извлекаются категории. Берутся ссылки внутри
product_meta → posted_in, а не ссылки из меню сайта. Из адреса после/product-category/выделяется полный путь категории, без языкового префикса и завершающего слеша. - Извлекаются назначения. Парсер читает подписи из блока «назначение:» / «призначення:» и сопоставляет их со знакомыми slug. Если подписей нет, но на товаре есть классы
pa_naznachenie-*, используется этот запасной источник. Неизвестная подпись получает ключ из парсера и может потребовать нового правила. - Применяются совпадения. Каждый источник направляется во все указанные для него значения. Повтор одного значения объединяется, а список источников сохраняется. Спорные и неизвестные источники отмечаются отдельно.
- Показываются две версии. Для UK выводятся новые украинские названия, для RU — русские. Сверху видно, совпали ли итоговые наборы. Ниже доступны исходные данные, объяснения переносов и файлы правил.
Без выбранного товара страница показывает список доступных файлов и правила. Предпросмотр карточки появляется после выбора. При обновлении страницы и HTML, и правила читаются заново.
3. Что лежит в work/classification
work/classification/
├── README.md Краткая инструкция для работы в редакторе
├── sources.json Исходный список категорий и назначений
└── rules/ Действующие правила предпросмотра
├── fabric_types.json Виды ткани
├── materials.json Материалы
├── material_groups.json Группы по происхождению
├── purposes.json Назначения
├── properties.json Свойства
├── finishes.json Поверхность и отделка
├── processing.json Пригодность для обработки
├── collections.json Подборки и продвижение
├── catalog_sections.json Общие разделы каталога
└── manual_review.json Очередь неоднозначных рубрик
README.md — текстовое объяснение
Нужен человеку, который открывает папку в редакторе. Изменения этого файла не влияют на карточки. Текст этой веб-инструкции также не исполняется как правило.
sources.json — исходная опись
Сохраняет предоставленные 82 категории и 18 назначений. Для каждой записи указаны source — ключ с префиксом, number — номер в исходном списке, uk и ru — старые названия, counts.uk и counts.ru — исходные количества товаров.
Эти количества исторические: они не пересчитываются при открытии товара. Предпросмотр не берёт названия или правила из sources.json. Файл нужен для сверки полноты; автоматический тест проверяет, что каждый источник из описи присутствует в правилах. Если в новых HTML появился дополнительный ключ, он будет виден как неизвестный до добавления правила.
rules/*.json — то, что действительно меняет результат
| Файл | Что сюда относится | Граница смысла |
|---|---|---|
fabric_types.json | Бифлекс, трикотаж, деним, креп, подкладочная и пальтовая ткани. | Торговый вид ткани; он не определяет точный состав. |
materials.json | Лён, вискоза, шёлк, кашемир, тенсел. | Материал, названный в старой рубрике; это не утверждение о 100% волокна. |
material_groups.json | Натуральные и синтетические. | Широкая группа происхождения отдельно от конкретного материала. |
purposes.json | Брюки, рубашки, платья, спорт, декор и другие применения. | Что можно изготовить или где использовать ткань. |
properties.json | Плотная, стрейч, светоотражающая, гипоаллергенная. | Заявленное в рубрике свойство; испытания и состав не проверяются. |
finishes.json | Матовая поверхность, пайетки, плиссированная ткань. | Уже существующая поверхность или отделка. |
processing.json | Для печати, для плиссирования. | Пригодность к обработке; готовый принт или складки из этого не следуют. |
collections.json | Акция, новинки, премиум. | Подборки из снимка. Срок акции, цена и дата поступления не вычисляются. |
catalog_sections.json | Ткани для одежды. | Общий раздел, который сам по себе не задаёт конкретное назначение. |
manual_review.json | Смешанные рубрики, смысл которых нужно уточнить. | Рабочая очередь, а не будущий справочник значений товара. |
Это начальная схема. Можно добавлять свои справочники. Для программы имя файла служит подсказкой в расшифровке; идентификатор справочника задаётся полем table внутри JSON. Исключение в отображении: manual_review не показывается как поле карточки.
4. Формат JSON: что означает каждое поле
Ниже учебный пример файла с одним значением. В действующем purposes.json значений больше; при редактировании не заменяйте весь файл этим примером.
{
"table": "purposes",
"title": "Назначения",
"title_uk": "Призначення",
"description": "Изделия и области применения.",
"terms": [
{
"key": "shirts",
"uk": "Сорочки",
"ru": "Рубашки",
"sources": [
"category:tkani-dlya-odezhdy/dlya-rubashek",
"purpose:rubashka"
],
"note": "Два источника объединяются в одно назначение.",
"review": false
}
]
}
| Поле | Что задаёт | Требования |
|---|---|---|
table | Общий ключ справочника, например purposes. | Обязательно. Латинские строчные буквы, цифры, подчёркивание; первый символ — буква. Уникально среди файлов. |
title | Русское название раздела и заголовок в интерфейсе правил. | Обязательная непустая строка. |
title_uk | Украинский заголовок поля в карточке. | Необязательно. Если отсутствует, используется title. Для полной локализации лучше заполнять. |
description | Объяснение назначения справочника. | Обязательная непустая строка. Не участвует в сопоставлении. |
terms | Список новых значений этого справочника. | Обязательный JSON-массив []. Может быть пустым. |
terms[].key | Стабильный ключ значения, например shirts. | Обязательно. Строчные латинские буквы, цифры, дефис и подчёркивание; начало — буква или цифра. Уникален внутри справочника. |
terms[].uk, terms[].ru | Новые названия значения на двух языках. | Обе непустые строки обязательны. Перевод не генерируется автоматически. |
terms[].sources | Список старых ключей, которые дают это значение. | Обязательный непустой массив строк с префиксом category: или purpose:. |
terms[].note | Пояснение конкретной замены или сомнения. | Необязательная строка. Видна в расшифровке, не меняет результат. |
terms[].review | Нужно ли отложить это значение для проверки. | Необязательно; по умолчанию false. Допустимы boolean true / false без кавычек. |
JSON пишется в UTF-8, с двойными кавычками, без комментариев и запятой после последнего элемента. Если нужно оставить объяснение, используйте note или description. Отдельных условий по товару, регулярных выражений или команд в JSON сейчас нет.
5. Как определяются совпадения и замены
Источник — это тип и точный ключ
category:rubashka и purpose:rubashka — два разных источника. Первый соответствует старой составной категории «Рубашка Платье Блуза», второй — назначению «РУБАШКА». Одинаковая часть после двоеточия не делает их одним правилом.
Для вложенной категории сохраняется полный путь: category:tkani-dlya-odezhdy/dlya-rubashek. Сокращение до category:dlya-rubashek не совпадёт. Ключи ищутся буквально: нет поиска по подстроке, автоматического перевода или угадывания по названию товара.
В sources перечислены альтернативы
Если у значения два источника, достаточно любого одного, чтобы получить это значение. Наличие обоих не требуется. Если присутствуют оба, в карточке всё равно будет одно значение, а в расшифровке сохранятся оба основания.
Один источник может дать несколько значений
Программа применяет все совпадения во всех файлах. Здесь нет приоритета «последний файл побеждает». Если один источник указан в трёх значениях, все три сработают, кроме помеченных review: true.
Повторы объединяются по table + key
Два источника для purposes + shirts дают одну «Рубашки». Одинаковые названия с разными ключами останутся разными значениями. И наоборот, новые подписи UK/RU могут различаться, но один ключ означает одно смысловое значение.
6. Примеры: что куда переходит
Эти примеры объясняют начальное разделение. Если вы поменяете JSON, актуальный результат смотрите в предпросмотре и списке текущих правил.
Два старых источника → одно назначение
category:tkani-dlya-odezhdy/dlya-rubashek ─┐
purpose:rubashka ────────────────────────┴→ purposes / shirts
UK: Сорочки
RU: Рубашки
Если товар имеет только один из этих источников, результат будет тем же. При двух источниках дубликат «Рубашки» не появится.
Составная категория → три разных признака
category:bifleks-matovyi-shchilnyi
→ fabric_types / biflex → Біфлекс / Бифлекс
→ finishes / matte → Матова / Матовая
→ properties / dense → Щільна / Плотная
В названии явно присутствуют вид, поверхность и плотность. Поэтому один источник записан в трёх справочниках. Если дополнительно есть категория bifleks, она объединится с уже полученным видом ткани.
Ошибочно размещённое назначение → вид ткани
purpose:trikotazh направляется в fabric_types / knit. В будущих назначениях «Трикотаж» больше не появляется, но в исходных данных остаётся видимым.
Пиджаки и жакеты → два отдельных назначения
category:tkani-dlya-odezhdy/dlya-pidzhakov и purpose:pidzhak дают purposes / blazers — «Піджаки / Пиджаки». Категория category:tkani-dlya-odezhdy/tkani-dlya-zhaketov даёт purposes / jackets — «Жакети / Жакеты». Эти значения не объединяются. Если у товара есть оба источника, в назначениях будут оба значения.
Назначение плаща и подкладки → отдельно от вида ткани
purpose:plashhevye даёт purposes / raincoats — «Плащі / Плащи» и объединяется с категорией «Для плащей». purpose:podklad даёт purposes / lining — «Підкладка / Подкладка». Эти старые назначения сами по себе не добавляют вид ткани.
«Плащова тканина / Плащевая ткань» в fabric_types / raincoat и «Підкладкова тканина / Подкладочная ткань» в fabric_types / lining берутся из соответствующих старых категорий. Если в снимке есть и категория вида, и назначение, карточка покажет оба признака в разных полях.
Уже обработана и подходит для обработки — разные поля
category:plissirovanaya-tkan даёт отделку «Плиссированная». category:tkan-dlya-plissirovaniya даёт «Для плиссирования» в пригодности к обработке. Эти значения не объединяются.
Неоднозначная категория → очередь проверки
category:neopren в исходном списке называется «Сетка спорт, Неопрен». Назначить товару сразу оба вида было бы предположением. Сейчас источник ведёт в manual_review.json с review: true, поэтому в карточку значение не добавляется, а причина показывается ниже.
7. Как самостоятельно менять правила
- Откройте нужный товар в предпросмотре. В «Исходных данных» найдите значение, а в «Что куда перешло» — его точный ключ, файл и новое значение.
- Откройте соответствующий JSON в
work/classification/rulesв редакторе. Перед крупной перестройкой сохраните копию вне папкиrules: копия с расширением.jsonв этой папке тоже будет прочитана как правило. - Измените нужную запись, сохраните корректный JSON и обновите страницу товара. Перезапуск Docker и очистка кеша Laravel не нужны.
- Проверьте обе версии, объяснения переносов, спорные значения и ещё несколько товаров с тем же источником. Изменение действует на все соответствующие товары.
Переименовать значение или исправить перевод
Меняйте uk и/или ru. Для заголовка поля меняйте title и title_uk. Ключи table и key при обычном переименовании оставляйте прежними: они определяют идентичность значения.
Перенести источник в другой справочник
Удалите его строку из старого sources и добавьте в sources нужного значения в другом файле. Если старый список стал пустым, удалите всю ненужную запись из terms: пустой sources не допускается. Если оставить источник в обоих местах, он даст оба результата.
Объединить синонимы
Соберите их исходные ключи в одном sources у одного значения. Отдельные старые записи с ненужными новыми ключами удалите. Пример начального объединения: «Костюм» и «Костюмная ткань» ведут в один вид ткани suiting.
Разделить одно название на несколько признаков
Добавьте один и тот же исходный ключ нескольким значениям. Разделение будет применяться ко всем товарам с этой рубрикой; отдельных исключений по slug товара текущий формат не поддерживает.
Добавить новый справочник
Создайте файл вроде my_group.json прямо в rules. Задайте уникальный table, названия, описание и массив terms по формату выше. Новая группа появится в предпросмотре автоматически. Новая таблица в базе при этом не создастся.
Разобрать спорную рубрику
Перенесите её источники из manual_review.json в нужные рабочие справочники и удалите запись очереди. Не просто снимайте review внутри manual_review: эта группа скрыта среди полей карточки. В обычном справочнике можно временно поставить review: true, чтобы отложить конкретное значение.
Что произойдёт при удалении
Удалённое правило перестанет давать результат при следующем открытии. Если для источника больше нет совпадений, он попадёт в нераспределённые. Удаление целого файла само по себе не считается ошибкой формата, пока остаются другие корректные файлы: приложение не хранит обязательный список имён справочников.
8. Как работают UK и RU
Две стороны рассчитываются независимо: украинские источники читаются только из файла в raw_pages/uk, русские — из raw_pages/ru. Отсутствующее значение не дополняется из соседнего языка.
Исходные подписи показываются такими, как они записаны в снимке, даже если там опечатка или русский текст в украинской версии. В новых полях используются uk и ru из правил. Поэтому старое «ДЛЯ ПРИНТОВАНИЯ» в UK может превратиться в корректное «Для друку» без редактирования HTML.
| Ситуация | Результат |
|---|---|
| Одинаковые источники, разные языки | Ключи итоговых значений совпадают, подписи локализованы. Статус — значения совпадают. |
| Разные источники объединились в один новый ключ | Итог может совпадать, хотя набор старых категорий различался. Для проверки старых наборов есть отдельные страницы сравнения. |
| В одной версии нет источника | Если ничто другое не даёт то же значение, итоговые наборы различаются. Уникальные значения выделяются. |
| Одного файла нет или он ошибочный | Эта сторона не получает предпросмотр, сравнение недоступно. Корректная сторона может отображаться. |
| Язык в HTML не соответствует папке | Показывается предупреждение. Файл не переносится между языками автоматически; для результата используется язык папки. |
Сравнение проводится по парам table + key, а не по тексту перевода. Если итоговые значения совпадают, но часть источников требует проверки, рядом будет отдельная отметка о неполном результате.
9. Ошибки, предупреждения и очередь проверки
«Правило отсутствует»
Источник прочитан из HTML, но его точного ключа нет ни в одном sources. Он остаётся в расшифровке, не добавляет значение и увеличивает счётчик нераспределённых. Скопируйте ключ из страницы и добавьте правило.
«Требует проверки»
Совпадение найдено, но у него review: true. Это конкретное значение не переносится. Если у того же источника есть другие совпадения без такой отметки, они всё равно применяются. Счётчик показывает число исходных ключей с проблемами, а не число всех отложенных назначений.
Начальная очередь содержит четыре рубрики: «Сетка спорт, Неопрен», «Рубашка Платье Блуза», «Для сорочек и пижам» и «Хай-тек». Причины и текущий состав очереди можно посмотреть в текущих правилах на отдельной странице.
«Ошибка правил»
Ошибка синтаксиса JSON, пропущенное обязательное поле, неверный тип, повтор table между файлами или повтор key внутри группы останавливают предпросмотр обеих версий. В сообщении указано имя файла и причина. Так ошибка одного справочника не выглядит как успешное частичное преобразование.
Если папка правил пуста или ни одного JSON не найдено, это тоже ошибка. Но корректность формата не гарантирует правильный смысл: допустимый, но ошибочно набранный путь категории просто не совпадёт с источником.
Ошибки снимков
Отсутствующий, пустой, нечитаемый файл, нераспознанная карточка, страница каталога, другой товар в canonical, нераспознанный адрес категории или отсутствие категорий блокируют результат соответствующей версии. В таком случае нужно проверить исходный снимок, а не пытаться исправить его правилом.
Несовпадение языка и повреждённые символы UTF-8 показываются предупреждениями. Предпросмотр может строиться, но предупреждение остаётся видимым.
10. Где это работает в коде
Этот раздел пригодится, если потребуется менять сам механизм, а не только список соответствий.
| Файл проекта | Ответственность |
|---|---|
app/Services/ClassificationRules.php | load() читает и проверяет JSON, строит индекс источников. apply() применяет совпадения, объединяет значения и формирует расшифровку. |
app/Services/ClassificationPreview.php | Находит локальные товары, вызывает парсеры, рассчитывает UK/RU и сравнивает итоговые ключи. |
app/Services/CategoryAudit.phpapp/Services/PurposeAudit.php | Извлекают категории и назначения из HTML, проверяют карточки и собирают предупреждения. |
app/Http/Controllers/ClassificationPreviewController.php | Принимает выбранный product, передаёт результат в страницу. Ответ не кешируется браузером. |
resources/views/audit/classification.blade.php | Показывает поля товара, исходники, переносы и список правил. |
app/Http/Controllers/ClassificationGuideController.phpresources/views/audit/classification-guide.blade.php | Текущее разделение по файлам правил. HTML товаров здесь не разбирается. |
resources/views/audit/classification-instructions.blade.php | Эта инструкция. Открывается отдельно от просмотра действующих правил. |
tests/Feature/ClassificationPreviewTest.php | Проверки покрытия исходного списка, объединений, языков, обновления файлов, ошибок и отсутствия SQL-запросов в предпросмотре. |
Данные результата существуют только до завершения запроса. Постоянный файл с «переписанным товаром» не создаётся. Если позже понадобится перенос в базу, это будет отдельная операция с согласованной схемой и отдельной проверкой данных.
Перейти к проверке товара →