> ## Documentation Index
> Fetch the complete documentation index at: https://docs.yume.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Модель пользователя и членство в компании

> Единая учётная запись пользователя, общая для всех компаний и не привязанная к одной из них, и отдельная запись членства на каждую компанию: глобальные флаги против вычисляемых ролей в компании, определение компании по токену, менеджер создания учётных записей и автоматические действия при сохранении.

Полный перечень полей — в [глоссарии](/ru/logic/user/model-glossary).

## Что описывает эта страница

Эта часть модуля отвечает за то, **кто такой пользователь** в системе и **как он связан с конкретной компанией**. Здесь один человек — это одна учётная запись с единым глобальным паролем, общая для всех компаний и не привязанная к какой-то одной из них. Принадлежность к компании и роль внутри неё описываются отдельной записью членства, поэтому один и тот же человек может быть клиентом в одной компании, сотрудником в другой и субарендатором в третьей — не заводя новых учётных записей и не меняя пароль.

## Модель данных

### Пользователь

Центральная сущность — Пользователь. Это телефон-центричная учётная запись: основным идентификатором для входа служит телефон, но у записи также есть необязательные имя пользователя (логин) и электронная почта.

| Поле                             | Тип                   | Назначение                                                                          |
| -------------------------------- | --------------------- | ----------------------------------------------------------------------------------- |
| Идентификатор                    | число                 | первичный ключ                                                                      |
| Имя пользователя (логин)         | текст до 150 символов | необязательное, может отсутствовать; проверяется валидатором формата                |
| Телефон                          | текст                 | основной идентификатор для входа; может отсутствовать                               |
| Электронная почта                | текст                 | пустая строка при сохранении автоматически превращается в «нет значения»            |
| Пароль (хэш)                     | текст                 | единый глобальный пароль человека                                                   |
| Имя, Фамилия                     | текст                 | обязательны при создании учётной записи                                             |
| Дата рождения                    | дата                  | необязательное поле профиля                                                         |
| Аватар                           | изображение           | при изменении у уже существующей записи автоматически пересчитывается миниатюра     |
| Доп. данные                      | JSON                  | произвольные дополнительные поля профиля                                            |
| Активен                          | флаг                  | стандартный признак активности учётной записи                                       |
| Персонал (глобально)             | флаг                  | глобальный доступ в админку                                                         |
| Суперпользователь (глобально)    | флаг                  | глобальные права                                                                    |
| Субарендатор (глобально)         | флаг                  | глобальный признак                                                                  |
| Группа (роль)                    | связь                 | устаревающая глобальная привязка роли (помечена как подлежащая переносу в членство) |
| Программа лояльности             | связь                 | тариф лояльности человека                                                           |
| Последний вход, Дата регистрации | дата/время            | служебные даты; список сортируется по дате регистрации по убыванию                  |

<Note>
  Учётные записи — общая (глобальная) модель, одна для всех компаний. Пароль тоже общий: сменив его, человек меняет вход во все компании, где он состоит.
</Note>

При сохранении учётной записи срабатывают две автоматические поправки: если у уже существующей записи аватар был изменён — по нему строится миниатюра; если электронная почта пришла пустой строкой — она приводится к отсутствию значения (это важно для темы дубликатов, см. ниже).

### Членство пользователя в компании

Роль и права человека **внутри конкретной компании** описывает отдельная запись — Пользователь компании (членство). Именно она, а не глобальные флаги, определяет, кем человек является в данной компании.

| Поле                       | Тип   | Назначение                          |
| -------------------------- | ----- | ----------------------------------- |
| Компания                   | связь | к какой компании относится членство |
| Пользователь               | связь | чьё это членство                    |
| Суперпользователь компании | флаг  | полные права в рамках компании      |
| Персонал компании          | флаг  | сотрудник (доступ к CRM)            |
| Субарендатор               | флаг  | признак субаренды в компании        |
| Группа (роль)              | связь | роль внутри компании                |
| Доп. данные                | JSON  | произвольные поля членства          |

Комбинация «компания + пользователь + группа» должна быть уникальной.

### Вспомогательные сущности

* **Группа компании** расширяет стандартную группу прав, добавляя привязку к компании и отображаемое название роли (связь один-к-одному со стандартной группой).
* **Доверенность** — документ, связанный один-к-одному с пользователем, с уникальным номером и датой; доверенности могут выстраиваться в иерархию через ссылку на родительскую доверенность (родителя нельзя удалить, пока есть дочерние).

## Роли: глобальные против ролей в компании

Ключевая идея: у пользователя есть глобальные флаги (персонал, суперпользователь, субарендатор), но в обычной работе система смотрит не на них, а на **вычисляемые свойства в контексте текущей компании**. Каждое такое свойство:

1. Определяет, какая компания сейчас активна для запроса.
2. Если компания не определена (запрос идёт вне компании) — возвращает соответствующий **глобальный** флаг.
3. Иначе — читает членство человека в этой компании и возвращает роль оттуда, кэшируя результат, чтобы не обращаться к базе на каждый вопрос.

| Свойство                   | Что возвращает в компании          | Что возвращает вне компании       |
| -------------------------- | ---------------------------------- | --------------------------------- |
| Суперпользователь компании | есть ли членство с полными правами | глобальный флаг суперпользователя |
| Персонал компании          | есть ли членство сотрудника        | глобальный флаг персонала         |
| Субарендатор компании      | есть ли членство субарендатора     | глобальный флаг субарендатора     |
| Группа в компании          | роль из членства                   | глобальная группа                 |

<Info>
  Ответы этих свойств кэшируются по паре «компания + пользователь» на короткое время (по умолчанию около 15 секунд). Отдельного принудительного сброса этих кэшей при смене роли в компании нет — обновлённая роль начинает действовать только после истечения короткого срока жизни кэша. (Пересохранение учётной записи и изменение её групп прав сбрасывают отдельный кэш аутентификации пользователя, но не эти кэши ролей в компании.)
</Info>

Дополнительно у пользователя есть удобная проверка «есть ли хотя бы одно из перечисленных прав» — она возвращает утвердительный ответ, если человек обладает любым правом из переданного списка, и вычисляемое «полное имя» (имя плюс фамилия).

## Определение компании пользователя

Отдельный механизм отвечает на вопрос «в какую компанию направить этого пользователя, если компания не задана хостом или заголовком запроса». Это используется при разрешении компании по токену для мобильных и API-клиентов.

Логика такова:

* Если компания уже определена контекстом запроса — возвращается именно она.
* Если нет — система ищет членства этого человека и берёт **одно** из них, кэшируя результат на короткое время (около минуты). Если членств нет — компания не определяется.

<Warning>
  Когда компания не задана, а человек состоит **в нескольких** компаниях, выбор детерминированный, но не «умный»: берётся членство с наибольшим внутренним идентификатором компании. Практически это означает, что при нескольких компаниях пользователь может быть направлен не в ту компанию, которую ожидал. Надёжный способ адресовать нужную компанию — задавать её явно (хостом или заголовком запроса).

  Явное указание работает только для компаний, где человек действительно состоит: для остальных обращение будет отклонено проверкой участия — см. [«Как система определяет вашу компанию»](/ru/logic/user/active-company).
</Warning>

## Создание учётных записей

За создание отвечает менеджер пользователей с несколькими способами:

* **Получить пользователя** — находит учётную запись по переданным признакам или возвращает ошибку «не найдено».
* **Создать пользователя** — простое создание без тарифа лояльности.
* **Создать клиента** — создание с автоматическим назначением **самого дешёвого** тарифа лояльности (берётся тариф с наименьшей ценой).
* **Создать суперпользователя** — сразу с активностью и глобальными флагами персонала и суперпользователя.

## Автоматические действия при сохранении

С учётной записью связаны автоматические действия, которые срабатывают без явного вызова.

### Создание или привязка CRM-клиента

После сохранения учётной записи система, находясь в контексте компании, пытается сопоставить пользователю CRM-клиента. Это действие **пропускается**, если:

* запрос идёт вне компании;
* человек является персоналом компании;
* человек является субарендатором в компании;
* у человека уже есть привязанный к нему CRM-клиент;
* у человека нет телефона.

Иначе телефон нормализуется (удаляются скобки, пробелы и дефисы) и по нему ищется клиент компании:

* если клиент найден и у него не проставлен или отличается пользователь/почта — клиент привязывается к этому пользователю и ему проставляется почта;
* если клиент найден — на этом всё;
* если клиент не найден и учётная запись только что создана — заводится новый клиент с этим телефоном, именем «фамилия имя» и почтой.

### Обновление кэша аутентификации

После сохранения учётной записи сбрасывается кэш этого пользователя и заново собирается общий список активного персонала (перечень идентификаторов активных сотрудников, используемый в аутентификации). Исключение: если сохранение затронуло **только** отметку о последнем входе, пересчёт не выполняется — такое изменение считается несущественным для прав.

### Сброс кэша при смене групп прав

При добавлении, удалении или очистке групп прав у пользователя его кэш аутентификации также сбрасывается — как для самого пользователя, так и для всех затронутых учётных записей.

## Админка пользователя

Пользователь зарегистрирован в админке на базе Unfold с отдельными формами создания, редактирования и смены пароля.

* Список показывает идентификатор, имя, фамилию, телефон, логин, глобальные флаги персонала и суперпользователя и группу; по умолчанию сверху идут записи персонала, затем сортировка по идентификатору.
* Даты последнего входа и регистрации доступны только для чтения.
* Поля разбиты на блоки: учётные данные (логин, телефон, почта, пароль, группа), персональная информация с глобальными флагами и важные даты.
* Список в админке строится через отдельный служебный менеджер выборки (простой менеджер без дополнительной фильтрации), а не через основной менеджер учётных записей.

## Связанные страницы

<CardGroup cols={2}>
  <Card title="Глоссарий: Модель пользователя и членство в компании" icon="book" href="/ru/logic/user/model-glossary">
    Полный перечень полей учётной записи, членства и вспомогательных сущностей.
  </Card>

  <Card title="Пользователи и доступ" icon="user-lock" href="/ru/logic/user">
    Обзорная страница раздела: аккаунт, участие в компании, роли и права.
  </Card>

  <Card title="Проблемы и логические ошибки" icon="bug" href="/ru/logic/user/issues">
    Сводка известных подводных камней и логических ошибок всего модуля.
  </Card>

  <Card title="Вход в систему" icon="right-to-bracket" href="/ru/logic/user/login">
    По каким данным можно войти — телефон, логин или адрес почты — и откуда берутся права.
  </Card>

  <Card title="Сессии и срок действия входа" icon="key" href="/ru/logic/user/sessions">
    Сколько живёт вход, как он продлевается и когда потребуется войти заново.
  </Card>

  <Card title="Как система определяет вашу компанию" icon="route" href="/ru/logic/user/active-company">
    Определение компании по адресу сайта или по аккаунту и что делать, если компании ещё нет.
  </Card>

  <Card title="Профиль и управление сотрудниками" icon="id-card" href="/ru/logic/user/profile">
    Редактирование своего профиля, добавление сотрудников и назначение им ролей.
  </Card>

  <Card title="Сброс пароля по коду" icon="unlock-keyhole" href="/ru/logic/user/password-reset">
    Восстановление доступа по коду из письма, с ограничением частоты запросов.
  </Card>

  <Card title="Вход через Google" icon="google" href="/ru/logic/user/google-login">
    Вход по аккаунту Google и связывание его с существующим профилем.
  </Card>

  <Card title="Уровни лояльности и карты" icon="star" href="/ru/logic/user/loyalty">
    Уровни лояльности клиентов и оформление их карт для Apple и Google Wallet.
  </Card>
</CardGroup>
