Бизнес-сайты

Корпоративные и бизнес-сайты на чистом стеке — без CMS и фреймворков. Многостраничная и мультиязычная структура, формы заявок с защитой от спама, SEO и оптимизация производительности.

Если вы не разработчик

Сайт компании отличается от лендинга не размером, а сроком жизни. Услуги, объекты, документы, контакты по филиалам — к такому сайту возвращаются, его читают по частям и ищут в нём конкретное. Поэтому у него другая структура и другие требования к скорости и к поиску.

Здесь такие сайты собраны без CMS. Это значит: нечего обновлять ради безопасности, нечему ломаться после чужого обновления и нет ежемесячной платы за движок. Заявки приходят в мессенджер, а не копятся в панели, куда никто не заходит.

Бизнес-сайт

МосКомДез — сайт службы дезинфекции

РольЕдинственный разработчик — full-stack: архитектура, бэкенд, фронтенд, вёрстка, админ-панель, интеграция с amoCRM, подготовка изображений, SEO, оптимизация и деплой
СтекPHP 8 · HTML5 · CSS3 · JavaScript · JSON вместо СУБД — без CMS, фреймворков, npm и Composer

Действующий сайт службы дезинфекции, дезинсекции и дератизации «МосКомДез»: главная, 27 страниц услуг, контакты и политика, собственная админ-панель. Полная замена лендинга на Tilda — с переносом контента, чисткой технических косяков донора и сохранением SEO. Ключевая особенность: один физический сайт обслуживает 80 городских версий на wildcard-поддоменах — Москва на основном домене и 79 городов Московской области, без единой копии файлов. Заявки уходят одновременно в amoCRM заказчика и в Telegram. Всё написано на чистом PHP без CMS и базы данных, работает на обычном shared-хостинге и не требует ни одной сборки на сервере.

Что было нужноСайт стоял на Tilda, упирался в её ограничения и не позволял завести отдельные страницы под города области.

Что получилосьОдин сайт обслуживает 80 городских версий, заявки уходят в amoCRM и Telegram, позиции при переезде не потеряны.

Мультигородская архитектура

Требование заказчика — городские посадочные под всю Московскую область. Копировать сайт 80 раз нельзя: контент правится через админку и мгновенно разъехался бы.

  • Реестр городов — один JSON: слаг (он же поддомен), название и четыре падежных формы, флаги «основной», «работает», «в поиске». Он же источник списка городов на странице и переключателя версий.
  • Городские названия подставляются плейсхолдерами {CITY}, {CITY_IN}, {CITY_TO} и другими — заменой по готовому HTML через колбэк буфера вывода. Поэтому они работают везде разом: в шаблонах, в текстах из админки, в alt и title, в скрытых полях форм и в микроразметке. Забыть подключить подстановку в новом блоке физически негде.
  • Персонализированы title, description, keywords, заголовки H1–H3, основной и SEO-текст, FAQ, подписи к картинкам и формы. Намеренно не персонализированы адрес офиса и реальные локации примеров работ.
  • Разбор хоста решается до любого вывода: неизвестный поддомен отдаёт честный 404, поддомен основного города — 301 на главный домен, чтобы не плодить дубли.
  • Canonical и og:url считаются от текущего хоста и сами держатся на поддомене. robots.txt генерится PHP: строка Sitemap указывает на текущий хост, а на городских версиях её нет вовсе.
  • Вся логика поддоменов заперта в одном файле — остальной код про них не знает.
  • Админка на поддоменах отдаёт 404: 79 лишних точек входа в логин не нужны.

Контент и собственная админ-панель

Контента много — 27 страниц услуг, девять прайс-таблиц, 80 городов, — и весь он лежит в JSON, а правится через самописную панель.

  • Редактор страницы услуги на вкладках: SEO, герой (заголовок, чек-лист, картинка, цена), тексты, прайс из нескольких таблиц, FAQ и набор блоков страницы — галерею, методы, сертификаты, квиз и прочее можно выключить по каждой услуге.
  • Отдельные экраны: герой главной, прайс главной, слайдер услуг, примеры работ «до/после», города, настройки, корзина с восстановлением удалённых услуг.
  • Запись всегда одинаковая: валидация → бэкап старой версии (10 копий на файл) → контрольная распаковка того, что собрались писать → временный файл → атомарный rename. Оборванный запрос не оставит битый JSON, а ошибка выходит человеческим текстом, а не пятисоткой.
  • Тексты чистятся белым списком тегов с полным срезанием атрибутов: копипаст из Word не сломает вёрстку и не пронесёт скрипт.
  • Загрузка фотографий: приём файла с проверкой типа, кроп и конвертация в WebP на сервере через GD.
  • В таблице городов намеренно нет колонки «Основной»: сервер берёт этот флаг из действующего файла и игнорирует присланный, а строку основного города нельзя ни удалить, ни выключить — заказчик не должен мочь случайно переназначить главный домен.

Заявки, квиз и интеграция с amoCRM

Шесть точек входа заявки на сайте: промо-полоса, форма героя, «назначить специалиста», модальное окно, две формы на контактах и квиз-калькулятор.

  • Квиз из четырёх шагов плюс финальный экран. На странице услуги нужный вариант шага «проблема» отмечен заранее — человек уже прочитал заголовок, повторно тыкать очевидное не заставляем. С клиента приходят только индексы ответов, тексты сервер берёт из своего JSON: прислать произвольную строку нельзя.
  • Город заявки определяется по хосту, а не по полю формы — подделать нельзя.
  • Защита приёмника: honeypot, серверная валидация телефона и согласия, обрезка полей по символам, лимит 5 заявок с одного IP за 10 минут на файле под flock.
  • Интеграция с живой amoCRM заказчика без тестового контура: заявка кладётся в «Неразобранное» нужной воронки — физлица и юрлица разводятся по первому шагу квиза. Ответы квиза раскладываются по реальным полям CRM, рекламные метки — по служебным API-полям, остальное уходит примечанием.
  • Поиск дубля по телефону обязателен, а не опционален: в CRM уже пишут телефония и сервис обратного звонка. Поиск в amo строковый и по всем полям сразу, поэтому ищем по последним десяти цифрам номера и потом сверяем найденный контакт — иначе заявка прилипает к чужой карточке.
  • Ни один ID поля не написан руками: карта соответствий генерится скриптом из выгрузки аккаунта, проверяется отдельной командой, а раскладка заявки по полям прогоняется локально без обращения к сети.
  • Telegram оставлен вторым каналом по просьбе заказчика: заявка считается принятой, если сработал хотя бы один канал, а если не сработал ни один — дописывается в закрытый лог на диске. Терять лид нельзя: второй раз человек писать не станет.
  • Обратный вебхук: при переходе сделки на финальный этап в Telegram-группу уходит сообщение с городом, проблемой, контактами и ссылкой на сделку.
  • Рекламные метки первого захода (utm, gclid, yclid, referrer) запоминаются в куку на базовом домене — она переживает гео-редирект на поддомен, поэтому источник не затирается и реклама не превращается в прямые заходы.

Определение города посетителя

Отдельное требование заказчика: человек должен сразу попадать на версию своего города.

  • Браузер спрашивается о геолокации, при отказе или таймауте город определяется по IP — обе ветки идут через DaData.
  • Название нормализуется (город из сервиса и город из реестра сравниваются без «г.», регистра и «ё»), город ищется в реестре; чужой город — остаёмся на Москве.
  • Свой город — переход на его поддомен тем же путём, дальше поп-ап «Нужна обработка в …?»: «Да» — остаться, «Нет» — полноэкранный список городов с живым поиском.
  • Результат и подтверждение кладутся в куки на базовом домене, чтобы поддомены видели их друг у друга: определение выполняется один раз на посетителя.
  • У бесплатной квоты сервиса 10 000 запросов в сутки, поэтому эндпоинт держит собственный лимит — 20 определений с IP в час, счётчик в файле под flock.

SEO

  • Уникальные метаданные на каждую из 27 услуг, персонализированные по городу.
  • JSON-LD: LocalBusiness с телефонами, разобранным на части адресом и зоной обслуживания текущего города, плюс FAQPage — но только там, где блок вопросов реально выводится на странице.
  • sitemap.xml собирается из индекса услуг, дата изменения берётся с файла контента и обновляется сама при правке через админку.
  • Плоские ЧПУ, канонический адрес доводится 301-м с сохранением UTM-меток.
  • Городские версии закрыты от индексации мета-тегом и HTTP-заголовком, при этом robots.txt их не запрещает — робот должен зайти и увидеть noindex. Включение города в поиск — рычаг в админке.
  • Open Graph и Twitter card на всех страницах, осмысленная страница 404 с noindex.

Производительность и доступность

PageSpeed Insights, боевой домен, август 2026. Страница услуги: Performance 100, Accessibility 100, Best Practices 96, SEO 100 на мобильных и 99/100/96/100 на десктопе. Главная: 92/100/88/100 на мобильных.

  • Скорость вытянута вёрсткой и ассетами, а не инфраструктурой: ни CDN, ни кэш-слоя, ни сборщиков на сервере — обычный shared-хостинг.
  • Свой Roboto вместо Google Fonts убрал render-blocking около 2 секунд и цепочку из пяти внешних запросов: три вариативных woff2 по подмножествам, preload кириллицы и латиницы.
  • Минификация своими средствами и версионирование ассетов по времени файла: CSS 91,6 → 54,6 КБ (10,2 КБ по сети), JS 33,1 → 14,3 КБ (4,7 КБ). Если минифай устарел, отдаётся исходник — сайт не ломается.
  • Все изображения в WebP с явными размерами, srcset и fetchpriority на LCP-картинке, ленивая загрузка остального, content-visibility на нижних секциях. CLS около нуля.
  • Accessibility 100: контраст AA во всех местах, где цветной текст шёл по светлому фону, aria-подписи в формах, тач-цели не меньше 24 px, закрытие модалок по Esc, ветка prefers-reduced-motion у анимаций.
  • Минус четыре балла в Best Practices — цена запроса геолокации на загрузке страницы: Lighthouse хочет разрешение по клику, но тогда автоперехода на нужный город не получится. Осознанный размен баллов на функциональность, оговорённый с заказчиком. До подключения геолокации сайт брал 100 по всем четырём категориям.

Безопасность и надёжность

  • Секреты только в конфиге вне репозитория; в HTML и JS не попадает ни один токен.
  • Папки с контентом, служебным PHP, кусками шаблонов и скриптами разработчика закрыты от прямого доступа, с подстраховкой на случай выключенного mod_rewrite.
  • Экранирование вывода везде, где в разметку идут данные; микроразметка кодируется так, что случайный </script> в тексте не порвёт страницу; обход директорий отсечён на всех путях, которые собираются из входных данных.
  • Админка: хэш пароля, сравнение с защитой от тайминга, задержка на неудачную попытку, регенерация сессии, CSRF-токен на всех пишущих действиях, кука только для раздела админки с httponly и secure по фактическому протоколу.
  • Вебхук CRM защищён секретом в адресе — подписи у amoCRM-вебхуков нет.
  • Мягкая деградация везде: нет конфига — берётся шаблон, нет минифая — исходник, недоступна CRM — работает Telegram, не сработало ничего — заявка ложится в лог.

Чем интересен проект

  • 80 городских версий сайта без единой копии файлов — подстановка падежей через буфер вывода оказалась и проще, и надёжнее шаблонных функций.
  • Интеграция с чужой живой CRM без тестового контура: карта полей, собранная скриптом из выгрузки аккаунта, склейка дублей по последним десяти цифрам номера и сухой прогон раскладки заявки локально, без единого запроса наружу.
  • Заявка не теряется никогда: CRM → Telegram → лог на диске, успех при срабатывании любого звена.
  • 100/100/96/100 на странице услуги при полностью самописном стеке, без CDN, кэш-слоя и сборщиков — на дешёвом shared-хостинге.
  • Полный цикл одним человеком: перенос контента с Tilda → архитектура → бэкенд → фронтенд → админка → интеграция с CRM → подготовка 100+ изображений → SEO → оптимизация → деплой на боевой домен.
Бизнес-сайт

ПрайсСмета — площадка цифровых товаров

РольЕдинственный разработчик — full-stack: архитектура, бэкенд на PHP/MySQL, фронтенд, кабинет и оплата, админка, SEO и деплой
СтекPHP · MySQL · HTML · CSS · JavaScript — без фреймворков и CMS

Самописная площадка цифровых товаров «ПрайсСмета»: готовые автоматические сметы и прайс-листы в Excel для электриков, сантехников, плиточников, бригад и строительных компаний. Полноценный продукт на PHP + MySQL, без CMS и фреймворков — каталог, карточки товаров, личный кабинет, онлайн-оплата с выдачей файлов, раздел статей, FAQ и кастомная админ-панель.

Что было нужноПродавать готовые сметы в Excel так, чтобы покупатель заплатил и сразу получил файл — без переписки и ручной отправки.

Что получилосьОплата и выдача файлов работают сами. У покупателя есть кабинет с историей покупок, у владельца — админка со статистикой.

Что внутри

Полный жизненный цикл цифрового товара — от витрины до выдачи файла после оплаты.

  • Каталог цифровых товаров и страницы товаров; на главную выводятся последние публикации из базы.
  • Личный кабинет: регистрация, вход, восстановление пароля.
  • Онлайн-оплата с подписью транзакции (HMAC) и автоматической выдачей файла после покупки.
  • Раздел статей (блог) и FAQ, оферта и политика обработки данных.

Архитектура

Серверный рендеринг на PHP с базой MySQL (PDO), без CMS и фреймворков.

  • Товары и статьи хранятся в базе, публикация управляется флагом — на сайт попадает только опубликованное.
  • Код разнесён на переиспользуемые инклюды (шапка, подвал, попапы) и хелперы навигации.
  • Сессии для авторизации, защита служебных страниц и оплаты.

Кастомная админ-панель

Полностью самописная панель управления контентом и продажами: каталог товаров, статьи (публикация и снятие), работа с заказами.

Доступность и SEO

  • Семантический лендмарк main, контраст и доступная навигация.
  • Keyword-first title, meta description, Open Graph, осмысленная разметка.

Чем интересен проект

  • Самый крупный из бизнес-проектов: полноценная продуктовая площадка с кабинетом, оплатой и админкой — на чистом PHP + MySQL, без CMS.
  • Полный цикл одним человеком: архитектура → бэкенд и база → фронтенд → оплата → админка → SEO → деплой.
Бизнес-сайт

Металлообработка — корпоративный сайт на 9 языках

РольЕдинственный разработчик: дизайн, фронтенд, бэкенд формы, мультиязычность (9 языков), SEO и деплой
СтекPHP · HTML · CSS · JavaScript — без фреймворков и CMS

Корпоративный сайт компании по металлообработке: токарная и фрезерная обработка деталей по чертежам, прототипы и серия, работа по Европе. Задача — внятно показать производственные возможности и собирать заявки с приложенными чертежами сразу на девяти языках. Многосекционный сайт на чистом стеке, без CMS и фреймворков.

Что было нужноПоказать производственные возможности европейским заказчикам и принимать заявки с приложенными чертежами — сразу на девяти языках.

Что получилосьДевять языковых версий на одном сайте, форма принимает чертежи файлом, заявка приходит с указанием языка и страницы.

Что внутри

Многосекционная структура с акцентом на производственные возможности.

  • Hero, блок метрик компании: опыт работы, парк оборудования, выполненные заказы.
  • Слайдер оборудования и портфолио выполненных проектов (слайдер на десктопе, грид на мобайле).
  • Услуги и типы фрезерных операций с поясняющим видео.
  • Модальная форма «Получить расчёт» и анимации появления секций при скролле.

Форма заявки под производство

Главный рабочий элемент — приём заявки с техническими чертежами, а не просто «имя + телефон».

  • Загрузка до 10 файлов в производственных форматах (DXF, DWG, PDF, ZIP, изображения, документы), отправка письмом с вложениями.
  • Защита от спама в три слоя: серверная арифметическая капча, honeypot и таймер-ловушка против мгновенной отправки ботом.
  • Валидация на клиенте и на сервере, отправка через AJAX без перезагрузки страницы.

Девять языков

Сайт полностью переведён на девять языков: английский (основной), русский, немецкий, французский, итальянский, испанский, польский, румынский и сербский.

  • У каждого языка свой контент и свой серверный обработчик формы.
  • Кастомный переключатель языков с флагами.
  • hreflang + x-default по всем девяти версиям.

Доступность

  • Семантический лендмарк main, aria-метки на интерактивных элементах (бургер, переключатель языков).
  • Корректная иерархия заголовков и осмысленные alt-тексты.
  • Контраст и фокус-навигация по WCAG.

Чем интересен проект

  • Серьёзный B2B-сайт со сложной формой под реальный производственный процесс — приём чертежей в инженерных форматах.
  • Полноценная мультиязычность на девять локалей на чистом стеке, без i18n-фреймворков.
  • Полный цикл одним человеком: дизайн → вёрстка → бэкенд формы → локализация → деплой.

Что дальше

Сроки и вилки цен по такому сайту — на странице сколько стоит сделать сайт. Если задача проще и хватит одной страницы, это раздел лендингов.