Разбираем разработку фронтенд-модулей для коммерческой B2B-платформы на Next.js и TypeScript
Коммерческая электронная торговая площадка для B2B-закупок. Организаторы публикуют тендеры, поставщики ищут профильные, подают заявки и торгуются на аукционах.
Компании работают на площадке не одним аккаунтом, а структурой: у организации есть дочерние филиалы, а сотрудник может состоять сразу в нескольких компаниях. Поэтому площадка с самого начала проектировалась не вокруг пользователя, а вокруг связки пользователя с организацией, от которой он действует.
Компания, которая живёт на тендерах, не выбирает закупки глазами. Профильных тендеров в её нише может выходить несколько десятков в неделю, разбросанных по кодам ОКВЭД и формулировкам названий, и почти каждый со своим сроком подачи. Пропустил публикацию на четыре дня, а окно подачи было пять.
Второй риск другой природы. Когда участник дошёл до аукциона, он торгуется в реальном времени и по таймеру. Здесь любая заминка интерфейса стоит денег напрямую: не успел подтвердить шаг, проиграл лот.
Площадке нужно было закрыть оба сценария. Первый – чтобы тендер сам приходил к участнику по его правилам. Второй – чтобы в момент торгов ничего не мешало.

Права доступа сложнее обычных. Сотрудник состоит в нескольких организациях сразу, у организации есть дочерние филиалы, а обсуждения и чаты видны только внутри своей компании. Это значит, что почти каждый экран рендерится по-разному в зависимости от того, от лица какой организации пользователь в него зашёл.
Два противоположных требования к рендерингу. Новости, статьи, FAQ и инструкции должны индексироваться и открываться быстро. Личный кабинет, календарь, чаты и аукцион должны вести себя как приложение с мгновенной реакцией.
Уведомления с произвольным расписанием. Пользователь настраивает не «включить или выключить», а когда именно: сразу, в выбранные дни недели, во временном интервале или в конкретную дату и час, на сайт, на почту, в SMS. Это не флажок в настройках, а планировщик.
Аукцион не прощает ошибок. Пошаговый процесс с таймером не допускает состояния, когда пользователь видит одно время, а сервер считает другое.
Один фреймворк на два режима рендеринга. Взяли Next.js: информационные разделы отдаются статикой и индексируются, кабинеты, торги и обсуждения работают в динамике. Иначе пришлось бы держать два отдельных приложения и дублировать в них авторизацию и права.
Права как часть состояния интерфейса, а не как проверка на входе. Членство в организации и филиале определяет видимость комментариев, чатов и данных на каждом экране.
Сквозная типизация клиента и сервера. Типы данных описаны на TypeScript с обеих сторон. На платформе, где ошибка в структуре заявки или сметного расчёта означает потерянный тендер, расхождение контрактов должно падать на сборке, а не у пользователя в форме подачи.
Redis перед PostgreSQL. Ленты тендеров, календарь и обсуждения читаются несопоставимо чаще, чем меняются. Кэш снимает эту нагрузку с базы, при изменении инвалидируется точечно.
MinIO для документов. Уставные документы при подтверждении организации, приложения к тендерам, инструкции и картинки новостей лежат в объектном хранилище. База остаётся базой.
Storybook как контроль регрессии. На платформе такого размера один и тот же компонент живёт в десятке контекстов: карточка тендера, календарь, избранное, результаты поиска. Компоненты собирались и проверялись изолированно, поэтому правка в одном месте не ломала вёрстку в другом.
Docker на всех окружениях. Одинаковые версии Node.js и библиотек у разработчиков и на тестовом контуре.

Участник настраивает поисковый шаблон по своим кодам ОКВЭД и ключевым словам один раз, дальше площадка сама сообщает о подходящих закупках и об изменении их статусов, в том канале и в то время, которое он выбрал. Тендеры видны в календаре по датам, ближайшие по срокам вынесены на главную.
Внутри компании работа над тендером не уходит в личные переписки: обсуждение хранится в карточке и доступно только сотрудникам своей организации, вопросы к организатору и в поддержку идут через отдельные чаты. Данные по тендеру выгружаются в Excel.
Организация подтверждается через проверку ИНН и КПП и загрузку документов, поэтому в торгах участвуют проверенные юрлица. Контентом, новостями с отложенной публикацией, инструкциями и пользователями администраторы управляют сами, без разработчиков.
Как устроен поиск тендеров по ОКВЭД?
Поиск идёт по названию, тегам, кодам ОКВЭД и ключевым словам, а набор условий сохраняется как пользовательский шаблон. Дальше подходящие закупки приходят в уведомлениях, и площадку не нужно открывать вручную.
Как разграничить доступ, если сотрудник работает в нескольких компаниях сразу?
Видимость данных привязывается не к пользователю, а к паре «пользователь и организация». Обсуждения и чаты остаются внутри компании, из которой сотрудник зашёл, даже если он состоит ещё в трёх.
Можно ли совместить индексируемые разделы и закрытый кабинет в одном приложении?
Да, Next.js отдаёт информационные страницы статикой, а закрытые разделы рендерит динамически. Отдельный сайт под контент заводить не нужно.
Что должна уметь площадка, чтобы участник не пропускал закупки?
Три вещи: сохранённые поисковые запросы, уведомления с настраиваемым расписанием по нескольким каналам и календарь со сроками. Без первого пункта остальные два работают вхолостую.