Тема
Обработка ошибок: анализ и план для платформы Endge
Ориентация на лучшие практики Low-Code Enterprise движков с учётом нашей архитектуры (Endge, Raph, федерация модулей, Vue 3).
Что используют успешные Low-Code/Enterprise платформы
Mendix
- Транзакционная модель: Rollback (по умолчанию), Custom with/without rollback, Continue (не рекомендуется).
- Savepoints в начале микрофлоу; при ошибке — откат к savepoint и вызов кастомного flow обработки.
- Логирование через «Log message»; пользователю показываются кастомные сообщения, а не сырой стек.
- Рекомендации: явные под-микрофлоу для сложной логики, не полагаться на глобальные обработчики для бизнес-ошибок.
OutSystems
- Типизированные исключения: статические сущности для типов (ApiError, MaintenanceMode и т.д.), структуры с сообщением и кодом.
- Сериализация деталей в JSON при пересечении границ модулей (нет публичных User Exceptions между модулями).
- Глобальный обработчик: Switch по типу исключения и маршрутизация в нужную логику (повтор, уведомление, редирект).
- Масштабируемость за счёт единого контракта ошибки и централизованной маршрутизации.
Общие принципы (Enterprise)
- Единая точка входа для «что делать при ошибке» (глобальный handler / error boundary).
- Классификация: ожидаемые бизнес-ошибки (валидация, 4xx) vs неожиданные (5xx, падение рендера).
- Логирование с контекстом (traceId, userId, route, component) и отправка в мониторинг (Sentry и др.).
- Пользователю — понятное сообщение и действие (повторить, перейти, связаться с поддержкой); разработчику — полный контекст в логах.
Текущее состояние в Endge
Где обрабатываются ошибки
- App.vue:
onErrorCaptured— перехват ошибок из дочерних компонентов; определение имени компонента обходом вверх по дереву; вызовcaptureAppRenderFailure; отображениеErrorViewпри фатальном состоянии или локальной ошибке. - app-render-guard.ts: защита от «error storm» и рекурсивных обновлений Vue; лимит ошибок в окне 2 с; при превышении — фатальное состояние, сброс persisted state админки, опционально reset EndgeAdmin; состояние в
appRenderGuardState. - ErrorView: отображение ошибки (сообщение, component name, route); нет явного репорта в Sentry/backend, нет типизации вида ошибки.
- Роутер:
router.onError— толькоconsole.errorпо навигационным ошибкам. - API: в
EndgeApiи прикладных сервисах ошибки пробрасываются какErrorс текстом; нет единого формата (код, тип, retryable).
Чего не хватает
- Единого контракта ошибки: тип (business / network / validation / fatal), код, сообщение для пользователя vs для лога, retryable, traceId.
- Централизованной маршрутизации: по типу/коду решать — показать toast, показать ErrorView, отправить в Sentry, повторить запрос.
- Интеграции с диагностикой: каждая серьёзная ошибка должна попадать в
Endge.diagnostics(event/measurement) и при включённых exporters — в внешние системы. - Error boundary по поддеревьям: изолировать падение одного виджета/вкладки, не ронять весь layout (как в React error boundary).
- Типизированных пользовательских ошибок: приложение и модули должны бросать не голый
Error, а, например,ValidationError,AuthError,NetworkErrorс полями, по которым глобальный handler выберет поведение.
Рекомендации с учётом нашей архитектуры
Что совпадает с лучшими практиками
- Глобальный перехват в корне приложения (
onErrorCaptured) — аналог глобального handler. - Отдельный «guard» от лавины ошибок и рекурсии — разумная защита.
- Сброс состояния при фатале (localStorage, EndgeAdmin) — правильный шаг для восстановления.
Что скорректировать
Не держать всю логику в App.vue
- Вынести обработку в отдельный модуль/сервис (например, в core или отдельный пакет
@endge/errors): классификация ошибки, решение (toast / full page / boundary), логирование, репорт. - App.vue только вызывает что-то вроде
ErrorHandling.capture(err, { component, info, route })и по флагу «fatal» или «show full page» переключает layout на ErrorView.
- Вынести обработку в отдельный модуль/сервис (например, в core или отдельный пакет
Ввести контракт ошибки
- Базовый тип:
code,message,userMessage,type(business | validation | auth | network | fatal),retryable,traceId, опциональноpayload. - Бизнес-ошибки (например, от API) маппить в этот контракт в одном месте (например, в HTTP-интерцепторе или в EndgeApi).
- Базовый тип:
Error boundary по поддеревьям
- Во Vue 3 нет встроенного Error Boundary как в React; реализуется обёрткой-компонентом с
onErrorCapturedи слотом fallback. Имеет смысл такой компонент ввести (например, в @endge/ui-vue) и использовать для виджетов админки и тяжёлых секций, чтобы падение одного блока не показывало полноэкранную ErrorView.
- Во Vue 3 нет встроенного Error Boundary как в React; реализуется обёрткой-компонентом с
Роутер
- В
router.onErrorи вbeforeEachпри сбоях навигации вызывать тот же централизованный handler и при необходимости показывать toast или страницу «ошибка навигации», а не только логировать в консоль.
- В
Диагностика
- При любой обработанной ошибке вызывать
Endge.diagnostics.writeEvent(или writeLog) с каналомerrors, типом и контекстом. Тогда экспортеры (Sentry, лог-сервер) получат единый поток.
- При любой обработанной ошибке вызывать
Типизированные исключения
- В core или в shared: классы или фабрики
AppError,ValidationError,NetworkErrorи т.д. с полями контракта. Приложение и модули бросают их; глобальный handler поtype/`code» решает, что делать.
- В core или в shared: классы или фабрики
Предлагаемая структура
- Модуль/пакет: централизованная обработка ошибок (можно в
@endge/coreкак подмодуль или отдельно@endge/errors).- Контракт типов ошибок.
capture(error, context)- классификация, запись в diagnostics, решение (toast / full page / boundary), опционально репорт во внешний сервис.- Интеграция с Vue: плагин или composable, регистрирующий глобальный
onErrorCapturedи предоставляющийuseErrorBoundary()для локальных boundary.
- App.vue: тонкая обвязка — вызов capture и отображение ErrorView только при «fatal» или «full page» из решения handler’а.
- app-render-guard: оставить как есть; при переходе в фатальное состояние дополнительно вызывать
ErrorHandling.captureс типомfatal, чтобы событие ушло в диагностику и экспортеры.
Риски и ограничения
- Централизованный handler не должен «глотать» критические ошибки без логирования; связь с Diagnostics_Logging_Telemetry обязательна для репорта в мониторинг. Вызов уведомлений пользователю — через единый слой Notifications, чтобы не дублировать логику отображения ошибок.
Вывод
- Ориентируемся на подходы Mendix/OutSystems: единый контракт ошибки, глобальный handler, типизация, разделение «для пользователя» и «для лога».
- С учётом нашей архитектуры: вынести логику из App.vue в отдельный модуль обработки ошибок, связать его с
Endge.diagnostics, ввести Vue-компонент error boundary для изоляции поддеревьев и типизированные классы ошибок для приложения и модулей.