Заголовок

Описание
Контекст проекта
Проект EWAtender — это поисково-аналитическая IT-платформа и SaaS для B2B, которая агрегирует тендеры. Помимо самой платформы, у клиента есть онлайн-школа и услуги тендерного сопровождения.
Проблема
В лице EWAtender нам представился классический пример легаси-проекта. На протяжении около 5 лет разработку вёл один человек. Документация отсутствовала полностью. Когда этот разработчик отказался поддерживать проект дальше, владельцы бизнеса осознали, что не разбираются в собственном продукте.

Наше взаимодействие началось с оценки проекта, во время которой мы изучали принципы работы площадки и параллельно писали документацию. Позднее часть документации была продана клиенту как отдельная работа.
Технический стек
На этом проекте мы столкнулись с непривычными для нас технологиями. Знакомство прошло с пользой не только для нас, но и для будущих проектов, у которых будет подобное под капотом.

Бэкенд: Laravel (PHP)
Фронтенд: Vue.js + Nuxt
База данных: PostgreSQL
Основные задачи и их решение
Инвентаризация и работа над ошибками
В процессе изучения проекта выяснилось, что часть парсеров (ботов, которые собирают данные о тендерах с площадок) не работает — пользователи жаловались на отсутствие тендеров, хотя на самом деле они были. Мы провели аудит всех парсеров, убедившись, что они работают в разных режимах для разных видов площадок (госзакупки, коммерческие и др.).
Критический инцидент (API главной тендерной площадки)
Основной источник данных — портал zakupki.gov.ru — отключил старый способ получения данных через протокол FTP. Новый метод имел жёсткие лимиты (около 10 тысяч запросов), что не позволяло выгружать все 15 тысяч ежедневных тендеров, для чего требовало около 60 тысяч запросов с учётом сопутствующих данных об участниках и документах.

Мы отказались от внедрения сырого и неудобного протокола от «Закупок». Вместо этого мы проанализировали экосистему и нашли обходной путь — через API мобильного приложения «Закупок». Это позволило нам парсить данные в обход новых ограничений.

Однако при внедрении возникла новая проблема — API мобильного приложения не позволял листать больше 50 страниц. Это ограничивало выборку; представьте примерочную в магазине одежды, где можно померить только пять вещей в день, а нам нужно примерить 50. Решение — «заходить в примерочную вдесятером»: раздробить запросы по категориям и типам тендеров, чтобы обойти лимит и собирать полный объём данных.
Документирование и наведение порядка
Мы написали порядка 30 файлов документации. В них описали:
  • Принципы работы каждого бота для парсинга.
  • Процедуры запуска системы и резервных копий данных (бэкапов).
  • Информацию о всех внешних сервисах (прокси-сервера, платёжные системы, SMS-рассылки, интеграции с Яндекс), о которых клиент даже не подозревал, так как всем единолично управлял прошлый разработчик.
Миграция кода
До нашего прихода на проект код либо отсутствовал в репозиториях, либо хранился персонально у ушедшего разработчика. Сейчас все боты разделены по отдельным проектам; мы загрузили в единый репозиторий и передали управление клиенту.
Подробнее о работе с PostgreSQL
В процессе изучения легаси-кода мы столкнулись с необычным для нас стеком, где в качестве основной базы данных использовался PostgreSQL. Это отличалось от нашего привычного подхода с MySQL и потребовало погружения в специфику новой СУБД. В проекте были задействованы интересные возможности PostgreSQL, которые ранее мы не применяли:

  1. Работа с CSV как с таблицей (Foreign Data Wrappers). В проекте использовалась возможность подключения внешних CSV-файлов к базе данных как обычных таблиц. Это позволяло выполнять SQL-запросы к содержимому файла и даже изменять данные в исходном CSV через SQL-команды. Удобный механизм для интеграции с внешними источниками без импорта.
  2. Партиционирование таблиц. Огромные таблицы с тендерами были разбиты на множество мелких физических таблиц (например, по годам и месяцам). При этом для разработчика и приложения все выглядело как единая таблица. Это решение критически важно для производительности: поиск по датам не сканирует всю историю целиком, а работает только с нужным диапазоном.
  3. JSON как полноценный тип данных. В PostgreSQL колонки с типом JSON используются для хранения сложных вложенных структур. Например, в одной колонке мог храниться целый документ с параметрами тендера, а SQL-запрос мог обращаться к конкретным полям внутри этого JSON, что сильно расширяет гибкость модели данных. Например, можно попросить найти все тендеры, где ОКПД2 = 02.3, что выдаёт тендеры с ОКПД2: 02.3 — «Продукция лесного хозяйства прочая».
  4. Полнотекстовый поиск без внешних движков. В PostgreSQL был реализован полнотекстовый поиск прямо внутри базы данных. Это избавляло от необходимости подключать отдельные поисковые движки (вроде Sphinx или Elasticsearch) для индексации документов — база справлялась сама.
  5. Хранимые процедуры и триггеры. Использовались процедуры, которые автоматически обрабатывали данные при вставке или обновлении записей. Например, перед сохранением сложной структуры она могла автоматически преобразовываться в нужный формат прямо на стороне базы данных.
Почему это важно для проекта и что это давало клиенту
Все эти технические решения (особенно партиционирование и работа с JSON) были заложены предыдущим разработчиком для решения конкретных бизнес-задач:

  • Скорость работы с большими данными. Партиционирование позволяло базе не «захлебываться» при работе с миллионами тендеров за несколько лет. Без него выборки по датам могли бы занимать минуты и ронять сервер.
  • Гибкость хранения. JSON-поля давали возможность хранить разнородные данные тендеров (у каждого тендера свой набор полей и параметров) без необходимости создавать сотни пустых колонок в таблице или ломать голову над структурой.
  • Автономность. Наличие встроенного полнотекстового поиска и обработчиков внутри PostgreSQL снижало зависимость от внешних сервисов и упрощало развертывание проекта.
Однако, когда мы пришли на проект, никакой документации по этим техническим решениям не существовало. Разработчик, который 10 лет выстраивал эту архитектуру, просто ушёл и забрал понимание работы проекта с собой в голове. Нам пришлось проводить обратный инжиниринг, чтобы разобраться, как именно работают эти механизмы и почему они были выбраны. В процессе мы задокументировали все эти особенности, чтобы клиент не потерял преимущества, заложенные в архитектуру, и понимал, как поддерживать систему дальше.

Этот опыт расширил нашу экспертизу: теперь мы работаем не только с MySQL, но и с проектами на PostgreSQL, используя его продвинутые возможности — партиционирование, внешние таблицы, JSON-запросы и хранимые процедуры.
Что было сделано на проекте
  • Проведен аудит и рефакторинг парсеров. Диагностированы и восстановлены неработающие боты для сбора тендеров с различных площадок (включая Сбер и др.).
  • Разработано нестандартное решение для парсинга. Найден и реализован рабочий способ обхода блокировок и лимитов через API мобильного приложения основного источника данных, когда официальный канал стал непригоден.
  • Полная инвентаризация внешних зависимостей. Выявлены, задокументированы и переданы клиенту данные доступа ко всем внешним сервисам (прокси, платежные шлюзы, SMS), которые ранее были известны только ушедшему разработчику.
  • Создана техническая документация. Написано более 30 инструкций и мануалов, описывающих архитектуру, запуск и обслуживание системы.
  • Код перемещен в Git. Создан и передан клиенту единый репозиторий с историей изменений, что сделало код прозрачным и управляемым.
Что получил клиент
  • Прозрачность и контроль. Клиент перестал зависеть от конкретного специалиста. Теперь у него есть полная документация и доступ к коду в репозитории.
  • Работоспособность продукта. Ключевые парсеры были починены, что вернуло актуальность данных на платформу и решило проблему с жалобами пользователей на отсутствие тендеров.
  • Управляемость и безопасность бизнеса. Информация о критически важных внешних сервисах (прокси, платежи) стала доступна бизнесу. Это снижает риски остановки сервиса в будущем.
  • Юридическая защита. Клиент получил актив, который теперь можно передать любой другой команде разработки, продать или развивать дальше.
Какую экспертизу получила веб-студия
  • Новый стек. Команда веб-студии НАДО успешно вошла в нетипичный для себя стек (Laravel + Vue/Nuxt + PostgreSQL), оказавшись способной работать с разными, даже прежде незнакомыми, технологиями.
  • Уровень технической подготовки. Разработчики изучили и применили на практике продвинутые возможности PostgreSQL, которые ранее не использовали. В частности, это партиционирование таблиц, работа с JSON-документами внутри колонок, внешние таблицы из CSV, полнотекстовый поиск и хранимые процедуры. Это расширило технический арсенал студии.
  • Умножение компетенций по работе с легаси. Получен опыт распутывания проектов, где бизнес-логика и доступы были завязаны на одного человека, а документация отсутствовала.
  • Навыки документирования. Отработан процесс обратного инжиниринга для создания качественной технической документации на основе уже существующего, но неописанного кода.
  • Управление рисками. Получен практический опыт работы в ситуации, когда бизнес клиента находился под угрозой остановки из-за ухода ключевого сотрудника. Мы отработали алгоритм действий по «спасению» такого проекта.