# Модели данных Эта страница описывает основные сущности, найденные в `apps/backend/src/Entity` и `apps/cabinet/src/Entity`. В проектах есть много справочных полей; ниже выделены доменные ядра и связи, которые важны для понимания системы. ## Backend ER-схема ```mermaid erDiagram SPECIALIST ||--o{ LOCATION : "id -> specialist_id" SPECIALIST ||--o{ REVIEW : "id -> specialist_id" SPECIALIST ||--o{ SPECIALIST_DOCS : "id -> specialist_id" SPECIALIST ||--o{ SPECIALIST_DCODE_DESCRIPTION : "id -> specialist_id" SPECIALIST }o--o{ STOCK : "join table" RECORD ||--o| ALERT_SMS : "id -> record_id" WIDGET_FORM ||--o{ WIDGET_FORM_INPUT : "id -> widget_form_id" SPECIALIST { int id PK string name string alias int region_id string post string experience bool active bool display_schedule jsonb dcodes } LOCATION { bigint id PK int specialist_id FK bigint dcode bigint department int filial bool online_mode date nearest_date } REVIEW { int id PK int specialist_id FK bool active date date_create string author float rating string source int external_id } SPECIALIST_DOCS { int id PK int specialist_id FK string name string picture bool active string type } SPECIALIST_DCODE_DESCRIPTION { int id PK int specialist_id FK bigint dcode bigint department text content } STOCK { int id PK string name text content date start_date date end_date } RECORD { int id PK int specialist_id string phone datetime create_at string hash json reserve } ALERT_SMS { int id PK int record_id FK datetime date_create text response } WIDGET_FORM { int id PK string name } WIDGET_FORM_INPUT { int id PK int widget_form_id FK string text string type string bitrix24_id int sort } ``` ### Backend: перевод сущностей | Сущность на диаграмме | Русское название | Смысл | | --- | --- | --- | | `SPECIALIST` | Врач | Карточка врача в новом API | | `LOCATION` | Локация приема | Привязка врача к отделению, филиалу и режиму приема | | `REVIEW` | Отзыв | Отзыв о враче | | `SPECIALIST_DOCS` | Документ врача | Сертификат/документ/изображение врача | | `SPECIALIST_DCODE_DESCRIPTION` | Описание врача по `dcode` | Текстовое описание для конкретного кода врача/отделения | | `STOCK` | Акция | Акция, связанная с врачами через `ManyToMany` | | `RECORD` | Запись пациента | Локальная запись факта бронирования | | `ALERT_SMS` | SMS-уведомление | Ответ SMS-провайдера по записи | | `WIDGET_FORM` | Форма виджета | Конструктор формы | | `WIDGET_FORM_INPUT` | Поле формы | Поле формы виджета | ### Backend: ключи связей | Связь | Тип | Ключи | | --- | --- | --- | | Врач -> Локация приема | `OneToMany` / `ManyToOne` | `specialist.id = location.specialist_id` | | Врач -> Отзыв | `OneToMany` / `ManyToOne` | `specialist.id = review.specialist_id` | | Врач -> Документ врача | `OneToMany` / `ManyToOne` | Doctrine создает `specialist_docs.specialist_id -> specialist.id` | | Врач -> Описание по dcode | `ManyToOne` на стороне описания | `specialist_dcode_description.specialist_id -> specialist.id` | | Врач <-> Акция | `ManyToMany` | join-таблица генерируется Doctrine; владелец связи `Stock::$specialist` | | Запись -> SMS-уведомление | `OneToOne` | Doctrine создает `alert_sms.record_id -> record.id` | | Форма виджета -> Поле формы | `OneToMany` / `ManyToOne` | Doctrine создает `widget_form_input.widget_form_id -> widget_form.id` | `Record.specialistId` в backend не является Doctrine-связью с `Specialist`: это логический внешний идентификатор врача, сохраненный как число. ## Backend справочники и контент ```mermaid classDiagram class Department { id did name groupName onlineMode alias active } class Filial { id fid name address regionId siteId company phone email } class PriceDepartment { id name groupId doctCount viewInWeb } class PriceList { id kodoper schname specname speccode priceInfo discprice filial groupId } class SiteService { id name alias regionId anons content faq tags clinics } class Disease { id name alias regionId symptom content tags staffList } class MedicalCenter { id name alias regionId doctors services content } class Article { id name alias doctors services content } class News { id name alias regionId content photos } class Promo { id name alias regionId clinics period } ``` ## Cabinet ER-схема ```mermaid erDiagram CITY ||--o{ FILIAL : "id -> city_id" CITY ||--o{ REVIEW_SOURCE : "id -> city_id" CITY ||--o| BANNER : "id -> city_id" FILIAL ||--o{ REVIEW_SOURCE : "id -> filial_id" CATEGORY_PAGE ||--o{ PAGE : "id -> category_id" RECORD ||--o| ALERT_SMS : "id -> record_id" WIDGET_FORM ||--o{ WIDGET_FORM_INPUT : "id -> widget_form_id" CITY { int id PK string name int region_id int time_zone } FILIAL { int id PK int city_id FK int fid string name string address int site_id bool active string company } REVIEW_SOURCE { int id PK int city_id FK int filial_id FK string name int count_row bool active float rating date date_create } BANNER { int id PK int city_id FK string href string src bool active } CATEGORY_PAGE { int id PK string name bool active } PAGE { int id PK int category_id FK string name string alias text description bool active } RECORD { int id PK int specialist_id string phone datetime create_at string hash json reserve } ALERT_SMS { int id PK int record_id FK datetime date_create text response } WIDGET_FORM { int id PK string name } WIDGET_FORM_INPUT { int id PK int widget_form_id FK string text string type string bitrix24_id int sort } ``` ### Cabinet: перевод сущностей | Сущность на диаграмме | Русское название | Смысл | | --- | --- | --- | | `CITY` | Город | Региональная привязка кабинета | | `FILIAL` | Филиал | Клиника/филиал, привязанный к городу | | `REVIEW_SOURCE` | Источник отзывов | Внешний источник рейтинга/отзывов по городу или филиалу | | `BANNER` | Баннер | Региональный баннер | | `CATEGORY_PAGE` | Категория страниц | Группа CMS-страниц | | `PAGE` | Страница | CMS-страница | | `RECORD` | Запись пациента | Локальная запись факта бронирования | | `ALERT_SMS` | SMS-уведомление | Ответ SMS-провайдера по записи | | `WIDGET_FORM` | Форма виджета | Конструктор формы | | `WIDGET_FORM_INPUT` | Поле формы | Поле формы виджета | ### Cabinet: ключи связей | Связь | Тип | Ключи | | --- | --- | --- | | Город -> Филиал | `OneToMany` / `ManyToOne` | Doctrine создает `filial.city_id -> city.id` | | Город -> Источник отзывов | `OneToMany` / `ManyToOne` | Doctrine создает `review_source.city_id -> city.id`, `nullable=false` | | Город -> Баннер | `OneToOne` | Doctrine создает `banner.city_id -> city.id` | | Филиал -> Источник отзывов | `OneToMany` / `ManyToOne` | Doctrine создает `review_source.filial_id -> filial.id` | | Категория страниц -> Страница | `OneToMany` / `ManyToOne` | Doctrine создает `page.category_id -> category_page.id`, `nullable=false` | | Запись -> SMS-уведомление | `OneToOne` | Doctrine создает `alert_sms.record_id -> record.id` | | Форма виджета -> Поле формы | `OneToMany` / `ManyToOne` | Doctrine создает `widget_form_input.widget_form_id -> widget_form.id` | `Record.specialistId`, `SpecialistView.dcode`, `LocationView.specialistId`, `PriceList.filial`, `PriceList.groupId`, `PriceList.kodoper` в cabinet используются как логические внешние ключи и фильтры, но не оформлены как Doctrine relations. ## Cabinet представления и справочники ```mermaid classDiagram class SpecialistView { id name speciality category experience description alias dcode regionId kodoper acceptsDms } class LocationView { id dcode department filial specialistId onlineMode active nearestDate } class PriceDepartment { id name groupId groupName doctCount viewInWeb } class PriceList { id kodoper schname specname speccode priceInfo discprice filial groupId } class User { id email roles uid token fullName phone confirm createdAt lastActivityAt } class Usrlog { id pcode agent clientIp method createdAt } class DirectCompany { id name companyId city } class DirectReport { id date adGroupId campaignId adId impressions clicks cost conversions } ``` ## Общие доменные понятия - `Specialist` / `SpecialistView` - врач. В `backend` это полноценная сущность с явными связями; в `cabinet` это view-модель для чтения. - `Location` / `LocationView` - где и как врач принимает. - `PriceList` и `PriceDepartment` - прайс и группы услуг. - `Record` - запись пациента, хранит payload бронирования в `reserve`. - `AlertSms` - SMS-уведомление по записи. - `Filial` и `Department` - филиалы и отделения. - `Review` и `ReviewSource` - отзывы и источники отзывов. - `WidgetForm` и `WidgetFormInput` - динамические формы для виджетов. ## Особенности модели - В `backend` используются PHP attributes Doctrine, в `cabinet` - annotations. - Часть связей хранится не как Doctrine relation, а как внешние идентификаторы (`dcode`, `fid`, `did`, `regionId`, `groupId`, `kodoper`). Это важно: не все связи можно увидеть по `ManyToOne`. - `backend` подключается к нескольким источникам данных: основной PostgreSQL, Bitrix MySQL и базе cabinet. - `cabinet` содержит view-сущности (`SpecialistView`, `LocationView`), поэтому часть данных, вероятно, приходит из SQL views или синхронизированных таблиц.