Финтех · MVP
Splitta
Рассрочка для интернет-магазинов: проверка покупателя, график платежей и возврат — на реальных платежах с первого дня.
- Роль
- Продуктовый дизайн, фронтенд, бэкенд, инфраструктура
- Срок
- 7 недель
- Стек
- Next.js · Node.js · Docker
Что изменилось
- 46 дней
- от первой встречи до первого платежа настоящего покупателя. Дату выбирал не проект: магазин входил в сезон на сорок девятый.
- 210 заявок
- за первые шесть недель пилота, 138 из них одобрены. Гипотезу проверяли на них, а не на слайдах.
- 16 возвратов
- каждый девятый оформленный заказ, и график пересчитался сам. Это та часть, которую чуть не отложили во вторую версию.
- 11 минут
- медиана от заявки до решения в рабочие часы. Ночная заявка ждала утра: решение принимает человек, а не правило.
Экономику рассрочки проект не менял и не мог: кому одобрять, на какой срок и на каких условиях — правила заказчика, код их исполняет, а не пишет. И семь недель ничего не доказали про рынок: шесть недель на одном магазине отвечают, держится ли сценарий и правильно ли ходят деньги, а не нужен ли продукт многим. Чем заплачено за скорость, перечислено выше: ручная проверка, отсутствие автотестов за пределами денежных путей, один способ оплаты. Это работа, которую кто-то сделает, а не работа, которая не понадобилась.
Что было до
Продукт собирали с нуля, и параллельно шло подключение к платёжному провайдеру: без боевых ключей рассрочка остаётся презентацией, а дату выдачи ключей назначаем не мы. Заявку провайдеру подали на третий день проекта, раньше первой строки кода. Песочница пришла на девятый день, боевые ключи — на тридцать седьмой, за двенадцать дней до даты, к которой всё должно было работать.
- Рассрочку компания выдавала несколько лет, но только в залах партнёров: решение принимал человек, у которого покупатель стоит перед глазами. Онлайн-заявок не было ни одной, а значит, не было и истории по ним.
- Четыре интернет-магазина сказали «интересно, покажите, как это работает». Показывать было нечего: сценарий существовал на слайдах, а слайдам чекаут не отдают.
- Дату назначил не проект. Партнёрский магазин пускал рассрочку в сезон, до начала которого оставалось сорок девять дней; следующее окно открывалось через полгода, и до него гипотеза просто лежала бы.
Что сделали
Сценарий покупателя: заявка, проверка, график и первый платёж — девять экранов на нашем домене, магазин отдаёт покупателя ссылкой и получает один вебхук.
Платёжный слой за одним интерфейсом: списание, отмена, возврат и повтор с ключом идемпотентности — провайдер меняется конфигурацией, а не переписыванием.
Админка ручной проверки: на время пилота заявку открывает сотрудник заказчика — решение, комментарий и возврат с пересчётом графика в одном месте.
Результат
Сервис вышел в продакшен внутри семи недель: первый платёж настоящего покупателя прошёл на сорок шестой день, за три дня до сезона, ради которого срок и назначался. Проверять стало что — не демонстрацию, а весь путь денег: заявку, отказ банка, повтор, возврат с пересчётом графика. За скорость заплачено ручной проверкой заявок, одним способом оплаты и одним магазином в пилоте; всё это названо ценой заранее, а не найдено после запуска.
Кто заказчик
Финансовая компания, которая выдаёт рассрочку несколько лет — но только в залах партнёров, где напротив покупателя сидит менеджер, а документы лежат на столе. В интернете у неё не было ничего: ни одной заявки, ни истории по заявкам, ни одного подключённого магазина.
В зале решение занимает у менеджера минут двадцать, и половину вопросов можно задать вслух. В браузере от покупателя остаются анкета, карта и несколько секунд терпения. Поэтому проверять предстояло не умение компании считать риск, а две чужие вещи: дойдёт ли покупатель до конца сценария и пустит ли магазин новый способ оплаты в свой чекаут.
Задача
- Как ставил заказчик
- «Сделайте, как у больших»: покупатель нажимает кнопку в чекауте, через секунду видит решение и график. В первую версию просили автоматический скоринг, личный кабинет покупателя и кабинет партнёра, чтобы магазины подключались сами.
- Как задача выглядела после разбора
- Скоринг строить было не на чем. Офлайн-решение опирается на то, что менеджер видит через стол, а онлайн-заявок не существовало: любой порог в первой версии был бы выдумкой за счёт заказчика. Дорогое место оказалось другим — возврат. В этой товарной категории назад едет примерно каждый девятый заказ, а возврат по рассрочке — не отмена платежа, а пересчёт действующего графика. Отсюда другая формулировка: за семь недель делается не продукт для рынка, а один сценарий целиком — на одном магазине, на настоящих деньгах, вместе с ветками, где всё пошло не так. Решение по заявке принимает человек, и это записано в план, а не обнаружено на второй неделе.
Почему нельзя было в лоб
Семь недель — это не скорость, а расписание, составленное чужими решениями. Четыре условия пришли снаружи и не двигались; два мы приняли сами и договорились о них до старта.
- Дата сезона
- Магазин пускал рассрочку с фиксированной даты и ни с какой другой: вне сезона его трафик — около трети, и пилот на нём отвечал бы месяцами. Сорок девять дней — весь бюджет проекта, и занять у конца было нечего: конец принадлежал не нам.
- Боевые ключи провайдера
- Проверку компании перед подключением провайдер ведёт по своему расписанию, а не по нашему плану. Песочница похожа на боевой контур ровно там, где провайдер это обещал, а расходится на отказах, повторах и возвратах, то есть ровно там, где в этом проекте и происходит вся работа.
- Два дня чужого разработчика
- Разработчика магазин мог выделить на два дня, в преддверии своего самого горячего сезона. Всё, что больше ссылки и вебхука, в срок бы не встало, как бы хорошо оно ни выглядело у нас на схеме.
- Каждый девятый заказ возвращают
- В этой категории возврат — обычное дело, а не редкая ветка. Значит, самая дорогая логика проекта попадала в первую версию, а дешёвые части оставались ждать своей очереди.
- Настоящие деньги, а не песочница
- Решение наше. Пилот на тестовых платежах доказал бы, что работает наш код, а не что работает продукт: отказ банка, повтор, частичный возврат, карта, истёкшая между двумя платежами, — всё это живёт только там, где деньги настоящие. Цена — нельзя выкатить «почти работает» и посмотреть, что будет.
- Решение принимает человек
- Тоже наше и тоже до старта: заявку открывает сотрудник заказчика. Один человек проходит около пятидесяти заявок за смену — по три минуты плюс звонок там, где что-то не сходится. На пилоте их было пять, и упирались мы не в число, а в часы: заявка, поданная ночью, ждала утра. Со вторым и третьим магазином ждать пришлось бы уже заметной части покупателей, поэтому пилот с самого начала ограничен одним магазином.
Как шла работа
- 01
Разбор и сценарий
1 неделяПять дней ушло на путь денег: что происходит между «покупатель выбрал рассрочку» и «магазин получил перевод», и каждая ветка, где происходит не это, — отказ, отмена, несостоявшееся списание, возврат. Из недели вышли два решения, определившие остальные шесть: скоринга в первой версии не будет, возврат в неё войдёт. На третий день ушла заявка провайдеру — она всё равно ждала бы дольше кода.
- 02
Платёжный слой и график
1,5 неделиСписание, отмена, возврат и повтор — за одним интерфейсом, чтобы провайдер остался сменной деталью, а не фундаментом. Здесь же арифметика графика: целые копейки, остаток от деления в первый платёж, пересчёт после частичного возврата. Это единственная часть проекта, на которую писали тесты, и первая, которая заработала на песочнице.
- 03
Заявка, проверка, админка
1,5 неделиДевять экранов покупателя на нашем домене и админка, в которой заявку открывает сотрудник заказчика: анкета, результат привязки карты, то, что компания уже знает об этом покупателе, решение и комментарий к нему. Дизайн-систему не заводили: рисовали один сценарий целиком и делали компоненты по мере надобности — на четверых и на семь недель библиотека окупиться не успевает.
- 04
Возврат и пересчёт
1 неделяДорогая неделя, и дорогой она была запланирована. Полный возврат закрывает график и возвращает уплаченное; частичный уменьшает остаток и пересобирает будущие платежи, не трогая прошедшие. Трудность не в формуле: возврат начинает магазин, деньги идут через провайдера, а график живёт у нас — три стороны обязаны сойтись на одной сумме, причём в любом порядке прихода.
- 05
Прод, боевые ключи, первые платежи
2 неделиИнфраструктуру не откладывали на конец: тот же образ, что стоял на стенде, поднимался с первой недели. На тридцать седьмой день пришли боевые ключи, и переход на них занял смену конфигурации с перезапуском. Дальше девять дней своими картами и мелкими суммами: списание, отказ банка, повтор, возврат. Первый платёж настоящего покупателя прошёл на сорок шестой день, за три дня до сезона.
Технические решения
Стек отвечает не задаче вообще, а трём обстоятельствам этого проекта: команда из четырёх человек на два интерфейса, арифметика денег, которая обязана совпадать в трёх местах, и дата боевых ключей, назначенная снаружи.
Провайдер как сменная деталь
Списание, отмена, возврат и статус платежа спрятаны за одним интерфейсом; остальной код знает четыре метода и один набор ошибок. Реализаций две: боевая и второго провайдера, доведённая до песочницы. Вторая нужна была не как запасной аэродром на бумаге, а как проверка интерфейса: пока реализация одна, интерфейс неизбежно повторяет форму первого провайдера. Точку невозврата назначили на сороковой день — нет ключей, переезжаем, четыре дня из оставшихся девяти. Ключи пришли на тридцать седьмой. Сработал бы переезд, мы не знаем.
Деньги целыми, график — записями
Ни одной суммы в дробных числах: только целые копейки. График считается один раз, при оформлении, и ложится в базу отдельными платежами с датами, а не формулой, которую пересчитывают на каждом экране. Остаток от деления кладётся в первый платёж, а не размазывается по всем: тогда сумма графика равна сумме заказа буквально, и это одно сравнение вместо рассуждения об округлении.
Ключ идемпотентности и журнал заявки
Каждый запрос к провайдеру несёт ключ, собранный из идентификатора платежа: повтор после таймаута приходит к тому же платежу, а не заводит второе списание. Каждая смена состояния заявки — строка журнала: кто, когда, что ответил провайдер, чем стало. На настоящих деньгах вопрос «что случилось с этим платежом» задают в тот же день, и отвечать на него походом в поддержку провайдера — значит отвечать завтра.
Ссылка и вебхук вместо SDK
Вся интеграция магазина — подписанная ссылка с составом заказа и суммой, а обратно один вебхук: оформлено или нет. Ключей и графиков магазин не касается. Так вышло не от красоты, а от двух дней его разработчика. Побочный эффект оказался важнее замысла: раз сценарий живёт у нас, он одинаков у всех магазинов и правится без их релизов. Next.js здесь ровно за это — девять экранов покупателя и админка собраны одним приложением, с одним деплоем и одним набором форм.
Один образ, две конфигурации
Стенд и продакшен — один и тот же образ; отличаются они переменными окружения, и ключи провайдера среди них. Поэтому день прихода боевых ключей не стал событием: конфигурация и перезапуск вместо ветки, выкатки и второго круга тестов. Docker здесь не про масштабирование — на пилоте один контейнер и одна база, — а про то, чтобы неизвестная дата снаружи не превращалась в риск внутри.
Что осталось за рамками
Ниже — список того, чего в первой версии нет. Он писался до запуска, а не после: у каждой строки есть причина и цена.
Автоматическое решение по заявке. Правило нельзя написать раньше, чем закроется первый полный цикл платежей: пока ни один график не дошёл до конца, неизвестно, кого одобрили зря. Первые двести заявок с их исходами — материал, а не ответ.
Автотесты за пределами денежных путей. График, возврат и повторы покрыты; админку и боковые экраны проверяли руками. Цена известна: из четырёх дефектов, найденных в первые две недели после запуска, три были в админке.
Подключение магазинов. Второй и третий подключаем мы, руками, примерно за день каждый. Кабинет партнёра, в котором магазин подключается сам, не делали: строить его до того, как сценарий устоялся, — значит закрепить в интерфейсе то, что ещё двигается.
Просрочка. Автоматизированы напоминания; всё, что после них, ведёт человек по правилам заказчика — их писал его юрист, и в код мы их намеренно не переносили.
Способы оплаты. В первой версии одна привязанная карта на весь график. Каждый следующий способ — это ещё одна ветка возврата, а возврат мы уже посчитали самым дорогим местом.
Сейчас в работе: второй магазин и правила автоматического одобрения для самых простых заявок — по данным первых месяцев. Всё, что сложнее правила, по-прежнему открывает человек.
Другие проекты
Производство
Naryado
Мебельное производство: заявка, план цеха и отгрузка идут одним номером. Пять систем, которые уже стояли, обмениваются данными через общий контур, а не через таблицы.
5 систем
работают на одном номере заявки
Python · PostgreSQL · Redis
Логистика
Vezira
Транспортная компания со смешанным автопарком: ассистент понимает запрос диспетчера, собирает данные из CRM, TMS и телематики, проверяет ограничения и делает разрешённое.
3 системы
отвечают на один запрос диспетчера
NestJS · PostgreSQL · OpenAI API
Контакты
Пришлите описание задачи
Ответ с объёмом работ, сроками и оценкой бюджета придёт в течение 24 часов.
Первый звонок — 30 минут, без обязательств с вашей стороны.