Идеи
Арена решений/design/task-shop.md

Задача 1: интернет-магазин (v0)

Первая задача Арены. Нарочно маленькая: пять экранов, один сценарий покупки, простая админка. Достаточно, чтобы различать варианты, и мало, чтобы один прогон занимал вечер, а не неделю.

Что строим

Магазин одного продавца. Покупатель смотрит каталог, кладёт в корзину, оформляет заказ. Продавец управляет товарами в админке. Оплаты нет, заказ фиксируется со статусом «новый».

Экраны

Экран Что на нём
Каталог / Список товаров: фото, название, цена. Фильтр по категории. Поиск по названию. Пагинация или «показать ещё» по 12.
Товар /p/:slug Фото, название, цена, описание, остаток. Кнопка «В корзину» неактивна при остатке 0.
Корзина /cart Строки с количеством (можно менять), сумма, кнопка «Оформить». Пустая корзина показывает подсказку.
Оформление /checkout Имя, телефон, город, комментарий. Валидация. После отправки страница «Заказ №N принят».
Админка /admin Таблица товаров. Создать, изменить, удалить. Поля: название, slug, цена, категория, остаток, фото (URL), описание. Вход по одному паролю из env.

Данные

  • Товар: id, slug, название, цена (целое, копейки), категория, остаток, фото URL, описание, активен.
  • Категория: id, название, slug.
  • Заказ: id, номер, дата, покупатель (имя, телефон, город, комментарий), строки (товар, количество, цена на момент заказа), сумма, статус.
  • Хранилище на усмотрение исполнителя: SQLite, JSON-файл, что угодно. Сид из 30 товаров и 4 категорий даётся в задаче.

Ограничения

  • Корзина переживает перезагрузку страницы.
  • Цена в заказе фиксируется на момент заказа, изменение цены товара потом не меняет заказ.
  • Нельзя заказать больше, чем остаток. После заказа остаток уменьшается.
  • Slug уникален. Удалённый товар не открывается, но в старых заказах остаётся.
  • Адаптив до 375px, без горизонтального скролла.
  • Никаких внешних сервисов: всё поднимается одной командой локально.

Требования (контракт для тестов и графа)

Это и есть requirements.md. Исполнитель получает этот список. Тесты ниже он не получает.

id Требование
REQ-shop-01 Каталог показывает только активные товары
REQ-shop-02 Фильтр по категории оставляет товары только этой категории
REQ-shop-03 Поиск по названию без учёта регистра
REQ-shop-04 Страница товара открывается по slug, несуществующий slug даёт 404
REQ-shop-05 «В корзину» недоступна при остатке 0
REQ-shop-06 Добавление в корзину увеличивает счётчик в шапке
REQ-shop-07 Корзина сохраняется между перезагрузками
REQ-shop-08 Изменение количества пересчитывает сумму
REQ-shop-09 Количество в корзине не превышает остаток
REQ-shop-10 Удаление строки из корзины
REQ-shop-11 Пустая корзина не даёт перейти к оформлению
REQ-shop-12 Оформление требует имя и телефон, телефон валидируется
REQ-shop-13 Успешный заказ получает номер и показывает его
REQ-shop-14 После заказа остаток товара уменьшен
REQ-shop-15 Цена в заказе не меняется при смене цены товара
REQ-shop-16 Админка закрыта без пароля
REQ-shop-17 Создание товара делает его видимым в каталоге
REQ-shop-18 Редактирование товара меняет данные на его странице
REQ-shop-19 Удаление товара убирает его из каталога, страница даёт 404
REQ-shop-20 Дублирующий slug отклоняется
REQ-shop-21 Каталог на 375px без горизонтального скролла
REQ-shop-22 Проект поднимается одной командой из README

Скрытые e2e-сценарии (Playwright)

Один сценарий на требование, имя теста содержит id. Каждый начинается с чистого сида.

  1. REQ-shop-01 деактивировать товар через админку, проверить что в каталоге его нет.
  2. REQ-shop-02 выбрать категорию «Кофе», все карточки из неё, счётчик совпадает с сидом.
  3. REQ-shop-03 ввести «ЧАЙ», найти товары с «чай» в названии.
  4. REQ-shop-04 открыть /p/net-takogo, получить 404.
  5. REQ-shop-05 открыть товар с остатком 0, кнопка disabled.
  6. REQ-shop-06 добавить два товара, счётчик в шапке «2».
  7. REQ-shop-07 добавить товар, перезагрузить, корзина не пуста.
  8. REQ-shop-08 поставить количество 3, сумма = цена × 3.
  9. REQ-shop-09 остаток 2, попытка поставить 5, в корзине 2 и сообщение.
  10. REQ-shop-10 удалить строку, сумма пересчитана, при пустой корзине подсказка.
  11. REQ-shop-11 зайти на /checkout с пустой корзиной, редирект или блок.
  12. REQ-shop-12 отправить без имени и с телефоном «123», две ошибки валидации.
  13. REQ-shop-13 оформить, увидеть «Заказ №» и число.
  14. REQ-shop-14 остаток 5, купить 2, на странице товара остаток 3.
  15. REQ-shop-15 оформить заказ, в админке поменять цену, заказ в хранилище с прежней ценой (проверка через админку заказов или API, на усмотрение).
  16. REQ-shop-16 открыть /admin без пароля, получить форму входа или 401.
  17. REQ-shop-17 создать товар в админке, найти в каталоге.
  18. REQ-shop-18 поменять название, проверить на странице товара.
  19. REQ-shop-19 удалить товар, в каталоге нет, страница 404.
  20. REQ-shop-20 создать товар с существующим slug, ошибка.
  21. REQ-shop-21 viewport 375×812, document.scrollingElement.scrollWidth <= 375.
  22. REQ-shop-22 выполняется раннером: команда из README поднимает сервер за 60 секунд.

Что получает исполнитель

Папку tasks/shop/: brief.md (экраны, данные, ограничения), requirements.md (таблица REQ), rules.md (архитектурные правила, см. scoring.md), сид seed.json. И одну инструкцию: «Сделай, чтобы проект поднимался командой из README. В коммитах и тестах указывай REQ-id».

Контракт запуска (обязателен для любого варианта)

  • Команды: npm install, npm run build, npm start. После npm start приложение слушает http://localhost:3000 не позже чем через 60 секунд.
  • Данные при старте читаются из seed.json. Хранилище любое, без внешних сервисов.
  • Переменные окружения: ADMIN_PASSWORD (по умолчанию arena), ARENA_TEST=1 включает тестовый режим.
  • В тестовом режиме есть POST /api/test/reset, который возвращает данные к сиду и отвечает 200. Вне тестового режима маршрут отвечает 404.
  • Обязательные data-testid на элементах перечислены в tasks/shop/brief.md репо arena. Без них скрытые тесты не найдут элементы, и это засчитывается как провал требования.

Зачем контракт: раннер и тесты не знают стек варианта. Единственное, на что они опираются, это порт, команда запуска, сброс данных и data-testid. Это цена за независимость от стека.