Skip to content

Latest commit

 

History

History
161 lines (97 loc) · 13.7 KB

File metadata and controls

161 lines (97 loc) · 13.7 KB

План: довести второй бренд (Sprint Power) до целевой модели

Дата: 2026-05-04
Цель: закрыть разрыв между текущим кодом и two-storefronts-architecture.md: отчётность, UX регистрации, явный бренд заказа, выгрузки, контент/юридика, визуал.
Инварианты: один бэкенд; смешанной корзины нет; ЮKassa — разные shopId по брендам (уже поддерживается настройками).


Критерий готовности (Definition of Done)

  1. У каждого заказа в БД есть явный brand (inner | sprint-power), выставляется при создании и используется в админке/экспортах без эвристики «по строкам».
  2. При регистрации с уже существующим email — понятный сценарий: сообщение про сеть магазинов + ссылка на /login (копирайт согласовать; опционально — ключ в content blocks).
  3. В админке есть выгрузка с обоих брендов там, где нужна сводная отчётность (минимум: лиды; при необходимости — заказы/статистика — отдельное решение в рамках фазы 3).
  4. Юридические и ключевые статические страницы либо редактируются по бренду из админки, либо зафиксировано исключение (оставляем static + чеклист ручной синхронизации).
  5. В ЛК в списке заказов видно с какой витрины заказ (колонка/бейдж).
  6. Документация: STATUS.md, чеклист в two-storefronts-architecture.md обновлены после внедрения.

Фаза 0 — Срез «как сейчас» (0.5–1 день)

Задачи

  • Зафиксировать список экранов и API, где бренд выводится из состава заказа (order.service.ts, CRM, webhooks, письма).
  • Проверить создание платежа ЮKassa и webhook: везде ли передаётся/определяется brandId для выбора credentials (уже частично есть — не сломать при добавлении Order.brand).

Результат: короткая таблица «файл → сегодняшняя логика»; нет кода (или только комментарии в задаче).
Срез зафиксирован: order-brand-phase-0-snapshot.md.


Фаза 1 — Явный бренд заказа (приоритет 1)

Зачем: отчёты, экспорт, интеграции, защита от будущих изменений в составе.

Задачи

  1. Prisma: добавить в Order поле brand (String, значения как у BrandId), индекс (brand, createdAt) при необходимости.
  2. Миграция данных: для существующих заказов выставить brand по правилу, совпадающему с текущей эвристикой (есть позиция с product.brand === 'sprint-power'sprint-power, иначе inner). Обработать пустые/аномальные случаи вручную или скриптом.
  3. Создание заказа: при POST /api/orders (и любых других путях создания) записывать brand из контекста витрины / валидации корзины (все позиции одного бренда — уже должно выполняться).
  4. Чтение: getOrdersForAdmin, корзина удалённых, синк ЮKassa, выгрузки — фильтровать по order.brand, а не только по items.
  5. Тесты: unit/integration на создание заказа и миграцию (где уместно).

Результат: одно поле истины; старые запросы по items удалены или оставлены только как fallback на период релиза (лучше без fallback после бэкфила).

Ориентир по файлам: nextjs-project/prisma/schema.prisma, nextjs-project/src/app/api/orders/route.ts, nextjs-project/src/services/order.service.ts, миграции в nextjs-project/prisma/migrations/.


Фаза 2 — Регистрация и «сеть магазинов» (приоритет 2)

Задачи

  1. API POST /api/auth/register: при конфликте email возвращать структурированный ответ (например code: 'EMAIL_ALREADY_REGISTERED') + человекочитаемое сообщение на русском (или i18n-ключ).
  2. UI /register: при этом коде показывать блок с текстом из ТЗ + кнопка «Войти» (/login), опционально сохранить email в query для /login?email=.
  3. Тесты: обновить route.test.ts для регистрации.

Результат: поведение совпадает с разделом 2 архитектурного документа.

Файлы: src/app/api/auth/register/route.ts, src/app/register/page.tsx, тесты рядом.

Статус: реализовано (константы и текст — src/lib/auth/email-already-registered.ts, предзаполнение email на /login).


Фаза 3 — Выгрузки «оба бренда» (приоритет 2)

Задачи

  1. Лиды: в UI выгрузки лидов и в GET API — параметр или чекбокс «все бренды»; сервис getAllLeadsForExport принимает режим all | inner | sprint-power (или brandId | null где null = все).
  2. Заказы (опционально в этой же итерации): если CRM/статистика экспортирует CSV — добавить тот же паттерн; иначе завести подзадачу.
  3. Права: только роли с доступом к админке (как сейчас); при росте команды можно ограничить отдельной ролью позже.

Результат: отчётность на одном компьютере без двух ручных выгрузок (минимум — лиды).

Файлы: src/services/leads-export.service.ts, src/app/api/admin/leads/export/route.ts, src/app/admin/leads-export/page.tsx.

Статус: реализовано — allBrands=1|on, LeadsExportBrandScope, колонка «Витрина», имя файла leads-all-brands-*.csv при объединении.


Фаза 4 — ЛК: маркировка заказа по витрине (приоритет 3)

Задачи

  1. В DTO/API списка заказов для аккаунта отдавать brand (из Order.brand после фазы 1).
  2. В AccountOrdersTable (или аналоге) — колонка или бейдж «Inner Health» / «Sprint Power».

Результат: пользователь видит, с какой витрины покупка, без открытия деталей.

Статус: реализовано — Order.brand в данных списка/детали; AccountOrdersTable: колонка «Витрина» (desktop) и бейдж в карточке (mobile); /account/orders/[id] — бейдж в шапке; account-order-storefront-badge.tsx.


Фаза 5 — Юридика и статические страницы по бренду (приоритет 3–4)

Задачи

  1. Выбрать механику: content blocks по ключам страниц (privacy, oferta, …) с brand, либо отдельная сущность «LegalPage» — проще расширять таблицей ключей.
  2. Миграция: опционально засидить текущий HTML/текст из кода как brand_default для inner, для sprint-power — черновики или копии.
  3. Storefront: страницы читают контент из БД с fallback на static только если нет записи (короткий переходный период).
  4. Обновить storefront-copy-ownership.md — строка Legal → content blocks / выбранная модель.

Результат: юристы/маркетинг правят тексты без релиза кода.

Статус: реализовано для /privacy и /oferta — страницы legal-privacy / legal-oferta в контент-блоках, LegalPageRichOrStatic + fallback на текущий статический JSX; storefront-copy-ownership.md обновлён.


Фаза 6 — Витрина Sprint: визуал и продуктовые хвосты (приоритет 4)

Задачи

  1. Тема: свести цвета/лого/фавикон к токенам (layout, CSS variables), убрать расхождения между страницами.
  2. Внешние ссылки: решение продукта — оставить переход на sprintpower.ru в блоках или вести всё на свою витрину; после решения — один PR на ссылки/копирайт.
  3. Адаптив: по adaptive-pages-inventory.mdSprintPowerBlock и приоритетные страницы Sprint (если отстают).

Результат: визуально цельная вторая витрина на уровне «перекрас + консистентность».

Статус: реализовано — data-brand на <html>, акцентные CSS-переменные для Sprint, фон body и превью Open Graph/Twitter по бренду; иконки в метаданных сайта — файлы из public/; блок Sprint на главной ведёт на /catalog (своя витрина); SprintPowerBlock на FluidGrid; инвентаризация адаптива обновлена.


Фаза 7 — СДЭК и инфра (по необходимости)

Задачи

  1. Документировать в docs/env's.md / DEPLOY: как включить второй набор CDEK-ключей в настройках бренда (уже поддерживается схемой ключей — проверить все call sites используют brandId).
  2. Smoke: оформление заказа Sprint с теми же глобальными учётками СДЭК; при появлении второго договора — только смена значений в админке.

Результат: готовность к разводке без переделки архитектуры.

Статус: ключи cdek_* внесены в brand-scoped список; админка с выбранным брендом сохраняет brand:cdek_*, runtime читает scoped → глобальный fallback; описано в env's.md и two-storefronts-architecture.md §7. Smoke оформления Sprint — на стенде вручную.


Рекомендуемый порядок внедрения

Фаза 0 (срез) → Фаза 1 (Order.brand) → Фаза 2 (регистрация) → Фаза 3 (экспорт)
    → Фаза 4 (ЛК бейдж) → Фаза 5 (юридика) → Фаза 6 (визуал/ссылки) → Фаза 7 (СДЭК-док)

Фазы 2 и 3 можно параллелить разными исполнителями после фазы 1, если фаза 1 не блокирует экспорт (экспорт заказов по order.brand логично делать сразу после фазы 1).


Риски и как снять

Риск Митигация
Бэкфил Order.brand расходится с реальностью Скрипт отчёта «аномалии» до применения миграции; ручная правка единиц.
Webhook ЮKassa без brand Явно искать заказ по yookassaPaymentId и дальше использовать order.brand для credentials.
Дубли SEO Редакционная политика + разный контент в блоках/постах по brand (не задача одного PR).

После релиза

  • Обновить two-storefronts-architecture.md — таблицу «расхождения с кодом».
  • Обновить STATUS.md — дата и краткий список «сделано по второму бренду».