invin.uz
invin.uz — площадка, где продают и покупают готовый бизнес, франшизы, стартапы и доли в инвестиционных проектах. Веб-версия, админка и мобильные приложения под iOS и Android.
Кейс без прикрас: в основе это обычная доска объявлений, и большая часть работы здесь типовая. Интересного в ней два места — и ещё одно следует из самого предмета торговли.
Данные на снимках — тестовые, интерфейс настоящий. Объявления, имена продавцов и суммы придуманы для проверки; числа про объявления, сделки и пользователей на главной — оформление макета, а не отчёт о работе площадки. Площадка не запущена, считать пока нечего.
Проект не сдан и не запущен. Клиент взял паузу и вернётся, когда будет выводить продукт на рынок.
Мобильные приложения написаны под обе платформы, проверены и работают. В сторах их нет: сборка под публикацию не настраивалась — это последний шаг, и делать его до решения о запуске незачем. Идентификаторы (uz.invin.app) заданы, диплинки на домен прописаны, дальше нужен только клиентский аккаунт разработчика.
Адрес invin.uz на момент написания кейса не отвечает — поэтому ссылки на живой сайт здесь нет.
С этого стоит начать, потому что отсюда растёт всё остальное.
В обычной доске объявлений карточка — это фотографии, описание и цена. Здесь цена — только одно поле из полутора десятков, и далеко не главное. Продавец заполняет:
- среднемесячную выручку, прибыль и расходы;
- рентабельность и срок окупаемости;
- долю, которая продаётся — бизнес нередко продают частями;
- год основания, число сотрудников, площадь;
- форму собственности — ИП, ООО, АО, ЧП, физлицо;
- помещение в собственности или в аренде;
- стадию проекта — для стартапов;
- приложенные документы.
И фильтры соответствующие. Цена в них есть — но она не одна и не главная: рядом рентабельность, срок окупаемости и площадь, а набор полей разный у бизнеса, франшизы, стартапа и инвестиций. Покупатель здесь считает, за сколько лет вернутся деньги, а не выбирает вещь.
Та же модель работает и в обратную сторону. Покупатель подаёт не «куплю бизнес», а такое же объявление со своими цифрами: желаемая доля, желаемый доход, желаемая окупаемость, предпочтительный год основания. Спрос и предложение описаны одинаково — иначе их нельзя было бы искать одним фильтром.
Это не приём и не находка — это следствие того, что читать чужой бизнес по трём фотографиям нельзя. Но именно поэтому готовый движок доски объявлений сюда не встаёт: у него другая модель данных.
Первое из двух мест, ради которых кейс стоит читать.
Человек ищет не «бизнес». Он ищет «купить кафе в Самарканде», «продать франшизу», «инвестиции в производство». Каждый такой запрос — это комбинация четырёх фильтров: тип объявления × продажа или покупка × категория × город.
Под комбинацию заводится отдельная страница со своим H1, своими мета-тегами и своими текстами до и после выдачи. У каждой — уникальный составной ключ из тех же четырёх полей, так что двух страниц на одну комбинацию не бывает.
Арифметика объясняет, почему это нельзя сделать руками. Четыре типа объявлений, три состояния «продажа / покупка / без разбора», 37 категорий плюс «все», 14 городов плюс «все» — 6840 комбинаций. Руками написано 28 страниц: разделы верхнего уровня, ходовые категории и Ташкент. Остальное закрывается механикой.
Механика такая:
- Точное совпадение — если страница под комбинацию есть, отдаётся она.
- Откат к менее точной — нет страницы под «кафе в Намангане», берётся «кафе», а если и её нет, то раздел целиком. Ответ помечается как неточный, чтобы фронт знал, что показывает не своё.
- Заготовка на будущее — если не нашлось ничего, комбинация всё равно записывается в базу как заготовка. Значит, кто-то по ней ходил — потом её заполнят.
Отдельно скажем про то, чего в этой механике нет: заготовка создаётся закрытой от индексации. Пустая страница, автоматически заведённая по чужому клику, не попадает в карту сайта и не уходит в поиск, пока в ней не появится содержимое. Автоматическое размножение пустых страниц — самый быстрый способ испортить сайту выдачу, и здесь этот путь перекрыт по умолчанию.
Где тексты пишет модель, а где ещё нет
Тексты для категорий и городов генерирует Google Gemini — на русском и узбекском (английский пишут руками). В админке задаются ключ, модель и её настройки, там же кнопки проверки связи и пробной генерации; запустить можно и по одной записи, и пачкой, и командой из консоли. А вот сами задания для модели лежат в коде — поменять их без разработчика нельзя, и об этом лучше знать заранее.
Честно про границу: автоматическое заполнение самих комбинаций пока не доделано. Механизм заведён — таблица, ключ, откат, заготовки, флаг индексации, — но команда, которая пройдёт по заготовкам и наполнит их, в коде оставлена явной заглушкой. Это долг, и мы его называем долгом, а не «работой на будущее». Отдельного экрана в админке под эти страницы тоже пока нет: их правят в базе.
Ещё одна граница, помельче. У посадочных страниц в данных стоит отметка «текст завёлся сам» и дата — по ней видно, что человек ещё не перечитывал. У текстов категорий и городов такой отметки нет: кто их написал, модель или редактор, по данным не восстановить.
Второе место, и оно необычнее первого.
Доска объявлений обычно устроена как витрина: посмотрел, позвонил, дальше разбирайтесь сами. Здесь торг встроен в площадку:
- подписка на цену — покупатель отмечает объявление, и когда продавец меняет цену, приходит уведомление;
- история цены — каждое изменение записывается: было, стало, когда и кто поменял. Тому, кто подписался, прямо в карточке рисуется график — но только когда есть что рисовать, то есть начиная со второго изменения. Для бизнеса, который висит в продаже полгода, движение цены говорит больше, чем сама цена;
- встречное предложение — покупатель называет свою сумму прямо в карточке, продавец принимает или отклоняет, обоим приходит уведомление.
Витрина превращается в переговорную площадку. Для сделки, где торг — норма, а не исключение, это ближе к тому, как всё происходит на самом деле.
Снимки объясняют устройство лучше, чем описание. Что на них стоит увидеть:
Главная — четыре витрины. Бизнес, франшиза, стартапы, инвестиции: у каждого своя полка и свой парный переключатель. У бизнеса и франшизы это «продажа / покупка», у стартапов и инвестиций — «поиск инвестора / поиск инвестпроекта». Это одно и то же второе измерение, просто названное словами предмета. Ниже — плитки регионов с числом объявлений в каждом: отсюда попадают на городские посадочные. В шапке переключаются язык (русский, узбекский, английский), валюта и оформление — светлое и тёмное нарисованы оба, поэтому главная показана дважды.
Кабинет продавца. У каждого объявления — статус, «Изменить», сколько дней осталось у продвижения, «Посмотреть статистику», «Предложения цен», «Продано» и «Поместить в архив». В меню рядом — уведомления, избранное и «Отслеживание»: там лежит то, за чьей ценой человек следит, и его собственные отправленные предложения.
Карта. Метки — не булавки, а суммы: видно, сколько стоит бизнес в этой точке, ещё до открытия карточки. Слева список, справа карта, вернуться к обычной выдаче можно одной кнопкой.
Карточка объявления. Вкладки: фото, описание, общая информация, финансы, местоположение. Финансы — шесть плиток: среднемесячные выручка, расходы и прибыль, год основания, окупаемость и доля к продаже. Сбоку — цена, продавец с датой прихода на площадку и три действия: «Контакты продавца», «Предложить цену», «Следить за ценой». Два последних — это и есть торг из предыдущего раздела.
Посадочная под фильтр. «Продажа готового бизнеса в Узбекистане» — не выдача с параметрами в адресе, а страница со своим заголовком, текстом до списка и текстом после него («Как купить бизнес на Invest In»), да ещё с подборкой соседних категорий. Рядом — сортировка, город, категория, цена и кнопка «Ещё фильтры»: за ней окупаемость, рентабельность и площадь. Ровно та механика, о которой выше, только показанная, а не рассказанная.
Подача объявления — шесть шагов. Раздел, тип, информация, оплата, публикация, готово. Язык объявления выбирается отдельно от языка сайта. На снимке — покупка франшизы, и это интереснее продажи: у покупателя те же поля, только со словом «желаемая». Ниже — тумблеры на все случаи: парковка, база клиентов, база поставщиков, оборудование и активы, поставки из-за рубежа, контракты на экспорт, отсутствие кредита, филиалы, а для франшизы ещё международная и мастер-франшиза.
Оплата — про продвижение, а не про размещение. Само объявление разместить бесплатно: шаг оплаты пропускается кнопкой, вернуться к нему можно позже из кабинета. Платно поднятие в топ — на 7, 15 или 30 дней, картой с подтверждением по SMS. Выключатель «платные объявления» в админке есть, но по умолчанию он выключен.
Оба приложения — клиенты к тому же API, что и сайт: каталог, карта, фильтры, кабинет продавца, подача объявления с фотографиями и документами, избранное, статистика по своим объявлениям, платное продвижение, push-уведомления, вход по биометрии, ru / uz / en.
Логику писать заново не пришлось: состояние, слой запросов, формы, валидация и переводы перенесены из веб-версии как есть — менялся платформенный слой, не бизнес-правила. Это скучное решение, и оно правильное: две реализации одних и тех же правил рано или поздно разъезжаются.
Владелец про этот проект сказал: «тут ничего особенного, просто сделали сервис, без упарывания». Раздувать не будем. Вот где сознательно осталось просто:
Поиск — обычный запрос к базе. Ищет вхождение по заголовку и описанию на трёх языках, поисковый движок не ставился, морфологии нет: «кафе» найдётся, «кафешки» — нет. На каталоге, который ещё не запущен, это соразмерно. Когда объявлений станут тысячи — это первое, что придётся менять, и мы об этом предупредили.
Модерация ручная. Объявление уходит к модератору, тот публикует или отклоняет — и причину отказа продавец видит текстом. Очередь на проверку идёт первой. Автоматического антиспама нет, барьер на входе — регистрация по телефону с кодом из SMS (есть ещё вход через Google). А поскольку размещение бесплатное, модератор — единственное, что стоит между площадкой и мусором. Для сделок, где человек торгует своим бизнесом, ручной просмотр — не временная мера, а нормальный режим: цена ошибки тут выше стоимости просмотра.
Платёжка одна. Payme, своя реализация: привязка карты, подтверждение кодом из SMS, оплата продвижения с привязанной карты, приём обратных вызовов. Вторую подключать не стали — до запуска непонятно, нужна ли она.
Автотестов в проекте нет. Ни в бэкенде, ни в вебе, ни в приложениях — проверяли руками. В бэкенде лежат два файла, которые Laravel создаёт сам при установке, и проверяют они, что правда — это правда. Это долг, и записывать его в достоинства мы не будем.
И не может быть: площадка не запущена, посетителей нет, сделок нет, статистики нет. Любое число здесь было бы выдуманным.
Что можно проверить — это устройство, и снимки выше показывают его целиком: модель данных под продажу бизнеса, страницы под комбинации фильтров с откатом и защитой от пустых, торг с историей цены, два мобильных клиента на общей логике с вебом. Остальное покажет запуск, который делает клиент.
Оставьте номер, и мы перезвоним
Одно поле. Расскажете задачу — как удобно: звонком, в Telegram или голосовым. Сразу назовём срок и вилку цены, а на следующий день пришлём три концепции. Бесплатно.