feat: migrate to VitePress from monorepo docs, add test-contour section

This commit is contained in:
sova-bootstrap
2026-05-28 12:29:31 +03:00
parent e90dfe1bd4
commit e3e438df68
76 changed files with 11998 additions and 60 deletions
+474
View File
@@ -0,0 +1,474 @@
# Модели данных
Эта страница описывает основные сущности, найденные в `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 или синхронизированных таблиц.