Динамическая генерация медицинских документов

Динамическая генерация медицинских документов

Next.js 13Tanstack QueryLayout Engine

Контекст

В рамках медицинской платформы каждый ресурс пациента мог быть преобразован в печатный документ (будь то отчёт об анализах, медицинское заключение или общий отчёт).

Эти документы должны были:

  • 🖌️ Строго соответствовать дизайну, заданному в Figma
  • 📐 Поддерживать разные форматы (A4, A3 и т.д.)
  • 📏 Оставаться корректными при переменном объёме контента

Разработанное мной приложение на Next.js было частью более широкой цепочки генерации и выполняло конкретную роль:

  1. Получать запрос с параметрами документа
  2. Загружать связанные данные
  3. Генерировать веб-страницу, которая затем обрабатывалась Puppeteer для создания финального PDF

Технический вызов

Добиться pixel-perfect соответствия макету Figma в фиксированном формате - задача достаточно стандартная.

Сложности начинаются при работе с динамическим контентом. На бумаге страница не может автоматически адаптироваться:

Переполнение контента за пределы A4 документа

Некоторые секции могли быть очень короткими или, наоборот, очень длинными в зависимости от данных пациента.

Главная сложность - заранее определить, когда контент выйдет за пределы доступного пространства.

Одной интуиции недостаточно, чтобы решить такую задачу. Это настоящий инженерный вызов, требующий креативности и системного подхода.

Моё решение: сначала измерить, потом рендерить

Система использует два параллельных рендера:

«Призрачный» рендер

Контент генерируется вне экрана. Он служит эталоном и позволяет получить точные размеры контента до этапа верстки:

Невидимый рендер для измерения контента

Финальный рендер

После получения размеров контент распределяется по одной или нескольким страницам. Если страница заполнена, оставшаяся часть автоматически переносится на следующую. Процесс повторяется, пока всё не будет корректно размещено. ✅

Финальный рендер документа

Преимущества и ограничения

✅ Преимущества

  • 📄 Поддержка любых форматов документов (A3, A4, кастомных и т.д.)
  • 🖋️ Опциональные header и footer
  • ⚡ Поддержка динамических страниц: можно оставить статический режим, если контент неизменен
  • 🔢 Автоматическая нумерация страниц, включая динамически добавленные

⚠️ Ограничения

  • 🧩 Делимые элементы должны быть прямыми потомками контейнера
  • 📏 Для отступов используется только padding, а не margin
💡 Чтобы гарантировать соблюдение этих ограничений, я реализовал:
  • Понятную документацию
  • Соглашения на уровне кода, реализованные через специализированные компоненты, которые можно использовать «не задумываясь», чтобы система оставалась надёжной даже при добавлении контента другими разработчиками

Инструмент для команды: предпросмотр в реальном времени

Чтобы упростить разработку и тестирование, я создал внутренний интерфейс, позволяющий:

  • ✏️ Редактировать данные пациента в реальном времени
  • 👀 Мгновенно просматривать финальный результат
Предпросмотр документа в реальном времени

Быстрое тестирование различных сценариев внутри команды и мгновенная демонстрация для стейкхолдеров. ✅

Итоги

Во фронтенде мы обычно стремимся делать интерфейсы всё более адаптивными.

Здесь было наоборот: вписать динамику в фиксированную структуру.

Этот проект научил меня:

  • 🔄 Адаптировать подход под задачу, а не действовать по привычке
  • 🔗 Понимать, как отдельный модуль вписывается в общую инфраструктуру
  • 🧩 Проектировать системы, которыми можно пользоваться без необходимости разбираться в их внутренностях