Соответствие таблиц требованиям¶
Проверка полноты: каждая обязательная группа данных и каждое функциональное требование должны иметь место хранения. Таблица без требования — лишняя; требование без таблицы — пробел.
Семь обязательных групп данных¶
[ОП] Формулировки групп — дословно из требований заказчика.
| # | Группа данных | Основные таблицы | Вспомогательные |
|---|---|---|---|
| 1 | Входящие запросы на наличие свободных мест в стационаре | bed_requests |
inbound_messages, providers |
| 2 | Входящая информация по направлению пациента в приёмное отделение: номер кареты скорой, персональная информация по пациенту, его состояние на момент начала транспортировки | transport_notifications, patients, ambulances |
practitioners, inbound_messages, vital_observations (исходный набор), transport_events |
| 3 | Параметры изменения состояния пациента в процессе транспортировки. Регистрируются основные жизненные показатели | vital_observations |
inbound_messages |
| 4 | Лог запросов на уточнение положения кареты скорой помощи | location_requests |
ambulance_locations, integration_log |
| 5 | Информация о доставке пациента | deliveries |
transport_notifications, transport_events |
| 6 | Постановка пациента в очередь на сортировку ТРИАЖ | triage_queue, appeals |
appeal_events |
| 7 | Результаты сортировки пациента и передача информации в медицинскую информационную систему | triage_assessments, mis_handoffs |
triage_assessment_inputs, triage_rule_versions, triage_rules |
flowchart LR
G1["1 · Запросы мест"] --> T1["bed_requests"]
G2["2 · Направление"] --> T2["transport_notifications<br/>patients · ambulances"]
G3["3 · Состояние в пути"] --> T3["vital_observations"]
G4["4 · Лог координат"] --> T4["location_requests<br/>ambulance_locations"]
G5["5 · Доставка"] --> T5["deliveries"]
G6["6 · Очередь ТРИАЖ"] --> T6["triage_queue · appeals"]
G7["7 · Результаты + МИС"] --> T7["triage_assessments<br/>mis_handoffs"]
Группа 2 хранится в трёх таблицах, а не в одной
Формулировка объединяет разнородные сущности: направление (событие), пациент (долгоживущая запись ПДн), карета (справочник) и состояние на момент старта (наблюдения). Хранить их одной таблицей означало бы дублировать ПДн пациента при каждом обращении и терять возможность связать пациента с его прошлыми визитами. Требование выполнено полностью — просто нормализованно.
Группа 4 — именно лог запросов, а не только координаты
Требование говорит о логе запросов, а не о позициях. Поэтому location_requests (каждый запрос: когда, к кому, с каким результатом, сколько длился, была ли ошибка) — основная таблица, а ambulance_locations — полученные данные. Реализация, хранящая только координаты, требование не закрывает: разобрать «почему карета пропала с карты» без лога запросов невозможно.
Покрытие функциональных требований¶
Подсистема «Триаж»¶
| Требование | Где реализуется |
|---|---|
| FR-T-1 приём сообщений сервер-сервер | inbound_messages, provider_endpoints |
| FR-T-2 пять типов сообщений | inbound_messages.message_type |
| FR-T-3 ответ на запрос мест | bed_requests.decision, decision_reason, decided_by |
| FR-T-4 регистрация кареты | transport_notifications, ambulances |
| FR-T-5 изменения состояния в пути | vital_observations |
| FR-T-6 координаты кареты | location_requests, ambulance_locations |
| FR-T-7 мультипровайдерность координат | providers.axis='geo', adapter_class, settings |
| FR-T-8 мультипровайдерность API СМП | providers.axis='smp' |
| FR-T-9 мультипровайдерность МИС | providers.axis='mis', mis_handoffs.provider_id |
| FR-T-10 интерфейс направляющихся | чтение transport_notifications + ambulance_locations |
| FR-T-11 ручная передача в МИС | mis_handoffs.kind='team_request', initiated_by |
| FR-T-12 отмена транспортировки | transport_notifications.status='cancelled', cancel_reason, mis_handoffs.kind='cancel_notice' |
| FR-T-13 регистрация доставки, отсечка времени | deliveries.delivered_at, accepted_at |
| FR-T-14 терминал самообращения | appeals.source='self' |
| FR-T-15 анонимная очередь | appeals.patient_id IS NULL, triage_assessment_inputs |
| FR-T-16 цвет и талон | triage_assessments.color, ticket_code |
| FR-T-17 правила сортировки | triage_rules, triage_rule_versions.conditions |
| FR-T-18 СМП-пациенты не зелёные | ограничение в правилах + проверка приложения |
| FR-T-19 автозаполнение из данных СМП | appeals.notification_id → transport_notifications |
| FR-T-20 приоритетная очередь | triage_queue.priority_rank |
| FR-T-21 нормативное время выбытия | triage_queue.sla_deadline, sla_breached |
| FR-T-22 оформление обращения | appeals.status='registered', registered_at |
| FR-T-23 передача обращения в МИС | mis_handoffs.kind='appeal' |
| FR-T-24 выписка из приёмного отделения | appeals.closed_at, closed_reason |
| FR-T-25 режим массового поступления | triage_assessments.mode='mass_casualty' |
| FR-T-26 печать браслета/талона | appeals.appeal_number → штрих-код |
Общие требования¶
| Требование | Где реализуется |
|---|---|
| FR-C-1 своя БД и логи | вся схема + integration_log |
| FR-C-2 журнал событий ИБ ≥ 1 года | security_events + политика ретеншна |
| FR-C-3 ЭЦП | triage_assessments.signature_ref, users.cert_thumbprint |
| FR-C-4 разграничение доступа | users, roles, user_roles |
| FR-C-5 отчётность по КПЭ | вычисляется из deliveries, triage_queue, appeals |
| FR-C-6 администрирование | providers, facilities.settings, triage_rule_versions |
| FR-C-7 обезличивание | шифрование patients + выгрузки без patient_id |
| FR-C-8 синхронизация времени | timestamptz везде + NTP на уровне ОС |
Расчёт показателей эффективности¶
[ТЗ] Два КПЭ паспорта должны считаться из схемы, иначе достижение целей нечем подтвердить (FR-C-5).
Среднее время ожидания оказания медицинской помощи¶
Цель: 30–120 мин → 15–60 мин.
-- По категориям (цветам) за период
SELECT
ta.color,
count(*) AS patients,
avg(tq.called_at - a.opened_at) AS avg_wait,
percentile_cont(0.5) WITHIN GROUP (ORDER BY tq.called_at - a.opened_at) AS median_wait,
percentile_cont(0.9) WITHIN GROUP (ORDER BY tq.called_at - a.opened_at) AS p90_wait
FROM appeals a
JOIN triage_queue tq ON tq.appeal_id = a.id
JOIN triage_assessments ta ON ta.appeal_id = a.id
WHERE a.facility_id = $1
AND a.opened_at >= $2 AND a.opened_at < $3
AND tq.called_at IS NOT NULL
GROUP BY ta.color;
Количество пациентов, обслуженных за единицу времени¶
Цель: 0,5–2 в час → 1–4 в час.
-- Пропускная способность приёмного отделения по часам
SELECT
date_trunc('hour', a.closed_at) AS hour,
count(*) AS patients_completed
FROM appeals a
WHERE a.facility_id = $1
AND a.closed_at >= $2 AND a.closed_at < $3
AND a.status = 'closed'
GROUP BY 1
ORDER BY 1;
«Время ожидания» нужно определить однозначно до внедрения
[?] Запрос выше считает от opened_at (момент обращения) до called_at (вызов на оформление). Возможны и другие трактовки: до начала оказания помощи, до сортировки, для СМП-пациентов — от delivered_at или от accepted_at.
Разные определения дают разные числа при одной и той же работе, а показатель приёмочный. Определение должно быть согласовано с заказчиком и зафиксировано в частном ТЗ до начала измерений — иначе на приёмке возникнет спор о методике, а не о результате. См. R-7.
Пробелы и осознанные исключения¶
| Что | Статус |
|---|---|
Учёт коечного фонда и занятости для решения по bed_requests |
[?] Источник данных о свободных местах не определён: собственный учёт в 3H или запрос в МИС. См. R-6 |
Хранение сканов документов (DocumentReference) |
[ПР] Файлы — во внешнем объектном хранилище, в БД только ссылка и хеш |
| ЭКГ как изображение (п. 21.18) | [?] Зависит от ответа вендора — файл или текст. См. вопрос 6 в наборе данных |
Расписания и слоты (Appointment, Schedule, Slot) |
Осознанно не хранятся: ведутся в МИС, ПАК их не использует |
| Назначения и направления | Осознанно не хранятся: «система направлений и назначений работает в МИС» |
Электронные рецепты (List) |
Осознанно не хранятся: вне контура ПАК |