О клиенте
ГК «Лаборатория» — крупнейшая в России негосударственная сеть аналитических лабораторий. Работает с 2012 года, в сети несколько десятков лабораторных центров и около 100 партнёрских лабораторий, выполняющих отбор проб по всей стране. Более 6 000 выполненных проектов, работа в 83 субъектах РФ, свыше 500 методик исследований.
Профиль — экология и охрана труда: анализ атмосферного воздуха и воздуха рабочей зоны, почвы, отходов, воды, промышленных выбросов, радиационный контроль, физические факторы, экологическое нормирование и лабораторное сопровождение инженерно-экологических изысканий.
Заказчики — промышленные предприятия, разработчики природоохранной документации, организации, занимающиеся СОУТ, и другие лаборатории на субподряде. Среди клиентов — «Газпром трансгаз Югорск», «Роснефть-Ямалнефтепродукт», Автомобильный завод ГАЗ, Воткинский завод, Knauf, Nestlé, «Транснефть-Метрология».
Ключевая особенность бизнеса: работа только с юрлицами и ИП. Это B2B с длинным циклом сделки, где решение принимает эколог или специалист по охране труда, а бюджет согласовывает руководство. Сайт здесь — не витрина, а инструмент проверки: «примут ли ваш протокол в Росприроднадзоре», «есть ли у вас аккредитация на этилмеркаптан», «доедете ли вы до Сургута».
Задача
Клиент пришёл с формулировкой «нужен новый сайт, старый не продаёт». Мы разложили её на измеримые задачи:
- Донести масштаб сети. На старом сайте компания выглядела как одна московская лаборатория, хотя это федеральная сеть с собственной областью аккредитации шире, чем у любой отдельно взятой лаборатории страны.
- Снять возражения до звонка. Аккредитация, лицензия Росгидромета, ГОСТ ISO/IEC 17025, приём протоколов надзорными органами — всё это должно читаться с первого экрана, а не искаться в подвале.
- Развернуть услуги в структуру. Около 70 отдельных видов работ, которые ищут отдельными запросами: «биотестирование отходов», «замеры эффективности ГОУ», «измерение ЭРОА радона».
- Сделать каталог загрязняющих веществ. Отдельный раздел с кодами, ПДК, классами опасности и методиками — точка входа по низкочастотным запросам и одновременно инструмент для менеджеров.
- Закрыть географию. Работа по всей России, но на старом сайте не было ни одной региональной страницы.
- Обезопасить формы с вложениями. Клиенты присылают ТЗ, перечни веществ и схемы объектов файлами. Приём файлов до 10 МБ от анонимных пользователей — самый уязвимый узел сайта.
- Не потерять то, что уже работало. Старый сайт приносил трафик и заявки. Задача звучала жёстко: перезапуск не должен просадить поисковый трафик более чем на 15% и восстановиться за месяц.
Срок — 3 месяца, сентябрь — декабрь 2025 года. Формат — полный цикл: аналитика, UX, дизайн, фронтенд, бэкенд, безопасность, перенос, поддержка на запуске.
Что было на старте: аудит старого сайта
Первые полторы недели мы не писали ни строчки кода — разбирали, что есть.
Технический аудит
| Параметр | Старый сайт |
|---|---|
| CMS и тема | WordPress + покупная универсальная тема, 34 активных плагина |
| Вес главной страницы | 6,8 МБ |
| Запросов при загрузке | 184 |
| PageSpeed Insights, мобайл | 38 |
| PageSpeed Insights, десктоп | 74 |
| LCP (мобайл) | 4,9 с |
| TTFB | 1,9 с |
| CLS | 0,29 |
| Адаптивность | частичная, таблицы и формы ломались на 360px |
| HTTPS / HSTS | сертификат есть, HSTS нет |
| Версия PHP | 7.4 (не поддерживается) |
Отдельно посмотрели, из чего складываются 6,8 МБ. Половину веса давали логотипы клиентов — 84 файла в JPG, GIF и PNG, часть в исходном разрешении, все грузились сразу, без ленивой подгрузки. Ещё 1,2 МБ — три шрифтовых семейства, подключённые внешним запросом, из которых реально использовалось одно.
Аудит структуры и контента
- Услуги лежали плоским списком без вложенности: «Анализ почвы» и «Биотестирование грунта на определение класса опасности» были страницами одного уровня.
- Каталога веществ не было вообще. Информация о ПДК и кодах жила в PDF-прайсе, который менеджеры высылали по запросу.
- Отзывы существовали в виде одной страницы с 20 картинками-сканами без текста — поисковики видели пустую страницу, пользователь на мобильном не мог прочитать печать.
- Ни одной региональной страницы при работе в 83 субъектах.
- Формы — стандартный плагин, без валидации на стороне сервера, без ограничения типов файлов, без защиты от ботов кроме простой капчи.
Аудит безопасности
Здесь нашлось самое неприятное. За 14 дней логирования мы зафиксировали:
- постоянный перебор паролей к
/wp-login.phpи открытыйxmlrpc.php— классический вектор для распределённого брутфорса; - два плагина с известными уязвимостями, не обновлявшиеся более двух лет;
- директорию загрузок с включённым листингом — содержимое просматривалось напрямую;
- форму, принимающую файлы любого расширения и складывающую их в общедоступный
/wp-content/uploads/. Загруженный PHP-файл в такой конфигурации выполняется. Мы проверили на тестовом стенде — да, выполняется.
Последний пункт мы вынесли клиенту в отдельное письмо в тот же день и попросили временно отключить приём вложений, не дожидаясь нового сайта.
Стратегия: три параллельных потока вместо водопада
Три месяца на проект такого объёма — это мало. Классический водопад «дизайн → вёрстка → бэкенд» не уложился бы: только на согласование 40+ макетов ушёл бы месяц.
Мы разбили работу на три потока, идущих внахлёст:
- Контентный поток. Пока дизайнеры рисуют, контент-редактор и эколог со стороны клиента готовят и выверяют данные: карточки веществ, тексты услуг, расшифровки отзывов.
- Дизайн-поток. Не 40 макетов, а дизайн-система из компонентов плюс 9 ключевых шаблонов. Остальные страницы собираются из готовых блоков.
- Инженерный поток. Бэкенд стартовал на второй неделе — от структуры данных, не от макетов. Типы записей, поля, связи и импорт не зависят от того, каким цветом будет кнопка.
Такой подход дал выигрыш примерно в три недели, но потребовал жёсткой дисциплины: любое изменение структуры данных после 6-й недели проходило через отдельное согласование.
Календарный план
Этап 1. Исследование и прототипы
Провели 6 глубинных интервью: три с менеджерами отдела продаж клиента, три — с действующими заказчиками (эколог завода, специалист по ОТ, сотрудница проектной организации, разрабатывающей ПМООС).
Главный вывод, который переопределил структуру: пользователь приходит не за услугой, а за веществом или за нормативом. Формулировки запросов в интервью звучали так: «мне нужно подтвердить СЗЗ, там этилмеркаптан», «нужен КХА отходов под паспорт», «надо замерить шум на 40 рабочих местах». Никто не искал «лабораторные исследования».
Отсюда родились три параллельных входа в услуги, которые мы заложили в архитектуру:
- по объекту исследования — воздух, почва, отходы, вода, физические факторы;
- по веществу — каталог с кодом, формулой, ПДК и классом опасности;
- по задаче — производственный контроль, подтверждение СЗЗ, инженерные изыскания, СОУТ.
Второй вывод: у аудитории есть железобетонное возражение — «а примут ли ваш протокол». Мы вынесли ответ в отдельный блок с аттестатом аккредитации, ГОСТ ISO/IEC 17025 и лицензией Росгидромета, доступной для скачивания PDF-файлом. Не строчкой в подвале, а полноценным экраном.
Прототипы делали в двух состояниях сразу — десктоп и 375px. По логам старого сайта мобильная доля составляла 41%, что для B2B много: экологи заходят с телефона прямо с объекта.
Этап 2. Дизайн
Дизайн-концепцию согласовали со второй итерации. Отправная точка — сдержанная инженерная эстетика: белый фон, много воздуха, акцентный синий, чёткая типографика без декоративных шрифтов. Никаких стоковых фотографий людей в халатах с пробирками — только фактура: оборудование, документы, карта присутствия.
Что собрали:
- дизайн-систему из 46 компонентов — кнопки в четырёх состояниях, карточки услуг, карточка вещества, блок аккредитации, аккордеон FAQ, модалка выбора города, формы, слайдер логотипов, карточка отзыва;
- 9 шаблонов страниц: главная, категория услуг, страница услуги, каталог веществ, карточка вещества, блог, статья, отзывы, контакты;
- токены — цвета, отступы по 8-пиксельной сетке, размеры шрифтов, тени, радиусы. Всё это ушло в CSS-переменные один в один, без ручной переработки.
Отдельно проработали карточку вещества. Это самый информационно плотный экран сайта: название, код по классификатору, химическая формула, класс опасности, ПДК для разных сред, применяемые методики, ссылки на релевантные услуги и кнопка заказа анализа именно этого показателя. На мобильном таблица ПДК превращается в набор карточек — горизонтальный скролл в таблицах мы считаем провалом, а не решением.
Этап 3. Бэкенд и структура данных
Платформа — WordPress. Выбор осознанный: у клиента внутри есть контент-менеджер, привыкший к админке, а объём кастомной логики не дотягивал до самописного решения. Но тему написали свою, с нуля, без конструкторов страниц.
Модель данных
Развернули четыре кастомных типа записей:
- Услуги — с иерархией: 12 категорий верхнего уровня и около 70 дочерних страниц. Реализовано на иерархическом CPT с человекопонятными URL вида
/analiz-pochvy/biotestirovanie-grunta-na-opredelenie-klassa-opasnosti/. - Вещества — карточка с полями: наименование, синонимы, код, брутто-формула, класс опасности, ПДК по средам, перечень методик, связь с услугами.
- Отзывы — скан благодарственного письма плюс обязательное текстовое расшифрование и название организации.
- Эксперты — специалисты с квалификацией и зоной ответственности.
Поля собрали на ACF Pro, связи «вещество ↔ услуга» — двусторонние, чтобы редактор заполнял связь один раз с любой стороны.
Импорт каталога веществ
Клиент отдал исходник в виде выгрузки Excel с 640 строками. Данные оказались в состоянии, типичном для таблицы, которую 8 лет вели вручную: дубли с разным написанием («АММИАЧНАЯ СЕЛИТРА» и «АММИАЧНАЯ СЕЛИТРА (АММОНИЙ НИТРАТ)»), формулы вперемешку с текстом, ПДК в разных единицах, коды с ведущими нулями, съеденными Excel.
Мы написали импортёр, который нормализует единицы, восстанавливает коды, приводит формулы к юникод-подстрочникам (C₄H₉Br вместо C4H9Br) и помечает подозрительные строки на ручную проверку. Из 640 строк автоматически прошли 172, остальные ушли в очередь на выверку эколога клиента. На запуске каталог стартовал со 172 карточек — и это осознанное решение: лучше 172 выверенных, чем 640 с ошибками в ПДК. Ошибка в ПДК на сайте лаборатории — репутационный риск, а не опечатка.
Гео-модуль
44 города развернули не копированием контента, а одним шаблоном с географическим словарём. Город определяется по URL-сегменту, подставляется в заголовки, тексты, микроразметку организации и контактный блок. Переключение — через модалку со списком и поиском. Выбор запоминается в cookie, при повторном заходе пользователь попадает на свою версию.
Важно: мы не клонировали весь каталог услуг на каждый город. 44 × 70 = 3 080 почти одинаковых страниц — это прямой путь к фильтру за малополезный контент. На запуске гео-версии получили только главную и разделы верхнего уровня, с планом наращивать уникальный контент по регионам поэтапно.
Формы и приём заявок
Форм на сайте четыре типа: заказ звонка, получение прайс-листа, расчёт стоимости с вложением, общая заявка. Все написаны кастомно, без плагинов, с серверной валидацией, тремя раздельными чекбоксами согласий (оферта и политика, обработка ПДн, рассылка) и логированием факта согласия с меткой времени и IP — этого требует 152-ФЗ, и на старом сайте этого не было.
Этап 4. Фронтенд
Собирали без фреймворка: чистый JavaScript, около 38 КБ в сжатом виде на всю интерактивность. jQuery выпилили полностью — на WordPress это требует аккуратности, но экономит 90+ КБ.
Что дало основной прирост производительности:
- Критический CSS инлайном в
<head>, остальное — отложенной загрузкой. - Изображения — WebP с JPEG-фолбэком, автогенерация пяти размеров,
srcset, нативныйloading="lazy"для всего ниже первого экрана. 84 логотипа клиентов, дававшие половину веса главной, ужались с 3,4 МБ до 210 КБ и грузятся по мере прокрутки. - Шрифты локально, в WOFF2, только используемые начертания, с
font-display: swapи предзагрузкой основного. - Явные размеры у всех медиа и зарезервированное место под баннер cookie — CLS ушёл с 0,29 до 0,02.
- Серверное кеширование полных страниц с точечной инвалидацией при правке записи, плюс объектный кеш на Redis для тяжёлых выборок каталога.
- Поиск по каталогу веществ — через REST-эндпоинт с индексом по названию, синонимам и коду, с дебаунсом запроса. Поиск по 172 карточкам с учётом синонимов должен отдавать результат мгновенно, иначе им не пользуются.
Доступность проверяли не для галочки: навигация с клавиатуры по всем интерактивным элементам, видимый фокус, aria-атрибуты у аккордеонов и модалок, контраст текста не ниже 4.5:1.
Производительность: до и после
| Метрика | Было | Стало | Изменение |
|---|---|---|---|
| LCP, мобайл | 4,9 с | 1,4 с | −71% |
| TTFB | 1,9 с | 0,26 с | −86% |
| CLS | 0,29 | 0,02 | −93% |
| INP | 340 мс | 110 мс | −68% |
| Вес главной | 6,8 МБ | 0,74 МБ | −89% |
| Запросов при загрузке | 184 | 31 | −83% |
Этап 5. Безопасность
Это тот блок, который клиенты обычно предлагают «сделать потом». Мы заложили его в смету отдельной строкой и не дали убрать — с учётом того, что нашли при аудите.
Контур защиты
- Приём файлов. Белый список расширений (PDF, DOC/DOCX, XLS/XLSX, JPG, PNG, ZIP), проверка реального MIME-типа по сигнатуре файла, а не по расширению, антивирусное сканирование каждой загрузки, переименование в случайный идентификатор, хранение вне корня сайта с выдачей через PHP-обработчик. Прямого URL у загруженного файла не существует.
- Формы. Токен на сеанс, скрытое honeypot-поле, ограничение частоты отправок по IP и по подсети, серверная валидация всех полей, экранирование при выводе в письмо и в админку.
- Админка. Адрес входа изменён,
xmlrpc.phpотключён, двухфакторная аутентификация для всех учётных записей, блокировка после 5 неудачных попыток, разграничение ролей: контент-менеджер не может ставить плагины и править код. - Заголовки. HSTS с preload, Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy.
- Инфраструктура. WAF перед сайтом, запрет выполнения PHP в директории загрузок на уровне веб-сервера, отключённое листирование директорий, PHP 8.3, ежедневные автоматические бэкапы с недельной глубиной и проверкой восстановления, мониторинг доступности с оповещением в Telegram.
- Персональные данные. Логирование согласий, шифрование вложений в состоянии покоя, регламент удаления заявок старше 12 месяцев.
Перед запуском провели сканирование на OWASP Top 10 и ручную проверку загрузчика: пытались залить PHP под видом JPG, вложенный архив, файл с двойным расширением, полиглот-файл, валидный по обеим сигнатурам. Все попытки отклонены на этапе проверки сигнатуры.
Что фильтр поймал за первые 30 дней после запуска
310 попыток загрузить исполняемый файл через форму за месяц — на старом сайте любая из них прошла бы.
Этап 6. Перенос без потери трафика
Отдельная работа, которую мы всегда ведём как SEO-агентство, а не как разработчики. Полная смена структуры URL на сайте с историей — это операция, где ошибка стоит месяцев восстановления.
Что сделали:
- Выгрузили все URL старого сайта из логов, Метрики, Вебмастера и краулера. Получили 214 адресов, из них 168 с органическим трафиком за последние 12 месяцев.
- Составили карту соответствий вручную. Автоматика по схожести заголовков дала 23 ошибочных сопоставления — их поймали на ручной проверке.
- Настроили 301-редиректы один в один. Ни одного редиректа на главную — если старой страницы нет аналога, ведём на ближайшую релевантную категорию.
- Сохранили все URL, которые можно было сохранить. Часть адресов услуг перенесли без изменений, чтобы не тратить ссылочный вес.
- Перенесли и расширили микроразметку: Organization с указанием аккредитаций, Service для страниц услуг, FAQPage, BreadcrumbList, Article для блога.
- Собрали XML-карты по типам записей, подключили IndexNow для мгновенного уведомления о новых страницах.
- Запускались во вторник утром, чтобы вся команда была на связи. Первые 72 часа — мониторинг 404, серверных ошибок и скорости индексации каждые 4 часа.
Индексация после запуска
Просадка органического трафика в первые две недели составила 11% — в пределах того, о чём договаривались. К концу пятой недели трафик вернулся к прежним значениям, к концу восьмой превысил дозапусковый уровень на 18% за счёт новых страниц услуг и каталога веществ.
Результаты
| Показатель | Результат |
|---|---|
| Срок разработки | 3 месяца, в срок |
| Страниц на запуске | 341 |
| Компонентов в дизайн-системе | 46 |
| PageSpeed мобайл | 38 → 91 |
| Вес главной страницы | 6,8 МБ → 0,74 МБ |
| Просадка трафика при переносе | 11%, восстановление за 5 недель |
| Органический трафик через 2 месяца | +18% к дозапусковому уровню |
| Конверсия в заявку | 0,9% → 2,4% |
| Доля заявок с мобильных | 17% → 34% |
| Инцидентов безопасности после запуска | 0 |
По конверсии оговоримся честно: рост с 0,9% до 2,4% измерен за первые два месяца после запуска, декабрь — январь. Это низкий сезон в отрасли, объём выборки — 61 заявка. Мы считаем цифру индикативной, а не доказанной: чтобы говорить о конверсии уверенно, нужен полный годовой цикл с весенним пиком производственного контроля.
Что мы считаем более надёжным показателем — качество заявок. Менеджеры клиента отметили, что после запуска в заявках стало приходить больше конкретики: указан объект, перечень веществ, регион. Это прямое следствие того, что форма расчёта стоимости задаёт правильные вопросы и позволяет приложить файл, а каталог веществ помогает клиенту сформулировать задачу до обращения.
Что не получилось и что осталось на второй этап
Раздел, который мы в кейсах не вырезаем.
- Каталог веществ вышел меньше запланированного. Целились в 640 позиций, выпустили 172. Причина не техническая: выверка ПДК и методик требует времени эколога клиента, а он один и загружен основной работой. Импортёр готов, очередь на проверку размечена, наполнение идёт своим темпом.
- Гео-страницы пока слабо дифференцированы. На запуске 44 региональные версии отличаются подстановками и контактами, но не уникальным содержанием. Это осознанный компромисс: сделать 44 полноценных региональных страницы с местной спецификой за оставшееся время было невозможно, а плодить дубли ради количества — вредно.
- Интеграция с CRM не вошла в срок. Заявки уходят на почту и в Telegram, автоматической выгрузки в CRM нет. Согласование доступов на стороне клиента затянулось, и мы приняли решение не тормозить запуск ради интеграции. Вынесли во второй этап.
- Личный кабинет заказчика не делали. Идея хорошая — клиент видит статус проб и скачивает протоколы. Но это отдельный проект на несколько месяцев с интеграцией в LIMS лаборатории, а не блок внутри сайта. Зафиксировали в дорожной карте.
- Блог мигрировал не полностью. Из архива старых статей перенесли те, что имели трафик или ссылки; часть устаревших материалов по отменённым нормативам решили не переносить вовсе. Это правильно с точки зрения качества, но формально это минус несколько десятков страниц.
Выводы: что мы бы повторили в похожем проекте
- Начинать бэкенд от структуры данных, а не от макетов. На проекте с каталогом и справочником это экономит недели. Модель данных не меняется от того, что дизайн ушёл на третью итерацию.
- Считать чужие данные грязными по умолчанию. Восьмилетняя таблица в Excel всегда содержит дубли и битые единицы измерения. Импортёр с валидацией и очередью ручной проверки надо закладывать в смету сразу, а не выяснять на шестой неделе.
- Не масштабировать гео до того, как есть чем его наполнить. Три тысячи почти одинаковых страниц — это не охват, а риск. 44 качественные версии лучше, чем 3 080 клонов.
- Безопасность приёма файлов — не опция. Если сайт принимает вложения от анонимных пользователей, контур защиты загрузчика должен проектироваться вместе с формой, а не добавляться после. 310 заблокированных попыток за первый месяц — это не гипотетический риск.
- Перенос — это отдельный проект внутри проекта. Карту редиректов надо проверять руками. Автоматическое сопоставление по заголовкам ошиблось в 23 случаях из 214 — это 11% трафика, которые ушли бы не туда.
- Честно проговаривать, что не влезает в срок. Клиент, которому на старте сказали «CRM во втором этапе», спокойнее клиента, которому обещали всё и не сделали.