Клиенты — Список
Роут: /customers
API: GET /api/v1/admin/customers
Статус реализации
- Backend: готов — Customer Service имеет полный CRUD (
erp-customer-service, все endpoints из API.md реализованы)- Фронт: не начат — в
erp-admin/web/src/pages/нет папкиcustomers/- Sidebar-пункт: ещё не добавлен в
components/layout/Layout.tsx- Permission-guard:
customers.readуже в permission-каталоге User Service (миграция 024), но не используется
Источники
- Бизнес: Клиенты
- BR: BR 3.1
- API: Customer Service API
Что видит пользователь
Страница со списком клиентов в виде таблицы. Вверху — заголовок «Клиенты», строка поиска и фильтры. Справа от заголовка — кнопка «+ Создать клиента».
Поля LTV, orders_count, last_visit_at в таблице — агрегации из Order Service, клеятся Admin BFF’ом (Customer Service их не возвращает).
Таблица
Колонки
| Колонка | Данные | Примечание |
|---|---|---|
| ФИО | first_name + last_name | Кликабельное — переход в карточку. Если last_name null — показываем только first_name |
| Телефон | phone | В формате +7 (999) 123-45-67 для отображения, под капотом E.164 |
email | Или «—» | |
| ДР | birthday | В формате DD.MM (без года для краткости); или «—». Если ДР в ±14 дней — иконка 🎂 рядом |
| Дата регистрации | registered_at | Формат DD.MM.YYYY |
| Источник | registration_source | Chip: POS / Веб / Приложение / Админка / Импорт. Цвет по типу |
| Группы | groups[].name | Chips групп; max 3 видимых, остальные — «+N» с tooltip-полным списком. Пустой список — «—» |
| LTV | агрегат из Order Service | Сумма closed заказов клиента. Формат N 500 ₽. Пусто если 0 заказов |
| Действия | — | Меню с действиями (см. ниже) |
Особенности отображения
- Soft-deleted клиенты (
deleted_at IS NOT NULL) в списке не отображаются (API фильтрует) - Клиент без заказов — колонка LTV пустая, без «0 ₽»
Фильтры
| Фильтр | Тип | Значения | Default |
|---|---|---|---|
| Группа | Select | Все / {список активных групп франшизы} | Все (query group_id) |
| Источник | Select | Все / POS / Веб / Приложение / Админка / Импорт | Все (query source) |
| Дата регистрации с | Date picker | — | — (query registered_from) |
| Дата регистрации по | Date picker | — | — (query registered_to) |
Фильтры применяются мгновенно (без кнопки «Применить»). При смене фильтра — сброс на page=1.
Поиск
- Поле ввода с placeholder «Поиск по ФИО, телефону или email»
- Debounce 300ms
- Query param:
search - Ищет по подстроке всех трёх полей одновременно на бэке
Сортировка
- По умолчанию — по дате регистрации DESC (новые клиенты сверху)
- Клик по заголовку «ФИО» — переключение A-Я / Я-A (query
sort=name_asc|name_desc) - Клик по заголовку «Дата регистрации» — переключение ASC / DESC
Пагинация
- 20 записей на страницу
- Постраничная навигация внизу (номера страниц + стрелки)
- Query params:
page,per_page
Действия
Кнопки в шапке
| Кнопка | Переход | Видимость |
|---|---|---|
| «+ Создать клиента» | /customers/new | Permission customers.edit |
Меню действий строки
Трёхточечное меню в последней колонке:
| Действие | Видимость | Что происходит |
|---|---|---|
| Редактировать | customers.edit | Переход в /customers/{id}/edit |
| Удалить | customers.delete + только owner франшизы | Модалка подтверждения (см. карточку) |
Состояния
| Состояние | Что показываем |
|---|---|
| Загрузка | Skeleton-таблица (placeholder строк) |
| Пусто (первый раз) | «Клиенты пока не добавлены» + CTA «Создать клиента» (если permission) или пояснение «Дождитесь когда кассиры заведут клиентов через POS» |
| Ошибка загрузки | «Не удалось загрузить данные» + кнопка «Повторить» |
| Пустой поиск | «Ничего не найдено по запросу «…»» + ссылка «Сбросить фильтры» |
Ролевой доступ
По Ролевой матрице:
Владелец франшизы
- Видит всех клиентов франшизы
- Все действия доступны
Владелец партнёра
- Видит всех клиентов франшизы (пул общий — см. бизнес-спеку § Scope)
- Может создавать, редактировать. Удаление и merge — только у Владельца франшизы
Обычный сотрудник
- Без
customers.readпункт меню «Клиенты» скрыт (см. UI-гейтинг) - Прямой URL → 403 NoAccessPage
Кассир
- В админку обычно не ходит. Взаимодействует с клиентами через POS (см. POS Flow прикрепления)
Переходы
| Откуда | Куда | Триггер |
|---|---|---|
| Список | Карточка (view) | Клик по ФИО |
| Список | Форма создания | «+ Создать клиента» |
| Список | Форма редактирования | Меню → «Редактировать» |
| Карточка группы | Список с фильтром по группе | Из /customer-groups/{id} ссылка «Участники в списке» |