Files
docs/data-model.md

475 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Модели данных
Эта страница описывает основные сущности, найденные в `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 или синхронизированных таблиц.