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
@@ -0,0 +1,86 @@
---
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).