Qadam Roadmap
проектdocs/frontend/frontend-change-log.md

Change Log для frontend-команды

Обновлён 14 апр. 2026 г., 17:16 · 0 комментариев

Change Log для frontend-команды

Паспорт документа

  • Статус документа: living document
  • Актуально на: 2 апреля 2026 года
  • Владелец: backend/platform-команда, совместно с frontend-командой
  • Пересмотр: при изменении backend/frontend handoff-процесса, ownership-модели или API change workflow
  • Область применения: операционная модель взаимодействия backend/platform-команды и отдельной frontend-команды
  • Связанные документы:

Цель документа

Этот документ фиксирует change packages, которые backend/platform-команда передаёт отдельной frontend-команде. Его задача не заменить OpenAPI и не дублировать всю документацию, а дать короткий операционный слой:

  • что уже готово на backend;
  • какие endpoint-группы можно брать в работу;
  • какие изменения важны для UI и integration layer;
  • какие проверки нужны со стороны frontend после внедрения.

Источники истины

Правила публикации change package

Каждый новый backend change package, который влияет на frontend, должен обновлять этот документ.

Минимальный состав записи:

  1. Package ID
  2. Статус
  3. Что изменилось на backend
  4. Какие endpoint'ы / контракты затронуты
  5. Что должна сделать frontend-команда
  6. Что считать готовностью
  7. Есть ли breaking / migration note
  8. Требуется ли действие frontend на roadmap-портале

Статусы пакетов

  • ready_for_frontend — backend-контур готов, можно брать в работу на frontend
  • in_progress — backend ещё меняется, фронту брать только после отдельного подтверждения
  • adopted_by_frontend — пакет уже внедрён frontend-командой
  • superseded — пакет исторический и заменён более новым change package

Обратная связь от frontend на roadmap-портале

Главная страница https://qadam-roadmap.2fab.app автоматически собирает отдельный блок Что сейчас должна сделать frontend-команда из этого документа.

Правила такие:

  • в блок попадают только пакеты со статусом ready_for_frontend;
  • если пакет требует действий от frontend, на портале показываются кнопки В работе, Сделано, Игнорировать;
  • если запись носит только информационный характер, в ней нужно явно указать строку - Требуется действие frontend: нет, и тогда кнопки подтверждения не показываются;
  • если строка не указана, пакет по умолчанию считается требующим действия, когда у него есть статус ready_for_frontend и непустой блок Что должна сделать frontend-команда;
  • feedback-статусы на портале являются operational overlay и не заменяют канонический changelog: backend-пакет остаётся источником истины, а портал только фиксирует факт реакции frontend-команды.

Допустимые значения обратной связи:

  • В работе — frontend-пакет взят в реализацию;
  • Сделано — frontend-команда подтверждает внедрение;
  • Игнорировать — пакет сознательно не берётся в работу сейчас и не должен висеть как немая задача.

Пакеты изменений

FE-BE-2026-04-06-01 — Refresh cookie qadam_rt переведена на root path для server-side refresh

  • Статус: ready_for_frontend
  • Scope: web auth stability, full page reload after access token expiry, proxy refresh behavior

Backend scope

  • POST /api/v1/auth/login
  • POST /api/v1/auth/register
  • POST /api/v1/auth/register/buyer
  • POST /api/v1/auth/register/seller
  • POST /api/v1/auth/refresh
  • POST /api/v1/auth/reset-password
  • POST /api/v1/auth/logout

Важные контрактные детали

  • qadam_rt теперь выставляется с path=/, а не только с path=/api/v1/auth
  • это сделано не ради нового security behavior, а чтобы server-side proxy на маршрутах вроде /seller и /me мог читать refresh cookie после истечения qadam_at
  • backend при выдаче новой пары токенов дополнительно чистит legacy qadam_rt с path=/api/v1/auth, чтобы не оставлять два refresh-cookie с одним именем и разными path
  • logout/clear tokens теперь тоже чистит обе версии refresh-cookie: legacy и новую root-scoped

Что должна сделать frontend-команда

  • Никакой новой интеграции не требуется
  • Перестать считать logout after reload через ~15 минут “известным ограничением backend”
  • При проверке stage/prod сценариев отдельно подтвердить: full page reload после истечения access token больше не должен выбрасывать пользователя на /login, если refresh token ещё жив

Acceptance для frontend

  • Web session переживает полную перезагрузку страницы после истечения qadam_at, если qadam_rt ещё валидна
  • Proxy refresh не ломается только из-за cookie path mismatch

Breaking / migration note

  • Для уже существующих браузерных сессий, выпущенных до фикса, может понадобиться один новый login, потому что legacy refresh-cookie с path=/api/v1/auth уже была выдана ранее
  • Требуется действие frontend: нет

FE-BE-2026-04-02-05 — Owner-facing status-change notifications включены для seller staff flow

  • Статус: ready_for_frontend
  • Scope: seller notification settings copy, seller/staff leads UX, operational expectations around owner alerts

Backend scope

  • GET /api/v1/seller/leads
  • PUT /api/v1/seller/leads/:id/status
  • GET /api/v1/seller/notification-settings
  • PATCH /api/v1/seller/notification-settings

Важные контрактные детали

  • Owner-facing status-change notifications больше не являются purely forward-compatible: если статус лида меняет активный SELLER_STAFF, backend отправляет owner-уведомление по каналам Telegram -> Email fallback
  • Список статусов для таких уведомлений не захардкожен во frontend и может меняться через runtime env SELLER_STATUS_CHANGE_NOTIFY_STATUSES; дефолтный набор на backend сейчас CONTACTED, ENROLLED, REJECTED
  • Если статус меняет сам owner (SELLER), backend не шлёт ему уведомление о его же собственном действии
  • Публичный HTTP-контракт notification settings не менялся: новых полей и новых endpoint'ов нет

Что должна сделать frontend-команда

  • Не считать notifyStatusChangeTelegram purely informational toggle: на окружениях с включённым seller notifications runtime он уже управляет live owner-facing уведомлениями для staff-driven status changes
  • Если в seller/staff UX есть текст, будто status-change alerts "появятся позже", обновить его под фактическое поведение backend

Acceptance для frontend

  • Seller settings UI не вводит пользователя в заблуждение относительно live status-change alerts
  • Seller/staff lead UX не обещает owner-уведомления для self-update сценария, которого backend сознательно не делает

Breaking / migration note

  • Это изменение поведения доставки без расширения публичного API-контракта
  • Требуется действие frontend: нет

FE-BE-2026-04-02-04 — Seller email fallback подготовлен на backend

  • Статус: ready_for_frontend
  • Scope: seller notification settings copy, operational expectations around email channel

Backend scope

  • POST /api/v1/leads
  • GET /api/v1/seller/notification-settings
  • PATCH /api/v1/seller/notification-settings

Важные контрактные детали

  • Для новых лидов backend теперь не ограничивается Telegram-only попыткой доставки: при недоступном Telegram и включённом notifyNewLeadEmail он умеет перейти на SMTP-capable email fallback
  • sellerEmail в GET /seller/notification-settings теперь резолвится из seller profile email с fallback на account email
  • Публичный HTTP-контракт не менялся: новых endpoint'ов и новых полей нет
  • Email fallback реально срабатывает только на тех окружениях, где backend/platform-команда настроила SMTP_* runtime env
  • notifyStatusChangeTelegram теперь уже управляет live owner-facing уведомлениями в non-owner staff flow; отдельный пакет ниже фиксирует это как поведенческое изменение без расширения API-контракта

Что должна сделать frontend-команда

  • Не считать notifyNewLeadEmail purely forward-compatible флагом на окружениях, где backend подтвердил SMTP runtime
  • Если в UI есть жёсткий текст "email ещё не работает", убрать его только после подтверждения, что конкретный target runtime уже получил SMTP_* конфиг
  • Показывать sellerEmail как фактический email-адрес доставки, а не только как account email из auth-контекста

Acceptance для frontend

  • Settings screen не вводит seller в заблуждение относительно email-канала
  • UI понимает, что email delivery зависит не только от toggle, но и от runtime readiness конкретного окружения

Breaking / migration note

  • Migration касается поведения доставки, а не формы API-ответа
  • Требуется действие frontend: нет

FE-BE-2026-04-02-03 — Seller Telegram onboarding bot flow подготовлен для frontend

  • Статус: ready_for_frontend
  • Scope: seller notifications UX, Telegram connect/disconnect CTA, onboarding follow-up

Backend scope

  • GET /api/v1/seller/telegram/connect-link
  • POST /api/v1/seller/telegram/verify
  • DELETE /api/v1/seller/telegram

Важные контрактные детали

  • Backend теперь отдаёт seller-facing deep link:
    • botUsername: string
    • connectUrl: string
    • expiresAt: string
  • connectUrl уже готов для открытия в Telegram и ведёт в bot /start flow; frontend не должен собирать deep link вручную
  • GET /seller/telegram/connect-link может вернуть TELEGRAM_NOT_CONFIGURED, если seller-bot не настроен на конкретном окружении; это operational state, а не generic network error
  • POST /seller/telegram/verify теперь явно возвращает ALREADY_VERIFIED, если Telegram уже подключён к seller
  • DELETE /seller/telegram теперь явно возвращает NOT_CONNECTED, если seller пытается отключить Telegram без текущей привязки
  • Internal route POST /api/v1/internal/telegram/webhook предназначен для Telegram и не требует frontend-работ

Что должна сделать frontend-команда

  • Добавить CTA/кнопку подключения Telegram через GET /seller/telegram/connect-link
  • Открывать connectUrl как внешний переход в Telegram, а не через локальную строковую сборку bot URL
  • На verify/disconnect корректно обрабатывать ALREADY_VERIFIED и NOT_CONNECTED как продуктовые состояния, а не как generic error
  • Синхронизировать seller notification settings screen с новым connect flow, чтобы telegramConnected и telegramUsername обновлялись после успешной привязки

Acceptance для frontend

  • Seller может запустить Telegram connect flow из кабинета без ручного знания bot username или start token
  • UI различает состояния подключено, уже подключено, не подключено
  • После успешного bot flow seller возвращается в кабинет и может завершить привязку кодом без локальных manual types

Breaking / migration note

  • Это расширение существующего Telegram flow; старые settings endpoints не ломаются
  • Frontend больше не должен считать, что seller сам знает, где взять verification code: source-of-truth теперь GET /seller/telegram/connect-link
  • Требуется действие frontend: да

FE-BE-2026-04-02-02 — Seller notifications baseline подготовлен для frontend

  • Статус: ready_for_frontend
  • Scope: seller settings page, lead notification preferences, seller onboarding follow-up

Backend scope

  • GET /api/v1/seller/notification-settings
  • PATCH /api/v1/seller/notification-settings

Важные контрактные детали

  • Backend публикует новый seller-facing settings contract:
    • notifyNewLeadTelegram: boolean
    • notifyNewLeadEmail: boolean
    • notifyStatusChangeTelegram: boolean
    • telegramConnected: boolean
    • telegramUsername: string | null
    • sellerEmail: string | null
  • Если запись NotificationSettings отсутствует у исторического seller-аккаунта, backend создаёт её автоматически с дефолтами
  • После POST /leads backend уже запускает неблокирующую попытку Telegram-доставки продавцу, но email transport пока не включён: notifyNewLeadEmail уже существует как forward-compatible setting, а не как подтверждённый delivery channel
  • Успешность или пропуск доставки не влияет на ответ создания лида: lead create остаётся продуктовым primary path

Что должна сделать frontend-команда

  • Добавить экран или секцию seller notification settings на GET/PATCH /seller/notification-settings
  • Показывать состояние Telegram binding по telegramConnected и telegramUsername, а не по локальным эвристикам
  • Не обещать пользователю живой email delivery, пока backend отдельно не подтвердит SMTP/provider package
  • Использовать sellerEmail только как read-only operational hint в настройках, а не как отдельный источник истины о seller profile

Acceptance для frontend

  • Seller видит текущие notification settings и может менять их без ручных локальных типов
  • UI корректно различает Telegram подключён / не подключён
  • Lead settings screen не вводит пользователя в заблуждение относительно email delivery

Breaking / migration note

  • Это новый settings surface; существующие seller profile и lead flows не ломаются
  • Email toggle уже появляется в контракте, но не означает, что email-канал backend уже доведён до production delivery
  • Требуется действие frontend: да

FE-BE-2026-04-02-01 — Auth contract получил change-password из кабинета

  • Статус: ready_for_frontend
  • Scope: buyer/seller account settings, password settings form, auth security UX

Backend scope

  • POST /api/v1/auth/change-password

Важные контрактные детали

  • Новый endpoint принимает:
    • currentPassword: string
    • newPassword: string
  • newPassword использует те же password rules, что и registration/reset-password:
    • минимум 8 символов
    • минимум одна цифра
  • Успешный ответ:
    • { message: string }
  • При неверном текущем пароле backend возвращает INVALID_CREDENTIALS
  • После успешной смены пароля backend отзывает refresh token family, поэтому фронт не должен рассчитывать на долгоживущие старые сессии на других устройствах

Что должна сделать frontend-команда

  • Добавить форму смены пароля в buyer/seller кабинете на POST /auth/change-password
  • Валидировать newPassword по тем же правилам, что и registration/reset-password
  • Показать отдельное UX-сообщение для неверного текущего пароля вместо generic error toast
  • После успешной смены пароля корректно показать success-state и быть готовыми к тому, что старые refresh-сессии на других устройствах больше невалидны

Acceptance для frontend

  • Из кабинета можно сменить пароль без flow forgot-password
  • Неверный текущий пароль отображается как ожидаемая продуктовая ошибка
  • Успешная смена пароля показывает явный success-state по message из backend

Breaking / migration note

  • Это новый endpoint, а не замена forgot-password / reset-password
  • Сброс пароля по коду и смена пароля из авторизованного кабинета теперь должны сосуществовать как два разных UX-потока
  • Требуется действие frontend: да

FE-BE-2026-03-31-03 — Public seller profile начал отдавать backend-generated SEO metadata

  • Статус: ready_for_frontend
  • Scope: public seller profile SSR page и metadata layer должны перейти с ad-hoc сборки SEO на backend-generated contract

Backend scope

  • GET /api/v1/sellers/:id

Важные контрактные детали

  • Public seller profile response теперь публикует не только витринные поля seller и список опубликованных айтемов, но и explicit seo block:
    • title
    • description
    • canonicalUrl
    • openGraph
    • jsonLd
  • Public response очищен от seller-only внутреннего контекста: backend больше не должен отдавать приватный seller profile shape как есть
  • Непубличный seller должен резаться как 404; contract для public page теперь рассчитан только на ACTIVE seller profile
  • Hidden addresses не должны попадать в public payload даже в обнулённом виде

Что должна сделать frontend-команда

  • Перевести public seller page metadata на backend-generated seo block вместо локальной ad-hoc сборки
  • Использовать seo.canonicalUrl, seo.openGraph и seo.jsonLd как канонический источник для SSR metadata и structured data
  • Не предполагать, что hidden seller addresses приходят в payload: если массив addresses пуст, секция не должна рендериться
  • Обрабатывать 404 как нормальный SEO-safe сценарий для non-active / missing seller profile

Acceptance для frontend

  • Public seller page использует backend-generated SEO metadata без ручного дублирования формул title/description/canonical
  • JSON-LD на seller page строится из seo.jsonLd, а не из разрозненных local selectors
  • Non-active / missing seller profile даёт корректный 404 page flow без пустого 200

Breaking / migration note

  • Это не просто cosmetic addition: contract public seller profile стал более строгим и более пригодным для SSR/SEO
  • Frontend не должен опираться на скрытые seller-only поля, если они раньше случайно приезжали в response
  • Требуется действие frontend: да

FE-BE-2026-03-31-02 — Seller review surface и complaint-driven moderation готовы для frontend

  • Статус: ready_for_frontend
  • Scope: seller review dashboard, seller reply/complaint UX, buyer/public/admin review screens должны учесть seller reply и complaint-driven moderation

Backend scope

  • GET /api/v1/seller/reviews
  • PATCH /api/v1/seller/reviews/:id/reply
  • POST /api/v1/seller/reviews/:id/complaint
  • GET /api/v1/me/reviews
  • GET /api/v1/catalog/items/:slug/reviews
  • GET /api/v1/admin/moderation/reviews/:id

Важные контрактные детали

  • GET /seller/reviews возвращает список отзывов по айтемам продавца c полями:
    • reviewId
    • status
    • rating
    • text
    • sellerReply
    • sellerReplyAt
    • moderationNote
    • canReply
    • canEditReply
    • activeComplaint
    • item
    • buyer
  • PATCH /seller/reviews/:id/reply доступен только для PUBLISHED-отзывов
  • После первого ответа продавца backend разрешает редактировать reply только в пределах 48 часов; затем возвращает REPLY_EDIT_WINDOW_EXPIRED
  • POST /seller/reviews/:id/complaint доступен только для PUBLISHED-отзывов и переводит отзыв в PENDING_MODERATION
  • Повторная жалоба на отзыв с активной нерешённой complaint запрещена и возвращает COMPLAINT_ALREADY_EXISTS
  • Buyer/public/admin review payloads теперь могут содержать seller reply и active complaint context:
    • GET /me/reviews публикует sellerReply и sellerReplyAt
    • GET /catalog/items/:slug/reviews публикует seller reply только для PUBLISHED-отзывов
    • GET /admin/moderation/reviews/:id публикует sellerReply, sellerReplyAt и activeComplaint

Что должна сделать frontend-команда

  • Построить seller review list/dashboard на GET /seller/reviews
  • Добавить seller reply editor с state-driven блокировкой по canReply / canEditReply
  • Обработать REVIEW_NOT_PUBLISHED, REPLY_EDIT_WINDOW_EXPIRED, COMPLAINT_ALREADY_EXISTS как ожидаемые продуктовые состояния, а не generic error
  • Добавить seller complaint UX и после успешной жалобы переводить review-card в состояние PENDING_MODERATION
  • Показывать seller reply в buyer cabinet и public review blocks там, где он приходит из backend
  • В admin review detail показывать active complaint context, если отзыв попал на повторную модерацию

Acceptance для frontend

  • Seller видит список отзывов по своим айтемам и различает PUBLISHED / PENDING / REJECTED / PENDING_MODERATION
  • Seller может ответить на опубликованный отзыв и видит, когда reply уже нельзя редактировать
  • Seller может отправить complaint на опубликованный отзыв и после этого UI показывает review как PENDING_MODERATION
  • Buyer/public/admin review screens корректно отображают seller reply и complaint-driven moderation state

Breaking / migration note

  • Это расширение review-контракта и seller dashboard surface, а не изолированный новый экран
  • Frontend больше не должен считать seller review interaction "локальной заметкой": reply и complaint влияют на public/admin review state machine
  • Требуется действие frontend: да

FE-BE-2026-03-31-01 — Backend review status model и admin review moderation baseline

  • Статус: ready_for_frontend
  • Scope: buyer reviews cabinet, public item reviews и admin review moderation

Backend scope

  • POST /api/v1/me/reviews
  • GET /api/v1/me/reviews
  • GET /api/v1/catalog/items/:slug/reviews
  • GET /api/v1/admin/moderation/reviews
  • GET /api/v1/admin/moderation/reviews/:id
  • PATCH /api/v1/admin/moderation/reviews/:id

Важные контрактные детали

  • Review flow на backend больше не предполагает мгновенную публикацию: новые отзывы создаются в PENDING
  • Исторические существующие отзывы мигрированы в PUBLISHED, чтобы не обнулить текущий public/social proof
  • GET /me/reviews теперь возвращает для каждого отзыва:
    • reviewId
    • itemId
    • itemName
    • itemSlug
    • rating
    • text
    • status
    • moderationNote
    • createdAt
  • Публичный GET /catalog/items/:slug/reviews и rating/reviews aggregates теперь учитывают только PUBLISHED
  • Появился новый admin moderation surface для отзывов:
    • GET /admin/moderation/reviews
    • GET /admin/moderation/reviews/:id
    • PATCH /admin/moderation/reviews/:id
  • PATCH /admin/moderation/reviews/:id принимает:
    • decision: PUBLISHED | REJECTED
    • note?: string
  • При REJECTED moderation note обязателен
  • PENDING_MODERATION уже существует в contract-layer как допустимый ReviewStatus, но complaint-driven переход в этот статус будет отдельным follow-up пакетом

Что должна сделать frontend-команда

  • Добавить buyer-facing UI для review status badge вместо скрытого допущения "отзыв всегда сразу опубликован"
  • Показывать moderationNote, если отзыв отклонён или имеет seller-visible moderation пояснение
  • В public item reviews и rating widgets больше не ожидать, что новые только что отправленные отзывы появятся мгновенно
  • Построить admin review moderation queue/detail на новых /admin/moderation/reviews* endpoints
  • Обработать INVALID_STATUS_TRANSITION для race-safe admin moderation UI

Acceptance для frontend

  • Buyer cabinet показывает PENDING / PUBLISHED / REJECTED / PENDING_MODERATION как отдельные UI-состояния
  • Public item reviews и rating counters не завышаются за счёт PENDING отзывов
  • Admin может открыть очередь review moderation, посмотреть карточку отзыва и перевести отзыв в PUBLISHED или REJECTED

Breaking / migration note

  • Это контрактное изменение поведения, а не только добавление admin endpoints
  • Старое frontend-допущение "отзыв после submit сразу виден в public UI" теперь неверно
  • Требуется действие frontend: да

FE-BE-2026-03-30-05 — Admin seller operational surface доведён до рабочего контура

  • Статус: ready_for_frontend
  • Scope: admin seller directory, status management и seller-facing реакция на account status

Backend scope

  • GET /api/v1/admin/sellers
  • PATCH /api/v1/admin/sellers/:sellerId/status
  • seller-facing защищённые маршруты, которые проходят через JwtAuthGuard

Важные контрактные детали

  • Появился новый endpoint GET /admin/sellers с фильтрами search, status, sellerType, page, limit
  • Ответ GET /admin/sellers имеет форму { items, total, page, limit, totalPages }
  • Каждый seller summary теперь содержит:
    • sellerId
    • accountId
    • sellerType
    • accountStatus
    • displayName
    • phone
    • email
    • telegramConnected
    • totalItems
    • pendingItems
    • activeItems
    • createdAt
  • PATCH /admin/sellers/:sellerId/status остаётся прежним по shape ответа, но теперь у admin есть полноценный list/search surface, из которого этот action можно вызывать без ручного знания sellerId
  • После перевода seller в UNDER_REVIEW или BLOCKED защищённые seller-facing маршруты больше не отвечают generic 401 Invalid or expired token
  • Вместо этого backend возвращает явные domain errors:
    • 403 ACCOUNT_UNDER_REVIEW
    • 403 ACCOUNT_BLOCKED

Что должна сделать frontend-команда

  • Построить admin seller directory/list screen на GET /admin/sellers
  • Подключить фильтры search, status, sellerType, page, limit
  • Показывать seller summary и item counters прямо из backend response, а не собирать их вручную из разрозненных API
  • Использовать PATCH /admin/sellers/:sellerId/status из этого списка как основной status-management action
  • В seller-facing UI перестать трактовать response после status change как token expiry: ACCOUNT_UNDER_REVIEW и ACCOUNT_BLOCKED должны обрабатываться как account state

Acceptance для frontend

  • Admin может найти seller по имени/телефону/email и отфильтровать список по ACTIVE / UNDER_REVIEW / BLOCKED
  • Admin seller list показывает текущее состояние аккаунта и item counters без дополнительных ad-hoc запросов
  • После перевода seller в UNDER_REVIEW или BLOCKED seller-facing UI показывает корректный state-driven экран/ошибку, а не generic auth expiry

Breaking / migration note

  • Нового breaking route change нет
  • Это operational contract package: статус account management теперь считается полноценным рабочим срезом, а не isolated action endpoint
  • Требуется действие frontend: да

FE-BE-2026-03-30-04 — Seller item moderation state machine доведён до рабочего вида

  • Статус: ready_for_frontend
  • Scope: seller item dashboard и admin moderation должны перейти на явный moderation lifecycle вместо старых неявных переходов

Backend scope

  • GET /api/v1/seller/items
  • POST /api/v1/seller/items
  • GET /api/v1/seller/items/:id
  • PUT /api/v1/seller/items/:id
  • POST /api/v1/seller/items/:id/submit
  • POST /api/v1/seller/items/:id/withdraw
  • POST /api/v1/admin/moderation/items/:id/approve
  • POST /api/v1/admin/moderation/items/:id/reject
  • GET /api/v1/admin/moderation/items
  • GET /api/v1/admin/moderation/items/:id

Важные контрактные детали

  • Item status-модель теперь включает DRAFT, PENDING, ACTIVE, REJECTED
  • Новый item после POST /seller/items создаётся в DRAFT, а не уходит на модерацию автоматически
  • PUT /seller/items/:id больше не разрешён для PENDING айтемов; backend отдаёт 400 ITEM_PENDING
  • POST /seller/items/:id/submit теперь валидирует обязательные поля и может вернуть ITEM_ALREADY_PENDING, ITEM_ALREADY_ACTIVE, ITEM_MISSING_REQUIRED_FIELDS
  • Появился новый endpoint POST /seller/items/:id/withdraw, который возвращает pending-айтем обратно в DRAFT
  • GET /seller/items и GET /seller/items/:id теперь публикуют latestModerationRecord
  • GET /admin/moderation/items публикует latestModerationRecord, а GET /admin/moderation/items/:id публикует latestModerationRecord и moderationHistory
  • approve и reject теперь работают только для PENDING айтемов и отдают 409 ITEM_NOT_PENDING, если item уже промодерирован

Что должна сделать frontend-команда

  • Добавить явный seller badge/UX для статуса DRAFT
  • Перестать считать, что create/update автоматически отправляют айтем на модерацию
  • Добавить UX для withdraw перед редактированием pending-айтема
  • Показывать latestModerationRecord.reason/comment в seller item dashboard и detail screen
  • Обработать новые item error codes: ITEM_PENDING, ITEM_ALREADY_PENDING, ITEM_ALREADY_ACTIVE, ITEM_MISSING_REQUIRED_FIELDS, ITEM_NOT_PENDING
  • Обновить admin moderation UI под новый race-safe сценарий, где non-pending item больше нельзя approve/reject

Acceptance для frontend

  • Seller item dashboard корректно показывает DRAFT / PENDING / ACTIVE / REJECTED
  • Seller может открыть причину последнего reject через latestModerationRecord
  • Редактирование pending-айтема не делается в обход backend, а требует сначала withdraw
  • Admin moderation UI корректно обрабатывает 409 ITEM_NOT_PENDING как race-condition, а не как неизвестную ошибку

Breaking / migration note

  • Это контрактное изменение поведения, а не только новый endpoint
  • Старое frontend-допущение “create/update автоматически отправляют item на модерацию” теперь неверно
  • Требуется действие frontend: да

FE-BE-2026-03-30-03 — Upload URL стал storage-agnostic

  • Статус: ready_for_frontend
  • Scope: подготовить frontend к object storage без ломки API-контракта upload endpoint

Backend scope

  • POST /api/v1/upload/image

Важные контрактные детали

  • Shape ответа не меняется: upload endpoint по-прежнему возвращает { url: string }
  • Значение url теперь нужно считать opaque public URL
  • При локальном storage это может быть /uploads/images/<fileName>
  • При S3/CDN storage это может быть абсолютный URL вида https://cdn.example.com/images/<fileName>
  • В текущем production для product media уже используется абсолютный URL из DigitalOcean Spaces
  • Frontend не должен собирать upload URL вручную и не должен предполагать same-origin относительный путь

Что должна сделать frontend-команда

  • Использовать url из backend response как готовый src/asset URL без преобразований
  • Не завязывать upload UI на префикс /uploads/images/
  • Проверить, что seller logo/photo и item image flows не ломаются от абсолютного CDN/S3 URL

Acceptance для frontend

  • Upload UI и asset forms сохраняют в модель ровно тот url, который вернул backend
  • Отрисовка изображений работает как для относительных, так и для абсолютных URL
  • В коде нет ручной конкатенации same-origin upload paths

Breaking / migration note

  • Формально breaking route change нет
  • Семантически это важное contract clarification: url больше не должен считаться обязательно локальным path

FE-BE-2026-03-30-02 — OpenAPI response schemas для seller items и admin

  • Статус: ready_for_frontend
  • Scope: убрать manual response layer на seller item dashboard и admin slices; активный backend-blocker backlog по OpenAPI coverage теперь равен 0

Backend scope

  • GET /api/v1/seller/items
  • POST /api/v1/seller/items
  • GET /api/v1/seller/items/:id
  • PUT /api/v1/seller/items/:id
  • DELETE /api/v1/seller/items/:id
  • POST /api/v1/seller/items/:id/submit
  • POST /api/v1/seller/items/:id/archive
  • GET /api/v1/admin/stats
  • GET /api/v1/admin/leads
  • GET /api/v1/admin/moderation/items
  • GET /api/v1/admin/moderation/items/:id
  • POST /api/v1/admin/moderation/items/:id/approve
  • POST /api/v1/admin/moderation/items/:id/reject

Важные контрактные детали

  • Seller item dashboard теперь публикует точные response schemas для списка, detail, create, update, delete, submit и archive flows
  • admin/leads и admin/moderation/items описаны как массивы, а не как ad-hoc обёртки { items: ... }
  • admin/moderation/items/:id/approve и reject возвращают { id, name, slug, moderationStatus, isVisible }
  • Активный frontend-значимый OpenAPI gap backlog теперь составляет 0

Что должна сделать frontend-команда

  • Перегенерировать openapi/openapi.json и contract layer
  • Убрать ручные response-типы на seller item dashboard и admin slices
  • Перевести item/admin queries и mutations на generated response types без локальных transport-заглушек
  • Считать оставшиеся ручные response-интерфейсы в этих зонах техническим долгом, а не допустимым baseline

Acceptance для frontend

  • Seller item dashboard использует generated response types для list/detail/create/update/delete/submit/archive
  • Admin dashboard и moderation UI используют generated response types без ручного response typing
  • После синхронизации frontend больше не держит manual response layer на seller items и admin slices

Breaking / migration note

  • Breaking route change нет
  • Это финальный contract-completeness package по CP-104: новые backend schema fixes для этих endpoint'ов больше не требуются
  • 204 No Content delete-маршруты остаются техническим хвостом OpenAPI-оформления, но не считаются blocker'ом для frontend

FE-BE-2026-03-30-01 — OpenAPI response schemas для auth auxiliary, staff и reference

  • Статус: ready_for_frontend
  • Scope: убрать manual transport layer на auth auxiliary, staff и reference slices

Backend scope

  • POST /api/v1/auth/forgot-password
  • POST /api/v1/auth/verify-reset-code
  • POST /api/v1/auth/reset-password
  • POST /api/v1/auth/add-buyer-role
  • GET /api/v1/seller/staff
  • POST /api/v1/seller/staff
  • PUT /api/v1/seller/staff/:id
  • DELETE /api/v1/seller/staff/:id
  • GET /api/v1/catalog/subjects
  • POST /api/v1/catalog/subjects
  • PUT /api/v1/catalog/subjects/:id
  • DELETE /api/v1/catalog/subjects/:id
  • GET /api/v1/catalog/locations
  • POST /api/v1/catalog/locations
  • PUT /api/v1/catalog/locations/:id
  • DELETE /api/v1/catalog/locations/:id
  • GET /api/v1/subjects

Важные контрактные детали

  • Эти endpoint'ы теперь публикуют response content в OpenAPI и готовы к generated response types
  • reset-password публикует тот же session response contract, что и login/register flows
  • add-buyer-role возвращает { profile }, а не отдельную ad-hoc форму
  • seller/staff стабилизирован на форме { staff: ... }
  • catalog/subjects, catalog/locations и публичный /subjects отдают явные списки/объекты справочников без необходимости ручного frontend typing

Что должна сделать frontend-команда

  • Перегенерировать openapi/openapi.json и contract layer
  • Убрать ручные response-типы на password reset auxiliary flow, seller staff и reference slices
  • Использовать generated response layer для buyer-role bind flow
  • Не держать custom parsers там, где shape теперь уже стабилизирован в OpenAPI

Acceptance для frontend

  • Password reset auxiliary flow использует generated response types
  • Staff management UI использует generated response types без ручных transport interfaces
  • Reference/admin reference screens используют generated response types для subjects/locations
  • Public /subjects больше не типизируется вручную

Breaking / migration note

  • Breaking route change нет
  • Это не новый endpoint package, а contract-completeness package: старые ручные response-типы теперь считаются техническим долгом и должны вытесняться generated contract layer

FE-BE-2026-03-28-01 — OpenAPI и контрактный контур

  • Статус: ready_for_frontend
  • Scope: source-of-truth контракт и базовый workflow синхронизации frontend с backend

Что сделано на backend

  • Поднят Swagger UI: GET /api/docs
  • Поднят runtime OpenAPI artifact: GET /api/openapi.json
  • Версионируемый OpenAPI artifact хранится в qadam-core/apps/api/openapi/openapi.json
  • Backend публикует точные response-схемы для ключевых auth/buyer/seller/public flows

Что должна сделать frontend-команда

  • Считать OpenAPI единственным источником истины по transport-типам
  • Не поддерживать вручную параллельные request/response types, если endpoint уже описан в OpenAPI
  • Для каждого backend-пакета сначала обновлять openapi/openapi.json, затем прогонять codegen

Acceptance для frontend

  • Обновлён qadam-web/openapi/openapi.json
  • Выполнен pnpm generate:api-contract
  • Нет ручного contract drift относительно backend artifact

Breaking note

  • Breaking change как таковой нет, но ручные transport-типы считаются legacy и подлежат вытеснению generated contract layer

FE-BE-2026-03-28-02 — Auth registration и password reset

  • Статус: ready_for_frontend
  • Scope: новый registration API и восстановление пароля

Backend scope

  • POST /api/v1/auth/check-availability
  • POST /api/v1/auth/register/buyer
  • POST /api/v1/auth/register/seller
  • POST /api/v1/auth/forgot-password
  • POST /api/v1/auth/verify-reset-code
  • POST /api/v1/auth/reset-password
  • POST /api/v1/auth/add-buyer-role

Важные контрактные детали

  • Для duplicate validation используются отдельные ошибки PHONE_TAKEN и EMAIL_TAKEN
  • Buyer может регистрироваться без email
  • Seller registration требует полный seller payload, включая sellerType, profile fields и subjectIds
  • Web-клиент продолжает жить на cookie auth (qadam_at, qadam_rt)
  • Mobile-клиенты по-прежнему могут получать токены в body
  • Password reset transport пока stub-овый: API создаёт токен/код корректно, но внешняя доставка пока не интегрирована с реальным SMS/email provider

Что должна сделать frontend-команда

  • Собрать новый registration wizard поверх check-availability, register/buyer, register/seller
  • Нормально маппить PHONE_TAKEN и EMAIL_TAKEN в field-level ошибки
  • Не строить отдельный frontend-only reset flow в обход backend-контракта
  • Использовать новый add-buyer-role для multi-role сценария seller → buyer

Acceptance для frontend

  • Регистрация buyer проходит end-to-end на новых endpoint'ах
  • Регистрация seller проходит end-to-end на новых endpoint'ах
  • Ошибки availability и финального register показываются на конкретных полях
  • Password reset UI использует backend token/code flow, а не локальные временные обходы

Breaking / migration note

  • Старый POST /api/v1/auth/register сохранён только как legacy route и не должен быть опорой новой frontend-разработки

FE-BE-2026-03-28-03 — Buyer profile, children, interests

  • Статус: ready_for_frontend
  • Scope: buyer cabinet и post-registration buyer flow

Backend scope

  • GET /api/v1/me/profile
  • POST /api/v1/me/profile
  • PATCH /api/v1/me/profile
  • PUT /api/v1/me/profile — legacy alias
  • GET /api/v1/me/children
  • POST /api/v1/me/children
  • PATCH /api/v1/me/children/:studentId
  • DELETE /api/v1/me/children/:studentId
  • PATCH /api/v1/me/interests

Важные контрактные детали

  • Канонический write-contract — PATCH, а не PUT
  • Отсутствующий buyer profile должен обрабатываться как отдельное UI-состояние, а не как “тихий create”
  • Buyer profile работает от account-centric модели
  • Parent и student сценарии расходятся по доступным endpoint'ам и состояниям

Что должна сделать frontend-команда

  • Собрать UI-сценарий отсутствующего buyer profile
  • Развести parent и student ветки кабинета
  • Перевести buyer profile flow на POST/PATCH /me/profile
  • Подключить children CRUD и interests update к новому контракту

Acceptance для frontend

  • Buyer profile create/edit не использует legacy assumptions
  • Parent видит children list и children CRUD
  • Student видит и обновляет interests
  • UI устойчив к BUYER_NOT_FOUND, PHONE_TAKEN, EMAIL_TAKEN, MAX_CHILDREN_REACHED, CHILD_NOT_FOUND

Breaking / migration note

  • PUT /me/profile не должен использоваться как канонический путь для новой реализации

FE-BE-2026-03-28-04 — Seller profile, addresses, Telegram, uploads

  • Статус: ready_for_frontend
  • Scope: seller onboarding/profile management и asset-related flows

Backend scope

  • GET /api/v1/seller/profile
  • POST /api/v1/seller/profile
  • PATCH /api/v1/seller/profile
  • PUT /api/v1/seller/profile — legacy alias
  • GET /api/v1/seller/addresses
  • POST /api/v1/seller/addresses
  • PATCH /api/v1/seller/addresses/:addressId
  • DELETE /api/v1/seller/addresses/:addressId
  • PATCH /api/v1/seller/addresses/:addressId/set-primary
  • POST /api/v1/seller/telegram/verify
  • DELETE /api/v1/seller/telegram
  • POST /api/v1/upload/image

Важные контрактные детали

  • PATCH /seller/profile теперь возвращает специфичные PHONE_TAKEN и EMAIL_TAKEN, если contact phone/email конфликтуют с другим аккаунтом
  • Telegram verify возвращает { success, username }, где username может быть null
  • Upload endpoint принимает multipart/form-data, файл в поле file
  • Upload validation: JPG/PNG/WebP, max 5 MB, min 200x200
  • Успешный upload возвращает url как готовый публичный URL; он может быть как локальным /uploads/images/<fileName>, так и абсолютным S3/CDN URL

Что должна сделать frontend-команда

  • Довести seller onboarding/profile UI до актуального backend-контракта
  • Нормально обрабатывать field-level duplicate errors для contact phone/email
  • Подключить address CRUD и primary switch к новому seller area
  • Подключить Telegram verification/unbind без самодельного контракта
  • Использовать backend upload endpoint для logo/photo/image flows

Acceptance для frontend

  • Seller profile edit работает через PATCH
  • Address management использует backend CRUD напрямую
  • Telegram binding flow использует POST /seller/telegram/verify
  • Upload UI корректно обрабатывает FILE_TOO_LARGE, INVALID_FORMAT, IMAGE_TOO_SMALL

Breaking / migration note

  • PUT /seller/profile — только legacy alias, новые UI-сценарии должны строиться на PATCH

FE-BE-2026-03-28-05 — Admin / governance hooks

  • Статус: ready_for_frontend
  • Scope: backend hooks, которые понадобятся admin-поверхности и governance-сценариям

Backend scope

  • PATCH /api/v1/admin/sellers/:sellerId/status

Важные контрактные детали

  • Валидные переходы состояний ограничены
  • После смены статуса seller refresh sessions инвалидируются на backend
  • Auth guard проверяет живой account status, а не только JWT payload

Что должна сделать frontend-команда

  • Использовать этот endpoint только в admin scope
  • Явно закладывать UI для INVALID_STATUS_TRANSITION
  • Не предполагать, что заблокированный seller сможет жить на старой refresh-сессии

Acceptance для frontend

  • Admin UI корректно меняет seller status и показывает новое состояние
  • После блокировки/under_review seller-facing UI правильно реагирует на новые auth errors

Что не считается frontend blocker прямо сейчас

  • Stub transport у password reset не блокирует UI-интеграцию, если flow строится против реального API-контракта
  • Локальный upload storage не блокирует frontend, если UI работает только через возвращаемый URL
  • Legacy compatibility поля в Prisma не должны протекать во frontend как источник истины

Как обновлять этот документ дальше

При каждом новом backend change package:

  1. Добавить новый блок в этот changelog
  2. Обновить frontend-handoff.md, если поменялся workflow handoff
  3. Обновить api-routes.md, если появился новый endpoint или changed behavior
  4. Обновить OpenAPI artifact
  5. Только после этого передавать пакет frontend-команде