---
# System prepended metadata

title: Вопросы по проекту простой CRM "+Агент"
tags: [+AgentCRM]

---

---
tags: +AgentCRM
---

# Вопросы по проекту простой CRM "+Агент"

## Вопросы по предметной области

#### 1. Нужна ли отдельная роль в системе "Администратор"? Если да, то чем она будет отличаться от агента, и что делать, если администратор решил сам продать объект

- **Ответ**: да, роль нужна. Администратор не сможет самостоятельно продавать объект.


#### 2. Решить следующую проблемную ситуацию. Оплата объявления происходит за счёт средств с кошелька агента. Администратор же может создать объект, прикрепить агента и без его согласия за его деньги выгружать этот объект. Так же, администратор может создавать муляжи и прикреплять их к другим объектам. Видимо, агент должен как-то соглашаться на установку его в главным в том или ином объявлении, либо нужна какая-то связь между агентом и администратором.

- **Ответ**: Делаем рабочие группы. Главный агент группы приглашает администраторов и агентов. В рамках группы администратор может свободно добавлять главных агентов к создаваемым объявленим. За выгрузку объявлений платит главный агент. Рабочая группа назвыается именем главного агента.

#### Перечислить возможные статусы объявления:

- **Ответ**: Активные: "В продаже". Неактивные: "Снят с продажи", "На предварительном договоре" (возможно, будут ещё). Объявления удаляются без возможности восстановления. Также, объявление может быть заблокировано менеджером. В таком случае оно пропадёт с ресурса и с внешних площадок, и видеть его сможет только менеджер.

#### 3. Как будет храниться и предствляться история изменений объявлений?

- **Ответ**: вероятно, для этой функции нужно будет хранить на бекенде названия полей. Для этого можно реализовать аннотацию "Label", как это делается C#. Хранить в историю придётся сразу значение (и новое, и старое), так как наименования аттрибутов в коде могут измениться.
- **Решить в дальнейшем**: при реализации функции просмотра изменений нужно будет решить, как будут храниться и отображаться сложные (не примиивные) поля: "Помещения", "Техника", "Статус" и другое.

#### 4. Как будут представляться в системе доли и части?
 
- **Ответ**: Доля может быть у типов "Квартира" и "Дом". каждая доля - это отдельная запись в истории объектов недвижимости. Тем не менее, сведения об объекте (площадь, количество комнат и т. д.) в разных долях в рамках одного объект будут одинаковыми и без проблем смогут подтягиваться из истории объектов даже если продавалась другая доля. Идентифицировать долю не обязательно, достаточно идентифицировать объект недвижимости. "Доля квартиры" и "Доля дома" выделяем на фронтенде в отдельные типы, на бекенде оставляем их как аттрибут. Часть дома" выделяем в подтип "Дома", так-же как "Коттедж", "Дача" и др.
- **Мысли**: *Уже не актуально, есть ответ* Суть вопроса с частями и долями домов сводится к следующему: как определить продажу части в доме? Дом либо может быть разделен на несколько кадастровых объектов (квартиры), либо в нем может продаваться доля, либо может продаваться доля в части дома.
Проблема для пользователя заключается в том, что он может запутаться между понятием часть дома (квартира в частном доме) и доля в доме, из-за чего начнётся путаница. Кроме того, жители разделённых домов сами могут не знать, каков номер части, в которой они живут, хотя по документам номер квартиры есть. Люди будут писать рандомные номера и случится та же проблема идентификации.
В Циан же сделаи проще и выделили тип "Часть дома" и туда попадают и доли, и разделенные дома. Нам такой вариант может плохо подойди, так для кадастровой истории важно, что именно продавалось (плюс, долю в объекте невозможно идентифицировать).
Нужно либо решить, как доступно представить и доли, и части, и доли в частях, либо и как корректно получить от пользователя номер его квартиры в частном доме, либо забить на идентификацию для кадастровой истории частей/долей домов и сделать как на Циан.

#### 5. Как будет храниться история объектов (т. е. как будут соотноситься различные объявления за разный период по объекту)

- **Ответ**: Каждое новое объявление по объекту - это новая версия этого объекта. Для каждой новой версии создаётся новая запись в БД и указывается дата создания. Для того, чтобы в дальнейшем собрать воедино эти версии необходим идентификатор объекта. Если такого идентификатора нет, то и отследить историю по объекту будет невозможно. Идентификатор объекта недвижимости - это его адрес.

- **Подводные камни**: Так как мы идентифицируем объекты по адресу, невозможно будет отслеживать историю для объектов с отсутствующим или неправильно заполненным адресом. Речь идёт главным образом о домах, участках и гаражах. Также, проблемой может стать отслеживание долевых объектов. Так в рамках квартиры доли никак не идентифицируются, система в ряде случаев не сможет понять, какая именно доля продаётся (например, если квартира поделена поровну - в системе это выглядит как два объекта с одинаковым адресом и одинаковым значением доли 1/2).

#### 6. Как хранить в системе здания - как отдельной неизменяемой сущностью или как встроенной изменяемой сущностью, отдельной для каждого объекта? Рассмотреть случаи для квартир и для частных домов.

Здания всех типов недвижимости храним как вложенные Entity (т. е. отношением композиции от Объекта к Зданию). Все виды зданий описываются одним классом с enum-полем "Тип".

#### 7. Сформировать список подтипов частного дома

- **Пояснение**: на данный момент это "Дача", "Коттедж", "Таунхаус", "Часть дома". Не хватает того, что посередине. Например, как охарактеризовать дом на "Крыльях Сургута"?
- **Мысли**: Нужно либо отказаться от подробного деления на подтипы и оставить только "Отдельный дом", "Часть дома" и "Таунхас", либо придумать остальные подробные категории.

- **Ответ**: "Отдельный дом", "Дача", "Таунхаус", "Часть дома".

## Вопросы по архитектуре

#### 1. Как реализовать валидацию в постраничной форме создания объявления

- **Ответ**: для нормальной валидации в такой форме нужен шаринг правил валидации между сервером и клиентом, что потребует создания собственной библиотеки валидации на базе `validatorjs`. Чтобы этого избежать, пока откажемся от постраничных форм и заменим их формами, которые открываются постепенно при заполнении полей.

#### 2. Как хранить поля с множественными значениями, такие как "Дополнительный статус", "Ремонт" и др.?

- **Ответ**: Для каждого такого поля создаётся сущность (можно для наглядности вместо аннотации `@Entity` создать аннотацию `@EmbeddedCollectionValue`) и отношение многие к одному. Также, создать менеджер вложенных коллекций `EmbeddedCollectionManager`, который будет содержать записывающие методы массива (`push`, `pop`  и т. д.), но применять их на коллекциях. За создание таких менеджеров будет отвечать репозиторий. После исключения из коллекции желательно удалить. Пример низкоуровневой работы без подобного менеджера содержится в тесте бекенда "Кошелька" `EntityEmbeddedCollection.spec.ts`.

- **Мысли**: После написания ответа нашел способ, как избежать ручного сохранения вложенных сущностей. Пример в указанных тестах. Однако, их все равно нужно вручную удалять, так что менеджер коллекций всё равно необходим.


#### 3. Как хранить поле "Помещения" и подобные сложные поля?

- **Мысли**:
    - Прежде всего, надо задуматься о необходимости таких полей. Как сказано в следующем пункте, для таких полей придется определить отдельное понятие - вложенная сущность; у этого подхода есть ряд проблем. Во-первых, в TypeORM "вложенные сущности" будут семантически конфликтовать с "вложенными значениями" (когда вложенный класс хранится в таблице своего родителя). Во-вторых, добавится +1 таблица в схему обхода.
    - Сложные поля можно хранить как вложенные значаения (`Embedded`) в случае, если они не имеют никаких связей. Если же они содержат связи или вложенные коллекции, то из-за ограничений придётся хранить их как отдельные вложенные сущности (`EmbeddedEntity`). Пример низкоуровневой работы с такой сущностью есть в тесте бекенда "Кошелька" `EntityEmbeddedEntity.spec.ts`. Так как перед назначением вложенную сущность тоже нужно сохранять, для работы с такими сущностями также может потребоваться менеджер `EmbeddedEntityManager`, содержащий методы `set` и `remove`. Для простоты его можно объединить с `EmbeddedCollectionManager`.
- **Ответ**:
    - По итогу, для реализации поля "Помещения" есть два варианта: выделить в отельную вложенную сущность или обойтись без неё; в обоих случаях значения (сами помещения) будут реализованы в форме вложенной коллекции сущностей. Для того, чтобы решить, снова обращаемся к DDD и думаем - а "достойно" ли поле "Помещения" быть выделенной в отдельную сущность? Очевидно, что нет; соответственно, поле стоит предствавить как коллекцию объектов-значений сущности.

#### 4. Как хранить в системе адрес?
- **Ответ**:
    - Можно выделить следующую структуру адреса:
        1. Страна
        2. Субъект
        3. Регион (область, округ, республика, край, город федерального значения); пример: *Кировская Область*, *Москва*
        4. [Муниципальное образование](https://ru.wikipedia.org/wiki/%D0%9C%D1%83%D0%BD%D0%B8%D1%86%D0%B8%D0%BF%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5) (район, городской округ); пример: *Белоярский район*, *Котельнич*, *МО Даниловский*
        5. Район городского округа, город районого/окружного подчинения, посёлок городского типа, сельское поселение и т. д.; пример: *Центральный район*, *Котельнич*, *СНТ Витамин*, *Покровское*
        6. Улица
        7. Дом
    - Наименование каждого из элементов структуры адреса (кроме, пожалуй, номера дома) может измениться, так что нужно сохранять в базу собственные идентификаоры ФИАС и сервиса геолокации
    - Номер квартиры и номер комнаты не включаем в адрес, а оставляем как свойство сущности "Объект". Таким образом, все объекты в одном доме будут
    - Некоторые типы нежилой недвижимости будут также иметь номер (например, гаражи)
    - Общее правило для всех объектов - улица обязательна. Для квартир и комнат также обязателен номер дома.
- **Подводные камни**: вероятно, будут проблемы с отслеживанием гаражей, размещённых в ГСК, так как мы на данный момент не храним ГСК. Для того, чтобы их идентифицировать, необходимо, чтобы пользователи правильно указывали улицу, номер гаража, а также либо номер дома, либо ГСК, либо местоположения (все три варинта плохи)