Назначение
Создание пользователя. Поддерживает два режима: создание через Keycloak (saga) или с готовыми UserIdentities (Bitrix24, AmmoCRM).
Цели
- Создание пользователя в БД
- Назначение ролей
- Привязка identity providers (если переданы)
- Запуск CreateEmployee Saga (если UserIdentities пусты — создание через Keycloak)
- Публикация AfterUserCreated через Outbox
Command: CreateUserCommand
Входные данные
| Поле | Тип | Обязательное | Описание |
|---|
| TenantId | Guid | Да | Идентификатор тенанта |
| Email | string | Да | Email |
| PhoneNumber | string? | Нет | Телефон |
| Name | FullName | Да | ФИО |
| UserIdentities | IReadOnlyCollection<ProviderIdPairDomainModel>? | Нет | Provider + ProviderUserId. Если пусто — пользователь создаётся через Keycloak (saga) |
| RoleIds | IReadOnlyCollection<long> | Да | Идентификаторы ролей |
| IdempotencyKey | Guid | Да | Ключ идемпотентности |
ProviderIdPairDomainModel
| Поле | Тип | Описание |
|---|
| Provider | IdentityProvider | Keycloak, Bitrix24, AmmoCRM |
| ProviderUserId | string | ID пользователя у провайдера |
Result: CreateUserCommandResult
| Поле | Тип | Описание |
|---|
| UserId | Guid | Идентификатор созданного пользователя |
Валидация
- Тенант должен существовать
- UserIdentities не должны содержать Keycloak (для Keycloak используется saga)
- Email уникален глобально (не только в рамках TenantId)
- Каждый (Provider, ProviderUserId) уникален глобально
- Все RoleIds должны существовать
- При пустых UserIdentities создаётся saga CreateEmployee (CreateKeycloakUser → UpdateUserKeycloakId)
Бизнес-логика
- Проверить существование тенанта.
- Если UserIdentities содержит Keycloak — ошибка.
- Начать транзакцию (Serializable).
- Проверить уникальность Email (FindBy Email).
- SetTenantContext(request.TenantId).
- Для каждого UserIdentity проверить уникальность (Provider, ProviderUserId).
- ValidateAndGetRoleEntities — проверить, что все RoleIds существуют.
- Создать UserEntity (Status = Pending).
- Если UserIdentities не пусты — создать UserIdentityEntity для каждого.
- Создать UserRoleReferenceEntity для каждой роли.
- Создать CreateEmployeeSaga (CreateKeycloakUser, UpdateUserKeycloakId) в SagaOutbox.
- Publish AfterUserCreatedNotification.
- Commit.
- Вернуть UserId.
События
- AfterUserCreatedNotification — публикуется после commit. Handler формирует AfterUserCreatedEvent и записывает в Outbox.
- CreateEmployee Saga — создаётся в Outbox, выполняется асинхронно (CreateKeycloakUser, UpdateUserKeycloakId).