API-сторона решения unified-upload-flow1. Унифицированный пользовательский UX (один drop-zone) опирается на новый отдельный endpoint, который не ломает существующий B2B контракт — мы пока сохраняем прежний формат.

API-сторона решения unified-upload-flow. Унифицированный пользовательский UX (один drop-zone) опирается на новый отдельный endpoint, который не ломает существующий B2B контракт.

Контекст

Существующий API для B2B-клиентов:

  • Один файл на входе → один TestID на выходе
  • Каждый TestID → один отчёт через downstream pipeline
  • Клиенты (лаборатории, EHR-партнёры) уже интегрированы и зависят от этого контракта

B2C-сторона хочет:

  • Принимать много разнотипных файлов разом (PDF/image анализы, выписки, рецепты, фото и т.д.)
  • Ничего конкретного как «test» не возвращать пользователю — test перестаёт быть юнитом вывода (см. recognition-enrichment-hourglass и unified-upload-flow)
  • Хранить всё в FHIR, отдавать пользователю плоский список файлов и их статусов через отдельный запрос
  • Lazy-генерировать тренды/обзоры по конкретному файлу при открытии

Если пытаться расширить существующий endpoint (multi-file response, опциональный TestID и т.д.) — поломаем B2B контракт. Если делать parallel endpoint — никто никого не ломает.

Выбрали: новый endpoint, B2B неизменен

B2B (existing):  POST /api/recognize  1 file   →  TestID
B2C (new):       POST /api/upload     N files  →  200 OK (нет TestID)
                 GET  /api/files               →  плоский список с статусами

Имена выбраны семантически: recognize — историческое имя для «один файл → структурированный результат с TestID», B2B-клиенты на этом уже интегрированы. upload — для нового multi-file flow. Альтернатива ingest для нового endpoint отвергнута из-за конфликта с inngest (легко перепутать в коде / логах / разговоре).

Что внутри новой ручки

  • Принимает N файлов разных форматов
  • Сохраняет всё в FHIR (DocumentReference / etc., см. fhir-document-reference)
  • Запускает recognition flow per файл асинхронно (см. recognition-enrichment-hourglass — это вход в верхний конус)
  • Возвращает только 200 OK; статусы файлов фронтенд берёт через GET
  • Без grouping / batch ID на старте — добавим если станет нужно

Почему

  • Backward-compat пока сохраняем — клиенты на existing API уже интегрированы; не ломаем формат, пока нет причины (semantic versioning без bump major)
  • Развязывает руки B2C — можно эволюционировать новый endpoint свободно (lazy processing, новые форматы, semantic batch grouping) без оглядки на B2B
  • Симметрия с архитектурой — separate endpoint = отдельный «вход в верхний конус» песочных часов; B2B path остаётся там же где был
  • Минимальная сложность — Вася просил не overengineer’ить (без grouping, batch ID, smart routing) пока не понадобится

Следствия

  • Новый endpoint требует поддержки async file status в FHIR — каждый файл переходит status uploaded → recognizing → recognized | failed. См. fhir-document-reference (carry-over: уточнить status field schema).
  • Frontend получает список файлов отдельным GET-запросом, не из upload response — другой UX-паттерн чем existing B2B clients
  • Когда endpoint готов — Ильдар прицепляет enrichment-ветку поверх (см. recognition-enrichment-hourglass нижний конус)
  • B2C сценарий перестаёт быть test-центричным; recognition стартует per file, а не «per TestID» — это часть paradigm shift из health-report-vision

Открытые вопросы

  • Async progress для пользователя — websocket / polling / SSE? Не зафиксировано.
  • File grouping logic — multipage PDF одного теста vs N фото одного теста vs два разных теста в один загруз. Серьёзный вопрос, отложен в multi-image-file-grouping (status: draft, не сформулировано).
  • Authorization модель — те же scopes, что у /api/recognize (per-org / per-patient — без изменений в access control).

Связанные решения

Связано

Источники

Сноски

  1. 2026-04-27 Daily + Sprint Review & Planning, https://github.com/Realai-plus/meeting-digests/blob/main/data/digest/2026/04/2026-04-27T08%3A00%3A00.000Z_Daily_%2B_Sprint_Review%26Planning_01KPX39F5EMF092HA0PGKSX1FV.md — решение про отдельный endpoint, имя upload (vs отвергнутого ingest), Артём в работу на конец недели.