Files
shop-server/.opencode/plans/2026-05-15-product-redesign-design.md
T
2026-05-15 12:50:39 +05:00

8.6 KiB
Raw Blame History

Design: Доработка товара — удаление «под заказ», обязательные quantity и категория

Дата: 2026-05-15 Статус: На согласовании

Цель

Упростить модель товара: убрать концепцию «под заказ», сделать количество и категорию обязательными полями. Категория «Не указано» остаётся технической заглушкой для переноса товаров при удалении категории, но не видна в каталоге и не выбирается при редактировании.

Архитектура изменений

1. База данных (Prisma)

Миграция:

  • Перед удалением полей: все товары с inStock = false получают quantity = 0
  • Удалить поля inStock и leadTimeDays из модели Product
  • Статус наличия определяется исключительно по quantity:
    • quantity > 0 → «В наличии»
    • quantity = 0 → «Нет в наличии»

server/prisma/schema.prisma:

model Product {
  // ... остальные поля без изменений ...
  quantity    Int      @default(0)
  // УДАЛЕНО: inStock     Boolean  @default(true)
  // УДАЛЕНО: leadTimeDays Int?
  category    Category @relation(fields: [categoryId], references: [id], onDelete: Restrict)
  categoryId  String
  // ...
}

2. Сервер — валидация и CRUD

server/src/routes/api/admin-products.js:

CREATE (POST):

  • quantity — required, Int >= 0 (было nullable)
  • categoryId — required (было: при пустом → авто-назначение «Не указано»)
  • Удалить валидацию leadTimeDays при !inStock
  • Удалить принудительную установку quantity = 1 для «под заказ»
  • Вернуть 400: 'Укажите категорию' если categoryId отсутствует

UPDATE (PATCH):

  • quantity — required, Int >= 0 (было nullable)
  • categoryId — required (было: при пустом → «Не указано»)
  • Удалить логику очистки leadTimeDays при inStock = true
  • Удалить принудительную установку quantity = 1
  • Вернуть 400 при отсутствии categoryId

JSON Schema:

  • CREATE_PRODUCT_SCHEMA: убрать leadTimeDays, сделать quantity required (убрать nullable)
  • PATCH_PRODUCT_SCHEMA: убрать leadTimeDays, quantity — если передан, то >= 0

server/src/routes/api/public-catalog.js:

  • Удалить ветку availability === 'in_stock' и availability === 'made_to_order'
  • Фильтрация «в наличии» больше не нужна — все товары в каталоге

3. Клиент — админка (две страницы)

client/src/pages/admin/ui/AdminPage.tsx и client/src/pages/admin-products/ui/AdminProductsPage.tsx:

FormState:

  • Удалить inStock: boolean и leadTimeDays: string
  • quantity: string — без nullable-семантики

UI:

  • Удалить Switch «В наличии / Под заказ»
  • Удалить TextField «Срок исполнения, дней»
  • TextField «Количество»:
    • Без helper «Оставьте пустым...»
    • Новый helper: «0 = нет в наличии»
    • Валидация: не может быть пустым, parseInt >= 0
  • Select «Категория»:
    • Удалить <MenuItem value=""> с «Не указано»
    • Валидация: не даёт сохранить без выбранной категории
    • Показать ошибку при попытке сохранить без категории

Submit-валидация:

  • Удалить проверку leadTimeDays при !inStock
  • Добавить проверку: categoryId не пустой → blocking error
  • Добавить проверку: quantity не пустой → blocking error

4. Клиент — каталог

client/src/entities/product/ui/ProductCard.tsx:

  • Удалить логику 'Под заказ · {leadTimeDays} дн.'
  • Новый статус:
    • quantity > 0 → «В наличии» (зелёный)
    • quantity === 0 → «Нет в наличии» (серый/red)

client/src/pages/product/ui/ProductPage.tsx:

  • Удалить chip 'Под заказ · {leadTimeDays} дн.'
  • Удалить alert 'Этот товар изготавливается под заказ...'
  • Статус определяется по quantity

client/src/pages/checkout/ui/CheckoutPage.tsx:

  • Удалить определение made-to-order товаров в корзине
  • Удалить info alert о доставке после изготовления

5. Клиент — фильтры

client/src/pages/home/lib/use-product-filters.ts:

  • Удалить availability: 'all' | 'in_stock' | 'made_to_order' из state
  • Удалить availability из параметров fetchPublicProducts()

client/src/pages/home/ui/ProductFilters.tsx:

  • Удалить ToggleButtonGroup с 'all', 'in_stock', 'made_to_order'
  • Удалить отображение категории «Не указано» из списка чипов (фильтр cat.slug !== 'ne-ukazano')

6. Категория «Не указано» — что остаётся

Где Что происходит
server/src/lib/default-category.js Остаётся — функция getOrCreateUnspecifiedCategory()
server/src/index.js Остаётся — вызов при старте
server/src/routes/api/admin-categories.js Остаётся — нельзя удалить/переименовать; при удалении категории товары переезжают в «Не указано»
Админка категорий Остаётся — кнопка удаления заблокирована
Фильтры каталога Скрыта — не показывается в чипах
Форма товара Скрыта — не выбирается в Select

Статус товара — новая логика

quantity > 0  →  «В наличии»  (зелёный chip/badge)
quantity = 0  →  «Нет в наличии»  (серый chip/badge)

Никаких других статусов. Поле inStock больше не существует.

Файлы для изменения

Сервер

Файл Изменения
server/prisma/schema.prisma Удалить inStock, leadTimeDays
server/src/routes/api/admin-products.js Валидация, schema, убрать логику под заказ
server/src/routes/api/public-catalog.js Убрать фильтр availability

Клиент

Файл Изменения
client/src/pages/admin/ui/AdminPage.tsx FormState, UI, валидация
client/src/pages/admin-products/ui/AdminProductsPage.tsx FormState, UI, валидация
client/src/entities/product/ui/ProductCard.tsx Статус по quantity
client/src/pages/product/ui/ProductPage.tsx Убрать под заказ UI
client/src/pages/checkout/ui/CheckoutPage.tsx Убрать made-to-order detection
client/src/pages/home/ui/ProductFilters.tsx Убрать availability toggle, скрыть «Не указано»
client/src/pages/home/lib/use-product-filters.ts Убрать availability

Миграция данных

// В Prisma migration:
// 1. UPDATE Product SET quantity = 0 WHERE inStock = false
// 2. ALTER TABLE Product DROP COLUMN inStock
// 3. ALTER TABLE Product DROP COLUMN leadTimeDays

Тестирование

Сервер:

  • CREATE без categoryId → 400
  • CREATE без quantity → 400
  • CREATE с quantity = 0 → OK
  • PATCH без categoryId → 400
  • PATCH с quantity = 0 → OK

Клиент:

  • Форма не сохраняется без категории
  • Форма не сохраняется без количества
  • Фильтры не содержат «Под заказ» и «Не указано»
  • Карточка товара показывает «Нет в наличии» при quantity = 0