Admin Franchise web — BR 3.4
Контракты
- Фронт-спека · Интеграция PayKeeper — описание блока «Каталог в PayKeeper» и модалки «Журнал прогонов»
- Adapter API — 4 эндпоинта
- Admin BFF decomposition — BFF-прокси (blocker)
Что делаем
API layer — web/src/api/paykeeper.ts
- Импортировать типы из
@erp-admin/shared(CatalogSyncStatus, CatalogSyncRunSummary, CatalogSyncRunDetail, ResyncCatalogResponse). - Функции:
resyncCatalog(accountId: string): Promise<ResyncCatalogResponse>→ POST/api/v1/admin/paykeeper/accounts/${id}/resync-cataloggetCatalogSyncStatus(accountId): Promise<CatalogSyncStatus>→ GETlistCatalogSyncRuns(accountId, { limit, since }): Promise<{ data: CatalogSyncRunSummary[], meta: { limit, total } }>getCatalogSyncRun(accountId, runId): Promise<CatalogSyncRunDetail>
- Обработка ошибок: типы
CatalogSyncErrorс кодами (ACCOUNT_NOT_ACTIVE,SYNC_ALREADY_RUNNING,RATE_LIMITED,FORBIDDEN,NOT_FOUND).
React-hook для polling
-
web/src/hooks/useCatalogSyncStatus.ts:function useCatalogSyncStatus(accountId: string) { // useQuery с refetchInterval: // 5000 мс если last_run.status === 'running' // 30000 мс иначе // Возвращает { data, isLoading, error, refetch } }
Компонент блока «Каталог в PayKeeper»
-
web/src/pages/legal-entities/components/CatalogSyncBlock.tsx(новый):- Показывается когда
account.status === 'active'. - Иначе — либо скрыт (not_configured), либо text-note для suspended.
- Использует
useCatalogSyncStatus(accountId)+usePermissions(). - Layout — grid с label/value:
- «Товаров в ЛК PK: {pk_products_synced}» (с пометкой ✓ если
diverged_count=0) - «(из {erp_products_total} товаров ERP × модификаторы)» — справочно
- «Последняя синхронизация: DD.MM.YYYY, HH:mm»
- «Триггер: …»
- «Статус: …» (badge по состоянию)
- При
diverged_count > 0— оранжевая строка «⚠ N вариантов требуют пересинхронизации»
- «Товаров в ЛК PK: {pk_products_synced}» (с пометкой ✓ если
- Категорий и модификаторов как отдельных счётчиков нет — они растворены в общем счётчике товаров.
- Кнопки:
- «Пересинхронизировать» — при
integrations.manage, disabled во времяrunning. Handler —resyncCatalog(), toast на успех/ошибки. - «Журнал прогонов» — при
integrations.read, открываетCatalogSyncRunsModal.
- «Пересинхронизировать» — при
- Показывается когда
Компонент модалки «Журнал прогонов»
-
web/src/pages/legal-entities/components/CatalogSyncRunsModal.tsx:- Таблица с колонками: Время, Триггер, Длительность, Статус, Товаров (+/-), Категорий (+/-), Модификаторов (+/-), Ошибок.
- Данные —
listCatalogSyncRuns(accountId, { limit: 20, since })+ кнопка «Загрузить ещё». - Клик на строку — раскрывается inline-accordion с деталями (
getCatalogSyncRun(accountId, runId)):last_error— красная плашка если не nullerrors_json— scrollable список[{entity_type, erp_id, message}]- Пустой список → «Без ошибок» серым
- Закрытие — стандартная кнопка.
Интеграция в PaykeeperTab
-
web/src/pages/legal-entities/PaykeeperTab.tsx:- Импорт
CatalogSyncBlock - Размещение: между карточкой интеграции и подвкладкой «Журнал» (новый div внутри tab content).
- Импорт
i18n / копирайты
- Все тексты на русском (как в BR 3.3 PaykeeperTab). Без отдельного i18n слоя — админка на русском по умолчанию.
Визуальные состояния для QA
- Проверить:
- Успешный прогон — зелёная галочка
- Частичный (errors > 0) — жёлтый треугольник, tooltip → журнал
- Failed — красный крест, раскрытие last_error
- Running — синий спиннер + timer
- Ещё не синхронизировался (last_run: null) — серый текст
- diverged_count > 0 — оранжевая строка
- account не active — блок скрыт / с подсказкой
Тесты
- Unit
CatalogSyncBlock.test.tsx— render для каждого из 6 состояний. - Unit
useCatalogSyncStatus.test.ts— polling interval переключается при running. - Visual (Storybook / Chromatic, если есть) — все состояния.
- E2E (если есть Cypress/Playwright): сценарий «нажать Пересинхронизировать → увидеть running → success».
Документация
- Обновить компонентный README если есть.
Deploy
После merge — /deploy-all admin-bff (web билдится вместе с BFF в этом репо).