Как мы построили модуль аварийных заявок и систему ролевого доступа для тысяч сотрудников ритейл-сети — на React, Redux-saga и TypeScript
Внутренний портал для сотрудников крупной федеральной розничной сети — система, через которую магазины, распределительные центры и офисы решают операционные проблемы. Когда ломается холодильное оборудование, выходит из строя касса или нужно вызвать подрядчика — заявка идёт через этот портал. Система хранит историю обращений, контакты сервисных компаний и график профилактики.
Команда Fortech подключилась к развитию платформы на этапе масштабирования функционала. Задача — разработать новый модуль ЗНА (заявки на аварийное обслуживание), расширить интерфейсы для разных ролей пользователей и обеспечить стабильность после запуска в production. Работа велась в связке с backend-командой на Java/Spring и дизайнерами, использующими Material UI как основу UI-кита.



Проект начался с аудита существующей архитектуры на React + Redux. Основная проблема — большое количество side-эффектов при обработке асинхронных запросов. Для управления логикой выбрана связка Redux + Redux-saga: саги позволили вынести работу с API в отдельные файлы, избежать callback hell и тестировать асинхронные флоу изолированно. Axios настроен с перехватчиками для обработки ошибок и автоматического обновления токенов. TypeScript помог избежать runtime-ошибок при работе со сложными объектами заявок, где одна неверная типизация поля могла сломать весь флоу подачи обращения.
Главный технический вызов — реализация системы ролевого доступа для разных типов пользователей. Роли определяли, какие заявки видны, какие действия доступны, какие поля можно редактировать. Решение построено на комбинации Redux-селекторов и Higher-Order Components: селекторы вычисляли набор прав из токена пользователя, а HOC оборачивали компоненты, динамически скрывая или блокируя элементы интерфейса. Для сложных форм с условной логикой использован react-hook-form — он снизил количество ре-рендеров и упростил валидацию полей, зависящих от роли. Backend на Spring интегрирован через Swagger-спецификацию, что дало автоматическую генерацию TypeScript-типов для API-контрактов.
Для работы с таблицами и диаграммами на базе Material UI разработаны переиспользуемые компоненты в Storybook: DataGrid с виртуализацией для больших списков заявок, фильтры с debounce на redux-saga, модальные окна для редактирования. RabbitMQ на backend обеспечивал асинхронную обработку массовых обновлений статусов — фронт подписывался на события через WebSocket, обновляя Redux-стор без перезагрузки. PostgreSQL хранила историю заявок, что потребовало оптимизации запросов с пагинацией и кешированием на уровне саг. Покрытие тестами включало проверку саг, селекторов и логики форм — использовали Jest и testing-library для симуляции пользовательских сценариев.


Сотрудники магазинов, РЦ и офисов получили единый интерфейс для подачи и отслеживания аварийных заявок с разделением по ролям. Модуль ЗНА позволил структурировать поток обращений, автоматизировать назначение исполнителей и отслеживать SLA. Таблицы с виртуализацией и реалтайм-обновлениями через WebSocket ускорили работу диспетчеров с сотнями заявок одновременно.
Бизнес получил масштабируемую платформу с переиспользуемыми компонентами в Storybook, что снизило время разработки новых разделов. Типизация на TypeScript и покрытие тестами уменьшили количество багов в production. Архитектура на Redux-saga позволила легко добавлять новые асинхронные флоу без переписывания кодовой базы. После запуска команда обеспечила стабильную поддержку с быстрым реагированием на инциденты.