Входящие сообщения (HL7 FHIR)¶
[ТЗ] Обмен обязан соответствовать HL7 FHIR — приказ МЗ РБ № 1001 от 08.10.2018. ПО подлежит регистрации в Регистре ИС, ИР и ПО, соответствующего требованиям HL7 FHIR, поэтому конформность проверяема, а не декларативна.
[ОП] Пять типов входящих сообщений. 3H слушает порт; сторона СМП инициирует обмен (ADR-1).
Обзор пяти типов¶
| Файл | Тип | Когда приходит | Ответ 3H | Идемпотентность |
|---|---|---|---|---|
transport_request.json |
Запрос на возможность госпитализации | До принятия решения о направлении | Синхронный содержательный ответ: принять / отказать / принять с условием | По message_uid |
transport_notification.json |
Извещение о направлении пациента в это УЗ | После решения бригады везти сюда | 202 Accepted |
По message_uid |
transport_health_status.json |
Изменение состояния пациента в пути | Многократно во время транспортировки | 202 Accepted |
По message_uid; наблюдения дедуплицируются по (encounter, code, effectiveDateTime) |
transport_cancel.json |
Извещение об отмене транспортировки | Пациент не будет доставлен | 202 Accepted |
По message_uid |
transport_complete.json |
Извещение о доставке | Машина прибыла, пациент передан | 202 Accepted |
По message_uid |
stateDiagram-v2
[*] --> Запрошено: transport_request
Запрошено --> Направлено: transport_notification
[*] --> Направлено: transport_notification<br/>(без предварительного запроса)
Направлено --> ВПути: transport_health_status
ВПути --> ВПути: transport_health_status
ВПути --> Доставлено: transport_complete
Направлено --> Доставлено: transport_complete
Направлено --> Отменено: transport_cancel
ВПути --> Отменено: transport_cancel
Запрошено --> Отклонено: отказ в госпитализации
Доставлено --> [*]
Отменено --> [*]
Отклонено --> [*]
transport_notification может прийти без transport_request
Бригада не обязана спрашивать о наличии мест — при жизнеугрожающем состоянии пациента везут в ближайшее профильное УЗ. Система обязана принимать transport_notification как первое сообщение по эпизоду. Реализация, требующая предварительного transport_request, будет отвергать самые тяжёлые случаи.
Транспорт и безопасность¶
[ПР]
| Параметр | Значение |
|---|---|
| Протокол | HTTPS, TLS 1.2+ |
| Аутентификация | mTLS (клиентский сертификат вендора) + IP allowlist |
| Целостность тела | Подпись (HMAC или JWS) — при поддержке вендором |
| Порт | Выделенный, конфигурируемый на инсталляцию УЗ |
| Content-Type | application/fhir+json |
| Корреляция | Заголовок X-Correlation-Id + Bundle.identifier |
| Таймаут ответа | 5 с для transport_request, 2 с для остальных |
Требования по криптографической защите — приказ ОАЦ № 66; средства защиты — только сертифицированные по приказу ОАЦ № 77. См. «Безопасность».
Эндпоинты¶
[ПР] Основной путь — стандартная FHIR-операция; типизированные пути оставлены для отладки и для вендоров, которым проще фиксированный маршрут.
| Метод | Путь | Назначение |
|---|---|---|
POST |
/fhir/$process-message |
Основной приём: тип определяется из MessageHeader.event |
POST |
/api/v1/smp/transport-request |
Явный маршрут — запрос мест |
POST |
/api/v1/smp/transport-notification |
Явный маршрут — направление |
POST |
/api/v1/smp/transport-health-status |
Явный маршрут — состояние в пути |
POST |
/api/v1/smp/transport-cancel |
Явный маршрут — отмена |
POST |
/api/v1/smp/transport-complete |
Явный маршрут — доставка |
GET |
/fhir/metadata |
CapabilityStatement — обязателен для FHIR-конформности |
CapabilityStatement — не факультатив
GET /fhir/metadata требуется спецификацией FHIR и будет проверяться при регистрации в Регистре HL7 FHIR-совместимого ПО. Реализовать его нужно с самого начала, а не перед подачей документов.
1. transport_request — запрос на возможность госпитализации¶
Назначение. Бригада или диспетчер спрашивает, может ли УЗ принять пациента с таким профилем.
Минимальный состав: MessageHeader, Patient (пол, возраст), Encounter (повод, приоритет), при наличии — Condition (предварительный диагноз).
Ответ 3H — синхронный, Bundle типа message с MessageHeader.response:
| Решение | Смысл |
|---|---|
accepted |
Место есть, профиль подходит — везите |
rejected |
Принять не можем; в MessageHeader.response.details — причина |
conditional |
Принять можем с оговоркой (например, только после освобождения места; ожидание N минут) |
{
"resourceType": "Bundle",
"type": "message",
"entry": [{
"resource": {
"resourceType": "MessageHeader",
"eventCoding": { "code": "transport-request-response" },
"response": {
"identifier": "req-2026-0714-0915-001",
"code": "ok",
"details": { "display": "accepted: профиль кардиология, место есть" }
}
}
}]
}
Хранение: таблица bed_requests (группа данных 1). Сохраняются и запрос, и решение, и его обоснование — иначе разбор спорных случаев невозможен.
Решение о госпитализации — не автоматическое
[?] Кто принимает решение — система по числу свободных коек или оператор вручную — операционными требованиями не определено. Проектное предположение: система предлагает решение по данным о занятости, оператор подтверждает; при отсутствии реакции в течение таймаута отдаётся conditional. Требует подтверждения заказчика — см. R-6.
2. transport_notification — извещение о направлении¶
Назначение. Пациента везут в это УЗ. Центральное сообщение: с него начинается работа приёмного отделения.
Состав: MessageHeader, Patient, Encounter, Device (машина СМП), Practitioner (бригада), набор Observation (состояние на момент начала транспортировки), Condition, AllergyIntolerance, при наличии — RelatedPerson.
Покрывает большую часть набора данных СМП — пп. 1–28, 34, 40.
Действия 3H:
- Регистрация направления →
transport_notifications(группа данных 2). - Создание/сопоставление пациента в каталоге.
- Сохранение исходного состояния как первого набора наблюдений.
- Появление карточки на центральном пульте и в списке направляющихся (FR-T-10).
- Запуск опроса координат по номеру машины (FR-T-6).
- Расчёт рекомендации по цвету — как подсказка оператору, не как решение.
Ответ: 202 Accepted.
3. transport_health_status — изменение состояния в пути¶
Назначение. Пул сообщений с обновлением жизненных показателей во время транспортировки (FR-T-5).
Состав: MessageHeader, ссылка на Encounter, набор Observation с effectiveDateTime.
Особенности обработки:
- Приходит многократно; объём заранее неизвестен — это главный драйвер роста БД.
- Наблюдения не перезаписывают предыдущие: хранится вся история, потому что важна динамика (ухудшение при стабильных абсолютных значениях — сигнал).
- Дедупликация по тройке
(encounter, code, effectiveDateTime)— повторная доставка того же измерения не создаёт дубль. - Каждое обновление пересчитывает рекомендацию цвета и, при ухудшении, подсвечивает карточку на пульте.
Хранение: vital_observations (группа данных 3), партиционирование по effective_at.
Ухудшение в пути обязано быть заметным
Смысл этого сообщения — дать приёмнику увидеть, что пациент, выехавший жёлтым, стал красным. Если интерфейс показывает только последнее значение без указания на изменение, канал бесполезен. Требование: карточка на пульте отображает тренд и явно сигнализирует о переходе через пороги правил. См. «Логику ТРИАЖ».
4. transport_cancel — отмена транспортировки¶
Назначение. Пациент не будет доставлен: отказ от госпитализации, смерть на месте, перенаправление в другое УЗ, безрезультатный выезд.
Состав: MessageHeader, ссылка на Encounter, Encounter.status = cancelled, причина; при отказе — Consent; при смерти — Patient.deceased[x].
Действия 3H:
- Перевод направления в состояние «отменено» с сохранением причины.
- Снятие карточки с борда направляющихся.
- Остановка опроса координат.
- Если бригада встречи уже собиралась — уведомление МИС об отмене.
- Освобождение зарезервированного места, если резервирование выполнялось.
Пункт 4 легко упустить
Отмена после ручного запроса на сбор бригады (FR-T-11) означает, что собранная бригада специалистов ждёт пациента, которого не будет. Уведомление об отмене обязано доходить до МИС, иначе система создаёт ровно ту проблему, которую призвана решать. Отдельная задача в эпике E5.
5. transport_complete — извещение о доставке¶
Назначение. Машина прибыла, пациент передан приёмному отделению (FR-T-13).
Состав: MessageHeader, Encounter.period.end, финальные Observation (состояние после транспортировки), Encounter.participant (кто передал и кто принял), километраж.
Действия 3H:
- Отсечка времени доставки — фиксация момента; это основа КПЭ «среднее время ожидания».
- Перевод направления в «доставлено» →
deliveries(группа данных 5). - Создание обращения (
appeals) или связывание с уже созданным. - Постановка в очередь на сортировку →
triage_queue(группа данных 6). - Инициация заполнения документов.
Доставка ≠ регистрация в приёмнике
Сообщение от вендора фиксирует факт прибытия по данным СМП. Фактическая передача пациента подтверждается в приёмном отделении действием медработника. Оба момента фиксируются раздельно: расхождение между ними — управленчески значимая метрика (сколько машина ждала приёма). См. «Жизненный цикл».
Обработка ошибок¶
[ПР] Ответы вендору при неуспехе:
| Код | Ситуация | Тело |
|---|---|---|
400 |
Невалидный FHIR | OperationOutcome с указанием проблемного элемента |
401 / 403 |
Не пройдена аутентификация mTLS, IP вне allowlist | OperationOutcome |
409 |
Конфликт состояния (например, complete по отменённому эпизоду) |
OperationOutcome |
422 |
FHIR валиден, но бизнес-правила нарушены | OperationOutcome |
429 |
Превышен лимит частоты | Retry-After |
503 |
Внутренняя недоступность | Retry-After; вендор обязан повторить |
Никогда не возвращать 200 на непринятое сообщение
Если сообщение не сохранено, ответ обязан быть ошибкой — иначе вендор считает доставку успешной и не повторит, а данные о едущем пациенте потеряны безвозвратно. Правило: 2xx возвращается только после успешной записи в БД, а не после постановки в очередь в памяти.
Пример полного Bundle — в «Примере Bundle».