Клиенты — Карточка
Три режима одного экрана: просмотр, создание, редактирование.
Статус реализации
Backend готов, фронт не начат. См. Клиенты — Список.
Источники
- Бизнес: Клиенты
- BR: BR 3.1
- API: Customer Service API
Общий layout (все режимы)
Шапка карточки:
- Breadcrumb: «Клиенты» → «{ФИО или “Новый клиент”}»
- Заголовок — имя клиента (в edit/new — пусто / placeholder «Создание клиента»)
- Chips групп клиента (справа от имени; только view/edit)
- Бейджи (только view/edit):
- «🎂 ДР через N дней» (если ДР в ±14 дней)
- «Новый клиент» (если регистрация < 30 дней назад)
- Справа — кнопки действий (зависят от режима)
Табы под шапкой:
- Профиль (все режимы)
- Адреса (все режимы; в new — вкладка есть, но контент после сохранения клиента)
- Заказы (только view/edit)
- Группы (только view/edit)
Переключение вкладок не меняет URL (состояние в компоненте). Default — «Профиль».
Сайдбар (только view/edit; справа или под шапкой на узких экранах):
- LTV:
{total_spent} ₽ - Средний чек:
{avg_check} ₽ - Заказов:
{orders_count} - Последний визит:
{last_visit_at}(или «Никогда») - Дней с последнего визита:
{days_since}
Вкладка 1: Профиль
| Поле | Режим | Тип | Required | Описание |
|---|---|---|---|---|
| Телефон | text input с маской +7 (___) ___-__-__ | string | Да | Нормализация в E.164 на blur. Уникальность проверяется на сервере |
| text input | string | Нет | Lower-case, валидация по RFC | |
| Имя | text input | string | Да | |
| Фамилия | text input | string | Нет | |
| Дата рождения | date picker | date | Нет | |
| Пол | radio (Мужской / Женский / Другое / Не указан) | enum | Нет | Default «Не указан» |
| Заметки | textarea | text | Нет | Свободный текст |
| Источник регистрации | readonly chip (view/edit), hidden в new (auto=admin) | enum | Auto | В view показываем chip |
| Кто завёл | readonly link на сотрудника (view/edit) | — | Auto | |
| Согласие на обработку ПД | checkbox + дата | — | Нет | «Клиент дал согласие на обработку ПД». При галке отмечается consent_signed_at = now(). В view — chip «Согласие получено DD.MM.YYYY» или «Не получено» (красный) |
Валидации (inline под полями):
- Телефон: после E.164 нормализации должен быть валидным российским номером (
+7XXXXXXXXXX). Иначе — «Неверный формат телефона» - Email: стандартная RFC-валидация. Иначе — «Неверный формат email»
- Имя: не пустое, не короче 1 символа
Вкладка 2: Адреса
Таблица адресов клиента + inline-форма добавления/редактирования.
Таблица
| Колонка | Данные |
|---|---|
| Default | Иконка 🏠 если is_default=true |
| Город | city |
| Улица | street |
| Квартира | apartment или «—» |
| Зона доставки | название из Store Service (delivery_zone_id) или «—» |
| Заметки | notes (truncate, tooltip при hover) |
| Действия | «Редактировать» / «Удалить» / «Сделать default» |
Форма добавления / редактирования (модалка или inline-раскрытие)
Поля (обязательные отмечены):
- Город *
- Улица *
- Квартира
- Подъезд
- Этаж
- Код домофона
- Зона доставки (select из Store Service
delivery_zones) - Заметки
- По умолчанию (checkbox) — при отметке предыдущий default снимается
Действия
- «+ Добавить адрес» — открывает форму
- «Сделать default» — PATCH с
is_default=true(старый снимается в одной транзакции сервером) - «Удалить» — DELETE, без модалки (адрес — это не PII по чувствительности)
Состояние «нет адресов»
- «У клиента ещё нет адресов. Добавьте первый — он станет default»
Вкладка 3: Заказы
Список заказов клиента. Агрегация на Admin BFF из Order Service (GET /api/v1/admin/orders?customer_id=X).
Таблица
| Колонка | Данные |
|---|---|
| Дата | created_at (формат DD.MM.YYYY HH:mm) |
| Номер | order_number (с бейджем ТТ в подписи) |
| Торговая точка | store.name |
| Сумма | total |
| Статус | Chip: new / ready / closed / cancelled |
| Способ оплаты | payment_method |
Фильтры
- Диапазон дат (from / to)
- Статус (все / closed / cancelled)
Переходы
- Клик по номеру/сумме →
/orders/{id}(карточка заказа)
Состояние «нет заказов»
- «У клиента ещё нет заказов»
Вкладка 4: Группы
Chips групп клиента (static + dynamic).
Отображение
- Chip группы с иконкой типа:
- 🔒 Static (ручное членство)
- ⚙️ Dynamic (по правилам)
- Клик по chip → переход в карточку группы
- Для static-групп: рядом с chip — кнопка «×» → удалить клиента из этой группы (видна только с
customer_groups.edit)
Действия
- «+ Добавить в группу» (если есть
customer_groups.edit) — модалка поиска статических групп → multi-select → добавить. Для dynamic групп недоступно (членство автоматическое)
Пояснение (info-блок)
- Для dynamic групп: «Клиент автоматически добавлен по правилам группы. Чтобы убрать — измените правила»
Режим «Просмотр» (view)
- Все поля readonly
- Кнопки в шапке:
- «Редактировать» →
/customers/{id}/edit(еслиcustomers.edit) - «Удалить» → модалка подтверждения (если
customers.delete+ owner франшизы)
- «Редактировать» →
- При клике «Удалить»:
- Модалка: «Клиент Иван Петров будет удалён. Персональные данные обезличены, но история заказов сохранится. Это действие необратимо.»
- Кнопки: «Отмена» / «Удалить» (красная)
- После успеха → redirect на
/customers+ toast «Клиент удалён»
Режим «Создание» (new)
- Обязательные поля с красной звёздочкой
- Кнопки в шапке:
- «Сохранить» — POST /customers. После успеха → redirect на
/customers/{id}(view) - «Отмена» →
/customers(без сохранения)
- «Сохранить» — POST /customers. После успеха → redirect на
- Вкладки «Заказы» и «Группы» не показываются
- На вкладке «Адреса» — плашка «Сохраните клиента сначала, потом добавьте адреса»
Режим «Редактирование» (edit)
- Поля редактируемы (кроме readonly: source, registered_by, registered_at)
- Кнопки в шапке:
- «Сохранить» — PATCH /customers/{id}
- «Отмена» →
/customers/{id}(view, без изменений)
- Если изменён телефон — на blur происходит pre-flight через
GET /customers/search?phone=...→ если занят, inline-ошибка «Телефон уже используется другим клиентом»
Ошибки при сохранении
| Код от API | Отображение |
|---|---|
VALIDATION_ERROR | Inline-ошибки под конкретными полями |
CUSTOMER_PHONE_TAKEN | Inline-ошибка под phone: «Клиент с таким телефоном уже есть в системе» + ссылка «Открыть его карточку» (требует resolve phone → id, через GET /customers/search) |
CUSTOMER_NOT_FOUND | Toast «Клиент не найден» + redirect на /customers |
FORBIDDEN | Toast «Нет прав» |
| Сеть / 500 | Toast «Не удалось сохранить» + кнопка «Повторить» |
Состояния
| Состояние | Что показываем |
|---|---|
| Загрузка (view) | Skeleton шапки + вкладок |
| Not found (404) | Страница «Клиент не найден или был удалён» + кнопка «← Назад к списку» |
| Сохранение (new/edit) | Кнопка «Сохранить» в loading, форма disabled |
| Ошибка (фатальная) | «Не удалось загрузить клиента» + «Повторить» |
Ролевой доступ (сводно)
| Действие | Владелец франшизы | Партнёр | Обычный сотрудник (c customers.read) |
|---|---|---|---|
| Просмотр | ✅ | ✅ | ✅ |
| Редактирование | ✅ | ✅ | ✅ если есть customers.edit |
| Удаление | ✅ | ❌ | ❌ |
| Merge | ✅ | ❌ | ❌ |
Ссылки
- Бизнес-спека: Клиенты
- Список клиентов
- Карточка группы
- Карточка заказа — переход из вкладки «Заказы»
- Customer Service API
- BR 3.1