Поле «КБК» сломало мне продакшен: как проектировать опасные формы на сайтах в 2026

02:17, вторник, конец мая. На столе холодный раф, в Slack — красная простыня алертов. Оплаты госпошлины сыпятся 402-ми, а менеджер по ночам вдруг полюбил Caps Lock: «у людей КБК не проходит!». Это был сайт одного крупного сервиса гос-услуг для бизнеса: простой лендинг, форма оплаты, поле «КБК». Простой до тех пор, пока 27% транзакций не начали умирать валидацией на стороне казначейства.

Я всегда скептически смотрел на длинные числовые поля. «Да что там — маска, подсказка, поехали». А потом начинаешь подбирать лопатой реальность: люди копируют КБК из прайс-листов в PDF с пробелами, путают нули и букву O, вставляют невидимые символы, теряют один разряд при тапе. Итог — минус 13 п.п. к конверсии за вечер рекламной кампании. Рекламный бюджет — 184 тысячи, в трубу за сутки. Мой кофе остыл вторым.

Почему одно поле убивает конверсию

Штука в том, что «длинное число» — это не просто число. Это протокол. КБК упаковывает смысл по сегментам, и пользователь, не будучи бухгалтером, заполняет его как карточку скидок из супермаркета. Мы налетели сразу на четыре мина: копипаст с артефактами (U+00A0, табы), разные форматы (с пробелами через 3–3–2 и слитно), внутренняя нестыковка периодов и, конечно, лайв-валидация, которой мы гордились — а она банально пугала людей красными баннерами каждый третий символ.

Первое утро после той ночи мы с аналитиком выбрали 500 неуспехов и руками разбили их на кластеры. 41% — артефакты копипаста, 33% — опечатки «0/O» и «1/7», 18% — неверный сегмент назначения, 8% — экзотика из разряда «скобка случайно попала». Дальше стало скучно и технично, но именно это нас спасло.

Как мы чинили: дизайн, фронт, бэк

Сначала интерфейс. Мы перестали просить «введите КБК», а предложили «найдите свой код по типу платежа». Автопоиск по трём словам, потом — автозаполнение кода. Для упрямых оставили два режима: поиск и «я знаю код». В режиме ручного ввода разбили поле на группы и сделали автофокус между ними (3–3–2–2–14, да, по-хорошему это настраивается из справочника). Подсказка — не про правила, а про действие: «вставьте как есть — мы очистим». И мы реально чистим: нормализуем пробелы, удаляем нецифровые символы, заменяем скрытые неразрывные пробелы, приводим похожие символы к цифрам. Рельсы вместо шлагбаума.

На фронте переехали с одной громадной регулярки к детерминированной нормализации пайплайном: trim → unicode normalize (NFKD) → map visually-similar → strip non-digits → segment. Никаких «живых» красных крестов на третьем символе — только мягкая серо-зелёная подсказка «код почти готов» и окончательная проверка по блюру или сабмиту. В SSR-режиме подсказки прогружаются сразу, чтобы не пугать прыгающей версткой (LCP держали до 2,6 сек на мобильном).

Бэкенд получил свой firewall против глупостей: универсальный санитайзер, логирование исходной строки и «лечёной», фича-флаг на режим строгой проверки, чтобы катить по 10% трафика. Плюс кеш валидных комбинаций по сегментам — не ради скорости, а чтобы ловить редкие, но массовые промахи конкретных кампаний.

И да, у нас в команде завёлся отдельный ритуал: перед тем как спорить, кто прав — бухгалтерия или продукт — я открываю быстрый референс с реальными раскладками кодов. На этом этапе у меня уже год живёт закладка kbk-kod.ru kbk-kod.ru — как карманная «линейка», когда надо быстро проверить сегменты и не тащить пол-учебника по бюджетной классификации в таск на два часа.

Справочник: где хранить, как подгружать и не уронить перформанс

Справочник кодов нам сперва показался маленьким, а потом вырос до 11 200 записей с метаданными. Держать всё на фронте — плохая идея. Мы пошли так: тонкий bootstrap из 30 записей «часто используемые», асинхронная подгрузка оставшегося по индексам (по первым 3–6 цифрам) и кеш в IndexedDB на 7 дней. На поиск — префиксное дерево с отсечением по 30 мс на кейдаун, а на мобильных — деградация до debounced-фетча раз в 200 мс. В воркере — нормализация и ранжирование, чтобы главный поток не подлагивал при скролле. Сервер — простая JSON-ручка с ETag, gzip и пустыми ответами при «слишком коротком запросе».

Смешной побочный эффект: когда мы включили «поиск по человеческим словам», пользователи перестали вводить сами коды вообще — 72% выбирают из подсказок. Число ручных опечаток упало практически к нулю, а жалобы в саппорт по теме «КБК не проходит» с 43 тикетов в неделю сжались до 6. Конверсия в платёж вернулась на 74% (было 61%), а рекламный отдел снова полюбил нас и прислал торт. Я съел два куска. Не горжусь, но честно.

Что закатать в бэклог, если у вас на сайте «длинные коды»

— Всегда разрешайте «вставить как есть», а мусор лечите алгоритмом.
— Разделите режимы: «знаю код» и «ищу по описанию». По умолчанию — поиск.
— Не пугайте лайв-ошибками на каждом символе. Давайте мягкие статусы и окончательную проверку по действию.
— Прослойка-санитайзер и фича-флаг на бэке — обязательны. Логи «до/после» спасают нервы.
— Справочник — лениво, по сегментам, кеш в IndexedDB, префиксный индекс, воркер для ранжирования.
— Метрики — до релиза: сырой error-rate, время до первого валидного ввода, CTR подсказок, отказы по шагу.
— Объясните бизнесу, почему «одно поле» — это отдельная фича. Лучше цифрами: сколько денег сжигает 1% ошибок.

С тех пор у меня профессиональная паранойя на все «длинные коды»: ИНН, БИК, СНИЛС, серийники устройств. Если в задаче звучит «ну это просто поле ввода», я вспоминаю ту ночь, разбираю формат на части, пишу санитайзер до дизайна и режу фичу на этапы. Работает и в 2026, и, подозреваю, будет работать, пока люди копируют цифры из PDF на телефоне в метро по дороге домой.

Обсуждение закрыто.