BR 6.1 → Admin Franchise

Репозиторий: erp-admin (содержит bff/ и web/) Спеки:

Admin BFF (bff/)

Прокси-эндпоинты

Все 5 эндпоинтов CRUD маркетинговых слайдов проксируются 1-к-1 в Store Service:

  • GET /admin/api/v1/stores/:storeId/marketing-slidesGET /api/v1/admin/stores/:storeId/marketing-slides
  • POST /admin/api/v1/stores/:storeId/marketing-slidesPOST /api/v1/admin/stores/:storeId/marketing-slides (multipart pass-through)
  • PUT /admin/api/v1/stores/:storeId/marketing-slides/:slideIdPUT /api/v1/admin/stores/:storeId/marketing-slides/:slideId
  • PATCH /admin/api/v1/stores/:storeId/marketing-slides/reorder → 1-к-1
  • DELETE /admin/api/v1/stores/:storeId/marketing-slides/:slideId → 1-к-1
  • При прокси multipart — использовать multipart/form-data pass-through (не парсить → не пересобирать; стримить body)
  • Forward JWT кассира из Authorization header

Расширить PATCH /admin/api/v1/stores/:id

  • Поля standby_idle_minutes / standby_transition_seconds теперь принимаются и прокси-пасуются в Store Service

Admin Web (web/)

  • В components/layout/Layout.tsx добавить новый TOP_ITEM:
    { label: 'Маркетинг', path: '/marketing', icon: <PostersIcon />, permission: 'marketing.read' }
  • Permission-guard через существующий usePermission hook
  • Иконка — постер / picture (lucide-react или существующий пакет)

Pages

  • pages/marketing/StoreListPage.tsx — список ТТ с числом активных слайдов
    • Route /marketing
    • Использует существующий API GET /api/v1/stores
    • Для счётчика активных — N параллельных запросов ?active=true (или агрегат, если решим расширить Store API)
    • Если scope = 1 ТТ → авто-redirect на /marketing/stores/{id}
  • pages/marketing/SlideListPage.tsx — список слайдов выбранной ТТ
    • Route /marketing/stores/:storeId
    • Таблица (см. спеку): drag-handle / превью / title / source / active toggle / actions
    • Drag-and-drop по образцу TablesSection.tsx (ручной handler)
    • Кнопки: «Превью карусели», «Загрузить слайд», «Сгенерировать через AI» (заглушка)
    • Empty state, лимит активных
  • components/marketing/UploadSlideModal.tsx — форма загрузки
    • File picker + drag-and-drop zone (по образцу PhotoStudioModal.tsx упрощённо)
    • Валидация на лету: MIME, size, dimensions (через new Image() + URL.createObjectURL)
    • POST multipart
  • components/marketing/EditSlideModal.tsx — редактирование
    • Pre-fill из props, PUT (json или multipart если меняется картинка)
    • Кнопка «Удалить» с confirm
  • components/marketing/CarouselPreviewModal.tsx — preview карусели
    • Полноэкранная модалка с <img> slideshow
    • Использует standby_transition_seconds из ответа API

Stores

  • web/src/stores/marketingStore.ts (Zustand или существующий паттерн):
    • slides: MarketingSlide[]
    • actions: loadByStore, create, update, reorder, delete
    • Использует marketingApi (см. ниже)

API client

  • web/src/api/marketing.ts:
    • listSlides(storeId, activeFilter?)
    • createSlide(storeId, file, title, active) — FormData
    • updateSlide(storeId, slideId, payload)
    • reorderSlides(storeId, orderArray)
    • deleteSlide(storeId, slideId)

Карточка ТТ — поля standby

  • В существующей странице pages/stores/EditPage.tsx добавить блок «Standby-режим» с двумя полями:
    • standby_idle_minutes (input number, 1..60)
    • standby_transition_seconds (input number, 3..60)
    • Disabled если нет stores.edit permission
  • PATCH использует существующий endpoint stores, прокси проброс работает через расширение admin-bff

AI-кнопка (заглушка для BR 6.2)

  • Кнопка «✨ Сгенерировать через AI» — disabled, title="Будет в BR 6.2 — AI-постер из Photo Studio"
  • При наведении — tooltip (можно через title или существующий tooltip-компонент)

Стили (Alfa Restyle)

  • Применить токены из lib/tokens.ts (см. скилл alfa-restyle) — после реализации функционала
  • Активный пункт сайдбара «Маркетинг» — красная линия слева (colors.red)
  • Toggle-switch активности слайда — красный (colors.red)
  • Chip «AI Photo Studio» — colors.redSoft фон + colors.red текст

Тесты

  • Smoke-тесты Jest/Vitest для marketingStore
  • Manual e2e на test VPS

Зависимости

Готово когда

  • В сайдбаре виден пункт «Маркетинг» для пользователей с marketing.read
  • Можно загрузить слайд через форму, увидеть его в списке
  • Drag-and-drop работает — порядок сохраняется на бэке
  • Кнопка «Превью карусели» открывает рабочий preview
  • В карточке ТТ можно менять standby_* поля
  • При деактивации слайда переходит вниз/исчезает из preview-карусели