# 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`).