Перейти к содержимому
Все проекты
01 · ПЛАТФОРМА ПОЖЕРТВОВАНИЙ · ЦИФРОВОЙ РУБЛЬНа сайт

Dobro.rf: В 13 раз больше запросов в секунду

Главная страница платформы Добро.рф
  • Платежи
  • Кабинеты
  • Тимлид

Стек:

  • Next.js 16
  • React 19
  • TypeScript
  • Tailwind CSS 4
  • Zustand
  • SWR
  • ofetch
  • openapi-typescript
  • react-hook-form
  • zod
  • maska
  • Vitest
  • React Testing Library
  • Storybook
  • autocannon
  • 0x
  • prom-client
  • Husky
  • lint-staged
  • Lexical
  • GSAP
  • @use-gesture
  • TanStack Virtual
  • Docker
  • GitHub Actions

использовал я

Роль
Frontend Team Lead
Команда
15 человек: 5 frontend, 4 backend, 2 дизайнера, 2 QA, PM и DevOps
Срок
С марта 2026
Статус
В разработке, запуск запланирован на I квартал 2027

Что сделал я

  • КодКодовая база — 37 страниц, из них 20 в кабинетах, и 110 переиспользуемых компонентов, покрытых тестами. Сам написал UI-кит и поля форм, кабинеты НКО и доноров, страницы НКО и сбора, главную, каталог, шапку и подвал, раздел модерации.
  • КомандаСтавил задачи и приоритеты четырём фронтенд-разработчикам, ревьюил и сливал PR. Написал регламенты и онбординг-документ, чтобы новые разработчики быстрее входили в проект и писали код в одном стиле.
  • Архитектура и стекВыбрал стек и заложил архитектуру фронтенда. React задал заказчик, а Next.js поверх него отдаёт страницы сборов и НКО готовыми с сервера: их находят поисковики, а донор видит сбор сразу, без ожидания загрузки. TypeScript в строгом режиме, без any и as, ловит ошибки до релиза, а это важно там, где через сайт проходят деньги. Компоненты разложены по слоям ui → form → base → страницы, Server Components по умолчанию, на каждый компонент есть тесты.
  • ПроизводительностьСайт выдерживает в 13 раз больше запросов в секунду, а сервер готовит страницу за 69 мс вместо 919. Для благотворительной платформы это значит, что сайт не тормозит, когда на него разом приходит много доноров, например после рассылки или в большую акцию. Всю оптимизацию провёл сам, от замеров до отчёта.

Контекст

Бизнес

Добро.рф (dobro.ru) — платформа прозрачной благотворительности, генеральный партнёр — Альфа-Банк. Доноры делают разовые и регулярные пожертвования, собирают корзину из нескольких сборов и смотрят историю. НКО и частные организаторы проходят онбординг, загружают документы, создают сборы и следят за статистикой. Модераторы проверяют сборы.

Ситуация

У заказчика уже была платформа, но за основу её не брали. Заказали новую с нуля: с новыми техническими требованиями и полностью новым дизайном. Поэтому архитектуру, дизайн-систему и интеграции строили заново, без наследия старого кода. Разработка идёт с марта 2026 по ТЗ заказчика.

Стек тоже задал заказчик: React. До проекта во фронтенд-команде на React писал только я, поэтому команде нужно было быстро освоить новый стек. При этом интеграций много: цифровой рубль, оплата в модальном окне прямо на сайте, Альфа-Банк, многоступенчатый онбординг НКО.

Процесс, архитектура и решения

Путь пожертвования

Донор может поддержать сразу несколько сборов одной оплатой: деньги распределяются автоматически, вся история остаётся в кабинете.

  1. 01КаталогФильтры по городу, направлению помощи, реестру СО НКО и приёму цифровых рублей. В разработке: каталог с кешем запросов, справочник фильтров вынесен из HTML, чтобы страница грузилась быстрее
  2. 02СборПрогресс, «осталось дней», отчёты и журнал транзакций. В разработке: страница в ISR, она отдаётся готовой и обновляется сама
  3. 03КорзинаНесколько сборов, одна оплата, распределение автоматически. В разработке: состояние корзины в Zustand, одна форма оплаты на все сборы
  4. 04ОплатаКарта в модальном окне на сайте, СБП или цифровой рубль. В разработке: способы оплаты приходят с бэкенда, данные карты вводятся в защищённые поля платёжного шлюза

Онбординг НКО

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

  1. 01ОрганизацияВход через Госуслуги, реквизиты с подсказками. В разработке: подсказки DaData через серверный роут, ключ не попадает в браузер
  2. 02АнкетаСведения об организации. В разработке: формы на react-hook-form и zod, замечания модератора выводятся ошибками полей
  3. 03СчётВход через Alfa ID и открытие счёта. В разработке: подключение Alfa ID и возврат в мастер на тот же шаг
  4. 04ДокументыЗагрузка PDF. В разработке: загрузка файлов с проверкой формата
  5. 05ПодписаниеПодписание документов. В разработке: шаг недоступен, пока не загружены все документы
  6. 06ЗавершениеИтог проверки, в том числе отказ. В разработке: отдельный экран для каждого итога проверки

Архитектура

  • STOREFRONTПубличная витрина

    Главная, каталог сборов, страница сбора, организации, документы. Главная в статике, сборы и НКО в ISR, каталог и организации — динамика с кешем запросов. Публичные страницы отдаются готовыми с сервера: их находят поисковики, а донор быстро открывает сбор по ссылке из соцсетей или рассылки.

  • ACCOUNTSКабинеты

    Кабинеты доноров и НКО, раздел модерации. Данные грузятся на клиенте: SWR и Zustand, формы на react-hook-form и zod. Кабинеты личные и поисковикам не нужны, поэтому данные грузятся в браузере и не нагружают сервер, а проверка форм не даёт отправить анкету с ошибкой.

  • SERVERСерверные роуты Next.js

    Прокси к API, подсказки DaData с ключом только на сервере, метрики приложения. Ключи платных сервисов не попадают в браузер, поэтому их нельзя украсть и потратить лимит, а метрики показывают рост нагрузки раньше, чем его заметят пользователи.

    • app/api/backend
    • app/api/dadata
    • app/metrics
  • APIREST бэкенда

    Типы ответов генерируются из OpenAPI, поэтому фронтенд узнаёт об изменении контракта на typecheck. Расхождения с бэкендом ловятся до релиза, а не на странице оплаты у донора.

Дизайн-система

Макеты рисовали два дизайнера команды в Figma. По ним фронтенд собрал свою дизайн-систему: токены темы, CSS-компоненты кнопок, карточек и полей, 110 переиспользуемых компонентов. Каждый переиспользуемый компонент принимается через Storybook.

Интеграции

  • Банковские карты · защищённые поля шлюза
  • СБП
  • Цифровой рубль
  • Alfa ID
  • Госуслуги
  • DaData
  • Яндекс Метрика

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

Оплата — одна из самых сложных частей платформы: три способа, и у каждого свои правила. Картой донор платит прямо на сайте, в модальном окне, без перехода на страницу банка. Поля для номера карты встраивает платёжный шлюз, поэтому сайт данные карты не видит и не хранит. Через СБП донор подтверждает платёж в приложении своего банка, а сайт дожидается ответа и показывает результат. Цифровой рубль — новая форма денег от Центробанка, и им можно оплатить только разовое пожертвование, а корзину и ежемесячные пожертвования — картой или через СБП. Какие способы доступны, решает бэкенд для каждого сбора и вида пожертвования, и сайт показывает донору только подходящие.

Безопасность данных

Ключ DaData живёт только на сервере, запросы идут через серверный роут. HTTP-клиент не отправляет cookie в кешируемых запросах, поэтому персональный ответ не может попасть в общий кеш. Для частных сборов есть согласие на публикацию персональных данных.

Качество и релизы

Vitest и React Testing Library: 48 файлов, около 450 тест-кейсов, базовые тесты на каждый компонент. Отдельно покрыты швы производительности: cookie и кеш в HTTP-клиенте, кеширование публичных ручек, клиентская загрузка справочников. E2E на Playwright пишет другой разработчик: корзина и пожертвование, авторизация, онбординг НКО.

  1. husky линт и юнит-тесты на пуше
  2. pull request ревью и CI
  3. develop dev-стенд
  4. preprod prod

Проверки на пуше настроил я, GitHub Actions, Docker и деплой — DevOps команды.

Работаем недельными спринтами с демо в конце каждого. Задачи в Jira, ветка на задачу, PR с ревью. Для новых разработчиков есть онбординг-документ: слои, нейминг, паттерны, формы, тесты, Storybook. Для AI-агентов — правила и скиллы проекта: ревью ветки, тесты, токены темы.

Сложности

20 rps на любой странице

Проблема
Корневой layout на каждый запрос ждал два ответа API, до секунды: проверку авторизации и данные шапки, из которых использовалось одно поле. Из-за чтения cookie все 39 маршрутов были динамическими, кеша не было нигде.
Решение
Замерил оба варианта и перенёс авторизацию в клиент: 182 rps против 15,5 у серверного с кешем шапки. Публичные ручки пометил на кеширование с тегами, главную перевёл в статику, страницы сбора и НКО — в ISR, справочник фильтров на 130 КБ вынес из HTML, кабинеты перевёл на клиентскую загрузку, 109 PNG — в webp.
Итог
17 маршрутов: 340 → 4552 rps суммарно, медиана ответа 919 → 69 мс. Статических маршрутов стало 17 и ещё 2 в ISR, HTML каталога похудел с 254 до 169 КБ, картинки в сборке — с 13 до 1,4 МБ.

Ускорение, которое оказалось пустой страницей

Проблема
После перевода страницы сбора в ISR замер показал рост в 15 раз. На деле сервер отдавал пустую оболочку: useSearchParams() ронял страницу в клиентский рендер, в HTML осталось 659 символов текста вместо 2398. Ни typecheck, ни 444 теста этого не поймали.
Решение
Нашёл это сам на ревью своей ветки. Чтение параметра суммы вынесли в эффект, а в регламент добавили проверку маркеров клиентского рендера и объёма видимого текста после перевода маршрута в статику.
Итог
Страница осталась в ISR и держит 196 rps уже с полным контентом.

Метрики и результаты

  • ×13больше запросов в секунду: 340 → 4552 rps
  • 69 мсмедиана ответа вместо 919 мс
  • 100Lighthouse в Accessibility, Best Practices и SEO, Performance 90+
  • 37страниц, из них 20 в кабинетах

Нагрузку мерил autocannon на prod-сборке, 20 соединений. Lighthouse — Unlighthouse по всем страницам сайта. Бизнес-метрик пока нет: платформа ещё не вышла в релиз.

Нужен большой проект на Next.js или команда, которая быстро освоит новый стек?

Заложу архитектуру и регламенты, выстрою работу фронтенд-команды и разгоню сайт под нагрузку.