diff --git a/docs/ANALYSIS.md b/docs/ANALYSIS.md new file mode 100644 index 0000000..592f1c8 --- /dev/null +++ b/docs/ANALYSIS.md @@ -0,0 +1,179 @@ +# Анализ сайта-источника la-rose.by + +**Дата аудита:** 2026-10-01 · **Метод:** обход живого сайта (HTML + headless-сессия для каталога и корзины). +**Статус документа:** факты о текущем сайте как есть. Плановые решения — в `docs/PLAN.md`. + +## 0. Кратко + +LaRose — минская доставка цветов (с 2018), ~94 уникальных товара, 11 категорий верхнего уровня, +8 информационных страниц, одностраничное оформление заказа, самовывоз + курьер по Минску. +Сайт работает на **Webasyst Shop-Script** (тема `free1`), интерфейс полностью русский, валюта — **BYN**. + +Ключевой вывод для переделки: сайт **функционально полный, но структурно бедный** — +на карточке товара нет структурированных полей (состав, размеры, количество стеблей, наличие), +нет фасетных фильтров (только диапазон цены), нет блога/FAQ, аккаунт не выведен в шапку. +Это и есть главный фронт работ по «крутому» сайту. + +## 1. Карта страниц (sitemap) + +```mermaid +graph TD + HOME["/ — Главная"] --> CAT["Каталог — 11 категорий"] + CAT --> C1["/category/bukety-tsvetov/ (~92)"] + CAT --> C2["/category/sbornye-bukety/ (~36)"] + CAT --> C3["/category/bukety-iz-alstromerii/ (~15)"] + CAT --> C4["/category/bukety-iz-gvozdiki/ (~16)"] + CAT --> C5["/category/bukety-iz-kustovoy-rozy/ (~20)"] + CAT --> C6["/category/bukety-iz-khrizantemy/ (~37)"] + CAT --> C7["/category/svadebnye-bukety-nevesty/ (3)"] + CAT --> C8["/category/monobuket/ (~23)"] + CAT --> C9["/category/kompozitsii/ (~7)"] + CAT --> C10["/category/tsvety-v-yashchike/ (1)"] + CAT --> C11["/category/tsvety-v-korzine/ (~6)"] + C1 --> PDP["/product/<slug|id> — ~94"] + C6 --> PDP + C8 --> PDP + CAT -. вне меню .-> H1["/category/bukety-iz-roz/ (22)"] + CAT -. вне меню .-> H2["/category/bukety-iz-gortenziy/ (0)"] + CAT -. вне меню .-> H3["/category/bukety-s-tyulpanami/ (0)"] + HOME --> TOP["Сервисное меню"] + TOP --> A1["/company/ — О компании"] + TOP --> A2["/dostavka/ — Доставка по Минску"] + TOP --> A3["/vozvrat/ — Возврат"] + TOP --> A4["/contacts/ — Контакты"] + A1 --> A1a["/company/b2b/ — Корпоративным клиентам"] + A1 --> A1b["/company/politika-konfidentsialnosti/"] + A2 --> A2a["/dostavka/oplata/ — Варианты оплаты"] + A2 --> A2b["/dostavka/zakaz/ — Как заказать"] + A4 --> A4a["/contacts/vakansii/ — Вакансии"] + HOME --> SYS["Транзакционные"] + SYS --> S1["/order/ — корзина + оформление (1 страница)"] + SYS --> S2["/cart/ — корзина (alt)"] + SYS --> S3["/login/ · /signup/ · /my/"] + SYS --> S4["/search/?query=…"] +``` + +## 2. Каталог + +- **Дерево:** 2 уровня — 11 категорий верхнего уровня → товары. Подкатегорий **нет**, фильтры не сгруппированы. +- **Товар может лежать в нескольких категориях** (кросс-листинг), поэтому сумма по категориям > числа уникальных товаров (~94). +- **Фильтры:** только диапазон цены (`price_min` / `price_max`, наблюдаемый диапазон 43–765 BYN) + «Показать» / «Очистить». Фасетов по поводу, цвету, цветку, размеру — нет. +- **Сортировки (`?sort=`):** Название, Цена, Хиты продаж, Оценка покупателей, Дата добавления, В наличии. +- **Пагинация:** номерная, ~28 товаров на страницу + селектор «Показывать по». +- **Блоки листинга:** «Хиты продаж», бейджи `ХИТ! / NEW! / СКИДКА!`, быстрая кнопка «В корзину», SEO-текст под сеткой. +- **Скрытые категории:** `bukety-iz-roz` (22 товара, есть только в SEO-тексте), `bukety-iz-gortenziy` и `bukety-s-tyulpanami` — отдают 200 и 0 товаров. + +## 3. Карточка товара — реальный набор полей + +Образец: `/product/buket-iz-15-roz-fridom/` + +| # | Поле (как на сайте) | Примечание | +|---|---|---| +| 1 | Название (`

`) | «Букет из 15 роз» | +| 2 | Бейдж | Хит! / New! / Скидка! | +| 3 | Текущая цена | `142 BYN` | +| 4 | Старая (зачёркнутая) цена | только при скидке | +| 5 | Валюта | BYN (`og:product:price:currency`) | +| 6 | Степпер количества | `мин.` + `шт.`, `name=quantity` | +| 7 | Кнопка «Купить» | добавление в корзину | +| 8 | Галерея | 4 превью + основное изображение | +| 9 | Хлебные крошки | Главная › Букеты цветов › Монобукеты | +| 10 | «Поделиться» | ya-share2 | +| 11 | Таб «Обзор» | единственный таб | +| 12 | Описание | свободный текст (SEO-заготовка) | +| 13 | «Просмотренные товары» | блок истории просмотра | + +**Чего нет как структурированных данных (главный разрыв):** размеры/варианты, состав букета, +количество стеблей, высота/габариты, уход, срок доставки, наличие/остаток, допы, отзывы и рейтинг. +Состав и количество цветов спрятаны внутри названия («Белая ромашка, примерно 51 цветочек»). + +## 4. Корзина и оформление + +Оформление **одностраничное** — `/order/`, секции: `Корзина → Оформление → Покупатель → Доставка → Оплата`. + +1. **Корзина:** строки, степпер `мин./шт.`, цена за единицу и за строку, «Удалить» / «Удалить все товары», промокод (`coupon_code` + «Активировать»), «Итого». +2. **Покупатель:** `firstname`, `phone`, `email`, **`nomer_skidochnoy_karty`** (номер скидочной карты — лояльность), `data_i_vremya_dostavki` (дата и время доставки). +3. **Доставка:** страна/регион/город предзаполнены и заблокированы (Беларусь / Минск). Типы: «Доставка курьером» (Бесплатно · Сегодня) и «Самовывоз из магазинов» (Бесплатно · Сегодня). Карточки вариантов доставки с выбором дня/интервала. Адрес: имя получателя, телефон получателя, улица, **`tekst-na-otkryt`** (текст для открытки), комментарий к заказу. Итоги: товары / доставка / итого. +4. **Оплата:** «Наличные при получении» и «Оплата картой онлайн (РБ, РФ, Мир)» — Visa, MasterCard, МИР, Google Pay, Yandex Pay, Apple Pay, ЕРИП. + +**Пробелы:** нет явной опции «анонимный подарок» (только текст открытки), логика бесплатной доставки в копирайте противоречива (50 / 80 / 100 BYN в разных местах). + +## 5. Информационные страницы + +| URL | О чём | +|---|---| +| `/company/` | О компании: с 2018, 5 точек самовывоза, импорт из 7 стран, бонусная система, B2B, заказ 24/7 | +| `/company/b2b/` | Корпоративным: подарки сотрудникам/партнёрам, брендирование, оформление офиса, доставка за 1 час, безнал, счёт, скидка 10% | +| `/dostavka/` | Доставка по Минску: бесплатно от 100 BYN, иначе 15 BYN; за МКАД +0.50 BYN/км; срок до 2 часов; самовывоз Притыцкого 10, 09:00–21:00 | +| `/dostavka/oplata/` | Оплата: курьеру/в магазине, карта онлайн (WebPay, ЕРИП, Альфа-Банк), VISA/MasterCard/BELCART, Apple/Samsung Pay, безнал для юрлиц | +| `/dostavka/zakaz/` | Как заказать: телефон/почта/корзина, круглосуточный приём, «Подтвердить заказ» → «Оплатить заказ» | +| `/vozvrat/` | Возврат: живые цветы возврату не подлежат; претензии только в момент передачи; возврат на исходный способ оплаты, карта до 30 дней | +| `/contacts/` | ООО «Диапазон Плюс», УНП 190438401, Притыцкого 10 пом. 1Н; 2 телефона; 09:00–21:00, праздники до 23:00 | +| `/contacts/vakansii/` | Вакансии: менеджер по работе с клиентами, флорист; 2/2, метро Пушкинская | +| `/company/politika-konfidentsialnosti/` | Политика обработки персональных данных | + +FAQ, блог, новостей и отдельной страницы «доставка за МКАД» — нет. + +## 6. Коммерческие факты (для констант сайта) + +- **Телефоны:** +375 (29) 657-30-00, +375 (33) 657-30-00 · **E-mail:** info@La-rose.by +- **Часы:** ежедневно 09:00–21:00, праздники до 23:00; приём заказов онлайн — 24/7 +- **Адрес:** г. Минск, ул. Притыцкого, 10, пом. 1Н (самовывоз, метро Пушкинская) +- **География:** Минск и Минская область; за МКАД +0.50 BYN/км +- **Срок доставки:** до 2 часов (B2B — приоритет 1 час) +- **Валюта:** BYN · **Доставка:** бесплатно от 100 BYN, иначе 15 BYN +- **Оплата:** наличные курьеру/в магазине, карта онлайн (Visa, MasterCard, БЕЛКАРТ, МИР; Google/Yandex/Apple/Samsung Pay; ЕРИП), безнал для юрлиц +- **Гарантии:** импорт 2 раза в неделю, свой курьер, претензии по качеству — при передаче + +## 7. Дополнительные возможности и интеграции + +- Поиск по каталогу (`/search/?query=`), аккаунт Webasyst (`/login/`, `/signup/`, `/my/`) — **не выведен в шапку/футер**. +- Избранное и сравнение: компоненты темы есть, отдельной страницы в sitemap нет. +- Лояльность: скидочная карта, промокоды, «Общая скидка», бонусная система, 10% корпоративным. +- Отзывы/рейтинг: сортировка «Оценка покупателей» есть, сами отзывы на PDP не рендерятся. +- Каналы: WhatsApp `wa.me/375296573000`, Telegram-бот `t.me/bot_a_nik_vsop`, VK `vk.com/La_Rose_by`, Instagram `instagram.com/larose_by`, онлайн-чат **Bitrix24**. +- Аналитика: Yandex Metrika (72956191, webvisor + ecommerce), GA4/GTM (G-GNXX0B3PD5, G-4SN20SG8SP, AW-837118909, GTM-W8NK6WWQ), Meta Pixel 128304465805329, Mail.ru top. + +## 8. Технические факты + +- Платформа: **Webasyst Shop-Script** (`/wa-data/public/shop/…`, `/webasyst/` отвечает 200, `sitemap-shop.xml` сгенерирован Webasyst). +- Тема: `free1`. `` отсутствует. +- `robots.txt`: 38 запретов, включая `/my/`, `/checkout/`, `/search/`, `/order/`, `/login/`, `/cart/`, все query-string (`/*?*`), `/webasyst/`. +- `sitemap-shop.xml` не перечисляет все товары: страницы `/product//` всплывают только из листингов. + +## 9. Что это значит для переделки + +| Разрыв | Решение (в `docs/PLAN.md`) | +|---|---| +| Поля товара не структурированы | Ввести контракт PDP: состав, количество стеблей, высота, размер/вариант, уход, наличие, срок доставки | +| Нет фасетных фильтров | Фасеты: повод, цвет, тип цветка, размер, цена + сортировки как сейчас | +| Аккаунт спрятан | Вывести вход/кабинет в шапку, добавить историю заказов и повтор заказа | +| Противоречивые условия доставки | Один источник констант: порог бесплатной доставки, за МКАД, срок, часы | +| Нет FAQ/блога | Добавить FAQ на страницы доставки/оплаты (низкая стоимость, высокий SEO-эффект) | +| SEO-слаги и числовые ID | Сохранить существующие слаги 1:1, для `/product//` подготовить 301-карту | +| Аналитика и чат | Решить судьбу Bitrix24, сохранить паритет по Метрике/GA4/Pixel | + +## 10. Дополнение от 2026-10-04 — полный инвентарь каталога и чек-аут + +Аудит дособран: полный дедуплицированный инвентарь (94 товара, 11 категорий, цены, старые цены, +бейджи, кросс-листинг), 3 дополнительных образца PDP, точные поля и способы оформления/оплаты, +константы. Полные таблицы и оговорки — в приложении [`docs/CATALOG.md`](CATALOG.md). + +Новые/уточнённые факты: + +- **Каталог:** 256 слотов в листингах → **94 уникальных товара**; размер страницы фиксирован (28), + селектор «Показывать по» не активен; бейджи ХИТ! × 24, NEW! × 13, СКИДКА! × 5. +- **Скрытые категории:** `/category/bukety-iz-roz/` (22 товара, только прямой URL и крошки); + «Гортензии» и «Тюльпаны» — HTTP 200, но 0 товаров. Дополнительно видны `/category/rozy-po-tsvetu/` + и `/category/krasnye-rozy/` (крошки PDP). +- **Битая ссылка:** карточка `/product/1997/` в листинге ведёт на **HTTP 404**. +- **PDP:** структурированных полей нет ни у одного образца; у части товаров есть варианты + («15/19/25 роз» → 198/240/325 BYN) с одной характеристикой «Кому дарим цветы». +- **Бесплатная доставка:** копирайт противоречив (50 / 80 / 100 BYN), а фактически в корзине + настроен **один бесплатный вариант** доставки по Минску без порога; тариф 15 BYN и «+0.50 BYN/км» + в корзине недостижимы (город заблокирован как Минск). +- **Оформление:** гостевой чекаут возможен; промокод `coupon_code` с ошибкой «Купон недействителен»; + поля получателя включают `tekst-na-otkryt` (текст открытки) и `nomer_skidochnoy_karty`. +- **Оплата:** «Наличные» и «Оплата картой онлайн» (плагин `begateway`; Visa/MasterCard/МИР, + Google/Yandex/Apple Pay, ЕРИП). +- **Не проверено:** отправка заказа и редирект оплаты, валидный промокод, тариф за МКАД. diff --git a/docs/CATALOG.md b/docs/CATALOG.md new file mode 100644 index 0000000..9d6e786 --- /dev/null +++ b/docs/CATALOG.md @@ -0,0 +1,265 @@ +# Каталог la-rose.by — полный инвентарь (приложение к аудиту) + +**Источник:** https://la-rose.by/ · **Дата сбора:** 2026-10-04 · **Метод:** обход живого сайта +(HTML + headless-браузер, карточки `div.Product-grid`, пагинация `?page=`). +**Статус документа:** факты «как есть». Сводный анализ — [`docs/ANALYSIS.md`](ANALYSIS.md), +плановые решения — [`docs/PLAN.md`](PLAN.md). + +> Примечание: у части карточек название в листинге может быть сокращено или отличаться от `

` +> на странице товара — сверить при наполнении. Данные волатильны (цены/акции на дату сбора). + +## 1. Категории — коды и объёмы + +| Код | Категория | URL | Страниц | Товаров в листинге | Уникальных | +|---|---|---|---|---|---| +| BC | Букеты цветов | `/category/bukety-tsvetov/` | 4 (28+28+28+8) | 92 | 92 | +| SB | Букеты сборные | `/category/sbornye-bukety/` | 2 (28+8) | 36 | 36 | +| AL | Букеты с альстромерией | `/category/bukety-iz-alstromerii/` | 1 | 15 | 15 | +| GV | Букеты с гвоздикой | `/category/bukety-iz-gvozdiki/` | 1 | 16 | 16 | +| KR | Букеты с кустовой розой | `/category/bukety-iz-kustovoy-rozy/` | 1 | 20 | 20 | +| HZ | Букеты с хризантемами | `/category/bukety-iz-khrizantemy/` | 2 (28+9) | 37 | 37 | +| SV | Свадебные букеты невесты | `/category/svadebnye-bukety-nevesty/` | 1 | 3 | 3 | +| MB | Монобукеты | `/category/monobuket/` | 1 | 23 | 23 | +| KZ | Цветочные композиции | `/category/kompozitsii/` | 1 | 7 | 7 | +| YS | Цветы в ящике | `/category/tsvety-v-yashchike/` | 1 | 1 | 1 | +| YK | Цветы в корзине | `/category/tsvety-v-korzine/` | 1 | 6 | 6 | +| | **Итого слотов / уникальных** | | | **256** | **94** | + +- Размер страницы фиксирован — 28; селектор «Показывать по» есть в разметке + (`select.cat-onpage_select`), но **не активен**. +- **Кросс-листинг массовый** (256 слотов → 94 товара): товар попадает до 6 категорий + (например, «Грезы»). +- Бейджи: `ХИТ!` × 24, `NEW!` × 13, `СКИДКА!` × 5. + +## 2. Скрытые и пустые категории + +| Категория | HTTP | Товаров | Доступность | +|---|---|---|---| +| `/category/bukety-iz-roz/` (Розы) | 200 | 22 (все — дубли видимых категорий) | по прямому URL и из хлебных крошек розовых PDP; **нет в меню** | +| `/category/bukety-iz-gortenziy/` (Гортензии) | 200 | 0 | только по SEO-ссылке в тексте; пустая выдача | +| `/category/bukety-s-tyulpanami/` (Тюльпаны) | 200 | 0 | только по SEO-ссылке в тексте; пустая выдача | + +Дополнительная скрытая таксономия (видна в хлебных крошках PDP, нет в меню): +`/category/rozy-po-tsvetu/` (Розы по цвету), `/category/krasnye-rozy/` (Красные розы). + +## 3. Полная таблица товаров (94, дедуплицировано) + +| # | Название | Slug / URL | Цена BYN | Старая BYN | Бейдж | Категории | +|---|---|---|---|---|---|---| +| 1 | «Летний» | `/product/buket-nostalgiya/` | 71 | 161 | ХИТ! | BC, HZ, MB | +| 2 | Корзина с кустовой розой «Золушка» | `/product/korzina-tsvetov-zolushka/` | 257 | 351 | ХИТ! | BC, KR, YK | +| 3 | Корзина с розой и гвоздикой «Диадема» | `/product/korzina-tsvetov-diadema/` | 174 | 197 | NEW! | BC, SB, KZ, YK | +| 4 | Композиция «Совершенство» | `/product/sovershenstvo/` | 125 | 140 | — | BC, SB, HZ, KZ | +| 5 | Корзина цветов «Розовая пантера» | `/product/275/` | 135 | 150 | — | BC, KR, YK | +| 6 | Сухоцветы гипсофила и лаванда | `/product/buket-iz-gipsofily-i-lavandy/` | 105 | 127 | — | BC, SV | +| 7 | Букет из пёстрой ромашки | `/product/buket-iz-pyostroy-romashki/` | 85 | 136 | — | BC, HZ | +| 8 | Корзина «Нежность» | `/product/korzina-nezhnost/` | 320 | 370 | — | BC, GV, HZ, YK | +| 9 | Свадебный букет из красной розы на роспись | `/product/svadebnyy-buket-na-rospis/` | 215 | — | — | BC, SV | +| 10 | Свадебный букет на роспись «Люблю» | `/product/svadebnyy-buket-na-rospis-lyublyu/` | 210 | — | — | BC, SV | +| 11 | Букет из 15 гвоздик и эвкалипта | `/product/buket-iz-15-gvozdik-i-evkalipta/` | 135 | 150 | ХИТ! | BC, GV, MB | +| 12 | Композиция из чёрных роз (Эквадор) | `/product/buket-iz-chernykh-roz-ekvador/` | 765 | — | NEW! | BC | +| 13 | Букет из синих роз | `/product/nezabyvaemyy-buket-iz-sinikh-roz/` | 150 | 165 | NEW! | BC, MB | +| 14 | Нежный букет с розой и альстромерией | `/product/nezhnyy-buket-iz-rozy-s-alstromeriey/` | 183 | 197 | — | BC, SB, AL | +| 15 | Букет из красных роз с эвкалиптом | `/product/buket-iz-krasnykh-roz-s-evkaliptom/` | 198 | 295 | ХИТ! | BC, MB | +| 16 | Букет красных роз Кения | `/product/1553/` | 165 | 187 | — | BC | +| 17 | Букет из французской розы | `/product/1565/` | 150 | 250 | СКИДКА! | BC, MB | +| 18 | Безмятежное счастье | `/product/buket-bezmyatezhnoe-schaste/` | 125 | 130 | ХИТ! | BC, SB, AL, GV | +| 19 | Нежный букет с хризантемой и диантусом | `/product/nezhnyy-buket-s-khrizantemoy-i-diantusom/` | 162 | 177 | ХИТ! | BC, SB, AL, GV, HZ | +| 20 | Букет 15 белых роз | `/product/buket-15-belykh-roz-1/` | 196 | — | ХИТ! | BC, MB | +| 21 | «Элегантность в простоте» | `/product/buket-elegantnost-v-prostote/` | 104 | 189 | ХИТ! | BC, SB, KR, HZ | +| 22 | Букет «Нежность» | `/product/buket-nezhnost-v-lepestkakh/` | 157 | 164 | NEW! | BC, SB, GV, KR, HZ | +| 23 | Букет «Сахарная вата» | `/product/buket-sakharnaya-vata/` | 73 | 99 | — | BC, GV | +| 24 | Сборный букет «Вспышка» | `/product/sbornyy-buket-vspyshka/` | 183 | 212 | — | BC, SB, GV, KR | +| 25 | Букет «Небесная симфония» | `/product/1814/` | 117 | 138 | — | BC, HZ, MB | +| 26 | Букет «Зефирная нежность» | `/product/buket-zefirnaya-nezhnost/` | 98 | 156 | — | BC, KR, MB | +| 27 | Композиция в корзине | `/product/kompozitsiya-v-korzine/` | 154 | 186 | — | BC, KR, MB, KZ, YK | +| 28 | Разрешите подарить вам радугу | `/product/razreshite-podarit-vam-radugu/` | 154 | 237 | ХИТ! | BC, HZ, MB | +| 29 | Романтика в воздухе | `/product/romantika-v-vozdukhe/` | 190 | 203 | — | BC, SB, KR, HZ | +| 30 | Весеннее настроение | `/product/vesennee-nastroenie/` | 148 | 187 | — | BC, SB, GV, KR, HZ | +| 31 | Роза кустовая Рефлекс | `/product/roza-kustovaya-pionovidnaya/` | 292 | 315 | — | BC, MB | +| 32 | Летний ветер | `/product/letniy-veter/` | 65 | 115 | — | BC, HZ, MB | +| 33 | Букет из 15 роз | `/product/buket-iz-15-roz-fridom/` | 142 | 175 | — | BC, MB | +| 34 | Обнимая ароматом | `/product/obnimaya-aromatom/` | 163 | 178 | — | BC, SB | +| 35 | Грезы | `/product/grezy/` | 141 | 168 | — | BC, SB, AL, GV, KR, HZ | +| 36 | Для Самой Любимой | `/product/dlya-samoy-lyubimoy/` | 207 | 298 | СКИДКА! | BC, SB, KR, HZ | +| 37 | Хризантема с ромашкой | `/product/khrizantema-s-romashkoy/` | 115 | 145 | NEW! | BC, HZ | +| 38 | Для тебя | `/product/dlya-tebya/` | 125 | 137 | — | BC, MB | +| 39 | Букет из нежной хризантемы и гипсофилы | `/product/buket-iz-nezhnoy-khrizantemy-i-gipsofily/` | 117 | 230 | ХИТ! | BC, SB, HZ, MB | +| 40 | Очарование | `/product/ocharovanie-1/` | 187 | 193 | — | BC, SB, AL, GV | +| 41 | Композиция в рамке | `/product/kompozitsiya-v-ramke/` | 91 | 104 | — | BC, KZ | +| 42 | Солнечный ангел | `/product/solnechnyy-angel/` | 153 | 193 | — | BC, SB, AL, GV | +| 43 | Цветы в шляпной коробке | `/product/tsvety-v-shlyapnoy-korobke-2/` | 117 | 125 | — | KZ | +| 44 | Тёплые объятия | `/product/teplye/` | 372 | 374 | — | BC, SB, AL | +| 45 | Букет «Для Самой Любимой» из хризантем | `/product/mamina-nezhnot/` | 143 | 210 | ХИТ! | BC, SB, HZ | +| 46 | Розовая хризантема Ромашка | `/product/rozovaya-khrizantema-romashka/` | 65 | 115 | ХИТ! | BC, HZ, MB | +| 47 | Белая ромашка, примерно 51 цветочек | `/product/belaya-romashka-primerno-51-tsvetochek/` | 55 | 137 | — | BC, HZ, MB | +| 48 | Голубая ромашка с гипсофилой | `/product/golubaya-romashka-s-gipsofiloy/` | 98 | 167 | ХИТ! | BC, HZ, MB | +| 49 | Кустовая роза Рефлекс с альстромерией | `/product/kustovaya-roza-refleks-s-alstromeriey/` | 134 | 187 | — | BC, AL, KR | +| 50 | Нежный поцелуй | `/product/nezhnyy-potseluy-1/` | 98 | 167 | — | BC, AL | +| 51 | Вдохновение природы | `/product/vdokhnovenie-prirody/` | 169 | 245 | — | BC, HZ, MB | +| 52 | Букет из кустовой розы и кустовой хризантемы | `/product/1982/` | 153 | 197 | — | BC, SB, HZ | +| 53 | Нежно-розовый букет из дуэта хризантем | `/product/nezhno-rozovyy-buket-iz-dueta-khrizantem/` | 155 | 245 | — | BC, SB, HZ | +| 54 | Зефирное облако нежных хризантем | `/product/zefirnoe-oblako-nezhnykh-khrizantem/` | 169 | 244 | NEW! | BC, HZ | +| 55 | Нежный букет для самой любимой | `/product/nezhnyy-buket-dlya-samoy-lyubimoy/` | 179 | 218 | NEW! | BC, SB, AL, KR, HZ | +| 56 | Букет в сиренево-розовых тонах | `/product/buket-v-sirenevo-rozovykh-tonakh-iz-khrizantemy-rozy-i-diantusa/` | 115 | 167 | — | BC | +| 57 | Нежный букет из кустовой и французской розы | `/product/1993/` | 113 | 137 | NEW! | BC, KR | +| 58 | ~51 небесно-голубая ромашка | `/product/51-nebesno-golubaya-romashka/` | 59 | 115 | — | BC, HZ | +| 59 | Букет «Небесная симфония» из пушистой хризантемы | `/product/1997/` ⚠️ **404** | 82 | 115 | — | BC, HZ, MB | +| 60 | Ящик деревянный с хризантемой «Радужный» | `/product/yashchik-derevyannyy-s-khrizantemoy-raduzhnyy/` | 124 | 139 | — | BC, HZ, KZ, YS | +| 61 | Композиция в ящике «Мечтаю о тебе» | `/product/kompozitsiya-v-yashchike-mechtayu-o-tebe/` | 89 | 127 | ХИТ! | BC | +| 62 | Нежно-бирюзовая ромашка | `/product/nezhno-biryuzovaya-romashka/` | 65 | 115 | ХИТ! | BC, HZ, MB | +| 63 | Букет из диантусов | `/product/2003/` | 117 | 157 | — | BC, SB, GV | +| 64 | Букет «Приятные моменты» | `/product/buket-priyatnye-momenty-iz-kustovoy-rozy-khrizantemy-i-alstromerii/` | 135 | 149 | — | BC, SB, AL, KR, HZ | +| 65 | Букет из хризантемы и кустовой розы Рефлекс | `/product/2008/` | 107 | 193 | СКИДКА! | BC, SB, KR, HZ | +| 66 | Букет из кустовой и французской розы с альстромерией | `/product/2009/` | 117 | 183 | СКИДКА! | BC, SB, AL, KR | +| 67 | Букет из голубой хризантемы и розы «Рефлекс» | `/product/buket-iz-goluboy-khrizantemy-i-rozy-refleks/` | 98 | — | — | BC | +| 68 | Нежный букет из французской розы и эвкалипта | `/product/nezhnyy-buket-iz-frantsuzskoy-rozy-i-evkalipta/` | 63 | 98 | ХИТ! | BC, SB, MB | +| 69 | Букет «Алые паруса» из 11 красных роз | `/product/buket-alye-parusa-iz-11-krasnykh-roz-s-limoniumom-i-evkaliptom/` | 146 | 193 | ХИТ! | BC, SB, MB | +| 70 | Букет из альстромерии, роз, хризантемы и эустомы | `/product/2028/` | 167 | 189 | NEW! | BC, SB | +| 71 | 3 веточки розовой хризантемы | `/product/2033/` | 43 | 65 | ХИТ! | BC, HZ | +| 72 | Букетик сухоцвет лаванды | `/product/buketik-sukhotsvet-lavandy/` | 43 | 57 | — | BC | +| 73 | Воздушный объёмный букет с розами | `/product/vozdushnyy-obyomnyy-buket-s-frantsuzskoy-i-kustovoy-rozami/` | 179 | — | — | BC, SB, KR, HZ | +| 74 | Сборный ароматный букет с лилией и розой | `/product/sbornyy-aromatnyy-buket-s-liliey-i-rozoy/` | 194 | — | — | BC, SB, KR | +| 75 | Букет из французских и кустовых роз | `/product/2048/` | 119 | 137 | — | BC, SB | +| 76 | Букет с зеркалом «Ты — Моё Всё» | `/product/2050/` | 154 | 186 | NEW! | BC, SB, GV, KZ | +| 77 | Букет из диантусов с лизиантусами | `/product/2051/` | 183 | 275 | NEW! | BC, SB, GV | +| 78 | Букет из альстромерии и диантусов | `/product/2052/` | 117 | 143 | NEW! | BC, SB, AL, GV | +| 79 | Букет из альстромерии и диантусов с лагурусом | `/product/2053/` | 129 | 161 | NEW! | BC, SB, AL, GV | +| 80 | Букет «Для моей Принцессы» | `/product/2054/` | 157 | 198 | — | BC, SB, HZ | +| 81 | Букет из французской и кустовой розы, эустомы | `/product/buket-iz-frantsuzskoy-rozy-kustovoy-rozy-eustomy/` | 125 | 153 | — | BC | +| 82 | Букет из розовых хризантем микс | `/product/buket-iz-rozovykh-khrizantem-miks/` | 51 | 63 | — | BC | +| 83 | Букет из кустовой розы, альстромерии и гипсофилы | `/product/buket-iz-kustovoy-rozy-alstromerii-i-gipsofila/` | 126 | 158 | — | BC | +| 84 | Букет из малиновой розы | `/product/buket-iz-malinovoy-rozy/` | 107 | 137 | — | BC | +| 85 | Корзина «Мамино Сердце» | `/product/2068/` | 537 | — | — | YK | +| 86 | Сиренево-белый букет из хризантемы Алтай | `/product/2069/` | 83 | 105 | — | BC, HZ | +| 87 | Сборный микс альстромерий | `/product/2070/` | 81 | 127 | — | BC, AL | +| 88 | Букет из хризантемы Алтай и лимониума | `/product/2071/` | 98 | 168 | — | BC, HZ | +| 89 | Букет нежный из кустовой хризантемы и лимониума | `/product/2072/` | 119 | 184 | — | BC, HZ | +| 90 | Букет из красной французской розы с эвкалиптом | `/product/2073/` | 93 | 173 | — | BC | +| 91 | Букет из красных роз и эустомы | `/product/2074/` | 157 | 210 | — | BC | +| 92 | Букет из французской розы, эустомы и кустовой розы | `/product/2075/` | 123 | 169 | — | BC | +| 93 | Нежный светлый букет с розой и хризантемой | `/product/2076/` | 144 | 193 | — | BC, KR | +| 94 | Букет из французской розовой розы и эвкалипта | `/product/2077/` | 98 | 132 | — | BC | + +⚠️ Строка 59 (`/product/1997/`) — **битая ссылка в листинге**: href ведёт на HTTP 404 +(у темы нет слага, fallback на числовой ID не резолвится). Остальные числовые ID — HTTP 200. + +## 4. Карточка товара (PDP) — реальный набор полей, 3 дополнительных образца + +Базовый образец (`/product/buket-iz-15-roz-fridom/`, id 1860, «Букет из 15 роз», 142/175 BYN, без бейджа, BC+MB). + +| Поле | A. Роза `/product/buket-iz-krasnykh-roz-s-evkaliptom/` | B. Хризантема `/product/buket-iz-nezhnoy-khrizantemy-i-gipsofily/` | C. Композиция/коробка `/product/tsvety-v-shlyapnoy-korobke-2/` | +|---|---|---|---| +| h1 | Букет из красных роз с эвкалиптом | Букет из нежной хризантемы и гипсофилы | Цветы в шляпной коробке | +| Бейдж | ХИТ! | ХИТ! | нет | +| Цена | 198 BYN | 117 BYN | 117 BYN | +| Старая цена | 295 BYN | 230 BYN | 125 BYN | +| Валюта | BYN | BYN | BYN | +| Степпер `input[name=quantity]` | value 1; **нет `min`/`max`/`step`** | value 1; нет min/max/step | value 1; нет min/max/step | +| Изображений в галерее | 1 | 4 | 3 | +| Хлебные крошки | Букеты цветов › Розы › Розы по цвету › Красные розы | Букеты цветов | Цветочные композиции | +| Описание | свободный SEO-блок, 614 симв., без короткого текста | короткий текст 191 симв. + «Подробное описание» + SEO 613 симв. | свободный SEO-блок, 582 симв. | +| Структурированные поля | нет | нет | нет | +| Табы | «Обзор» / «Характеристики»: **одна** характеристика «Кому дарим цветы» + варианты **15/19/25 роз → 198/240/325 BYN** | только «Кому дарим цветы»; вариантов нет | нет | +| Состав | нет | нет | нет | +| Количество стеблей | нет (только в метках вариантов «N роз») | нет | нет | +| Высота / размеры | нет | нет | нет | +| Уход | нет | нет | нет | +| Наличие / остаток | не показывается | не показывается | не показывается | +| Срок доставки | не показывается (только текст «от 80 руб») | не показывается | не показывается | +| «Просмотренные товары» | нет (первый в сессии) | да | да | + +**Пробелы:** состав, количество стеблей, высота/габариты, уход, наличие/остаток и срок доставки +не выводятся как структурированные данные; состав и число цветов спрятаны в названии +(«Белая ромашка, примерно 51 цветочек»). Варианты («N роз») есть только у части товаров и меняют цену. + +## 5. Корзина / оформление / оплата + +Оформление одностраничное — `/order/` (секции «Корзина → Оформление → Покупатель → Доставка → Оплата»). +Добавление в корзину: `POST /cart/add/` (JSON: `product_id`, `quantity`). + +**Промокод:** поле `input[name=coupon_code]` + кнопка «Активировать» (AJAX). Неверный код → ошибка +«Купон недействителен»; при успехе появляется «Отменить». Валидный код и размер скидки получить не удалось. + +**Порог бесплатной доставки — противоречие подтверждено:** + +| Источник | Утверждение | +|---|---| +| `/dostavka/` | бесплатно от 100 BYN, иначе 15 BYN; за МКАД 15 BYN + 0.50 BYN/км; срок до 2 ч | +| meta `/dostavka/` | бесплатная доставка при заказе от 100 BYN | +| копирайт `/category/bukety-tsvetov/` | бесплатно от 50 руб | +| meta `/category/bukety-tsvetov/` | бесплатно от 100 BYN | +| копирайт `/category/monobuket/` | бесплатно от 80 руб | +| meta `/category/monobuket/` | бесплатно от 100 BYN | +| текст PDP | бесплатно от 80 руб | +| **фактическая конфигурация (проверено)** | курьер «Бесплатно» при корзине 43 BYN и 117 BYN — минимума нет; доступен **один** вариант доставки `8.delivery` «Доставка цветов по Минску», Бесплатно; тариф 15 BYN в корзине недостижим | + +**Типы доставки:** + +| Тип | id | Цена | Дата | Варианты | +|---|---|---|---|---| +| Доставка курьером | `todoor` | Бесплатно | Сегодня | `8.delivery` «Доставка цветов по Минску», Бесплатно (`variants_count: 1`) | +| Самовывоз из магазинов | `pickup` | Бесплатно | Завтра | — | + +Слота времени нет: дата/время — свободное текстовое поле `auth[data][data_i_vremya_dostavki]` + +вычисляемая строка «Срок доставки». Адрес — через адаптер Yandex Maps (`possible_addresses: []`). + +**Поля формы (точные `name`):** + +| Секция | Поле | name | Обяз. | +|---|---|---|---| +| Покупатель | Имя | `auth[data][firstname]` | да | +| Покупатель | Телефон | `auth[data][phone]` | да | +| Покупатель | Email | `auth[data][email]` | нет | +| Покупатель | Номер скидочной карты | `auth[data][nomer_skidochnoy_karty]` | нет | +| Доставка | Дата и время доставки | `auth[data][data_i_vremya_dostavki]` | нет | +| Доставка | Страна / регион / город (заблокированы) | `region[country]=blr`, `region[region]=07`, `region[city]=Минск` | — | +| Доставка | Тип | `shipping[type_id]` (`todoor`/`pickup`) | — | +| Доставка | Вариант | `shipping[variant_id]` (`8.delivery`) | — | +| Получатель | Имя получателя | `details[shipping_address][imya-poluchatel]` | нет | +| Получатель | Телефон получателя | `details[shipping_address][telefon-polucha]` | нет | +| Получатель | Адрес доставки | `details[shipping_address][street]` | да | +| Получатель | Текст на открытке | `details[shipping_address][tekst-na-otkryt]` | нет | +| Комментарий | Комментарий к заказу | `confirm[comment]` | нет | +| Hidden | Пользователь / локация | `auth[user_id]`, `region[location_id]` | — | + +**Оплата (точный список):** + +| value | Способ | Описание | Плагин | +|---|---|---|---| +| `1` | Наличные | «Оплата наличными при получении» | `cash` | +| `29` | Оплата картой онлайн (РБ, РФ, Мир) | Visa, MasterCard, МИР, Google Pay, Yandex Pay, Apple Pay, ЕРИП | `begateway` | + +**Гостевой чекаут:** да — форма `/order/` открывается для анонимной сессии без логина (только +скрытый `auth[user_id]`; имя + телефон обязательны). Реальную отправку заказа выполнить не удалось. + +## 6. Контакты и константы (проверено) + +| Параметр | Значение | +|---|---| +| Телефон 1 | +375 (29) 657-30-00 (`tel:+375296573000`) | +| Телефон 2 | +375 (33) 657-30-00 (`tel:+375336573000`) | +| E-mail | info@La-rose.by (встречается info@la-rose.by) | +| WhatsApp | https://wa.me/375296573000 | +| Telegram | https://t.me/bot_a_nik_vsop | +| VK | https://vk.com/La_Rose_by | +| Instagram | https://www.instagram.com/larose_by/ | +| Часы | ежедневно 09:00–21:00; праздники/предпраздничные до 23:00; онлайн-заказы 24/7 | +| Салон (самовывоз) | г. Минск, ул. Притыцкого, 10, пом. 1Н (53.911005, 27.501101) | +| Юрлицо | ООО «Диапазон Плюс», УНП 190438401; 220073, Минск, ул. Притыцкого, 10, пом. 1Н | +| Торговый реестр | № 556600; свид. 19043840 от 18.02.2019 | +| География | Минск (Беларусь); «за МКАД» упоминается в текстах, но в корзине не настраивается | +| Аналитика | GA4 `G-GNXX0B3PD5`, `G-4SN20SG8SP`, `GTM-W8NK6WWQ`, `AW-837118909`; FB Pixel `128304465805329`; Яндекс.Метрика `72956191`; Mail.ru `3238855`; чат Bitrix24 | + +## 7. Что не проверено / оговорки + +- Отправка заказа и редиректы оплаты не выполнялись (нет реальных контактов/платежа) — проверена + только структура и валидация формы. +- Валидный промокод и размер скидки не получены. +- Тариф за МКАД / вне Минска не воспроизводится: город заблокирован как Минск, доступен один + бесплатный вариант доставки. +- `/product/1997/` возвращает 404, хотя это href карточки в листинге. +- Скрытые категории «Гортензии» и «Тюльпаны» отдают HTTP 200, но 0 товаров. +- Извлечение опирается на разметку `div.Product-grid`: товар, доступный только по прямому URL + и скрытый из всех листингов, в инвентарь не попал бы. Дедуплицированный итог — 94, совпадает с ожиданием. +- Цены и акции волатильны (дата сбора — 2026-10-04). diff --git a/docs/PLAN.md b/docs/PLAN.md new file mode 100644 index 0000000..1a4fa0d --- /dev/null +++ b/docs/PLAN.md @@ -0,0 +1,378 @@ +# La Rose — план переделки сайта (`docs/PLAN.md`) + +**Проект:** `SemianiakaVY/la-rose` · **Шаблон:** `online-shop` · **Стек:** Next.js +**Источники:** [`SPEC.md`](../SPEC.md) (контракт), [`docs/ANALYSIS.md`](ANALYSIS.md) (факты об +источнике), [`docs/CATALOG.md`](CATALOG.md) (полный инвентарь каталога). +**Дата:** 2026-10-04. + +## 0. Этап и рамки + +Текущий этап — **исследование, структура, схемы и карточки задач**. На этом этапе: + +- **Нового дизайна НЕ делаем** (решение зафиксировано в `.w4c/project.json`) — отдельная + дизайн-спецификация не выпускается; UI следует структуре источника и токенам, выбранным на + слое фронтенда. +- **Реальные платежи не подключаем** — провайдер за интерфейсом, реализация `mock`. +- Код приложения на этом этапе не пишется: результатом этапа являются этот план, mermaid-схемы + и карточки задач на доске. + +## 1. Цель продукта + +Интернет-магазин доставки цветов и подарков по Минску (переделка `la-rose.by`): каталог с +категориями и фасетными фильтрами, карточка товара со структурированными полями, корзина и +одностраничное оформление, личный кабинет с историей заказов и закрытая админ-панель. +Продукт должен **работать end-to-end на сид-данных** (SPEC.md §1), UI — русский. + +## 2. Зафиксированные решения + +| # | Решение | Значение | +|---|---|---| +| R1 | Стек | **Next.js** (App Router, TypeScript) — из диалога создания проекта | +| R2 | Деньги | Только целые минорные единицы (`priceMinor`, копейки); никаких float | +| R3 | Форматирование чисел | `Intl.NumberFormat` / `toLocaleString('en-US')` с кодом валюты (SPEC.md §4) | +| R4 | Валюта | Целевая валюта магазина — **BYN**; в настройках шаблона доступны только USD/EUR/RUB, поэтому работаем через одну константу `STORE_CURRENCY` (интерим `RUB`). Переключение на BYN — правка одной константы; курсовой пересчёт в рамки не входит, цены сидов берём из аудита как есть | +| R5 | Платежи | Провайдер за одним интерфейсом `PaymentProvider`; при `None (mock)` — мок-адаптер, flow работает без ключей (SPEC.md §6) | +| R6 | Оформление | Оформление — **одностраничное** `/checkout`, как у источника (`/order/`): корзина → покупатель → доставка → оплата. Аккаунт: по SPEC.md §2 чекаут требует аккаунта, у источника гостевой чекаут возможен — берём SPEC как контракт (чекаут после входа), гостю показываем логин с сохранением корзины | +| R7 | Доставка | **Один источник констант** (`lib/delivery/constants.ts`): порог бесплатной доставки, тариф, за МКАД, срок, часы. Противоречие источника (50/80/100 BYN, см. ANALYSIS.md §4) снимается на одном значении | +| R8 | Фильтры | Фасеты: **повод, цвет, тип цветка, размер/диапазон цены** + сортировки как у источника (название, цена, хиты, оценка, дата, наличие) | +| R9 | PDP-контракт | Обязательные структурированные поля: состав, количество стеблей, высота/габариты, вариант/размер, уход, наличие, срок доставки (сейчас отсутствуют — ANALYSIS.md §3, CATALOG.md §4) | +| R10 | URL | Существующие человекочитаемые слаги категорий и товаров сохраняем 1:1; для товаров с числовыми `/product//` готовим **301-карту** на новые слаги (CATALOG.md §3) | +| R11 | Контент | Информационные страницы источника переносим: О компании, B2B, Доставка, Оплата, Как заказать, Возврат, Контакты, Вакансии, Политика; добавляем **FAQ** (нет у источника) | +| R12 | Аналитика и чат | Паритет по Яндекс.Метрике/GA4/FB Pixel закладываем; судьба чата Bitrix24 — открытый вопрос (см. §9) | + +## 3. Информационная архитектура (маршруты) + +### Витрина + +| Маршрут | Экран | Источник | +|---|---|---| +| `/` | Главная: hero, категории, хиты | SPEC.md §3 | +| `/catalog` | Все товары, фильтры, сортировка, пагинация | SPEC.md §3, R8 | +| `/catalog/[categorySlug]` | Товары категории (11 категорий источника + скрытые, CATALOG.md §1–2) | SPEC.md §3 | +| `/product/[slug]` | Карточка: галерея, цена/старая цена, бейдж, варианты, PDP-контракт R9, в корзину | SPEC.md §3, R9 | +| `/cart` | Строки, количество, промокод, итоги | SPEC.md §3, ANALYSIS.md §4 | +| `/checkout` | Оформление (одна страница): покупатель → доставка → оплата | SPEC.md §5.2, R6 | +| `/checkout/success/[orderId]` | Подтверждение с номером заказа | SPEC.md §3 | +| `/account/orders`, `/account/orders/[orderId]` | История и детали заказа | SPEC.md §3 | +| `/login`, `/register`, `/logout` | Аутентификация | SPEC.md §3 | +| `/search?query=` | Поиск по названию/описанию | SPEC.md §6 | +| `/pages/[slug]` | Информационные страницы (R11) | ANALYSIS.md §5 | + +### Админ (за ролью `admin`) + +| Маршрут | Экран | +|---|---| +| `/admin` | Дашборд: последние заказы, низкий остаток, выручка за период | +| `/admin/products` | Список/создание/правка/архив, изображения, цена и остаток | +| `/admin/categories` | Список/создание/правка/порядок | +| `/admin/orders`, `/admin/orders/[orderId]` | Список со статусами, детали и смена статуса | + +### Карта страниц + +```mermaid +graph TD + HOME["/ — Главная"] --> CAT["/catalog — все товары (фасеты, сортировки)"] + CAT --> C1["/catalog/bukety-tsvetov (92)"] + CAT --> C2["/catalog/sbornye-bukety (36)"] + CAT --> C3["/catalog/bukety-iz-alstromerii (15)"] + CAT --> C4["/catalog/bukety-iz-gvozdiki (16)"] + CAT --> C5["/catalog/bukety-iz-kustovoy-rozy (20)"] + CAT --> C6["/catalog/bukety-iz-khrizantemy (37)"] + CAT --> C7["/catalog/svadebnye-bukety-nevesty (3)"] + CAT --> C8["/catalog/monobuket (23)"] + CAT --> C9["/catalog/kompozitsii (7)"] + CAT --> C10["/catalog/tsvety-v-yashchike (1)"] + CAT --> C11["/catalog/tsvety-v-korzine (6)"] + C1 --> PDP["/product/[slug] — 94 товара"] + PDP --> CART["/cart — корзина + промокод"] + CART --> CHECKOUT["/checkout — одна страница"] + CHECKOUT --> OK["/checkout/success/[orderId]"] + HOME --> AUTH["/login · /register"] + AUTH --> ACC["/account/orders"] + ACC --> ORD["/account/orders/[orderId]"] + HOME --> SRC["/search?query="] + HOME --> PAGES["/pages/[slug] — о компании, доставка, оплата, как заказать, возврат, контакты, b2b, вакансии, политика, FAQ"] + HOME --> ADMIN["/admin — дашборд (роль admin)"] + ADMIN --> AP["/admin/products"] + ADMIN --> AC["/admin/categories"] + ADMIN --> AO["/admin/orders"] +``` + +## 4. Модель данных + +Расширяем модель SPEC.md §4 полями, которые требует источник (кросс-листинг, бейджи, старая цена, +варианты, промокоды, контент). Ключевые дополнения выделены. + +- **Category** — id, slug, name, description, position, parentId?, `visible` (скрытые категории + источника: розы/гортензии/тюльпаны — CATALOG.md §2). +- **Product** — id, slug, name, description, `priceMinor` (**R2**), `oldPriceMinor?` (старая цена), + `currency`, `badge` (`hit`|`new`|`sale`|null), `stock`, status (`draft`|`active`|`archived`), + createdAt, **`composition`**, **`stems?`**, **`heightCm?`**, **`care`**, **`deliveryTime`** (**R9/R11**). +- **ProductCategory** — productId, categoryId (кросс-листинг: 256 слотов → 94 товара). +- **ProductImage** — productId, url, position. +- **ProductVariant** — productId, label («15 роз»), priceMinor, stock (у источника: 15/19/25 роз → 198/240/325 BYN). +- **ProductFeature** — productId, key («Кому дарим цветы»), value[] (характеристики/фасеты, R8). +- **Cart** / **CartItem** — productId, quantity, цена всегда из продукта. +- **Customer** / **Address** — email, passwordHash, name, addresses[]. +- **Order** — number, customerId, status (`pending`|`paid`|`fulfilled`|`cancelled`), + subtotalMinor, shippingMinor, `discountMinor`, totalMinor, currency, shippingAddress (получатель, + телефон, `giftNote` = текст открытки, deliveryDate/Time), promoCodeId?, createdAt. +- **OrderItem** — orderId, productId, name, unitPriceMinor, quantity (**иммутабельный снимок**). +- **Payment** — orderId, provider, providerRef, status, amountMinor. +- **PromoCode** — code, type, value, activeFrom/To (`coupon_code` источника). +- **ContentPage** — slug, title, body (R11; FAQ — блоком или страницей). +- **DeliveryOption** — id, name (`todoor`/`pickup`), priceMinor, freeOverMinor (`R7`). + +```mermaid +erDiagram + CATEGORY { + int id PK + string slug + string name + int parentId FK + bool visible + } + PRODUCT { + int id PK + string slug + string name + int priceMinor + int oldPriceMinor + string currency + string badge + int stock + string status + string composition + int stems + int heightCm + } + PRODUCT_CATEGORY { + int productId FK + int categoryId FK + } + PRODUCT_IMAGE { + int id PK + int productId FK + string url + int position + } + PRODUCT_VARIANT { + int id PK + int productId FK + string label + int priceMinor + int stock + } + PRODUCT_FEATURE { + int id PK + int productId FK + string key + string value + } + CART { + int id PK + int customerId FK + } + CART_ITEM { + int id PK + int cartId FK + int productId FK + int quantity + } + CUSTOMER { + int id PK + string email + string passwordHash + string name + } + ADDRESS { + int id PK + int customerId FK + string street + } + ORDER { + int id PK + string number + int customerId FK + string status + int subtotalMinor + int shippingMinor + int discountMinor + int totalMinor + string currency + string giftNote + int promoCodeId FK + datetime createdAt + } + ORDER_ITEM { + int id PK + int orderId FK + int productId FK + string name + int unitPriceMinor + int quantity + } + PAYMENT { + int id PK + int orderId FK + string provider + string providerRef + string status + int amountMinor + } + PROMO_CODE { + int id PK + string code + string type + int value + } + CONTENT_PAGE { + int id PK + string slug + string title + string body + } + DELIVERY_OPTION { + string id PK + string name + int priceMinor + int freeOverMinor + } + CATEGORY ||--o{ CATEGORY : "parent of" + CATEGORY ||--o{ PRODUCT_CATEGORY : lists + PRODUCT ||--o{ PRODUCT_CATEGORY : "listed in" + PRODUCT ||--o{ PRODUCT_IMAGE : has + PRODUCT ||--o{ PRODUCT_VARIANT : has + PRODUCT ||--o{ PRODUCT_FEATURE : has + PRODUCT ||--o{ CART_ITEM : "added as" + PRODUCT ||--o{ ORDER_ITEM : "snapshot in" + CUSTOMER ||--o| CART : owns + CART ||--o{ CART_ITEM : contains + CUSTOMER ||--o{ ADDRESS : has + CUSTOMER ||--o{ ORDER : places + PROMO_CODE ||--o{ ORDER : discounts + ORDER ||--|{ ORDER_ITEM : contains + ORDER ||--o{ PAYMENT : "paid by" +``` + +## 5. Ключевые потоки + +### 5.1 Витрина: каталог → корзина + +```mermaid +flowchart LR + A["Каталог / фасеты"] --> B["Карточка товара"] + B --> C{"В наличии?"} + C -- нет --> D["Кнопка disabled + причина"] + C -- да --> E["POST /api/cart — добавить"] + E --> F["Бейдж корзины обновлён"] + F --> B +``` + +### 5.2 Чекаут и оплата + +```mermaid +sequenceDiagram + actor C as Покупатель (вошёл) + participant UI as /checkout + participant API as API + participant PAY as PaymentProvider (mock) + participant DB as БД + C->>UI: Заполняет получателя, доставку, промокод + UI->>API: POST /api/checkout (idempotency-key) + API->>DB: Ревалидация цен и остатков серверно + alt Товар распродан + API-->>UI: 409 + какой товар недоступен + else Всё доступно + API->>DB: Создать Order (status=pending) + OrderItem (снимок) + API->>PAY: charge(amountMinor) + alt Оплата успешна + PAY-->>API: succeeded, providerRef + API->>DB: Order=paid, Payment=succeeded + API-->>UI: 201 {orderNumber} + UI-->>C: /checkout/success/[orderId] + else Оплата не прошла + PAY-->>API: failed + API->>DB: Order остаётся pending + API-->>UI: 402 + путь повтора + end + end +``` + +### 5.3 Админ: жизненный цикл товара и заказа + +```mermaid +stateDiagram-v2 + [*] --> draft: создать товар + draft --> active: опубликовать + active --> archived: архивировать + archived --> active: вернуть + note right of archived + Архивный товар исчезает из витрины, + но остаётся в прошлых заказах. + end note +``` + +```mermaid +stateDiagram-v2 + [*] --> pending: заказ создан + pending --> paid: оплата подтверждена + pending --> cancelled: отклонён + paid --> fulfilled: выдан/доставлен + paid --> cancelled: возврат +``` + +## 6. Данные для наполнения (сиды из аудита) + +- **Категории:** 11 видимых (+ 3 скрытых: розы/гортензии/тюльпаны, CATALOG.md §2). +- **Товары:** 94 уникальных с ценами, старыми ценами и бейджами (CATALOG.md §3); кросс-листинг + через `ProductCategory`. +- **Варианты:** у части товаров («N роз» → цена) — `ProductVariant`. +- **Константы магазина:** телефоны, e-mail, часы, адрес самовывоза, юрлицо, мессенджеры + (CATALOG.md §6) → `lib/store/constants.ts`. +- **PDP-контракт R9** заполняется вручную/скриптом при переносе: состав, стебли, высота, уход, + наличие, срок доставки (в источнике отсутствуют). + +## 7. Слои сборки и приёмка (definition of done) + +| # | Слой | Владелец | Проверка (команда / runtime) | +|---|---|---|---| +| 1 | План и рамки | Startup Creator | `docs/PLAN.md` + `docs/CATALOG.md` в репозитории; каждая карточка слоя содержит проверку | +| 2 | Диаграмма архитектуры | Diagram Expert | ERD/архитектура на `/diagrams` открываются без потерь; сущности = §4 | +| 3 | БД и формы | DataTables Expert | миграции + сид на чистом клоне; агрегатный запрос = пересчитанному вручную итогу | +| 4 | Бэкенд и API | Code Expert | `npm run lint`/`typecheck` + неавторизованный запрос к админ-маршруту → 401/403 | +| 5 | Фронтенд | Code Expert | `npm run build` + browse → cart → checkout → confirmation проходится на мок-провайдере | +| 6 | Админ-панель | Code Expert | нон-админ на `/admin/*` получает отказ серверно; смена статуса логируется | +| 7 | Control Panel | Control Panel Builder | виджеты показывают данные или пустое состояние; нет спиннера вечно; нет гориз. скролла 390×844 | +| 8 | Workflows | Elsa Workflows Manager | тестовый вебхук создаёт задачу и запись письма; неоплаченная ветка пропускает письмо | +| 9 | Качество и поставка | Code Expert | `npm run ci` (install + lint + typecheck + test + build) зелёный; README quickstart на чистом клоне | +| 10 | Деплой | Server Ops | публичный URL отдаёт приложение; рестарт контейнера восстанавливает сервис | + +Полные критерии приёмки — `SPEC.md` §8. + +## 8. Поэтапный порядок сборки + +1. Каркас Next.js: install → dev-server → пустая оболочка → коммит. +2. Схема и миграции по §4, сид из §6. +3. Каталог и карточка (витрина становится демонстрируемой). +4. Корзина + чекаут + оплата (сначала мок). +5. Аккаунт + история заказов. +6. Админ-панель. +7. Качество: тесты, CI, README, `.env.example`, доступность. + +## 9. Открытые вопросы (нужно решение пользователя) + +| # | Вопрос | Варианты | +|---|---|---| +| Q1 | Валюта витрины на этом этапе | интерим `RUB` с константой (рекомендую) ↔ сразу включить `BYN`, если платформа позволит | +| Q2 | Скрытые категории источника | перенести как невидимые (рекомендую) ↔ удалить ↔ сделать видимыми | +| Q3 | SEO-слаги | сохранить 1:1 (рекомендую) ↔ новая схема + 301 | +| Q4 | Чат Bitrix24 | сохранить ↔ заменить на WhatsApp/Telegram ↔ убрать | +| Q5 | FAQ/блог | FAQ-страница на этом этапе (рекомендую) ↔ отложить блог | +| Q6 | Числовой ID `/product/1997/` (404) | выяснить живой URL у владельца ↔ исключить товар | + +## 10. Вне рамок + +Мультивендор-маркетплейс, подписки, склад/инвентарные интеграции, налоговые движки, +мультиязычная витрина (SPEC.md §1); реальные платёжные шлюзы; новый визуальный дизайн на этом +этапе; перенос аналитики и чата — только решение и закладки (R12).