---
title: Карточка врача и локации приёма (Backend)
---

# Сценарий 2.1: Карточка врача и локации (`Specialist` + `Location`)

## Бизнес-цель

Пользователю нужна **карточка врача** (ФИО, медиа, признаки активности, регион и т.д.) вместе с **локациями приёма**: привязка к отделению, филиалу, режиму online и пр., чтобы выбрать место и сценарий записи.

## Точки входа

| Тип | Метод + URL | Класс |
| --- | --- | --- |
| HTTP | `GET /specialist/{id}` | `SpecialistController::show` (`id` — целое) |
| HTTP | `GET /specialist/by/{identifier}?regionId=` | `SpecialistController::showBy` |

Список врачей: `GET /specialist/list` — отдельный сценарий фильтрации, тот же репозиторий.

CLI / Messenger для **чтения карточки** не используются.

## Как собирается «агрегат» в рамках Symfony / ORM

Doctrine-сущность `App\Entity\Specialist` содержит `OneToMany` на `App\Entity\Location` (`mappedBy: 'specialist'`, каскады `persist`/`remove`). Для API **отдельного сервиса-сборщика нет**: при `GET /specialist/{id}` используется param converter и сериализация.

Группы Serializer **`specialist:detail`** и **`from.specialist:read`** включают в ответ связанные локации (см. атрибуты `Groups` на поле коллекции локаций в `Specialist`).

Маршрут **`showBy`**:

1. `SpecialistService::getSpecialist($identifier, $regionId)`;
2. если `identifier` числовой — выборка по `id`;
3. иначе — по `alias` и опциональному `regionId` через `SpecialistRepository::createFilteredQueryBuilder`;
4. при `null` — **404** `{"error":"not found"}`.

## Пошаговый алгоритм — `GET /specialist/{id}`

1. Загрузка `Specialist` из БД по `id` (или 404 на уровне фреймворка, если не найден).
2. `JsonResponse` с группами `specialist:detail`, `from.specialist:read`.
3. При обходе графа сериализатором Doctrine догружает `locations`.

## Mermaid

```mermaid
sequenceDiagram
    participant C as Клиент
    participant SC as SpecialistController
    participant SS as SpecialistService
    participant SR as SpecialistRepository
    participant SER as Serializer / ORM

    alt По числовому id
        C->>SC: GET /specialist/{id}
        SC->>SER: serialize(Specialist)
        SER->>SER: подтягивание Location
        SC-->>C: JSON
    else По alias
        C->>SC: GET /specialist/by/{identifier}
        SC->>SS: getSpecialist
        SS->>SR: QueryBuilder
        SR-->>SS: Specialist | null
        SS-->>SC: entity
        SC->>SER: serialize
        SC-->>C: 200 или 404
    end
```

## Внешние зависимости

| Система | Участие |
| --- | --- |
| PostgreSQL | данные `specialist` и `location` |
| Инфоклиника / Bitrix | **не вызываются** при чтении карточки |

## Обработка ошибок и edge cases

- **Не найден по alias** — `404` с простым телом.
- **Фото врача**: отдельные эндпоинты загрузки картинки (`specialistPicture`, upload) — не часть сценария «только чтение».

## Ссылки на классы

- `apps/backend/src/Controller/SpecialistController.php`
- `apps/backend/src/Service/Specialist/SpecialistService.php`
- `apps/backend/src/Entity/Specialist.php`, `Entity/Location.php`
- `apps/backend/src/Repository/SpecialistRepository.php`

Админские CRUD по локациям: `LocationController`. Карта домена: [backend-ddd.md](../backend-ddd.md).
