Клиенты

Источник требований

Референс

Клиенты — отдельная сущность, не связанная с сотрудниками. Единый пул на уровне франшизы: владелец бренда и все партнёры-франчайзи видят всех клиентов одной франшизы. На POS кассир ищет клиента по телефону и прикрепляет к заказу. В админке ведётся полноценная CRM-карточка с историей заказов.

Эта спека — фундамент для следующих модулей Phase 3 (Loyalty & Marketing): баллы, скидки, промо-кампании, подарочные карты.


Сущность «Клиент»

ПолеОбязательностьОписание
ИмяОбязательноИспользуется в карточке, на чеке (в будущем), в рассылках
ФамилияНеобязательно
ТелефонОбязательноНормализованный формат E.164 (+7XXXXXXXXXX). Основной ключ поиска
EmailНеобязательноLower-case. Валидация по RFC 5322
Дата рожденияНеобязательноИспользуется в промо «именинники ±N дней» (BR 3.4+) и для статистики
ПолНеобязательноМужской / Женский / Другое / Не указан
ЗаметкиНеобязательноСвободный текст кассира или менеджера
Источник регистрацииОбязательноPOS / Веб / Мобильное приложение / Админка / Импорт
Кто завёлНеобязательноСотрудник (кассир / админ), создавший запись. Для аудита
Согласие на обработку ПДНеобязательноДата отметки о согласии (ФЗ-152). Само поле есть, процесс сбора вне MVP — см.
СтатусОбязательноАктивен / Удалён (soft delete)

Нет поля «Номер карты лояльности» в MVP

В YumaPOS у клиента есть отдельный номер карты лояльности (физическая карта). В BR 3.1 это не вводится — появится в BR 3.2 «Баллы лояльности» когда будет Loyalty Service.


Адреса клиента

У одного клиента может быть несколько адресов доставки (дом / работа / родителям). Отдельная сущность — customer_addresses.

ПолеОбязательностьОписание
ГородОбязательно
УлицаОбязательно
КвартираНеобязательно
ПодъездНеобязательно
ЭтажНеобязательно
Код домофонаНеобязательно
ЗаметкиНеобязательно«Оставить у консьержа», «позвонить за 5 минут»
DefaultОбязательноРовно один адрес на клиента может быть default

Один default одновременно

При отметке нового адреса как default — предыдущий default автоматически снимается. Переключение в одной транзакции.


Источники регистрации

Откуда клиент попал в систему. Нужно для аналитики источников и для фильтров в списке клиентов.

ИсточникКогда применяетсяДоступен в MVP
Админка (admin)Владелец/партнёр/менеджер завёл клиента вручную
POS (pos)Кассир завёл через quick-create при заказе
Веб-сайт (web)Клиент сам зарегистрировался на сайте❌ — 3.6
Мобильное приложение (mobile)Клиент сам зарегистрировался в приложении❌ — BR 3.5/3.6
Импорт (import)Массовый импорт из Excel❌ — отдельная BR

Операции с клиентом

Создание

Полная форма в админке (Владелец франшизы, Владелец партнёра, или сотрудник с customers.edit):

  • Все поля сущности + блок адресов (можно добавить адреса сразу или позже)
  • Чекбокс «Клиент дал согласие на обработку ПД» — если отмечен, пишется consent_signed_at

Quick-форма на POS (Кассир с customers.create_quick):

  • Только Телефон и Имя обязательные
  • Опционально — Email и Дата рождения
  • Остальные поля пустые (можно будет дополнить в админке позже)
  • После создания — клиент автоматически прикрепляется к текущему заказу

Редактирование

  • Владелец франшизы/партнёра с customers.edit может менять любые поля кроме id, franchise_id, registered_at, registered_by
  • Изменение телефона проверяется на уникальность per franchise_id (см. Бизнес-правила)

Soft delete + анонимизация

Физическое удаление клиента запрещено — есть связи с заказами (FK из orders.customer_id), плюс требования 54-ФЗ по хранению истории транзакций.

При запросе на удаление (кнопка «Удалить» в карточке, доступна только Владельцу франшизы с customers.delete):

  1. deleted_at = now()
  2. PII обезличиваются: имя → «Удалён», фамилия → null, телефон → обезличенный (с сохранением уникальности), email → null, заметки → null, ДР → null
  3. Адреса очищаются (удаляются записи)
  4. Связь с заказами через customer_id сохраняется — история заказов остаётся видна в аналитике, но клиент анонимен

Это удовлетворяет требование ФЗ-152 «право на забвение» — персональные данные удалены, но обезличенная транзакционная история сохранена для учёта.

Объединение дубликатов (merge)

Если клиент случайно завёлся дважды (например, кассир не нашёл по другому формату телефона), есть операция объединения:

  • Выбирается целевой клиент (остаётся) и источник (soft-deleted)
  • На целевого переносятся: адреса, привязки в заказах
  • Источник становится deleted_at = now() с обезличенными PII
  • Доступна только Владельцу франшизы через customers.edit

Отложено в MVP

UI объединения дубликатов (модалка сравнения двух записей, предпросмотр результата) — отдельная BR. В MVP операция доступна только через API для ручных сценариев.


Привязка клиента к заказу (POS flow)

Заказ может быть анонимным (заказ на вынос без привязки) или именным (привязан к клиенту).

Бизнес-flow на POS

  1. Кассир на экране заказа нажимает «Клиент»
  2. Появляется модалка поиска: поле для ввода телефона
  3. По мере ввода система нормализует номер в E.164 (89991234567+79991234567) и ищет в базе по franchise_id
  4. Если найден:
    • Показываем карточку-мини: имя + chips групп клиента + LTV (сумма закрытых заказов) + бейдж «ДР скоро» если день рождения в ±14 дней
    • Кнопка «Прикрепить» → клиент связывается с текущим заказом
  5. Если не найден:
    • Предложение «Создать нового клиента»
    • Quick-форма: телефон (уже введён) + имя (обязательно) + опционально email, ДР
    • После создания клиент автоматически прикрепляется к заказу

Что кассир видит на экране заказа после прикрепления

  • Имя клиента (крупно, сверху заказа)
  • Chips групп клиента
  • Кнопка «Открепить клиента» — работает до закрытия заказа

Что кассир ПОКА НЕ видит на POS

  • Скидок по клиенту — в MVP BR 3.1 их нет. Появятся в BR 3.3+ (простые скидки), BR 3.4 (промо)
  • Баллов лояльности — BR 3.2+
  • Подарочных карт, кредитного счёта — BR 3.7/3.8

Список клиентов (в админке)

Колонки

  • ФИО (фамилия + имя)
  • Телефон
  • Email
  • Дата рождения
  • Дата регистрации
  • Источник регистрации (chip)
  • Группы (chips)
  • LTV (сумма всех закрытых заказов клиента)

Фильтры

  • По группе
  • По источнику регистрации (POS / Админка / …)
  • По диапазону даты регистрации

Поиск

  • По подстроке ФИО / телефона / email (единое поле поиска — ищет по всем трём)

Сортировка

  • По умолчанию — по дате регистрации (новые сверху)

Пагинация

  • 20 записей на страницу

Особенности отображения

  • Клиенты с deleted_at IS NOT NULL — не отображаются в основном списке. Отдельного фильтра «Удалённые» в MVP нет

Карточка клиента

Шапка карточки

  • Имя + телефон
  • Chips групп
  • Бейджи (если применимо): «ДР ±14 дней», «Новый клиент» (первый месяц), «Нет заказов»

Вкладки

ВкладкаСодержимоеКто видит
ПрофильВсе поля клиента + кнопки «Редактировать» / «Удалить»Все с customers.read
АдресаСписок адресов + CRUD + отметка «Default»Все с customers.read, редактирование — customers.edit
ЗаказыИстория заказов клиента — дата / ТТ / сумма / статус. Фильтр по датам. Ссылка на карточку заказаВсе с customers.read и orders.read
ГруппыChips групп. Возможность добавить/убрать из статической группы (для динамических — read-only, рассчитываются по правилам)Все с customers.read, редактирование — customer_groups.edit

Сайдбар карточки (информационный блок)

  • LTV — сумма закрытых заказов
  • Средний чек — LTV / количество заказов
  • N заказов — всего закрытых
  • Дней с последнего визита — рассчитывается от даты последнего заказа

Отложено в MVP

Вкладки «Баллы», «Транзакции баллов», «Промокоды», «Подарочные карты», «Кредит» появятся в следующих BR Phase 3. В BR 3.1 — только четыре вкладки выше.


Бизнес-правила

  1. Формат телефона — E.164. На входе (создание, редактирование, поиск) телефон нормализуется: 89991234567, +7 (999) 123-45-67, 79991234567+79991234567. В хранилище — всегда один формат.
  2. Уникальность телефона per франшиза. Два активных клиента с одним телефоном в рамках одного franchise_id недопустимы. Если кассир вводит телефон существующего клиента — POS предлагает «Использовать существующего».
  3. Email без уникальности. Один адрес может использоваться несколькими членами семьи, у агентов доставки — один корпоративный адрес.
  4. Soft delete + анонимизация — единственный способ удаления. Физический DELETE из БД запрещён.
  5. Один клиент — в нескольких группах. Принадлежность к статическим и динамическим группам не взаимоисключается.
  6. Клиент — строго в одной франшизе. Между франшизами клиенты не пересекаются. Два разных бренда с одинаковым клиентом хранят две разные записи.
  7. Frontend-пост-уведомление после quick-create на POS: кассиру показывается «Клиент создан. Убедитесь что согласие на обработку ПД получено». Отметку ставит позже админ в админке — это compliance-паттерн.

Влияние franchises.type на раздел

В отличие от раздела «Юр. лица» (скрытого для type=individual — см. Юридические лица), раздел «Клиенты» виден всегда — и в corporate, и в individual режиме франшизы.

Scope клиентов — по franchise_id, идентичен в обоих режимах. Разница только в том что в individual нет партнёров-франчайзи — соответственно, не с кем делить «общий пул». Технически API, permissions, БД-уровневый scope не имеют ни одной особой ветки для type=individual.

Для реализации

При реализации Customer Service ни в коде, ни в миграциях не должно быть if franchise.type == individual — scope всегда по franchise_id. Отличие только в UI в разделе «Юр. лица» (уже реализовано в другом модуле).


Ролевая матрица

ДействиеВладелец франшизыВладелец партнёраОбычный сотрудникPermission
Список клиентов в админке✅ (все той же франшизы)customers.read
Карточка клиентаcustomers.read
Создание в админке (полная форма)customers.edit
Редактирование клиентаcustomers.edit
Soft delete (анонимизация)customers.delete
Объединение дубликатовcustomers.edit + только owner франшизы
Поиск клиента на POS✅ Кассир — customers.create_quick (включает read своей франшизы)
Quick-create на POS✅ Кассир — customers.create_quick
Прикрепить клиента к заказу✅ Кассир — customers.create_quick

Почему customers.create_quick, а не customers.edit

Кассир не должен иметь доступ к списку всех клиентов в админке (это PII). Но он должен уметь создавать клиента при заказе и искать существующего по телефону. Поэтому выделяется отдельный permission, который даёт только эти операции на POS — без доступа к админке.

Подробно ролевая модель — Ролевая модель. Новые permissions добавляются в каталог разделов в Роли.


Пустые состояния

Клиентов пока нет

  • Первое посещение раздела — центральный блок «Клиентов пока нет. Добавьте первого клиента или дождитесь пока кассир заведёт через POS».
  • Кнопка «Создать клиента» (если есть customers.edit)

Поиск не дал результатов

  • «Клиентов по этому запросу не найдено. Попробуйте другой телефон / имя / email»
  • В POS-модалке поиска — предложение «Создать нового»

Отложено в MVP

ФичаКуда уйдёт
UI объединения дубликатовОтдельная BR 3.X (после MVP)
Автообнаружение дубликатов («возможно это один клиент»)Отдельная BR
Клубы/статусы как отдельный tag на карточкеНе планируется — реализуется через группы
Импорт клиентов из ExcelОтдельная BR 3.X (с учётом compliance)
Вкладка «Баллы» и «Транзакции баллов»BR 3.2
Вкладка «Подарочные карты»BR 3.7
Кредитный счётBR 3.8
Массовые операции (массовая рассылка, массовое перенесение в группу)Отдельная BR
LTV/когортная аналитика, customer revenue reportОтдельная BR (после накопления данных)

Открытые вопросы

Процесс сбора согласия на обработку ПД (ФЗ-152)

Поле consent_signed_at введено в сущности. Как именно собирается согласие (галочка в POS с аудио-записью / бумажная форма у кассира / электронная подпись через Госуслуги) — не определено. Это compliance-задача (юристы + продукт). В BR 3.1 фиксируем только наличие поля, UX/процесс — отдельной BR.

UI объединения дубликатов

В MVP операция merge доступна только через API. Интерфейс в админке (две колонки «Источник» и «Цель» + предпросмотр + подтверждение) — отдельная BR.


Связи с другими модулями

  • Заказы — заказ может быть привязан к клиенту через customer_id. Отображается в карточке заказа. При закрытии заказа — событие, которое триггерит пересчёт принадлежности к группам (см. Группы клиентов)
  • Группы клиентов — сегментация для маркетинга. Динамические группы пересчитываются по customer.updated и order.closed
  • Роли — добавляются permissions customers.read / customers.edit / customers.delete / customers.create_quick и customer_groups.read / customer_groups.edit в каталог разделов бэк-офиса и в POS-операции
  • Торговые точки — адреса клиентов могут быть связаны с delivery_zones (для правил групп «по зоне доставки»)
  • Customer BFF (мобильное приложение и сайт клиента) — пока не подключён. Появится в BR 3.5/3.6: регистрация клиента с внешней стороны, просмотр профиля, истории заказов

Ссылки