# Backend: бизнес-сущности и границы (DDD-обзор)

Страница описывает `apps/backend` с точки зрения **предметной области**: какие сущности относятся к одному смысловому блоку, какие HTTP-контроллеры и сервисы их обслуживают, и как устроены фоновые задачи. Это не «каноничное» DDD-приложение с явными bounded context в коде, а **карта домена поверх существующей Symfony-структуры** (`Entity`, `Repository`, `Controller`, `Service`, `Command`, `Message`).

См. также: [архитектура модулей](./backend-architecture.md), [бизнес-сценарии по потокам](./backend-scenarios/index.md), [CRUD контента](./backend-content-crud.md), [модели данных](../data-model.md), [потоки данных](../flows.md).

## Карта контекстов

```mermaid
flowchart TB
  subgraph identity[Идентичность и доступ]
    User[User]
  end

  subgraph org[Организация клиники]
    Filial[Filial]
    Department[Department]
    MedicalCenter[MedicalCenter]
  end

  subgraph staff[Врач, локации, расписание]
    Specialist[Specialist]
    Location[Location]
    Schedule[Schedule]
    Docs[SpecialistDocs]
    DcodeDesc[SpecialistDcodeDescription]
    Docinfo[WebGetDocinfo]
    Idoctor[Idoctor]
  end

  subgraph booking[Запись и уведомления]
    Record[Record]
    AlertSms[AlertSms]
    MarkKiosk[MarkKiosk]
  end

  subgraph pricing[Прайс]
    PriceList[PriceList]
    PriceDepartment[PriceDepartment]
  end

  subgraph content[Контент сайта]
    Article[Article]
    News[News]
    Promo[Promo]
    Disease[Disease]
    SiteService[SiteService]
    Stock[Stock]
  end

  subgraph reputation[Отзывы]
    Review[Review]
  end

  subgraph integrations[Интеграции и утилиты]
    Calltouch[Calltouch API]
    XmlFeed[XML фиды]
    MailCaptcha[Почта / SmartCaptcha]
  end

  Specialist --> Location
  Specialist --> Review
  Specialist --> Docs
  Specialist --> DcodeDesc
  Record --> AlertSms
  PriceList --> PriceDepartment
```

---

## 1. Идентичность и доступ

**Смысл:** учётная запись пользователя API, вход по паролю, JWT, регистрация, смена региона, сценарии с UID/pcode.

| Роль в DDD | Артефакт | Путь / класс |
| --- | --- | --- |
| Агрегат / сущность | `User` | `src/Entity/User.php` |
| Репозиторий | `UserRepository` | `src/Repository/UserRepository.php` |
| Входная точка API | `UserController` | префикс маршрута `/user` |
| Доменные сервисы | `AuthenticationService`, `RegistrationService`, `UserProfileService` | `src/Service/User/` |
| Инфраструктура | `JWTDecoderService`, Lexik JWT | `src/Service/DecoderJWT/` |
| DTO | `UserLoginDto`, `RegistrationDto`, `UserAuthDto`, `UserUidAuthDto`, `RegionDto` | `src/Dto/` |

Консольных команд импорта для `User` в текущем дереве нет: пользователи создаются через API и админские сценарии.

---

## 2. Организация клиники (филиалы, отделения, медцентры)

**Смысл:** где оказываются услуги, структура сети, справочники для сайта и записи.

| Сущность | Репозиторий | Контроллер (префикс) | Сервисы | Команды синхронизации |
| --- | --- | --- | --- | --- |
| `Filial` | `FilialRepository` | `FilialController` → `/filial` | `FilialService` | `UploadFilialsCommand` |
| `Department` | `DepartmentRepository` | `DepartmentController` → `/department` | `DepartmentService` | `UploadDepartmentsCommand` |
| `MedicalCenter` | `MedicalCenterRepository` | `MedicalCenterController` → `/medical-center` | `MedicalCenterCrudService` | `UploadMedicalCentersCommand` |

---

## 3. Врач, локации приёма, расписание и материалы

**Смысл:** центральный домен — **врач** (`Specialist`), его **локации** (`Location`: отделение, филиал, online, ближайшая дата), **слоты расписания** (`Schedule`), справочные тексты и медиа.

| Сущность | Репозиторий | Где в API | Основная логика |
| --- | --- | --- | --- |
| `Specialist` | `SpecialistRepository` | `SpecialistController` → `/specialist` | `SpecialistService` (список, карточка, расписание, фото, запись, интеграция с MIS) |
| `Location` | `LocationRepository` | `LocationController` (admin) — пути вида `/specialist/{id}/location/...`, `/locations/empty` | `LocationService`, `EntityManager` в контроллере |
| `Schedule` | `ScheduleRepository` | косвенно через `SpecialistService`, кеш | `ScheduleCacheService`, `ScheduleErrorHandlerService` |
| `SpecialistDocs` | `SpecialistDocsRepository` | `SpecialistDocsController` → `/specialist-docs/...` | загрузка файлов, `ImageService`, `FileUploaderService` |
| `SpecialistDcodeDescription` | `SpecialistDcodeDescriptionRepository` | `SpecialistDcodeDescriptionController` → `/specialist-dcode-description/...` | пагинация, CRUD |
| `WebGetDocinfo` | `WebGetDocinfoRepository` | `WebGetDocinfoController` → `/docinfo` | чтение внешнего/legacy-представления врача |
| `Idoctor` | `IdoctorRepository` | `InfoclinicaController` → `/idoctor/list` | фильтрация, пагинация |

**Асинхронные сообщения (Messenger):**

- `GetScheduleMessage` → `GetScheduleMessageHandler`
- `GetSpecialistPictureMessage` → `GetSpecialistPictureMessageHandler`
- `GetAnonymousReserveRequestMessage` → `GetAnonymousReserveRequestMessageHandler`

**Команды:** `UploadDoctorsCommand`, `BitrixUpdateDoctorsCommand`, `ClearScheduleCacheCommand`.

**Внешние системы в этом контексте:** Infoclinica/MIS (`InfoclinicaClientService`), Bitrix (`BitrixClientService`, `BitrixService`) для врачей и медиа.

---

## 4. Запись пациента, отметки киоска, SMS

**Смысл:** факт записи, уведомление по SMS, отметка прохождения для киоска.

| Сущность | Репозиторий / доступ | Где используется |
| --- | --- | --- |
| `Record` | `RecordRepository` | создание/учёт записи через `SpecialistService` и сценарии записи |
| `AlertSms` | `AlertSmsRepository` | связь записи с ответом SMS-провайдера (`Record` ↔ `AlertSms`) |
| `MarkKiosk` | `EntityManager::getRepository(MarkKiosk::class)` | `InfoclinicaController::clvisitsovacheckpass` — отметка по `pcode` и филиалу |

HTTP: `POST /reservation/anonymous-reserve` (`InfoclinicaController`) — анонимная запись; проверка киоска — `GET /infoclinica/clvisitsovacheckpass/{filial}` (требуется `ROLE_USER`).

SMS-клиенты: `Sms4bClientService`, `SmsruClientService`.

---

## 5. Прейскурант

| Сущность | Репозиторий | Контроллер | Сервис | Команды |
| --- | --- | --- | --- | --- |
| `PriceList` | `PriceListRepository` | `PriceListController` — префикс `/pricelist`, список `/list` | `PriceListService` | `UploadPriceCommand` |
| `PriceDepartment` | `PriceDepartmentRepository` | `PriceDepartmentController` — тот же префикс `/pricelist`, эндпоинт `/department` | через репозиторий и сервисы фидов | `UploadPriceDepCommand` |

`XmlFeedController` использует `PriceListService` и филиал для генерации фидов — см. контекст интеграций.

---

## 6. Контент сайта (статьи, новости, акции, услуги, заболевания, акции у врачей)

| Сущность | Репозиторий | Контроллер | Паттерн |
| --- | --- | --- | --- |
| `Article` | `ArticleRepository` | `ArticleController` → `/article` | `CrudResponder` + `Paginator` + `ContentFilterDto` ([описание CRUD](./backend-content-crud.md)) |
| `News` | `NewsRepository` | `NewsController` → `/news` | `NewsCrudService` + типовой CRUD |
| `Promo` | `PromoRepository` | `PromoController` → `/promo` | `PromoCrudService` |
| `Disease` | `DiseaseRepository` | `DiseaseController` → `/disease` | `DiseaseCrudService` |
| `SiteService` | `SiteServiceRepository` | `SiteServiceController` → `/site-services` | `SiteServiceCrudService` |
| `Stock` | `StockRepository` | `StockController` → `/stock/...` | CRUD, изображения, связь Many-to-Many с `Specialist` |

**Команды:** `UploadNewsCommand`, `UploadPromoCommand`, `UploadDiseasesCommand`, `UploadSiteServicesCommand` (остальные сущности этого блока подтягиваются согласно фактическим именам команд в `src/Command`).

---

## 7. Отзывы

| Сущность | Репозиторий | Контроллер | Прочее |
| --- | --- | --- | --- |
| `Review` | `ReviewRepository` | `ReviewController` → `/review` | список с фильтрами, создание от авторизованного пользователя, CRUD для админа |

**Команда:** `BitrixUpdateReviewsCommand` — синхронизация с Bitrix.

---

## 8. Интеграции и публичные утилиты

| Назначение | Контроллер / вход | Сервисы |
| --- | --- | --- |
| Лиды Calltouch | `CalltouchController` → `/calltouch/create-lead` | `CalltouchClientService` |
| XML для Яндекса | `XmlFeedController` → `/xml/feed` | `XmlFeedGeneratorService`, `XmlFeedGeneratorV1Service`, данные врачей/цен/филиалов |
| Отправка почты + captcha | `ServiceController` → `/service/sendmail` | `SendMailService`, `SmartCaptchaClientService` |
| Мелкие helper | `HelperController` → `/helper/text-year` | `HelperService` |
| Заглушка | `DefaultController` | `GET /` |

---

## 9. Аудит: логи пользователей (legacy БД)

| Назначение | Контроллер | Реализация |
| --- | --- | --- |
| Список записей `usrlog` | `UsrlogController` → `/usrlog/list` | DBAL-подключение `doctrine.dbal.cabinet_connection`, роль `ROLE_LOGS` |

Это **интеграционный контекст**: сущность в `apps/backend/src/Entity` не выделяется, данные читаются из базы cabinet.

---

## 10. Сущности без выделенного HTTP-слоя в текущем API

Их таблицы и Doctrine-модели есть, репозитории сгенерированы, но **отдельного REST-контроллера в `src/Controller` нет** (на момент описания документа):

| Сущность | Репозиторий | Зачем полезно знать |
| --- | --- | --- |
| `Banner` | `BannerRepository` | баннеры; возможна выдача через другие сервисы или будущие эндпоинты |
| `WidgetForm`, `WidgetFormInput` | `WidgetFormRepository`, `WidgetFormInputRepository` | Symfony Forms `WidgetFormType`, `WidgetFormInputType` — конструктор полей, данные в БД |

При появлении новых маршрутов их логично отнести к контексту **«виджеты и формы»** или **«маркетинг»**.

---

## Сводная таблица: контроллер → базовый префикс

| Контроллер | Префикс или примечание |
| --- | --- |
| `ArticleController` | `/article` |
| `CalltouchController` | `/calltouch` |
| `DefaultController` | `/` |
| `DepartmentController` | `/department` |
| `DiseaseController` | `/disease` |
| `FilialController` | `/filial` |
| `HelperController` | `/helper` |
| `InfoclinicaController` | без классового префикса: `/infoclinica/...`, `/idoctor/...`, `/reservation/...` |
| `LocationController` | без префикса: `/locations/...`, `/specialist/{id}/location/...` |
| `MedicalCenterController` | `/medical-center` |
| `NewsController` | `/news` |
| `PriceDepartmentController` | `/pricelist` |
| `PriceListController` | `/pricelist` |
| `PromoController` | `/promo` |
| `ReviewController` | `/review` |
| `ServiceController` | `/service/...` |
| `SiteServiceController` | `/site-services` |
| `SpecialistController` | `/specialist` |
| `SpecialistDcodeDescriptionController` | `/specialist-dcode-description/...` |
| `SpecialistDocsController` | `/specialist-docs/...` |
| `StockController` | `/stock/...` |
| `UserController` | `/user` |
| `UsrlogController` | `/usrlog/...` |
| `WebGetDocinfoController` | `/docinfo` |
| `XmlFeedController` | `/xml/feed` |

---

## Консольные команды по доменам

| Команда (класс) | Домен |
| --- | --- |
| `UploadDoctorsCommand` | Врачи |
| `BitrixUpdateDoctorsCommand` | Врачи (Bitrix) |
| `BitrixUpdateReviewsCommand` | Отзывы |
| `UploadDepartmentsCommand` | Отделения |
| `UploadDiseasesCommand` | Заболевания |
| `UploadFilialsCommand` | Филиалы |
| `UploadMedicalCentersCommand` | Медцентры |
| `UploadNewsCommand` | Новости |
| `UploadPriceCommand` | Цены |
| `UploadPriceDepCommand` | Группы цен |
| `UploadPromoCommand` | Акции |
| `UploadSiteServicesCommand` | Услуги сайта |
| `ClearScheduleCacheCommand` | Расписание (кеш) |

Точные имена команд Symfony: `docker exec -it php84 php bin/console list app` (или локальный `php bin/console` из `apps/backend`).
