О проекте

Это демонстрационная работа для портфолио, а не действующий магазин. Ниже честный список: что здесь работает по-настоящему и что придумано. Такой список — часть работы, а не оговорка: клиент должен понимать, за что он смотрит на демо.

Поиск

Индекс целиком в браузере: 320 позиций, около десяти килобайт после brotli. Конвейер запроса — нормализация, доменный словарь на 156 строк, стемминг Snowball, затем MiniSearch с порогом fuzzy по длине токена.

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

Отдельная история — словарь. Snowball схлопывает падежи, но не схлопывает существительное и относительное прилагательное: «плитка» → «плитк», а «плиточный» → «плиточн». Расстояние три, fuzzy не спасает и не должен. Лемматизатор решил бы задачу, но тянет словарь на мегабайты — в браузер такое не грузят.

Фасеты

Счётчики дизъюнктивные: для группы они считаются со всеми фильтрами, кроме фильтров самой группы. Поэтому мультивыбор внутри группы работает — выбрали один бренд, у остальных остались живые числа. Библиотечные фасеты так не умеют, и это дефект, а не придирка.

Всё считается за один проход по типизированным массивам, без аллокаций на кадр. Спиннеров нет намеренно: пересчёт занимает доли миллисекунды, и любой лоадер читался бы как имитация работы.

Каталог фильтруется и с отключённым JavaScript: каждый фасет — ссылка на статически собранную страницу одного фильтра.

Расчёт

Считает раскладку, а не площадь: симметрирует ряды, соблюдает правило «подрезка не уже половины плитки», учитывает шов между полем и подрезкой, знает про выход двух кусков из одной плитки только с противоположных краёв одной оси и про то, что направленный рисунок это правило отменяет.

Клей — по таблице гребёнок, обратное намазывание отдельным слагаемым, а не множителем. Затирка — по формуле, оба контрольных примера зафиксированы тестами до третьего знака. Округление до упаковок происходит один раз и в конце. Переплата показывается всегда.

Схема рисуется одним SVG-паттерном для поля целых плиток и индивидуально только для подрезок: иначе на мозаике в браузере оказалось бы десять тысяч узлов, и телефон бы встал.

Инженерная часть

Astro в режиме чистой статики плюс острова на Svelte. React в проекте отсутствует полностью — это второе демо в портфолио, и оно доказывает гибкость после первого на Next.js.

На сервере нет ни одного процесса Node: файлы раздаёт Caddy, прекомпрессия brotli делается на сборке. Данные — YAML в репозитории; сборка валидирует ссылки и реестр характеристик, детерминированно генерирует SKU, считает упаковку и вес из размеров и плотности. Ни одна упаковка не вбита руками.

Что вымышлено

Персональные данные не собираются

Формы «оставьте заявку» с именем и телефоном здесь нет намеренно. Из расчёта можно отправить смету — только позиции, количества и сумму, без контактов. Поэтому нет ни оператора персональных данных, ни политики, ни галочки согласия: 152-ФЗ просто не возникает.

Каталог и карточки отдают noindex, follow, микроразметка ограничена WebSite и BreadcrumbList. Отдавать поисковикам Product и Offer с выдуманными ценами — прямой риск для домена, который кормит.

Ссылки