BR 3.1 — Admin Franchise (BFF + Web)

erp-admin — monorepo: bff/ (Node.js + Fastify + TypeScript) + web/ (React SPA).

Контракты


BFF задачи

1. Shared types

  • shared/types/customer.ts:
    • Customer, CustomerResponse, CreateCustomerRequest, UpdateCustomerRequest
    • CustomerAddress, CustomerGroup, CustomerGroupRulesJson
  • Типы для правил JSON (discriminated union по type)

2. HTTP client Customer Service

  • bff/src/services/customer-service-client.ts — обёртка над fetch для :3013
  • Прокидывание Authorization header (Bearer JWT из запроса клиента)
  • X-Service-Token для internal-вызовов (из env)

3. Proxy routes (BFF)

  • /api/v1/admin/customers/* — проксирует в Customer Service /api/v1/customers/*
    • Для карточки клиента (GET /admin/customers/{id}) — агрегация: Customer + вызов Order Service GET /api/v1/orders?customer_id=X&limit=20 для вкладки «Заказы»
    • Список клиентов (GET /admin/customers) — можно также подтянуть LTV / orders_count из Order Service GET /internal/orders/customer-summary для каждого (batch — по 20 на страницу ок, либо добавить batch endpoint в Order Service в будущем)
  • /api/v1/admin/customer-groups/* — прокси 1:1 в Customer Service
  • /api/v1/admin/customers/{id}/addresses/* — прокси

4. Admin BFF — обновить карточку заказа

  • GET /api/v1/admin/orders/{id} — если в ответе customer_id != null, подтянуть клиента через GET /internal/customers/{id} Customer Service и подмерджить в response как customer: { id, first_name, last_name, phone, groups }

5. Тесты BFF

  • Unit: маппинг customer response, агрегация с Order Service
  • Integration: моки бэк-сервисов, проверка прокси

Web задачи

1. Routing + навигация

  • web/src/App.tsx — добавить роуты:
    • /customersCustomerListPage
    • /customers/newCustomerCreatePage
    • /customers/:idCustomerViewPage
    • /customers/:id/editCustomerEditPage
    • /customer-groupsCustomerGroupListPage
    • /customer-groups/newCustomerGroupCreatePage
    • /customer-groups/:idCustomerGroupViewPage
    • /customer-groups/:id/editCustomerGroupEditPage
    • Все обёрнуты в <PermissionRoute permission="..."> как в других разделах
  • web/src/components/layout/Layout.tsx — добавить группу «Клиенты» в sidebar:
    • Клиенты/customers с permission customers.read
    • Группы/customer-groups с permission customer_groups.read

2. Страницы — Клиенты

  • pages/customers/ListPage.tsx — таблица + фильтры + поиск + пагинация. По паттерну employees/ListPage
  • pages/customers/ViewPage.tsx — карточка с табами (Profile/Addresses/Orders/Groups). Паттерн employees/ViewPage
  • pages/customers/CreatePage.tsx и EditPage.tsx — формы. Можно через shared CustomerForm компонент
  • Компонент CustomerAddressesTab.tsx — таблица + форма добавления / редактирования
  • Компонент CustomerOrdersTab.tsx — список заказов клиента (подтягивает из /admin/orders?customer_id=X)
  • Компонент CustomerGroupsTab.tsx — chips групп + модалка добавления в static группы
  • Компонент CustomerSidebar.tsx — LTV, средний чек, заказы, дней без визита
  • Utility normalizePhoneE164(raw: string): string — нормализация на blur в форме
  • Модалка удаления клиента с подтверждением

3. Страницы — Группы клиентов

  • pages/customer-groups/ListPage.tsx
  • pages/customer-groups/ViewPage.tsx — условный рендер табов для static vs dynamic
  • pages/customer-groups/CreatePage.tsx — шаг 1 выбора типа (radio) → POST → redirect на edit
  • pages/customer-groups/EditPage.tsx — rendering table members (static) или конструктор правил (dynamic)
  • Компонент CustomerGroupStaticMembers.tsx — таблица + модалка «Добавить клиентов»
  • Компонент CustomerGroupDynamicRulesEditor.tsx — конструктор правил:
    • Dropdown типов правил
    • Форма параметров для каждого типа (switch по type)
    • Кнопки «Сохранить» и «Пересчитать сейчас»
  • Компонент CustomerGroupDynamicMembersReadonly.tsx — read-only таблица

4. Обновить карточку заказа

  • pages/orders/OrderDetailPage.tsx — добавить блок «Клиент» (если order.customer_id != null). Рендерить имя, телефон, chips групп, ссылка на карточку клиента

5. PermissionContext / гейтинг

  • Добавить новые permissions в PermissionContext если таковой есть (должен автоматически подхватываться из JWT)
  • Применить PermissionRoute и usePermission в новых страницах

6. Тесты

  • Unit: формы, валидация phone
  • Integration (Cypress/Playwright если есть): смок-тест flow (список → карточка → edit → save)

Definition of Done

  • В сайдбаре появляется группа «Клиенты» (если есть permission)
  • Раздел «Клиенты» — полноценный CRUD с карточкой и вкладками
  • Раздел «Группы клиентов» — static и dynamic группы работают (конструктор правил позволяет создать базовые правила)
  • Карточка заказа показывает привязанного клиента
  • Prohibited actions скрыты согласно ролевой матрице